Index: libc/locale/programs/ld-collate.c =================================================================== --- libc.orig/locale/programs/ld-collate.c +++ libc/locale/programs/ld-collate.c @@ -161,6 +161,24 @@ size_t line; }; +/* Data type for toggles. */ +struct toggle_list_t; + +struct toggle_list_t +{ + const char *name; + + /* Predecessor in the list. */ + struct toggle_list_t *last; + + /* This flag is set when a keyword is undefined. */ + int is_undefined; + + /* Where does the branch come from. */ + const char *file; + size_t line; +}; + /* Sparse table of struct element_t *. */ #define TABLE wchead_table #define ELEMENT struct element_t * @@ -214,6 +232,12 @@ /* This value is used when handling ellipsis. */ struct element_t ellipsis_weight; + /* Known keywords. */ + struct toggle_list_t *defined_keywords; + + /* This is a stack of toggle branches. */ + struct toggle_list_t *flow_control; + /* Known collating elements. */ hash_table elem_table; @@ -1456,6 +1480,56 @@ } +static struct token * +flow_skip (struct linereader *ldfile, const struct charmap_t *charmap, + struct locale_collate_t *collate) +{ + int level = 0; + struct token *now; + enum token_t nowtok; + while (1) + { + lr_ignore_rest (ldfile, 0); + now = lr_token (ldfile, charmap, NULL, NULL, 0); + nowtok = now->tok; + if (nowtok == tok_eof) + break; + else if (nowtok == tok_ifdef || nowtok == tok_ifndef) + ++level ; + else if (nowtok == tok_else) + { + if (strcmp (collate->flow_control->name, "else") == 0) + lr_error (ldfile, + _("%s: `else' statement at `%s:%d' cannot be followed by another `else' statement"), + "LC_COLLATE", collate->flow_control->name, collate->flow_control->line); + if (level == 0) + { + collate->flow_control->name = "else"; + collate->flow_control->file = ldfile->fname; + collate->flow_control->line = ldfile->lineno; + break; + } + } + else if (nowtok == tok_endif) + { + if (level == 0) + { + collate->flow_control = collate->flow_control->last; + break; + } + --level ; + } + } + if (nowtok == tok_eof) + WITH_CUR_LOCALE (error (0, 0, _("\ +%s: unterminated `%s' flow control beginning at %s:%d"), + "LC_COLLATE", collate->flow_control->name, + collate->flow_control->file, + collate->flow_control->line)); + return now; +} + + static void collate_startup (struct linereader *ldfile, struct localedef_t *locale, struct localedef_t *copy_locale, int ignore_content) @@ -3770,6 +3844,205 @@ repertoire, result, nowtok); break; + case tok_define: + /* Ignore the rest of the line if we don't need the input of + this line. */ + if (ignore_content) + { + lr_ignore_rest (ldfile, 0); + break; + } + + arg = lr_token (ldfile, charmap, result, NULL, verbose); + if (arg->tok != tok_ident) + goto err_label; + else + { + struct toggle_list_t *runp = collate->defined_keywords; + char *name; + + while (runp != NULL) + if (strncmp (runp->name, arg->val.str.startmb, + arg->val.str.lenmb) == 0 + && runp->name[arg->val.str.lenmb] == '\0') + break; + else + runp = runp->last; + + if (runp != NULL && runp->is_undefined == 0) + { + lr_ignore_rest (ldfile, 0); + break; + } + + if (runp == NULL) + { + runp = (struct toggle_list_t *) xcalloc (1, sizeof (*runp)); + runp->last = collate->defined_keywords; + collate->defined_keywords = runp; + } + else + { + free ((char *) runp->name); + runp->is_undefined = 0; + } + + name = (char *) xmalloc (arg->val.str.lenmb + 1); + memcpy (name, arg->val.str.startmb, arg->val.str.lenmb); + name[arg->val.str.lenmb] = '\0'; + runp->name = name; + } + lr_ignore_rest (ldfile, 1); + break; + + case tok_undef: + /* Ignore the rest of the line if we don't need the input of + this line. */ + if (ignore_content) + { + lr_ignore_rest (ldfile, 0); + break; + } + + arg = lr_token (ldfile, charmap, result, NULL, verbose); + if (arg->tok != tok_ident) + goto err_label; + else + { + struct toggle_list_t *runp = collate->defined_keywords; + while (runp != NULL) + if (strncmp (runp->name, arg->val.str.startmb, + arg->val.str.lenmb) == 0 + && runp->name[arg->val.str.lenmb] == '\0') + { + runp->is_undefined = 1; + break; + } + else + runp = runp->last; + } + lr_ignore_rest (ldfile, 1); + break; + + case tok_ifdef: + /* Ignore the rest of the line if we don't need the input of + this line. */ + if (ignore_content) + { + lr_ignore_rest (ldfile, 0); + break; + } + + arg = lr_token (ldfile, charmap, result, NULL, verbose); + if (arg->tok != tok_ident) + goto err_label; + else + { + struct toggle_list_t *runp = collate->defined_keywords; + struct toggle_list_t *flow = (struct toggle_list_t *) xcalloc (1, sizeof (*runp)); + flow->name = "ifdef"; + flow->file = ldfile->fname; + flow->line = ldfile->lineno; + flow->last = collate->flow_control; + collate->flow_control = flow; + + while (runp != NULL) + if (strncmp (runp->name, arg->val.str.startmb, + arg->val.str.lenmb) == 0 + && runp->name[arg->val.str.lenmb] == '\0') + break; + else + runp = runp->last; + + if (runp == NULL) + { + now = flow_skip(ldfile, charmap, collate); + if (now->tok == tok_eof) + WITH_CUR_LOCALE (error (0, 0, _("\ +%s: unterminated `%s' flow control"), "LC_COLLATE", collate->flow_control->name)); + } + } + lr_ignore_rest (ldfile, 1); + break; + + case tok_ifndef: + /* Ignore the rest of the line if we don't need the input of + this line. */ + if (ignore_content) + { + lr_ignore_rest (ldfile, 0); + break; + } + + arg = lr_token (ldfile, charmap, result, NULL, verbose); + if (arg->tok != tok_ident) + goto err_label; + else + { + struct toggle_list_t *runp = collate->defined_keywords; + struct toggle_list_t *flow = (struct toggle_list_t *) xcalloc (1, sizeof (*runp)); + flow->name = "ifndef"; + flow->file = ldfile->fname; + flow->line = ldfile->lineno; + flow->last = collate->flow_control; + collate->flow_control = flow; + + while (runp != NULL) + if (strncmp (runp->name, arg->val.str.startmb, + arg->val.str.lenmb) == 0 + && runp->name[arg->val.str.lenmb] == '\0') + break; + else + runp = runp->last; + + if (runp != NULL) + { + now = flow_skip(ldfile, charmap, collate); + if (now->tok == tok_eof) + WITH_CUR_LOCALE (error (0, 0, _("\ +%s: unterminated `%s' flow control"), "LC_COLLATE", collate->flow_control->name)); + } + } + lr_ignore_rest (ldfile, 1); + break; + + case tok_else: + /* Ignore the rest of the line if we don't need the input of + this line. */ + if (ignore_content) + { + lr_ignore_rest (ldfile, 0); + break; + } + + if (strcmp (collate->flow_control->name, "else") == 0) + lr_error (ldfile, + _("%s: `else' statement at `%s:%d' cannot be followed by another `else' statement"), + "LC_COLLATE", collate->flow_control->name, collate->flow_control->line); + collate->flow_control->name = "else"; + collate->flow_control->file = ldfile->fname; + collate->flow_control->line = ldfile->lineno; + now = flow_skip(ldfile, charmap, collate); + if (now->tok == tok_eof) + WITH_CUR_LOCALE (error (0, 0, _("\ +%s: unterminated `%s' flow control"), "LC_COLLATE", collate->flow_control->name)); + break; + + case tok_endif: + /* Ignore the rest of the line if we don't need the input of + this line. */ + if (ignore_content) + { + lr_ignore_rest (ldfile, 0); + break; + } + + if (collate->flow_control == NULL) + goto err_label; + else + collate->flow_control = collate->flow_control->last; + break; + case tok_end: /* Next we assume `LC_COLLATE'. */ if (!ignore_content) @@ -3799,6 +4072,12 @@ else if (state == 5) WITH_CUR_LOCALE (error (0, 0, _("\ %s: missing `reorder-sections-end' keyword"), "LC_COLLATE")); + if (collate->flow_control != NULL) + WITH_CUR_LOCALE (error (0, 0, _("\ +%s: unterminated `%s' flow control beginning at %s:%d"), + "LC_COLLATE", collate->flow_control->name, + collate->flow_control->file, + collate->flow_control->line)); } arg = lr_token (ldfile, charmap, result, NULL, verbose); if (arg->tok == tok_eof)