]> git.ipfire.org Git - thirdparty/glibc.git/blob - locale/programs/charmap.c
Update.
[thirdparty/glibc.git] / locale / programs / charmap.c
1 /* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <ctype.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <libintl.h>
28 #include <limits.h>
29 #include <obstack.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include "error.h"
35 #include "linereader.h"
36 #include "charmap.h"
37 #include "locfile.h"
38 #include "repertoire.h"
39
40 #include <assert.h>
41
42
43 /* Define the lookup function. */
44 #include "charmap-kw.h"
45
46
47 extern void *xmalloc (size_t __n);
48
49 /* Prototypes for local functions. */
50 static struct charmap_t *parse_charmap (const char *filename);
51 static void new_width (struct linereader *cmfile, struct charmap_t *result,
52 const char *from, const char *to,
53 unsigned long int width);
54 static void charmap_new_char (struct linereader *lr, struct charmap_t *cm,
55 int nbytes, char *bytes, const char *from,
56 const char *to, int decimal_ellipsis);
57
58
59 struct charmap_t *
60 charmap_read (const char *filename)
61 {
62 const char *pathnfile;
63 struct charmap_t *result = NULL;
64
65 if (filename != NULL)
66 {
67 if (euidaccess (filename, R_OK) >= 0)
68 pathnfile = filename;
69 else if (filename[0] != '/')
70 {
71 char *cp = xmalloc (strlen (filename) + sizeof CHARMAP_PATH + 1);
72 stpcpy (stpcpy (stpcpy (cp, CHARMAP_PATH), "/"), filename);
73
74 pathnfile = (const char *) cp;
75 }
76 else
77 pathnfile = NULL;
78
79 if (pathnfile != NULL)
80 {
81 result = parse_charmap (pathnfile);
82
83 if (result == NULL && !be_quiet)
84 error (0, errno, _("character map file `%s' not found"), filename);
85 }
86 }
87
88 if (result == NULL)
89 {
90 /* OK, one more try. We also accept the names given to the
91 character sets in the files. Sometimes they differ from the
92 file name. */
93 DIR *dir;
94 struct dirent *dirent;
95
96 dir = opendir (CHARMAP_PATH);
97 if (dir == NULL)
98 {
99 while ((dirent = readdir (dir)) != NULL)
100 if (strcmp (dirent->d_name, ".") != 0
101 && strcmp (dirent->d_name, "..") != 0)
102 {
103 char buf[sizeof (CHARMAP_PATH)
104 + strlen (dirent->d_name) + 1];
105 FILE *fp;
106 #ifdef _DIRENT_HAVE_D_TYPE
107 if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_REG)
108 continue;
109 #endif
110 stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"),
111 dirent->d_name);
112
113 fp = fopen (buf, "r");
114 if (fp != NULL)
115 {
116 char *name = NULL;
117
118 while (!feof (fp))
119 {
120 char junk[BUFSIZ];
121
122 if (fscanf (fp, " <code_set_name> %as", &name) == 1
123 || fscanf (fp, "%% alias %as", &name) == 1)
124 {
125 if (strcasecmp (name, filename) == 0)
126 break;
127
128 free (name);
129 name = NULL;
130 }
131
132 if (fgets (junk, sizeof junk, fp) != NULL)
133 {
134 if (strstr (junk, "CHARMAP") != NULL)
135 /* We cannot expect more aliases from now on. */
136 break;
137
138 while (strchr (junk, '\n') == NULL
139 && fgets (junk, sizeof junk, fp) != NULL)
140 continue;
141 }
142 }
143
144 fclose (fp);
145
146 if (name != NULL)
147 {
148 result = parse_charmap (buf);
149
150 free (buf);
151
152 if (result)
153 return result;
154
155 break;
156 }
157 }
158 }
159
160 closedir (dir);
161 }
162 }
163
164 if (result == NULL)
165 {
166 pathnfile = CHARMAP_PATH "/" DEFAULT_CHARMAP;
167
168 result = parse_charmap (pathnfile);
169
170 if (result == NULL)
171 error (4, errno, _("default character map file `%s' not found"),
172 DEFAULT_CHARMAP);
173 }
174
175 return result;
176 }
177
178
179 static struct charmap_t *
180 parse_charmap (const char *filename)
181 {
182 struct linereader *cmfile;
183 struct charmap_t *result;
184 int state;
185 enum token_t expected_tok = tok_error;
186 const char *expected_str = NULL;
187 char *from_name = NULL;
188 char *to_name = NULL;
189 enum token_t ellipsis = 0;
190
191 /* Determine path. */
192 cmfile = lr_open (filename, charmap_hash);
193 if (cmfile == NULL)
194 {
195 if (strchr (filename, '/') == NULL)
196 {
197 /* Look in the systems charmap directory. */
198 char *buf = xmalloc (strlen (filename) + 1 + sizeof (CHARMAP_PATH));
199
200 stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"), filename);
201 cmfile = lr_open (buf, charmap_hash);
202
203 if (cmfile == NULL)
204 free (buf);
205 }
206
207 if (cmfile == NULL)
208 return NULL;
209 }
210
211 /* We don't want symbolic names in string to be translated. */
212 cmfile->translate_strings = 0;
213
214 /* Allocate room for result. */
215 result = (struct charmap_t *) xmalloc (sizeof (struct charmap_t));
216 memset (result, '\0', sizeof (struct charmap_t));
217 /* The default DEFAULT_WIDTH is 1. */
218 result->width_default = 1;
219
220 #define obstack_chunk_alloc malloc
221 #define obstack_chunk_free free
222 obstack_init (&result->mem_pool);
223
224 if (init_hash (&result->char_table, 256)
225 || init_hash (&result->byte_table, 256))
226 {
227 free (result);
228 return NULL;
229 }
230
231 /* We use a state machine to describe the charmap description file
232 format. */
233 state = 1;
234 while (1)
235 {
236 /* What's on? */
237 struct token *now = lr_token (cmfile, NULL, NULL);
238 enum token_t nowtok = now->tok;
239 struct token *arg;
240
241 if (nowtok == tok_eof)
242 break;
243
244 switch (state)
245 {
246 case 1:
247 /* The beginning. We expect the special declarations, EOL or
248 `CHARMAP'. */
249 if (nowtok == tok_eol)
250 /* Ignore empty lines. */
251 continue;
252
253 if (nowtok == tok_charmap)
254 {
255 from_name = NULL;
256 to_name = NULL;
257
258 /* We have to set up the real work. Fill in some
259 default values. */
260 if (result->mb_cur_max == 0)
261 result->mb_cur_max = 1;
262 if (result->mb_cur_min == 0)
263 result->mb_cur_min = result->mb_cur_max;
264 if (result->mb_cur_min > result->mb_cur_max)
265 {
266 if (!be_quiet)
267 error (0, 0, _("\
268 %s: <mb_cur_max> must be greater than <mb_cur_min>\n"),
269 cmfile->fname);
270
271 result->mb_cur_min = result->mb_cur_max;
272 }
273
274 lr_ignore_rest (cmfile, 1);
275
276 state = 2;
277 continue;
278 }
279
280 if (nowtok != tok_code_set_name && nowtok != tok_mb_cur_max
281 && nowtok != tok_mb_cur_min && nowtok != tok_escape_char
282 && nowtok != tok_comment_char && nowtok != tok_g0esc
283 && nowtok != tok_g1esc && nowtok != tok_g2esc
284 && nowtok != tok_g3esc && nowtok != tok_repertoiremap
285 && nowtok != tok_include)
286 {
287 lr_error (cmfile, _("syntax error in prolog: %s"),
288 _("invalid definition"));
289
290 lr_ignore_rest (cmfile, 0);
291 continue;
292 }
293
294 /* We know that we need an argument. */
295 arg = lr_token (cmfile, NULL, NULL);
296
297 switch (nowtok)
298 {
299 case tok_code_set_name:
300 case tok_repertoiremap:
301 if (arg->tok != tok_ident)
302 {
303 badarg:
304 lr_error (cmfile, _("syntax error in prolog: %s"),
305 _("bad argument"));
306
307 lr_ignore_rest (cmfile, 0);
308 continue;
309 }
310
311 if (nowtok == tok_code_set_name)
312 result->code_set_name = obstack_copy0 (&result->mem_pool,
313 arg->val.str.startmb,
314 arg->val.str.lenmb);
315 else
316 result->repertoiremap = obstack_copy0 (&result->mem_pool,
317 arg->val.str.startmb,
318 arg->val.str.lenmb);
319
320 lr_ignore_rest (cmfile, 1);
321 continue;
322
323 case tok_mb_cur_max:
324 case tok_mb_cur_min:
325 if (arg->tok != tok_number)
326 goto badarg;
327
328 if (verbose
329 && ((nowtok == tok_mb_cur_max
330 && result->mb_cur_max != 0)
331 || (nowtok == tok_mb_cur_max
332 && result->mb_cur_max != 0)))
333 lr_error (cmfile, _("duplicate definition of <%s>"),
334 nowtok == tok_mb_cur_min
335 ? "mb_cur_min" : "mb_cur_max");
336
337 if (arg->val.num < 1)
338 {
339 lr_error (cmfile,
340 _("value for <%s> must be 1 or greater"),
341 nowtok == tok_mb_cur_min
342 ? "mb_cur_min" : "mb_cur_max");
343
344 lr_ignore_rest (cmfile, 0);
345 continue;
346 }
347 if ((nowtok == tok_mb_cur_max && result->mb_cur_min != 0
348 && (int) arg->val.num < result->mb_cur_min)
349 || (nowtok == tok_mb_cur_min && result->mb_cur_max != 0
350 && (int) arg->val.num > result->mb_cur_max))
351 {
352 lr_error (cmfile, _("\
353 value of <%s> must be greater or equal than the value of <%s>"),
354 "mb_cur_max", "mb_cur_min");
355
356 lr_ignore_rest (cmfile, 0);
357 continue;
358 }
359
360 if (nowtok == tok_mb_cur_max)
361 result->mb_cur_max = arg->val.num;
362 else
363 result->mb_cur_min = arg->val.num;
364
365 lr_ignore_rest (cmfile, 1);
366 continue;
367
368 case tok_escape_char:
369 case tok_comment_char:
370 if (arg->tok != tok_ident)
371 goto badarg;
372
373 if (arg->val.str.lenmb != 1)
374 {
375 lr_error (cmfile, _("\
376 argument to <%s> must be a single character"),
377 nowtok == tok_escape_char ? "escape_char"
378 : "comment_char");
379
380 lr_ignore_rest (cmfile, 0);
381 continue;
382 }
383
384 if (nowtok == tok_escape_char)
385 cmfile->escape_char = *arg->val.str.startmb;
386 else
387 cmfile->comment_char = *arg->val.str.startmb;
388
389 lr_ignore_rest (cmfile, 1);
390 continue;
391
392 case tok_g0esc:
393 case tok_g1esc:
394 case tok_g2esc:
395 case tok_g3esc:
396 case tok_escseq:
397 lr_ignore_rest (cmfile, 0); /* XXX */
398 continue;
399
400 case tok_include:
401 lr_error (cmfile, _("\
402 character sets with locking states are not supported"));
403 exit (4);
404
405 default:
406 /* Cannot happen. */
407 assert (! "Should not happen");
408 }
409 break;
410
411 case 2:
412 /* We have seen `CHARMAP' and now are in the body. Each line
413 must have the format "%s %s %s\n" or "%s...%s %s %s\n". */
414 if (nowtok == tok_eol)
415 /* Ignore empty lines. */
416 continue;
417
418 if (nowtok == tok_end)
419 {
420 expected_tok = tok_charmap;
421 expected_str = "CHARMAP";
422 state = 90;
423 continue;
424 }
425
426 if (nowtok != tok_bsymbol)
427 {
428 lr_error (cmfile, _("syntax error in %s definition: %s"),
429 "CHARMAP", _("no symbolic name given"));
430
431 lr_ignore_rest (cmfile, 0);
432 continue;
433 }
434
435 /* If the previous line was not completely correct free the
436 used memory. */
437 if (from_name != NULL)
438 obstack_free (&result->mem_pool, from_name);
439
440 from_name = (char *) obstack_copy0 (&result->mem_pool,
441 now->val.str.startmb,
442 now->val.str.lenmb);
443 to_name = NULL;
444
445 state = 3;
446 continue;
447
448 case 3:
449 /* We have two possibilities: We can see an ellipsis or an
450 encoding value. */
451 if (nowtok == tok_ellipsis3 || nowtok == tok_ellipsis4
452 || nowtok == tok_ellipsis2)
453 {
454 ellipsis = nowtok;
455 state = 4;
456 continue;
457 }
458 /* FALLTHROUGH */
459
460 case 5:
461 if (nowtok != tok_charcode)
462 {
463 lr_error (cmfile, _("syntax error in %s definition: %s"),
464 "CHARMAP", _("invalid encoding given"));
465
466 lr_ignore_rest (cmfile, 0);
467
468 state = 2;
469 continue;
470 }
471
472 if (now->val.charcode.nbytes < result->mb_cur_min)
473 lr_error (cmfile, _("too few bytes in character encoding"));
474 else if (now->val.charcode.nbytes > result->mb_cur_max)
475 lr_error (cmfile, _("too many bytes in character encoding"));
476 else
477 charmap_new_char (cmfile, result, now->val.charcode.nbytes,
478 now->val.charcode.bytes, from_name, to_name,
479 ellipsis != tok_ellipsis2);
480
481 /* Ignore trailing comment silently. */
482 lr_ignore_rest (cmfile, 0);
483
484 from_name = NULL;
485 to_name = NULL;
486
487 state = 2;
488 continue;
489
490 case 4:
491 if (nowtok != tok_bsymbol)
492 {
493 lr_error (cmfile, _("syntax error in %s definition: %s"),
494 "CHARMAP",
495 _("no symbolic name given for end of range"));
496
497 lr_ignore_rest (cmfile, 0);
498 continue;
499 }
500
501 /* Copy the to-name in a safe place. */
502 to_name = (char *) obstack_copy0 (&result->mem_pool,
503 cmfile->token.val.str.startmb,
504 cmfile->token.val.str.lenmb);
505
506 state = 5;
507 continue;
508
509 case 90:
510 if (nowtok != expected_tok)
511 lr_error (cmfile, _("\
512 `%1$s' definition does not end with `END %1$s'"), expected_str);
513
514 lr_ignore_rest (cmfile, nowtok == expected_tok);
515 state = 91;
516 continue;
517
518 case 91:
519 /* Waiting for WIDTH... */
520 if (nowtok == tok_eol)
521 /* Ignore empty lines. */
522 continue;
523
524 if (nowtok == tok_width_default)
525 {
526 state = 92;
527 continue;
528 }
529
530 if (nowtok == tok_width)
531 {
532 lr_ignore_rest (cmfile, 1);
533 state = 93;
534 continue;
535 }
536
537 if (nowtok == tok_width_variable)
538 {
539 lr_ignore_rest (cmfile, 1);
540 state = 98;
541 continue;
542 }
543
544 lr_error (cmfile, _("\
545 only WIDTH definitions are allowed to follow the CHARMAP definition"));
546
547 lr_ignore_rest (cmfile, 0);
548 continue;
549
550 case 92:
551 if (nowtok != tok_number)
552 lr_error (cmfile, _("value for %s must be an integer"),
553 "WIDTH_DEFAULT");
554 else
555 result->width_default = now->val.num;
556
557 lr_ignore_rest (cmfile, nowtok == tok_number);
558
559 state = 91;
560 continue;
561
562 case 93:
563 /* We now expect `END WIDTH' or lines of the format "%s %d\n" or
564 "%s...%s %d\n". */
565 if (nowtok == tok_eol)
566 /* ignore empty lines. */
567 continue;
568
569 if (nowtok == tok_end)
570 {
571 expected_tok = tok_width;
572 expected_str = "WIDTH";
573 state = 90;
574 continue;
575 }
576
577 if (nowtok != tok_bsymbol)
578 {
579 lr_error (cmfile, _("syntax error in %s definition: %s"),
580 "WIDTH", _("no symbolic name given"));
581
582 lr_ignore_rest (cmfile, 0);
583 continue;
584 }
585
586 if (from_name != NULL)
587 obstack_free (&result->mem_pool, from_name);
588
589 from_name = (char *) obstack_copy0 (&result->mem_pool,
590 now->val.str.startmb,
591 now->val.str.lenmb);
592 to_name = NULL;
593
594 state = 94;
595 continue;
596
597 case 94:
598 if (nowtok == tok_ellipsis3)
599 {
600 state = 95;
601 continue;
602 }
603
604 case 96:
605 if (nowtok != tok_number)
606 lr_error (cmfile, _("value for %s must be an integer"),
607 "WIDTH");
608 else
609 {
610 /* Store width for chars. */
611 new_width (cmfile, result, from_name, to_name, now->val.num);
612
613 from_name = NULL;
614 to_name = NULL;
615 }
616
617 lr_ignore_rest (cmfile, nowtok == tok_number);
618
619 state = 93;
620 continue;
621
622 case 95:
623 if (nowtok != tok_bsymbol)
624 {
625 lr_error (cmfile, _("syntax error in %s definition: %s"),
626 "WIDTH", _("no symbolic name given for end of range"));
627
628 lr_ignore_rest (cmfile, 0);
629
630 state = 93;
631 continue;
632 }
633
634 to_name = (char *) obstack_copy0 (&result->mem_pool,
635 now->val.str.startmb,
636 now->val.str.lenmb);
637
638 state = 96;
639 continue;
640
641 case 98:
642 /* We now expect `END WIDTH_VARIABLE' or lines of the format
643 "%s\n" or "%s...%s\n". */
644 if (nowtok == tok_eol)
645 /* ignore empty lines. */
646 continue;
647
648 if (nowtok == tok_end)
649 {
650 expected_tok = tok_width_variable;
651 expected_str = "WIDTH_VARIABLE";
652 state = 90;
653 continue;
654 }
655
656 if (nowtok != tok_bsymbol)
657 {
658 lr_error (cmfile, _("syntax error in %s definition: %s"),
659 "WIDTH_VARIABLE", _("no symbolic name given"));
660
661 lr_ignore_rest (cmfile, 0);
662
663 continue;
664 }
665
666 if (from_name != NULL)
667 obstack_free (&result->mem_pool, from_name);
668
669 from_name = (char *) obstack_copy0 (&result->mem_pool,
670 now->val.str.startmb,
671 now->val.str.lenmb);
672 to_name = NULL;
673
674 state = 99;
675 continue;
676
677 case 99:
678 if (nowtok == tok_ellipsis3)
679 state = 100;
680
681 /* Store info. */
682 from_name = NULL;
683
684 /* Warn */
685 state = 98;
686 continue;
687
688 case 100:
689 if (nowtok != tok_bsymbol)
690 lr_error (cmfile, _("syntax error in %s definition: %s"),
691 "WIDTH_VARIABLE",
692 _("no symbolic name given for end of range"));
693 else
694 {
695 to_name = (char *) obstack_copy0 (&result->mem_pool,
696 now->val.str.startmb,
697 now->val.str.lenmb);
698 /* XXX Enter value into table. */
699 }
700
701 lr_ignore_rest (cmfile, nowtok == tok_bsymbol);
702
703 state = 98;
704 continue;
705
706 default:
707 error (5, 0, _("%s: error in state machine"), __FILE__);
708 /* NOTREACHED */
709 }
710 break;
711 }
712
713 if (state != 91 && !be_quiet)
714 error (0, 0, _("%s: premature end of file"), cmfile->fname);
715
716 lr_close (cmfile);
717
718 return result;
719 }
720
721
722 static void
723 new_width (struct linereader *cmfile, struct charmap_t *result,
724 const char *from, const char *to, unsigned long int width)
725 {
726 struct charseq *from_val;
727 struct charseq *to_val;
728
729 from_val = charmap_find_value (result, from, strlen (from));
730 if (from_val == NULL)
731 {
732 lr_error (cmfile, _("unknown character `%s'"), from);
733 return;
734 }
735
736 if (to == NULL)
737 to_val = from_val;
738 else
739 {
740 to_val = charmap_find_value (result, to, strlen (to));
741 if (to_val == NULL)
742 {
743 lr_error (cmfile, _("unknown character `%s'"), to);
744 return;
745 }
746 }
747
748 if (result->nwidth_rules >= result->nwidth_rules_max)
749 {
750 size_t new_size = result->nwidth_rules + 32;
751 struct width_rule *new_rules =
752 (struct width_rule *) obstack_alloc (&result->mem_pool,
753 (new_size
754 * sizeof (struct width_rule)));
755
756 memcpy (new_rules, result->width_rules,
757 result->nwidth_rules_max * sizeof (struct width_rule));
758
759 result->width_rules = new_rules;
760 result->nwidth_rules_max = new_size;
761 }
762
763 result->width_rules[result->nwidth_rules].from = from_val;
764 result->width_rules[result->nwidth_rules].to = to_val;
765 result->width_rules[result->nwidth_rules].width = (unsigned int) width;
766 ++result->nwidth_rules;
767 }
768
769
770 struct charseq *
771 charmap_find_value (const struct charmap_t *cm, const char *name, size_t len)
772 {
773 void *result;
774
775 return (find_entry ((hash_table *) &cm->char_table, name, len, &result)
776 < 0 ? NULL : (struct charseq *) result);
777 }
778
779
780 static void
781 charmap_new_char (struct linereader *lr, struct charmap_t *cm,
782 int nbytes, char *bytes, const char *from, const char *to,
783 int decimal_ellipsis)
784 {
785 hash_table *ht = &cm->char_table;
786 hash_table *bt = &cm->byte_table;
787 struct obstack *ob = &cm->mem_pool;
788 char *from_end;
789 char *to_end;
790 const char *cp;
791 int prefix_len, len1, len2;
792 unsigned int from_nr, to_nr, cnt;
793 struct charseq *newp;
794
795 len1 = strlen (from);
796
797 if (to == NULL)
798 {
799 newp = (struct charseq *) obstack_alloc (ob, sizeof (*newp) + nbytes);
800 newp->nbytes = nbytes;
801 memcpy (newp->bytes, bytes, nbytes);
802 newp->name = obstack_copy (ob, from, len1 + 1);
803 newp->ucs4 = UNINITIALIZED_CHAR_VALUE;
804
805 insert_entry (ht, from, len1, newp);
806 insert_entry (bt, newp->bytes, nbytes, newp);
807 /* Please note that it isn't a bug if a symbol is defined more
808 than once. All later definitions are simply discarded. */
809 return;
810 }
811
812 /* We have a range: the names must have names with equal prefixes
813 and an equal number of digits, where the second number is greater
814 or equal than the first. */
815 len2 = strlen (to);
816
817 if (len1 != len2)
818 {
819 illegal_range:
820 lr_error (lr, _("invalid names for character range"));
821 return;
822 }
823
824 cp = &from[len1 - 1];
825 if (decimal_ellipsis)
826 while (isdigit (*cp) && cp >= from)
827 --cp;
828 else
829 while (isxdigit (*cp) && cp >= from)
830 {
831 if (!isdigit (*cp) && !isupper (*cp))
832 lr_error (lr, _("\
833 hexadecimal range format should use only capital characters"));
834 --cp;
835 }
836
837 prefix_len = (cp - from) + 1;
838
839 if (cp == &from[len1 - 1] || strncmp (from, to, prefix_len) != 0)
840 goto illegal_range;
841
842 errno = 0;
843 from_nr = strtoul (&from[prefix_len], &from_end, decimal_ellipsis ? 10 : 16);
844 if (*from_end != '\0' || (from_nr == ULONG_MAX && errno == ERANGE)
845 || ((to_nr = strtoul (&to[prefix_len], &to_end,
846 decimal_ellipsis ? 10 : 16)) == ULONG_MAX
847 && errno == ERANGE)
848 || *to_end != '\0')
849 {
850 lr_error (lr, _("<%s> and <%s> are illegal names for range"));
851 return;
852 }
853
854 if (from_nr > to_nr)
855 {
856 lr_error (lr, _("upper limit in range is not higher then lower limit"));
857 return;
858 }
859
860 for (cnt = from_nr; cnt <= to_nr; ++cnt)
861 {
862 char *name_end;
863 obstack_printf (ob, decimal_ellipsis ? "%.*s%0*d" : "%.*s%0*X",
864 prefix_len, from, len1 - prefix_len, cnt);
865 name_end = obstack_finish (ob);
866
867 newp = (struct charseq *) obstack_alloc (ob, sizeof (*newp) + nbytes);
868 newp->nbytes = nbytes;
869 memcpy (newp->bytes, bytes, nbytes);
870 newp->name = name_end;
871 newp->ucs4 = UNINITIALIZED_CHAR_VALUE;
872
873 insert_entry (ht, name_end, len1, newp);
874 insert_entry (bt, newp->bytes, nbytes, newp);
875 /* Please note we don't examine the return value since it is no error
876 if we have two definitions for a symbol. */
877
878 /* Increment the value in the byte sequence. */
879 if (++bytes[nbytes - 1] == '\0')
880 {
881 int b = nbytes - 2;
882
883 do
884 if (b < 0)
885 {
886 lr_error (lr,
887 _("resulting bytes for range not representable."));
888 return;
889 }
890 while (++bytes[b--] == 0);
891 }
892 }
893 }
894
895
896 struct charseq *
897 charmap_find_symbol (const struct charmap_t *cm, const char *bytes,
898 size_t nbytes)
899 {
900 void *result;
901
902 return (find_entry ((hash_table *) &cm->byte_table, bytes, nbytes, &result)
903 < 0 ? NULL : (struct charseq *) result);
904 }