summaryrefslogtreecommitdiff
path: root/locale/programs/ld-collate.c
diff options
context:
space:
mode:
Diffstat (limited to 'locale/programs/ld-collate.c')
-rw-r--r--locale/programs/ld-collate.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c
index d6c3de0147..6d8f3fb2f0 100644
--- a/locale/programs/ld-collate.c
+++ b/locale/programs/ld-collate.c
@@ -181,6 +181,14 @@ struct symbol_t
#include "3level.h"
+/* Simple name list for the preprocessor. */
+struct name_list
+{
+ struct name_list *next;
+ char str[0];
+};
+
+
/* The real definition of the struct for the LC_COLLATE locale. */
struct locale_collate_t
{
@@ -240,6 +248,15 @@ struct locale_collate_t
/* The arrays with the collation sequence order. */
unsigned char mbseqorder[256];
struct collseq_table wcseqorder;
+
+ /* State of the preprocessor. */
+ enum
+ {
+ else_none = 0,
+ else_ignore,
+ else_seen
+ }
+ else_action;
};
@@ -247,6 +264,9 @@ struct locale_collate_t
LC_COLLATE category descriptions in all files. */
static uint32_t nrules;
+/* List of defined preprocessor symbols. */
+static struct name_list *defined;
+
/* We need UTF-8 encoding of numbers. */
static inline int
@@ -2622,6 +2642,43 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap,
}
+static enum token_t
+skip_to (struct linereader *ldfile, struct locale_collate_t *collate,
+ const struct charmap_t *charmap, int to_endif)
+{
+ while (1)
+ {
+ struct token *now = lr_token (ldfile, charmap, NULL, NULL, 0);
+ enum token_t nowtok = now->tok;
+
+ if (nowtok == tok_eof || nowtok == tok_end)
+ return nowtok;
+
+ if (nowtok == tok_ifdef || nowtok == tok_ifndef)
+ {
+ lr_error (ldfile, _("%s: nested conditionals not supported"),
+ "LC_COLLATE");
+ nowtok = skip_to (ldfile, collate, charmap, tok_endif);
+ if (nowtok == tok_eof || nowtok == tok_end)
+ return nowtok;
+ }
+ else if ((!to_endif && (nowtok == tok_else || nowtok == tok_elifdef
+ || nowtok == tok_elifndef))
+ || nowtok == tok_endif)
+ {
+ lr_ignore_rest (ldfile, 1);
+ return nowtok;
+ }
+ else if (nowtok == tok_else)
+ {
+ lr_error (ldfile, _("%s: more then one 'else'"), "LC_COLLATE");
+ }
+
+ lr_ignore_rest (ldfile, 0);
+ }
+}
+
+
void
collate_read (struct linereader *ldfile, struct localedef_t *result,
const struct charmap_t *charmap, const char *repertoire_name,
@@ -2659,6 +2716,38 @@ collate_read (struct linereader *ldfile, struct localedef_t *result,
}
while (nowtok == tok_eol);
+ while (nowtok == tok_define)
+ {
+ if (ignore_content)
+ {
+ lr_ignore_rest (ldfile, 0);
+ continue;
+ }
+
+ arg = lr_token (ldfile, charmap, result, NULL, verbose);
+ if (arg->tok != tok_ident)
+ SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+ else
+ {
+ /* Simply add the new symbol. */
+ struct name_list *newsym = xmalloc (sizeof (*newsym)
+ + arg->val.str.lenmb + 1);
+ memcpy (newsym->str, arg->val.str.startmb, arg->val.str.lenmb);
+ newsym->str[arg->val.str.lenmb] = '\0';
+ newsym->next = defined;
+ defined = newsym;
+
+ 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);
@@ -3798,6 +3887,7 @@ error while adding equivalent collating symbol"));
break;
case tok_end:
+ seen_end:
/* Next we assume `LC_COLLATE'. */
if (!ignore_content)
{
@@ -3838,6 +3928,180 @@ error while adding equivalent collating symbol"));
lr_ignore_rest (ldfile, arg->tok == tok_lc_collate);
return;
+ case tok_define:
+ 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;
+
+ /* Simply add the new symbol. */
+ struct name_list *newsym = xmalloc (sizeof (*newsym)
+ + arg->val.str.lenmb + 1);
+ memcpy (newsym->str, arg->val.str.startmb, arg->val.str.lenmb);
+ newsym->str[arg->val.str.lenmb] = '\0';
+ newsym->next = defined;
+ defined = newsym;
+
+ lr_ignore_rest (ldfile, 1);
+ break;
+
+ case tok_undef:
+ 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;
+
+ /* Remove _all_ occurrences of the symbol from the list. */
+ struct name_list *prevdef = NULL;
+ struct name_list *curdef = defined;
+ while (curdef != NULL)
+ if (strncmp (arg->val.str.startmb, curdef->str,
+ arg->val.str.lenmb) == 0
+ && curdef->str[arg->val.str.lenmb] == '\0')
+ {
+ if (prevdef == NULL)
+ defined = curdef->next;
+ else
+ prevdef->next = curdef->next;
+
+ struct name_list *olddef = curdef;
+ curdef = curdef->next;
+
+ free (olddef);
+ }
+ else
+ {
+ prevdef = curdef;
+ curdef = curdef->next;
+ }
+
+ lr_ignore_rest (ldfile, 1);
+ break;
+
+ case tok_ifdef:
+ case tok_ifndef:
+ if (ignore_content)
+ {
+ lr_ignore_rest (ldfile, 0);
+ break;
+ }
+
+ found_ifdef:
+ arg = lr_token (ldfile, charmap, result, NULL, verbose);
+ if (arg->tok != tok_ident)
+ goto err_label;
+ lr_ignore_rest (ldfile, 1);
+
+ if (collate->else_action == else_none)
+ {
+ curdef = defined;
+ while (curdef != NULL)
+ if (strncmp (arg->val.str.startmb, curdef->str,
+ arg->val.str.lenmb) == 0
+ && curdef->str[arg->val.str.lenmb] == '\0')
+ break;
+
+ if ((nowtok == tok_ifdef && curdef != NULL)
+ || (nowtok == tok_ifndef && curdef == NULL))
+ {
+ /* We have to use the if-branch. */
+ collate->else_action = else_ignore;
+ }
+ else
+ {
+ /* We have to use the else-branch, if there is one. */
+ nowtok = skip_to (ldfile, collate, charmap, 0);
+ if (nowtok == tok_else)
+ collate->else_action = else_seen;
+ else if (nowtok == tok_elifdef)
+ {
+ nowtok = tok_ifdef;
+ goto found_ifdef;
+ }
+ else if (nowtok == tok_elifndef)
+ {
+ nowtok = tok_ifndef;
+ goto found_ifdef;
+ }
+ else if (nowtok == tok_eof)
+ goto seen_eof;
+ else if (nowtok == tok_end)
+ goto seen_end;
+ }
+ }
+ else
+ {
+ /* XXX Should it really become necessary to support nested
+ preprocessor handling we will push the state here. */
+ lr_error (ldfile, _("%s: nested conditionals not supported"),
+ "LC_COLLATE");
+ nowtok = skip_to (ldfile, collate, charmap, 1);
+ if (nowtok == tok_eof)
+ goto seen_eof;
+ else if (nowtok == tok_end)
+ goto seen_end;
+ }
+ break;
+
+ case tok_elifdef:
+ case tok_elifndef:
+ case tok_else:
+ if (ignore_content)
+ {
+ lr_ignore_rest (ldfile, 0);
+ break;
+ }
+
+ lr_ignore_rest (ldfile, 1);
+
+ if (collate->else_action == else_ignore)
+ {
+ /* Ignore everything until the endif. */
+ nowtok = skip_to (ldfile, collate, charmap, 1);
+ if (nowtok == tok_eof)
+ goto seen_eof;
+ else if (nowtok == tok_end)
+ goto seen_end;
+ }
+ else
+ {
+ assert (collate->else_action == else_none);
+ lr_error (ldfile, _("\
+%s: '%s' without matching 'ifdef' or 'ifndef'"), "LC_COLLATE",
+ nowtok == tok_else ? "else"
+ : nowtok == tok_elifdef ? "elifdef" : "elifndef");
+ }
+ break;
+
+ case tok_endif:
+ if (ignore_content)
+ {
+ lr_ignore_rest (ldfile, 0);
+ break;
+ }
+
+ lr_ignore_rest (ldfile, 1);
+
+ if (collate->else_action != else_ignore
+ && collate->else_action != else_seen)
+ lr_error (ldfile, _("\
+%s: 'endif' without matching 'ifdef' or 'ifndef'"), "LC_COLLATE");
+
+ /* XXX If we support nested preprocessor directives we pop
+ the state here. */
+ collate->else_action = else_none;
+ break;
+
default:
err_label:
SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
@@ -3848,6 +4112,7 @@ error while adding equivalent collating symbol"));
nowtok = now->tok;
}
+ seen_eof:
/* When we come here we reached the end of the file. */
lr_error (ldfile, _("%s: premature end of file"), "LC_COLLATE");
}