diff options
Diffstat (limited to 'locale/programs/ld-collate.c')
-rw-r--r-- | locale/programs/ld-collate.c | 337 |
1 files changed, 275 insertions, 62 deletions
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c index 2858f641d6..ae689e9122 100644 --- a/locale/programs/ld-collate.c +++ b/locale/programs/ld-collate.c @@ -54,6 +54,16 @@ struct section_list enum coll_sort_rule *rules; }; +struct element_t; + +struct element_list_t +{ + /* Number of elements. */ + int cnt; + + struct element_t **w; +}; + /* Data type for collating element. */ struct element_t { @@ -61,7 +71,7 @@ struct element_t const uint32_t *wcs; int order; - struct element_t **weights; + struct element_list_t *weights; /* Where does the definition come from. */ const char *file; @@ -158,16 +168,19 @@ make_seclist_elem (struct locale_collate_t *collate, const char *string, static struct element_t * new_element (struct locale_collate_t *collate, const char *mbs, - const uint32_t *wcs) + size_t len, const uint32_t *wcs) { struct element_t *newp; newp = (struct element_t *) obstack_alloc (&collate->mempool, sizeof (*newp)); - newp->mbs = mbs; + newp->mbs = obstack_copy0 (&collate->mempool, mbs, len); newp->wcs = wcs; newp->order = 0; + /* Will be allocated later. */ + newp->weights = NULL; + newp->file = NULL; newp->line = 0; @@ -404,6 +417,223 @@ read_directions (struct linereader *ldfile, struct token *arg, } +static struct element_t * +find_element (struct linereader *ldfile, struct locale_collate_t *collate, + const char *str, size_t len, uint32_t *wcstr) +{ + struct element_t *result = NULL; + + /* Search for the entries among the collation sequences already define. */ + if (find_entry (&collate->seq_table, str, len, (void **) &result) != 0) + { + /* Nope, not define yet. So we see whether it is a + collation symbol. */ + void *ptr; + + if (find_entry (&collate->sym_table, str, len, &ptr) == 0) + { + /* It's a collation symbol. */ + struct symbol_t *sym = (struct symbol_t *) ptr; + result = sym->order; + + if (result == NULL) + result = sym->order = new_element (collate, str, len, NULL); + } + else if (find_entry (&collate->elem_table, str, len, + (void **) &result) != 0) + { + /* It's also no collation element. So it is an element defined + later. */ + result = new_element (collate, str, len, wcstr); + if (result != NULL) + /* Insert it into the sequence table. */ + insert_entry (&collate->seq_table, str, len, result); + } + } + + return result; +} + + +static void +insert_weights (struct linereader *ldfile, struct element_t *elem, + struct charmap_t *charmap, struct repertoire_t *repertoire, + struct locale_collate_t *collate) +{ + int weight_cnt; + struct token *arg; + + /* Initialize all the fields. */ + elem->file = ldfile->fname; + elem->line = ldfile->lineno; + elem->last = collate->cursor; + elem->next = collate->cursor ? collate->cursor->next : NULL; + elem->weights = (struct element_list_t *) + obstack_alloc (&collate->mempool, nrules * sizeof (struct element_list_t)); + memset (elem->weights, '\0', nrules * sizeof (struct element_list_t)); + + if (collate->current_section->first == NULL) + collate->current_section->first = elem; + if (collate->current_section->last == collate->cursor) + collate->current_section->last = elem; + + collate->cursor = elem; + + weight_cnt = 0; + + arg = lr_token (ldfile, charmap, repertoire); + do + { + if (arg->tok == tok_eof || arg->tok == tok_eol) + break; + + if (arg->tok == tok_ignore) + { + /* The weight for this level has to be ignored. We use the + null pointer to indicate this. */ + elem->weights[weight_cnt].w = (struct element_t **) + obstack_alloc (&collate->mempool, sizeof (struct element_t *)); + elem->weights[weight_cnt].w[0] = NULL; + elem->weights[weight_cnt].cnt = 0; + } + else if (arg->tok == tok_bsymbol) + { + struct element_t *val = find_element (ldfile, collate, + arg->val.str.startmb, + arg->val.str.lenmb, + arg->val.str.startwc); + + if (val == NULL) + break; + + elem->weights[weight_cnt].w = (struct element_t **) + obstack_alloc (&collate->mempool, sizeof (struct element_t *)); + elem->weights[weight_cnt].w[0] = val; + elem->weights[weight_cnt].cnt = 1; + } + else if (arg->tok == tok_string) + { + /* Split the string up in the individual characters and put + the element definitions in the list. */ + const char *cp = arg->val.str.startmb; + int cnt = 0; + struct element_t *charelem; + void *base = obstack_base (&collate->mempool); + + if (*cp == '\0') + { + lr_error (ldfile, _("%s: empty weight string not allowed"), + "LC_COLLATE"); + lr_ignore_rest (ldfile, 0); + break; + } + + do + { + if (*cp == '<') + { + /* Ahh, it's a bsymbol. That's what we want. */ + const char *startp = cp; + + while (*++cp != '>') + { + if (*cp == ldfile->escape_char) + ++cp; + if (*cp == '\0') + { + /* It's a syntax error. */ + obstack_free (&collate->mempool, base); + goto syntax; + } + } + + charelem = find_element (ldfile, collate, startp, + cp - startp, NULL); + ++cp; + } + else + { + /* People really shouldn't use characters directly in + the string. Especially since it's not really clear + what this means. We interpret all characters in the + string as if that would be bsymbols. Otherwise we + would have to match back to bsymbols somehow and this + is also not what people normally expect. */ + charelem = find_element (ldfile, collate, cp++, 1, NULL); + } + + if (charelem == NULL) + { + /* We ignore the rest of the line. */ + lr_ignore_rest (ldfile, 0); + break; + } + + /* Add the pointer. */ + obstack_ptr_grow (&collate->mempool, charelem); + ++cnt; + } + while (*cp != '\0'); + + /* Now store the information. */ + elem->weights[weight_cnt].w = (struct element_t **) + obstack_finish (&collate->mempool); + elem->weights[weight_cnt].cnt = cnt; + + /* We don't need the string anymore. */ + free (arg->val.str.startmb); + } + else + { + syntax: + /* It's a syntax error. */ + lr_error (ldfile, _("%s: syntax error"), "LC_COLLATE"); + lr_ignore_rest (ldfile, 0); + break; + } + + arg = lr_token (ldfile, charmap, repertoire); + /* This better should be the end of the line or a semicolon. */ + if (arg->tok == tok_semicolon) + /* OK, ignore this and read the next token. */ + arg = lr_token (ldfile, charmap, repertoire); + else if (arg->tok != tok_eof && arg->tok != tok_eol) + { + /* It's a syntax error. */ + lr_error (ldfile, _("%s: syntax error"), "LC_COLLATE"); + lr_ignore_rest (ldfile, 0); + break; + } + } + while (++weight_cnt < nrules); + + if (weight_cnt < nrules) + { + /* This means the rest of the line uses the current element as + the weight. */ + do + { + elem->weights[weight_cnt].w = (struct element_t **) + obstack_alloc (&collate->mempool, sizeof (struct element_t *)); + elem->weights[weight_cnt].w[0] = elem; + elem->weights[weight_cnt].cnt = 1; + } + while (++weight_cnt < nrules); + } + else + { + if (arg->tok == tok_ignore || arg->tok == tok_bsymbol) + { + /* Too many rule values. */ + lr_error (ldfile, _("%s: too many values"), "LC_COLLATE"); + lr_ignore_rest (ldfile, 0); + } + else + lr_ignore_rest (ldfile, arg->tok != tok_eol && arg->tok != tok_eof); + } +} + + static void insert_value (struct linereader *ldfile, struct token *arg, struct charmap_t *charmap, struct repertoire_t *repertoire, @@ -413,7 +643,6 @@ insert_value (struct linereader *ldfile, struct token *arg, struct charseq *seq; uint32_t wc; struct element_t *elem = NULL; - int weight_cnt; /* First determine the wide character. There must be such a value, otherwise we ignore it (if it is no collatio symbol or element). */ @@ -438,24 +667,36 @@ insert_value (struct linereader *ldfile, struct token *arg, if (elem == NULL) elem = sym->order = new_element (collate, arg->val.str.startmb, + arg->val.str.lenmb, arg->val.str.startwc); } else if (find_entry (&collate->elem_table, arg->val.str.startmb, arg->val.str.lenmb, (void **) &elem) != 0) - /* It's also no collation element. Therefore ignore it. */ - return; + { + /* It's also no collation element. Therefore ignore it. */ + lr_ignore_rest (ldfile, 0); + return; + } } else { - /* Otherwise the symbols stands for an character. Make sure it is - not already in the table. */ - + /* Otherwise the symbols stands for a character. */ + if (find_entry (&collate->seq_table, arg->val.str.startmb, + arg->val.str.lenmb, (void **) &elem) != 0) + { + /* We have to allocate an entry. */ + elem = new_element (collate, arg->val.str.startmb, + arg->val.str.lenmb, + arg->val.str.startwc); + + /* And add it to the table. */ + if (insert_entry (&collate->seq_table, arg->val.str.startmb, + arg->val.str.lenmb, elem) != 0) + /* This cannot happen. */ + abort (); + } } - if (elem == NULL) - /* XXX HACK HACK HACK */ - return; - /* Test whether this element is not already in the list. */ if (elem->next != NULL || (collate->cursor != NULL && elem->next == collate->cursor)) @@ -463,57 +704,11 @@ insert_value (struct linereader *ldfile, struct token *arg, lr_error (ldfile, _("order for `%.*s' already defined at %s:%Z"), arg->val.str.lenmb, arg->val.str.startmb, elem->file, elem->line); + lr_ignore_rest (ldfile, 0); return; } - /* Initialize all the fields. */ - elem->file = ldfile->fname; - elem->line = ldfile->lineno; - elem->last = collate->cursor; - elem->next = collate->cursor ? collate->cursor->next : NULL; - elem->weights = (struct element_t **) - obstack_alloc (&collate->mempool, nrules * sizeof (struct element_t *)); - memset (elem->weights, '\0', nrules * sizeof (struct element_t *)); - - if (collate->current_section->first == NULL) - collate->current_section->first = elem; - if (collate->current_section->last == collate->cursor) - collate->current_section->last = elem; - - collate->cursor = elem; - - /* Now read the rest of the line. */ - ldfile->return_widestr = 1; - - weight_cnt = 0; - do - { - arg = lr_token (ldfile, charmap, repertoire); - - if (arg->tok == tok_eof || arg->tok == tok_eol) - { - /* This means the rest of the line uses the current element - as the weight. */ - do - elem->weights[weight_cnt] = elem; - while (++weight_cnt < nrules); - - return; - } - - if (arg->tok == tok_ignore) - { - /* The weight for this level has to be ignored. We use the - null pointer to indicate this. */ - } - else if (arg->tok == tok_bsymbol) - { - - } - } - while (++weight_cnt < nrules); - - lr_ignore_rest (ldfile, weight_cnt == nrules); + insert_weights (ldfile, elem, charmap, repertoire, collate); } @@ -749,6 +944,7 @@ collate_read (struct linereader *ldfile, struct localedef_t *result, symbol, symbol_len, new_element (collate, arg->val.str.startmb, + arg->val.str.lenmb, arg->val.str.startwc)) < 0) lr_error (ldfile, _("\ @@ -994,6 +1190,9 @@ error while adding equivalent collating symbol")); /* Now read the direction names. */ read_directions (ldfile, arg, charmap, repertoire, collate); + + /* From now be need the strings untranslated. */ + ldfile->translate_strings = 0; break; case tok_order_end: @@ -1099,7 +1298,21 @@ error while adding equivalent collating symbol")); if (state != 1) goto err_label; - /* XXX handle UNDEFINED weight */ + + /* See whether UNDEFINED already appeared somewhere. */ + if (collate->undefined.next != NULL + || (collate->cursor != NULL + && collate->undefined.next == collate->cursor)) + { + lr_error (ldfile, _("order for `%.*s' already defined at %s:%Z"), + 9, "UNDEFINED", collate->undefined.file, + collate->undefined.line); + lr_ignore_rest (ldfile, 0); + } + else + /* Parse the weights. */ + insert_weights (ldfile, &collate->undefined, charmap, + repertoire, collate); break; case tok_ellipsis3: |