]>
git.ipfire.org Git - thirdparty/glibc.git/blob - locale/programs/charmap.c
1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
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.
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.
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. */
34 #include "linereader.h"
38 /* Uncomment following line for production version. */
43 /* Define the lookup function. */
44 #include "charmap-kw.h"
47 extern void *xmalloc (size_t __n
);
49 /* Prototypes for local functions. */
50 static struct charset_t
*parse_charmap (const char *filename
);
51 static void new_width (struct linereader
*cmfile
, struct charset_t
*result
,
52 const char *from
, const char *to
,
53 unsigned long int width
);
57 charmap_read (const char *filename
)
59 const char *pathnfile
;
60 struct charset_t
*result
= NULL
;
64 if (euidaccess (filename
, R_OK
) >= 0)
66 else if (filename
[0] != '/')
68 char *cp
= xmalloc (strlen (filename
) + sizeof CHARMAP_PATH
+ 1);
69 stpcpy (stpcpy (stpcpy (cp
, CHARMAP_PATH
), "/"), filename
);
71 pathnfile
= (const char *) cp
;
76 if (pathnfile
!= NULL
)
78 result
= parse_charmap (pathnfile
);
80 if (result
== NULL
&& !be_quiet
)
81 error (0, errno
, _("character map file `%s' not found"), filename
);
87 /* OK, one more try. We also accept the names given to the
88 character sets in the files. Sometimes they differ from the
91 struct dirent
*dirent
;
93 dir
= opendir (CHARMAP_PATH
);
96 while ((dirent
= readdir (dir
)) != NULL
)
97 if (strcmp (dirent
->d_name
, ".") != 0
98 && strcmp (dirent
->d_name
, "..") != 0)
100 char buf
[sizeof (CHARMAP_PATH
)
101 + strlen (dirent
->d_name
) + 1];
103 #ifdef _DIRENT_HAVE_D_TYPE
104 if (dirent
->d_type
!= DT_UNKNOWN
&& dirent
->d_type
!= DT_REG
)
107 stpcpy (stpcpy (stpcpy (buf
, CHARMAP_PATH
), "/"),
110 fp
= fopen (buf
, "r");
119 if (fscanf (fp
, " <code_set_name> %as", &name
) == 1
120 || fscanf (fp
, "%% alias %as", &name
) == 1)
122 if (strcasecmp (name
, filename
) == 0)
129 if (fgets (junk
, sizeof junk
, fp
) != NULL
)
131 if (strstr (junk
, "CHARMAP") != NULL
)
132 /* We cannot expect more aliases from now on. */
135 while (strchr (junk
, '\n') == NULL
136 && fgets (junk
, sizeof junk
, fp
) != NULL
)
145 result
= parse_charmap (buf
);
163 pathnfile
= CHARMAP_PATH
"/" DEFAULT_CHARMAP
;
165 result
= parse_charmap (pathnfile
);
168 error (4, errno
, _("default character map file `%s' not found"),
176 static struct charset_t
*
177 parse_charmap (const char *filename
)
179 struct linereader
*cmfile
;
180 struct charset_t
*result
;
182 enum token_t expected_tok
= tok_error
;
183 const char *expected_str
= NULL
;
184 char *from_name
= NULL
;
185 char *to_name
= NULL
;
187 /* Determine path. */
188 cmfile
= lr_open (filename
, charmap_hash
);
191 if (strchr (filename
, '/') == NULL
)
193 /* Look in the systems charmap directory. */
194 char *buf
= xmalloc (strlen (filename
) + 1 + sizeof (CHARMAP_PATH
));
196 stpcpy (stpcpy (stpcpy (buf
, CHARMAP_PATH
), "/"), filename
);
197 cmfile
= lr_open (buf
, charmap_hash
);
207 /* Allocate room for result. */
208 result
= (struct charset_t
*) xmalloc (sizeof (struct charset_t
));
209 memset (result
, '\0', sizeof (struct charset_t
));
210 /* The default DEFAULT_WIDTH is 1. */
211 result
->width_default
= 1;
213 #define obstack_chunk_alloc malloc
214 #define obstack_chunk_free free
215 obstack_init (&result
->mem_pool
);
217 if (init_hash (&result
->char_table
, 256))
223 /* We use a state machine to describe the charmap description file
229 struct token
*now
= lr_token (cmfile
, NULL
);
230 enum token_t nowtok
= now
->tok
;
233 if (nowtok
== tok_eof
)
239 /* The beginning. We expect the special declarations, EOL or
241 if (nowtok
== tok_eol
)
242 /* Ignore empty lines. */
245 if (nowtok
== tok_charmap
)
250 /* We have to set up the real work. Fill in some
252 if (result
->mb_cur_max
== 0)
253 result
->mb_cur_max
= 1;
254 if (result
->mb_cur_min
== 0)
255 result
->mb_cur_min
= result
->mb_cur_max
;
256 if (result
->mb_cur_min
> result
->mb_cur_max
&& !be_quiet
)
259 %s: <mb_cur_max> must be greater than <mb_cur_min>\n"),
262 result
->mb_cur_min
= result
->mb_cur_max
;
265 lr_ignore_rest (cmfile
, 1);
271 if (nowtok
!= tok_code_set_name
&& nowtok
!= tok_mb_cur_max
272 && nowtok
!= tok_mb_cur_min
&& nowtok
!= tok_escape_char
273 && nowtok
!= tok_comment_char
&& nowtok
!= tok_g0esc
274 && nowtok
!= tok_g1esc
&& nowtok
!= tok_g2esc
275 && nowtok
!= tok_g3esc
)
277 lr_error (cmfile
, _("syntax error in prolog: %s"),
278 _("illegal definition"));
280 lr_ignore_rest (cmfile
, 0);
284 /* We know that we need an argument. */
285 arg
= lr_token (cmfile
, NULL
);
289 case tok_code_set_name
:
290 if (arg
->tok
!= tok_ident
)
293 lr_error (cmfile
, _("syntax error in prolog: %s"),
296 lr_ignore_rest (cmfile
, 0);
300 result
->code_set_name
= obstack_copy0 (&result
->mem_pool
,
304 lr_ignore_rest (cmfile
, 1);
309 if (arg
->tok
!= tok_number
)
312 if (arg
->val
.num
< 1 || arg
->val
.num
> 4)
315 _("value for <%s> must lie between 1 and 4"),
316 nowtok
== tok_mb_cur_min
? "mb_cur_min"
319 lr_ignore_rest (cmfile
, 0);
322 if ((nowtok
== tok_mb_cur_max
&& result
->mb_cur_min
!= 0
323 && (int) arg
->val
.num
< result
->mb_cur_min
)
324 || (nowtok
== tok_mb_cur_min
&& result
->mb_cur_max
!= 0
325 && (int) arg
->val
.num
> result
->mb_cur_max
))
327 lr_error (cmfile
, _("\
328 value of <mb_cur_max> must be greater than the value of <mb_cur_min>"));
330 lr_ignore_rest (cmfile
, 0);
334 if (nowtok
== tok_mb_cur_max
)
335 result
->mb_cur_max
= arg
->val
.num
;
337 result
->mb_cur_min
= arg
->val
.num
;
339 lr_ignore_rest (cmfile
, 1);
342 case tok_escape_char
:
343 case tok_comment_char
:
344 if (arg
->tok
!= tok_ident
)
347 if (arg
->val
.str
.len
!= 1)
349 lr_error (cmfile
, _("\
350 argument to <%s> must be a single character"),
351 nowtok
== tok_escape_char
? "escape_char"
354 lr_ignore_rest (cmfile
, 0);
358 if (nowtok
== tok_escape_char
)
359 cmfile
->escape_char
= *arg
->val
.str
.start
;
361 cmfile
->comment_char
= *arg
->val
.str
.start
;
363 lr_ignore_rest (cmfile
, 1);
370 lr_ignore_rest (cmfile
, 0); /* XXX */
375 assert (! "Should not happen");
380 /* We have seen `CHARMAP' and now are in the body. Each line
381 must have the format "%s %s %s\n" or "%s...%s %s %s\n". */
382 if (nowtok
== tok_eol
)
383 /* Ignore empty lines. */
386 if (nowtok
== tok_end
)
388 expected_tok
= tok_charmap
;
389 expected_str
= "CHARMAP";
394 if (nowtok
!= tok_bsymbol
)
396 lr_error (cmfile
, _("syntax error in %s definition: %s"),
397 "CHARMAP", _("no symbolic name given"));
399 lr_ignore_rest (cmfile
, 0);
403 /* If the previous line was not completely correct free the
405 if (from_name
!= NULL
)
406 obstack_free (&result
->mem_pool
, from_name
);
408 from_name
= (char *) obstack_copy0 (&result
->mem_pool
,
417 /* We have two possibilities: We can see an ellipsis or an
419 if (nowtok
== tok_ellipsis
)
427 if (nowtok
!= tok_charcode
&& nowtok
!= tok_ucs2
428 && nowtok
!= tok_ucs4
)
430 lr_error (cmfile
, _("syntax error in %s definition: %s"),
431 "CHARMAP", _("illegal encoding given"));
433 lr_ignore_rest (cmfile
, 0);
439 if (nowtok
== tok_charcode
)
440 /* Write char value in table. */
441 charset_new_char (cmfile
, result
, now
->val
.charcode
.nbytes
,
442 now
->val
.charcode
.val
, from_name
, to_name
);
444 /* Determine ISO 10646 value and write into table. */
445 charset_new_unicode (cmfile
, result
, now
->val
.charcode
.nbytes
,
446 now
->val
.charcode
.val
, from_name
, to_name
);
448 /* Ignore trailing comment silently. */
449 lr_ignore_rest (cmfile
, 0);
458 if (nowtok
!= tok_bsymbol
)
460 lr_error (cmfile
, _("syntax error in %s definition: %s"),
462 _("no symbolic name given for end of range"));
464 lr_ignore_rest (cmfile
, 0);
468 /* If the previous line was not completely correct free the
470 to_name
= (char *) obstack_copy0 (&result
->mem_pool
,
471 cmfile
->token
.val
.str
.start
,
472 cmfile
->token
.val
.str
.len
);
478 if (nowtok
!= expected_tok
)
479 lr_error (cmfile
, _("\
480 `%1$s' definition does not end with `END %1$s'"), expected_str
);
482 lr_ignore_rest (cmfile
, nowtok
== expected_tok
);
487 /* Waiting for WIDTH... */
488 if (nowtok
== tok_eol
)
489 /* Ignore empty lines. */
492 if (nowtok
== tok_width_default
)
498 if (nowtok
== tok_width
)
500 lr_ignore_rest (cmfile
, 1);
505 if (nowtok
== tok_width_variable
)
507 lr_ignore_rest (cmfile
, 1);
512 lr_error (cmfile
, _("\
513 only WIDTH definitions are allowed to follow the CHARMAP definition"));
515 lr_ignore_rest (cmfile
, 0);
519 if (nowtok
!= tok_number
)
520 lr_error (cmfile
, _("value for %s must be an integer"),
523 result
->width_default
= now
->val
.num
;
525 lr_ignore_rest (cmfile
, nowtok
== tok_number
);
531 /* We now expect `END WIDTH' or lines of the format "%s %d\n" or
533 if (nowtok
== tok_eol
)
534 /* ignore empty lines. */
537 if (nowtok
== tok_end
)
539 expected_tok
= tok_width
;
540 expected_str
= "WIDTH";
545 if (nowtok
!= tok_bsymbol
)
547 lr_error (cmfile
, _("syntax error in %s definition: %s"),
548 "WIDTH", _("no symbolic name given"));
550 lr_ignore_rest (cmfile
, 0);
554 if (from_name
!= NULL
)
555 obstack_free (&result
->mem_pool
, from_name
);
557 from_name
= (char *) obstack_copy0 (&result
->mem_pool
,
566 if (nowtok
== tok_ellipsis
)
573 if (nowtok
!= tok_number
)
574 lr_error (cmfile
, _("value for %s must be an integer"),
578 /* Store width for chars. */
579 new_width (cmfile
, result
, from_name
, to_name
, now
->val
.num
);
585 lr_ignore_rest (cmfile
, nowtok
== tok_number
);
591 if (nowtok
!= tok_bsymbol
)
593 lr_error (cmfile
, _("syntax error in %s definition: %s"),
594 "WIDTH", _("no symbolic name given for end of range"));
596 lr_ignore_rest (cmfile
, 0);
602 to_name
= (char *) obstack_copy0 (&result
->mem_pool
,
610 /* We now expect `END WIDTH_VARIABLE' or lines of the format
611 "%s\n" or "%s...%s\n". */
612 if (nowtok
== tok_eol
)
613 /* ignore empty lines. */
616 if (nowtok
== tok_end
)
618 expected_tok
= tok_width_variable
;
619 expected_str
= "WIDTH_VARIABLE";
624 if (nowtok
!= tok_bsymbol
)
626 lr_error (cmfile
, _("syntax error in %s definition: %s"),
627 "WIDTH_VARIABLE", _("no symbolic name given"));
629 lr_ignore_rest (cmfile
, 0);
634 if (from_name
!= NULL
)
635 obstack_free (&result
->mem_pool
, from_name
);
637 from_name
= (char *) obstack_copy0 (&result
->mem_pool
,
646 if (nowtok
== tok_ellipsis
)
657 if (nowtok
!= tok_bsymbol
)
658 lr_error (cmfile
, _("syntax error in %s definition: %s"),
660 _("no symbolic name given for end of range"));
663 to_name
= (char *) obstack_copy0 (&result
->mem_pool
,
666 /* XXX Enter value into table. */
669 lr_ignore_rest (cmfile
, nowtok
== tok_bsymbol
);
675 error (5, 0, _("%s: error in state machine"), __FILE__
);
681 if (state
!= 91 && !be_quiet
)
682 error (0, 0, _("%s: premature end of file"), cmfile
->fname
);
691 new_width (struct linereader
*cmfile
, struct charset_t
*result
,
692 const char *from
, const char *to
, unsigned long int width
)
694 unsigned int from_val
, to_val
;
696 from_val
= charset_find_value (result
, from
, strlen (from
));
697 if ((wchar_t) from_val
== ILLEGAL_CHAR_VALUE
)
699 lr_error (cmfile
, _("unknown character `%s'"), from
);
707 to_val
= charset_find_value (result
, to
, strlen (to
));
708 if ((wchar_t) to_val
== ILLEGAL_CHAR_VALUE
)
710 lr_error (cmfile
, _("unknown character `%s'"), to
);
715 if (result
->nwidth_rules
>= result
->nwidth_rules_max
)
717 size_t new_size
= result
->nwidth_rules
+ 32;
718 struct width_rule
*new_rules
=
719 (struct width_rule
*) obstack_alloc (&result
->mem_pool
,
721 * sizeof (struct width_rule
)));
723 memcpy (new_rules
, result
->width_rules
,
724 result
->nwidth_rules_max
* sizeof (struct width_rule
));
726 result
->width_rules
= new_rules
;
727 result
->nwidth_rules_max
= new_size
;
730 result
->width_rules
[result
->nwidth_rules
].from
= from_val
;
731 result
->width_rules
[result
->nwidth_rules
].to
= to_val
;
732 result
->width_rules
[result
->nwidth_rules
].width
= (unsigned int) width
;
733 ++result
->nwidth_rules
;