1 /* Copyright (C) 1996, 1997 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. */
33 #include "linereader.h"
37 /* Uncomment following line for production version. */
42 /* Define the lookup function. */
43 #include "charmap-kw.h"
46 void *xmalloc (size_t __n
);
48 /* Prototypes for local functions. */
49 static struct charset_t
*parse_charmap (const char *filename
);
50 static void new_width (struct linereader
*cmfile
, struct charset_t
*result
,
51 const char *from
, const char *to
,
52 unsigned long int width
);
56 charmap_read (const char *filename
)
58 const char *pathnfile
;
59 struct charset_t
*result
= NULL
;
63 if (euidaccess (filename
, R_OK
) >= 0)
67 char *cp
= xmalloc (strlen (filename
) + sizeof CHARMAP_PATH
+ 1);
68 stpcpy (stpcpy (stpcpy (cp
, CHARMAP_PATH
), "/"), filename
);
70 pathnfile
= (const char *) cp
;
73 result
= parse_charmap (pathnfile
);
75 if (result
== NULL
&& !be_quiet
)
76 error (0, errno
, _("character map file `%s' not found"), filename
);
81 pathnfile
= CHARMAP_PATH
"/" DEFAULT_CHARMAP
;
83 result
= parse_charmap (pathnfile
);
86 error (4, errno
, _("default character map file `%s' not found"),
94 static struct charset_t
*
95 parse_charmap (const char *filename
)
97 struct linereader
*cmfile
;
98 struct charset_t
*result
;
100 enum token_t expected_tok
= tok_error
;
101 const char *expected_str
= NULL
;
102 char *from_name
= NULL
;
103 char *to_name
= NULL
;
105 /* Determine path. */
106 cmfile
= lr_open (filename
, charmap_hash
);
109 if (strchr (filename
, '/') == NULL
)
111 /* Look in the systems charmap directory. */
112 char *buf
= xmalloc (strlen (filename
) + 1 + sizeof (CHARMAP_PATH
));
114 stpcpy (stpcpy (stpcpy (buf
, CHARMAP_PATH
), "/"), filename
);
115 cmfile
= lr_open (buf
, charmap_hash
);
125 /* Allocate room for result. */
126 result
= (struct charset_t
*) xmalloc (sizeof (struct charset_t
));
127 memset (result
, '\0', sizeof (struct charset_t
));
128 /* The default DEFAULT_WIDTH is 1. */
129 result
->width_default
= 1;
131 #define obstack_chunk_alloc malloc
132 #define obstack_chunk_free free
133 obstack_init (&result
->mem_pool
);
135 if (init_hash (&result
->char_table
, 256))
141 /* We use a state machine to describe the charmap description file
147 struct token
*now
= lr_token (cmfile
, NULL
);
148 enum token_t nowtok
= now
->tok
;
151 if (nowtok
== tok_eof
)
157 /* The beginning. We expect the special declarations, EOL or
159 if (nowtok
== tok_eol
)
160 /* Ignore empty lines. */
163 if (nowtok
== tok_charmap
)
168 /* We have to set up the real work. Fill in some
170 if (result
->mb_cur_max
== 0)
171 result
->mb_cur_max
= 1;
172 if (result
->mb_cur_min
== 0)
173 result
->mb_cur_min
= result
->mb_cur_max
;
174 if (result
->mb_cur_min
> result
->mb_cur_max
&& !be_quiet
)
177 %s: <mb_cur_max> must be greater than <mb_cur_min>\n"),
180 result
->mb_cur_min
= result
->mb_cur_max
;
183 lr_ignore_rest (cmfile
, 1);
189 if (nowtok
!= tok_code_set_name
&& nowtok
!= tok_mb_cur_max
190 && nowtok
!= tok_mb_cur_min
&& nowtok
!= tok_escape_char
191 && nowtok
!= tok_comment_char
&& nowtok
!= tok_g0esc
192 && nowtok
!= tok_g1esc
&& nowtok
!= tok_g2esc
193 && nowtok
!= tok_g3esc
)
195 lr_error (cmfile
, _("syntax error in prolog: %s"),
196 _("illegal definition"));
198 lr_ignore_rest (cmfile
, 0);
202 /* We know that we need an argument. */
203 arg
= lr_token (cmfile
, NULL
);
207 case tok_code_set_name
:
208 if (arg
->tok
!= tok_ident
)
211 lr_error (cmfile
, _("syntax error in prolog: %s"),
214 lr_ignore_rest (cmfile
, 0);
218 result
->code_set_name
= obstack_copy0 (&result
->mem_pool
,
222 lr_ignore_rest (cmfile
, 1);
227 if (arg
->tok
!= tok_number
)
230 if (arg
->val
.num
< 1 || arg
->val
.num
> 4)
233 _("value for <%s> must lie between 1 and 4"),
234 nowtok
== tok_mb_cur_min
? "mb_cur_min"
237 lr_ignore_rest (cmfile
, 0);
240 if ((nowtok
== tok_mb_cur_max
&& result
->mb_cur_min
!= 0
241 && (int) arg
->val
.num
< result
->mb_cur_min
)
242 || (nowtok
== tok_mb_cur_min
&& result
->mb_cur_max
!= 0
243 && (int) arg
->val
.num
> result
->mb_cur_max
))
245 lr_error (cmfile
, _("\
246 value of <mb_cur_max> must be greater than the value of <mb_cur_min>"));
248 lr_ignore_rest (cmfile
, 0);
252 if (nowtok
== tok_mb_cur_max
)
253 result
->mb_cur_max
= arg
->val
.num
;
255 result
->mb_cur_min
= arg
->val
.num
;
257 lr_ignore_rest (cmfile
, 1);
260 case tok_escape_char
:
261 case tok_comment_char
:
262 if (arg
->tok
!= tok_ident
)
265 if (arg
->val
.str
.len
!= 1)
267 lr_error (cmfile
, _("\
268 argument to <%s> must be a single character"),
269 nowtok
== tok_escape_char
? "escape_char"
272 lr_ignore_rest (cmfile
, 0);
276 if (nowtok
== tok_escape_char
)
277 cmfile
->escape_char
= *arg
->val
.str
.start
;
279 cmfile
->comment_char
= *arg
->val
.str
.start
;
281 lr_ignore_rest (cmfile
, 1);
288 lr_ignore_rest (cmfile
, 0); /* XXX */
293 assert (! "Should not happen");
298 /* We have seen `CHARMAP' and now are in the body. Each line
299 must have the format "%s %s %s\n" or "%s...%s %s %s\n". */
300 if (nowtok
== tok_eol
)
301 /* Ignore empty lines. */
304 if (nowtok
== tok_end
)
306 expected_tok
= tok_charmap
;
307 expected_str
= "CHARMAP";
312 if (nowtok
!= tok_bsymbol
)
314 lr_error (cmfile
, _("syntax error in %s definition: %s"),
315 "CHARMAP", _("no symbolic name given"));
317 lr_ignore_rest (cmfile
, 0);
321 /* If the previous line was not completely correct free the
323 if (from_name
!= NULL
)
324 obstack_free (&result
->mem_pool
, from_name
);
326 from_name
= (char *) obstack_copy0 (&result
->mem_pool
,
335 /* We have two possibilities: We can see an ellipsis or an
337 if (nowtok
== tok_ellipsis
)
345 if (nowtok
!= tok_charcode
&& nowtok
!= tok_ucs2
346 && nowtok
!= tok_ucs4
)
348 lr_error (cmfile
, _("syntax error in %s definition: %s"),
349 "CHARMAP", _("illegal encoding given"));
351 lr_ignore_rest (cmfile
, 0);
357 if (nowtok
== tok_charcode
)
358 /* Write char value in table. */
359 charset_new_char (cmfile
, result
, now
->val
.charcode
.nbytes
,
360 now
->val
.charcode
.val
, from_name
, to_name
);
362 /* Determine ISO 10646 value and write into table. */
363 charset_new_unicode (cmfile
, result
, now
->val
.charcode
.nbytes
,
364 now
->val
.charcode
.val
, from_name
, to_name
);
366 /* Ignore trailing comment silently. */
367 lr_ignore_rest (cmfile
, 0);
376 if (nowtok
!= tok_bsymbol
)
378 lr_error (cmfile
, _("syntax error in %s definition: %s"),
380 _("no symbolic name given for end of range"));
382 lr_ignore_rest (cmfile
, 0);
386 /* If the previous line was not completely correct free the
388 to_name
= (char *) obstack_copy0 (&result
->mem_pool
,
389 cmfile
->token
.val
.str
.start
,
390 cmfile
->token
.val
.str
.len
);
396 if (nowtok
!= expected_tok
)
397 lr_error (cmfile
, _("\
398 `%1$s' definition does not end with `END %1$s'"), expected_str
);
400 lr_ignore_rest (cmfile
, nowtok
== expected_tok
);
405 /* Waiting for WIDTH... */
406 if (nowtok
== tok_eol
)
407 /* Ignore empty lines. */
410 if (nowtok
== tok_width_default
)
416 if (nowtok
== tok_width
)
418 lr_ignore_rest (cmfile
, 1);
423 if (nowtok
== tok_width_variable
)
425 lr_ignore_rest (cmfile
, 1);
430 lr_error (cmfile
, _("\
431 only WIDTH definitions are allowed to follow the CHARMAP definition"));
433 lr_ignore_rest (cmfile
, 0);
437 if (nowtok
!= tok_number
)
438 lr_error (cmfile
, _("value for %s must be an integer"),
441 result
->width_default
= now
->val
.num
;
443 lr_ignore_rest (cmfile
, nowtok
== tok_number
);
449 /* We now expect `END WIDTH' or lines of the format "%s %d\n" or
451 if (nowtok
== tok_eol
)
452 /* ignore empty lines. */
455 if (nowtok
== tok_end
)
457 expected_tok
= tok_width
;
458 expected_str
= "WIDTH";
463 if (nowtok
!= tok_bsymbol
)
465 lr_error (cmfile
, _("syntax error in %s definition: %s"),
466 "WIDTH", _("no symbolic name given"));
468 lr_ignore_rest (cmfile
, 0);
472 if (from_name
!= NULL
)
473 obstack_free (&result
->mem_pool
, from_name
);
475 from_name
= (char *) obstack_copy0 (&result
->mem_pool
,
484 if (nowtok
== tok_ellipsis
)
491 if (nowtok
!= tok_number
)
492 lr_error (cmfile
, _("value for %s must be an integer"),
496 /* Store width for chars. */
497 new_width (cmfile
, result
, from_name
, to_name
, now
->val
.num
);
503 lr_ignore_rest (cmfile
, nowtok
== tok_number
);
509 if (nowtok
!= tok_bsymbol
)
511 lr_error (cmfile
, _("syntax error in %s definition: %s"),
512 "WIDTH", _("no symbolic name given for end of range"));
514 lr_ignore_rest (cmfile
, 0);
520 to_name
= (char *) obstack_copy0 (&result
->mem_pool
,
528 /* We now expect `END WIDTH_VARIABLE' or lines of the format
529 "%s\n" or "%s...%s\n". */
530 if (nowtok
== tok_eol
)
531 /* ignore empty lines. */
534 if (nowtok
== tok_end
)
536 expected_tok
= tok_width_variable
;
537 expected_str
= "WIDTH_VARIABLE";
542 if (nowtok
!= tok_bsymbol
)
544 lr_error (cmfile
, _("syntax error in %s definition: %s"),
545 "WIDTH_VARIABLE", _("no symbolic name given"));
547 lr_ignore_rest (cmfile
, 0);
552 if (from_name
!= NULL
)
553 obstack_free (&result
->mem_pool
, from_name
);
555 from_name
= (char *) obstack_copy0 (&result
->mem_pool
,
564 if (nowtok
== tok_ellipsis
)
575 if (nowtok
!= tok_bsymbol
)
576 lr_error (cmfile
, _("syntax error in %s definition: %s"),
578 _("no symbolic name given for end of range"));
581 to_name
= (char *) obstack_copy0 (&result
->mem_pool
,
584 /* XXX Enter value into table. */
587 lr_ignore_rest (cmfile
, nowtok
== tok_bsymbol
);
593 error (5, 0, _("%s: error in state machine"), __FILE__
);
599 if (state
!= 91 && !be_quiet
)
600 error (0, 0, _("%s: premature end of file"), cmfile
->fname
);
609 new_width (struct linereader
*cmfile
, struct charset_t
*result
,
610 const char *from
, const char *to
, unsigned long int width
)
612 unsigned int from_val
, to_val
;
614 from_val
= charset_find_value (result
, from
, strlen (from
));
615 if ((wchar_t) from_val
== ILLEGAL_CHAR_VALUE
)
617 lr_error (cmfile
, _("unknown character `%s'"), from
);
625 to_val
= charset_find_value (result
, to
, strlen (to
));
626 if ((wchar_t) to_val
== ILLEGAL_CHAR_VALUE
)
628 lr_error (cmfile
, _("unknown character `%s'"), to
);
633 if (result
->nwidth_rules
>= result
->nwidth_rules_max
)
635 size_t new_size
= result
->nwidth_rules
+ 32;
636 struct width_rule
*new_rules
=
637 (struct width_rule
*) obstack_alloc (&result
->mem_pool
,
639 * sizeof (struct width_rule
)));
641 memcpy (new_rules
, result
->width_rules
,
642 result
->nwidth_rules_max
* sizeof (struct width_rule
));
644 result
->width_rules
= new_rules
;
645 result
->nwidth_rules_max
= new_size
;
648 result
->width_rules
[result
->nwidth_rules
].from
= from_val
;
649 result
->width_rules
[result
->nwidth_rules
].to
= to_val
;
650 result
->width_rules
[result
->nwidth_rules
].width
= (unsigned int) width
;
651 ++result
->nwidth_rules
;