static struct convtable * use_both_charmaps (struct charmap_t *from_charmap, struct charmap_t *to_charmap) { /* In this case we iterate over all the entries in the from_charmap, determine the internal name, and find an appropriate entry in the to_charmap (if it exists). */ struct convtable *rettbl = allocate_table (); void *ptr = NULL; const void *key; size_t keylen; void *data; while (iterate_table (&from_charmap->char_table, &ptr, &key, &keylen, &data) >= 0) { struct charseq *in = (struct charseq *) data; struct charseq *out = charmap_find_value (to_charmap, key, keylen); if (out != NULL) add_bytes (rettbl, in, out); } return rettbl; }
static struct token * get_string (struct linereader *lr, const struct charmap_t *charmap, struct localedef_t *locale, const struct repertoire_t *repertoire, int verbose) { int return_widestr = lr->return_widestr; char *buf; wchar_t *buf2 = NULL; size_t bufact; size_t bufmax = 56; /* We must return two different strings. */ buf = xmalloc (bufmax); bufact = 0; /* We know it'll be a string. */ lr->token.tok = tok_string; /* If we need not translate the strings (i.e., expand <...> parts) we can run a simple loop. */ if (!lr->translate_strings) { int ch; buf2 = NULL; while ((ch = lr_getc (lr)) != '"' && ch != '\n' && ch != EOF) ADDC (ch); /* Catch errors with trailing escape character. */ if (bufact > 0 && buf[bufact - 1] == lr->escape_char && (bufact == 1 || buf[bufact - 2] != lr->escape_char)) { lr_error (lr, _("illegal escape sequence at end of string")); --bufact; } else if (ch == '\n' || ch == EOF) lr_error (lr, _("unterminated string")); ADDC ('\0'); } else { int illegal_string = 0; size_t buf2act = 0; size_t buf2max = 56 * sizeof (uint32_t); int ch; int warned = 0; /* We have to provide the wide character result as well. */ if (return_widestr) buf2 = xmalloc (buf2max); /* Read until the end of the string (or end of the line or file). */ while ((ch = lr_getc (lr)) != '"' && ch != '\n' && ch != EOF) { size_t startidx; uint32_t wch; struct charseq *seq; if (ch != '<') { /* The standards leave it up to the implementation to decide what to do with character which stand for themself. We could jump through hoops to find out the value relative to the charmap and the repertoire map, but instead we leave it up to the locale definition author to write a better definition. We assume here that every character which stands for itself is encoded using ISO 8859-1. Using the escape character is allowed. */ if (ch == lr->escape_char) { ch = lr_getc (lr); if (ch == '\n' || ch == EOF) break; } if (verbose && !warned) { lr_error (lr, _("\ non-symbolic character value should not be used")); warned = 1; } ADDC (ch); if (return_widestr) ADDWC ((uint32_t) ch); continue; } /* Now we have to search for the end of the symbolic name, i.e., the closing '>'. */ startidx = bufact; while ((ch = lr_getc (lr)) != '>' && ch != '\n' && ch != EOF) { if (ch == lr->escape_char) { ch = lr_getc (lr); if (ch == '\n' || ch == EOF) break; } ADDC (ch); } if (ch == '\n' || ch == EOF) /* Not a correct string. */ break; if (bufact == startidx) { /* <> is no correct name. Ignore it and also signal an error. */ illegal_string = 1; continue; } /* It might be a Uxxxx symbol. */ if (buf[startidx] == 'U' && (bufact - startidx == 5 || bufact - startidx == 9)) { char *cp = buf + startidx + 1; while (cp < &buf[bufact] && isxdigit (*cp)) ++cp; if (cp == &buf[bufact]) { char utmp[10]; /* Yes, it is. */ ADDC ('\0'); wch = strtoul (buf + startidx + 1, NULL, 16); /* Now forget about the name we just added. */ bufact = startidx; if (return_widestr) ADDWC (wch); /* See whether the charmap contains the Uxxxxxxxx names. */ snprintf (utmp, sizeof (utmp), "U%08X", wch); seq = charmap_find_value (charmap, utmp, 9); if (seq == NULL) { /* No, this isn't the case. Now determine from the repertoire the name of the character and find it in the charmap. */ if (repertoire != NULL) { const char *symbol; symbol = repertoire_find_symbol (repertoire, wch); if (symbol != NULL) seq = charmap_find_value (charmap, symbol, strlen (symbol)); } if (seq == NULL) { #ifndef NO_TRANSLITERATION /* Transliterate if possible. */ if (locale != NULL) { uint32_t *translit; if ((locale->avail & CTYPE_LOCALE) == 0) { /* Load the CTYPE data now. */ int old_needed = locale->needed; locale->needed = 0; locale = load_locale (LC_CTYPE, locale->name, locale->repertoire_name, charmap, locale); locale->needed = old_needed; } if ((locale->avail & CTYPE_LOCALE) != 0 && ((translit = find_translit (locale, charmap, wch)) != NULL)) /* The CTYPE data contains a matching transliteration. */ { int i; for (i = 0; translit[i] != 0; ++i) { char utmp[10]; snprintf (utmp, sizeof (utmp), "U%08X", translit[i]); seq = charmap_find_value (charmap, utmp, 9); assert (seq != NULL); ADDS (seq->bytes, seq->nbytes); } continue; } } #endif /* NO_TRANSLITERATION */ /* Not a known name. */ illegal_string = 1; } } if (seq != NULL) ADDS (seq->bytes, seq->nbytes); continue; } } /* We now have the symbolic name in buf[startidx] to buf[bufact-1]. Now find out the value for this character in the charmap as well as in the repertoire map (in this order). */ seq = charmap_find_value (charmap, &buf[startidx], bufact - startidx); if (seq == NULL) { /* This name is not in the charmap. */ lr_error (lr, _("symbol `%.*s' not in charmap"), (int) (bufact - startidx), &buf[startidx]); illegal_string = 1; } if (return_widestr) { /* Now the same for the multibyte representation. */ if (seq != NULL && seq->ucs4 != UNINITIALIZED_CHAR_VALUE) wch = seq->ucs4; else { wch = repertoire_find_value (repertoire, &buf[startidx], bufact - startidx); if (seq != NULL) seq->ucs4 = wch; } if (wch == ILLEGAL_CHAR_VALUE) { /* This name is not in the repertoire map. */ lr_error (lr, _("symbol `%.*s' not in repertoire map"), (int) (bufact - startidx), &buf[startidx]); illegal_string = 1; } else ADDWC (wch); } /* Now forget about the name we just added. */ bufact = startidx; /* And copy the bytes. */ if (seq != NULL) ADDS (seq->bytes, seq->nbytes); } if (ch == '\n' || ch == EOF) { lr_error (lr, _("unterminated string")); illegal_string = 1; } if (illegal_string) { free (buf); free (buf2); lr->token.val.str.startmb = NULL; lr->token.val.str.lenmb = 0; lr->token.val.str.startwc = NULL; lr->token.val.str.lenwc = 0; return &lr->token; } ADDC ('\0'); if (return_widestr) { ADDWC (0); lr->token.val.str.startwc = xrealloc (buf2, buf2act * sizeof (uint32_t)); lr->token.val.str.lenwc = buf2act; } }