[PATCH 4/7] localedef: allow preprocessor-like directives
From: Denis Barbier <bouzim@gmail.com>
Date: Tue, 19 Jun 2007 05:27:33 -0500
These keywords were already defined in locale/programs/locfile-kw.h,
an implementation for 'define', 'undef', 'ifdef', 'else' and 'endif'
is now provided in locale/programs/ld-collate.c. For the moment,
'ifndef' and 'elif' are not implemented because they do not appear in
locfile-kw.h.
Originally from belocs-locales-bin 2.3.3-13, 2005-01-20.
[madcoder@debian.org, 2007-06-19: updated it to work (with restrictions)
with depth >= 2 copies. The patch is scurvy and makes locale parsing
completely non reentrant. Motivated by the am_ET locale.]
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
locale/programs/ld-collate.c | 275 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 275 insertions(+), 0 deletions(-)
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index 4f94b24..7d1455a 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -160,6 +160,24 @@ struct symbol_t
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 *
@@ -215,6 +233,9 @@ struct locale_collate_t
/* This value is used when handling ellipsis. */
struct element_t ellipsis_weight;
+ /* This is a stack of . */
+ struct toggle_list_t *flow_control;
+
/* Known collating elements. */
hash_table elem_table;
@@ -1460,6 +1481,56 @@ order for `%.*s' already defined at %s:%Zu"),
}
+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:%Zu' 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:%Zu"),
+ "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)
@@ -2658,6 +2729,8 @@ collate_read (struct linereader *ldfile, struct localedef_t *result,
*/
int state = 0;
+ static struct toggle_list_t *defined_keywords = NULL;
+
/* Get the repertoire we have to use. */
if (repertoire_name != NULL)
repertoire = repertoire_read (repertoire_name);
@@ -2672,6 +2745,82 @@ collate_read (struct linereader *ldfile, struct localedef_t *result,
}
while (nowtok == tok_eol);
+ while (nowtok == tok_define || nowtok == 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);
+ now = lr_token (ldfile, charmap, result, NULL, verbose);
+ nowtok = now->tok;
+ continue;
+ }
+
+ arg = lr_token (ldfile, charmap, result, NULL, verbose);
+ if (arg->tok != tok_ident)
+ goto err_label;
+
+ if (nowtok == tok_define)
+ {
+ struct toggle_list_t *runp = 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')
+ SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+ else
+ runp = runp->last;
+
+ if (runp != NULL && runp->is_undefined == 0)
+ {
+ lr_ignore_rest (ldfile, 0);
+ SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+ }
+
+ if (runp == NULL)
+ {
+ runp = (struct toggle_list_t *) xcalloc (1, sizeof (*runp));
+ runp->last = defined_keywords;
+ 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;
+ }
+ else
+ {
+ struct toggle_list_t *runp = 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;
+ SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+ }
+ else
+ runp = runp->last;
+ }
+
+ lr_ignore_rest (ldfile, 1);
+ do
+ {
+ now = lr_token (ldfile, charmap, result, NULL, verbose);
+ nowtok = now->tok;
+ }
+ while (nowtok == tok_eol);
+ }
+
if (nowtok == tok_copy)
{
now = lr_token (ldfile, charmap, result, NULL, verbose);
@@ -3826,6 +3975,125 @@ error while adding equivalent collating symbol"));
repertoire, result, nowtok);
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 = 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 = 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:%Zu' 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)
@@ -3855,6 +4123,13 @@ error while adding equivalent collating symbol"));
else if (state == 5)
WITH_CUR_LOCALE (error (0, 0, _("\
%s: missing `reorder-sections-end' keyword"), "LC_COLLATE"));
+ if (collate->flow_control != NULL
+ && strcmp(collate->flow_control->file, ldfile->fname) == 0)
+ WITH_CUR_LOCALE (error (0, 0, _("\
+%s: unterminated `%s' flow control beginning at %s:%Zu"),
+ "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)
--
1.7.5.1
Reply to: