collate 3/4: Bring in input files for new LC_COLLATE format
[dragonfly.git] / usr.bin / colldef / parse.y
1 %{
2 /*-
3  * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
4  *              at Electronni Visti IA, Kiev, Ukraine.
5  *                      All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: head/usr.bin/colldef/parse.y 175038 2008-01-01 10:04:10Z imp $
29  */
30
31
32 #include <sys/types.h>
33 #include <arpa/inet.h>
34 #include <err.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <sysexits.h>
40 #include "collate.h"
41 #include "common.h"
42
43 extern FILE *yyin;
44 void yyerror(const char *fmt, ...) __printflike(1, 2);
45 int yylex(void);
46 static void usage(void);
47 static void collate_print_tables(void);
48
49 char map_name[FILENAME_MAX] = ".";
50 char curr_chain[STR_LEN];
51
52 char __collate_version[STR_LEN];
53 u_char charmap_table[UCHAR_MAX + 1][CHARMAP_SYMBOL_LEN];
54
55 #undef __collate_substitute_table
56 u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN];
57 #undef __collate_char_pri_table
58 struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
59 struct __collate_st_chain_pri *__collate_chain_pri_table;
60
61 int chain_index = 0;
62 int prim_pri = 1, sec_pri = 1;
63 #ifdef COLLATE_DEBUG
64 int debug;
65 #endif
66
67 const char *out_file = "LC_COLLATE";
68 %}
69 %union {
70         u_char ch;
71         u_char str[BUFSIZE];
72 }
73 %token SUBSTITUTE WITH ORDER RANGE
74 %token <str> STRING
75 %token <str> DEFN
76 %token <ch> CHAR
77 %%
78 collate : statment_list
79 ;
80 statment_list : statment
81         | statment_list '\n' statment
82 ;
83 statment :
84         | charmap
85         | substitute
86         | order
87 ;
88 charmap : DEFN CHAR {
89         if (strlen($1) + 1 > CHARMAP_SYMBOL_LEN)
90                 yyerror("Charmap symbol name '%s' is too long", $1);
91         strcpy(charmap_table[$2], $1);
92 }
93 ;
94 substitute : SUBSTITUTE CHAR WITH STRING {
95         if ($2 == '\0')
96                 yyerror("NUL character can't be substituted");
97         if (strchr($4, $2) != NULL)
98                 yyerror("Char 0x%02x substitution is recursive", $2);
99         if (strlen($4) + 1 > STR_LEN)
100                 yyerror("Char 0x%02x substitution is too long", $2);
101         strcpy(__collate_substitute_table[$2], $4);
102 }
103 ;
104 order : ORDER order_list {
105         FILE *fp;
106         int ch, substed, ordered;
107         uint32_t u32;
108
109         for (ch = 0; ch < UCHAR_MAX + 1; ch++) {
110                 substed = (__collate_substitute_table[ch][0] != ch);
111                 ordered = !!__collate_char_pri_table[ch].prim;
112                 if (!ordered && !substed)
113                         yyerror("Char 0x%02x not found", ch);
114                 if (substed && ordered)
115                         yyerror("Char 0x%02x can't be ordered since substituted", ch);
116         }
117
118         if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
119              sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
120                 yyerror("can't grow chain table");
121         (void)memset(&__collate_chain_pri_table[chain_index], 0,
122                      sizeof(__collate_chain_pri_table[0]));
123         chain_index++;
124
125 #ifdef COLLATE_DEBUG
126         if (debug)
127                 collate_print_tables();
128 #endif
129         if ((fp = fopen(out_file, "w")) == NULL)
130                 err(EX_UNAVAILABLE, "can't open destination file %s",
131                     out_file);
132
133         strcpy(__collate_version, COLLATE_VERSION1_2);
134         if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1)
135                 err(EX_IOERR,
136                 "IO error writting collate version to destination file %s",
137                     out_file);
138         u32 = htonl(chain_index);
139         if (fwrite(&u32, sizeof(u32), 1, fp) != 1)
140                 err(EX_IOERR,
141                 "IO error writting chains number to destination file %s",
142                     out_file);
143         if (fwrite(__collate_substitute_table,
144                    sizeof(__collate_substitute_table), 1, fp) != 1)
145                 err(EX_IOERR,
146                 "IO error writting substitute table to destination file %s",
147                     out_file);
148         for (ch = 0; ch < UCHAR_MAX + 1; ch++) {
149                 __collate_char_pri_table[ch].prim =
150                     htonl(__collate_char_pri_table[ch].prim);
151                 __collate_char_pri_table[ch].sec =
152                     htonl(__collate_char_pri_table[ch].sec);
153         }
154         if (fwrite(__collate_char_pri_table,
155                    sizeof(__collate_char_pri_table), 1, fp) != 1)
156                 err(EX_IOERR,
157                 "IO error writting char table to destination file %s",
158                     out_file);
159         for (ch = 0; ch < chain_index; ch++) {
160                 __collate_chain_pri_table[ch].prim =
161                     htonl(__collate_chain_pri_table[ch].prim);
162                 __collate_chain_pri_table[ch].sec =
163                     htonl(__collate_chain_pri_table[ch].sec);
164         }
165         if (fwrite(__collate_chain_pri_table,
166                    sizeof(*__collate_chain_pri_table), chain_index, fp) !=
167                    (size_t)chain_index)
168                 err(EX_IOERR,
169                 "IO error writting chain table to destination file %s",
170                     out_file);
171         if (fclose(fp) != 0)
172                 err(EX_IOERR, "IO error closing destination file %s",
173                     out_file);
174         exit(EX_OK);
175 }
176 ;
177 order_list : item
178         | order_list ';' item
179 ;
180 chain : CHAR CHAR {
181         curr_chain[0] = $1;
182         curr_chain[1] = $2;
183         if (curr_chain[0] == '\0' || curr_chain[1] == '\0')
184                 yyerror("\\0 can't be chained");
185         curr_chain[2] = '\0';
186 }
187         | chain CHAR {
188         static char tb[2];
189
190         tb[0] = $2;
191         if (tb[0] == '\0')
192                 yyerror("\\0 can't be chained");
193         if (strlen(curr_chain) + 2 > STR_LEN)
194                 yyerror("Chain '%s' grows too long", curr_chain);
195         (void)strcat(curr_chain, tb);
196 }
197 ;
198 item :  CHAR {
199         if (__collate_char_pri_table[$1].prim)
200                 yyerror("Char 0x%02x duplicated", $1);
201         __collate_char_pri_table[$1].prim = prim_pri++;
202 }
203         | chain {
204         if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
205              sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
206                 yyerror("can't grow chain table");
207         (void)memset(&__collate_chain_pri_table[chain_index], 0,
208                      sizeof(__collate_chain_pri_table[0]));
209         (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain);
210         __collate_chain_pri_table[chain_index].prim = prim_pri++;
211         chain_index++;
212 }
213         | CHAR RANGE CHAR {
214         u_int i;
215
216         if ($3 <= $1)
217                 yyerror("Illegal range 0x%02x -- 0x%02x", $1, $3);
218
219         for (i = $1; i <= $3; i++) {
220                 if (__collate_char_pri_table[(u_char)i].prim)
221                         yyerror("Char 0x%02x duplicated", (u_char)i);
222                 __collate_char_pri_table[(u_char)i].prim = prim_pri++;
223         }
224 }
225         | '{' prim_order_list '}' {
226         prim_pri++;
227 }
228         | '(' sec_order_list ')' {
229         prim_pri++;
230         sec_pri = 1;
231 }
232 ;
233 prim_order_list : prim_sub_item
234         | prim_order_list ',' prim_sub_item 
235 ;
236 sec_order_list : sec_sub_item
237         | sec_order_list ',' sec_sub_item 
238 ;
239 prim_sub_item : CHAR {
240         if (__collate_char_pri_table[$1].prim)
241                 yyerror("Char 0x%02x duplicated", $1);
242         __collate_char_pri_table[$1].prim = prim_pri;
243 }
244         | CHAR RANGE CHAR {
245         u_int i;
246
247         if ($3 <= $1)
248                 yyerror("Illegal range 0x%02x -- 0x%02x",
249                         $1, $3);
250
251         for (i = $1; i <= $3; i++) {
252                 if (__collate_char_pri_table[(u_char)i].prim)
253                         yyerror("Char 0x%02x duplicated", (u_char)i);
254                 __collate_char_pri_table[(u_char)i].prim = prim_pri;
255         }
256 }
257         | chain {
258         if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
259              sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
260                 yyerror("can't grow chain table");
261         (void)memset(&__collate_chain_pri_table[chain_index], 0,
262                      sizeof(__collate_chain_pri_table[0]));
263         (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain);
264         __collate_chain_pri_table[chain_index].prim = prim_pri;
265         chain_index++;
266 }
267 ;
268 sec_sub_item : CHAR {
269         if (__collate_char_pri_table[$1].prim)
270                 yyerror("Char 0x%02x duplicated", $1);
271         __collate_char_pri_table[$1].prim = prim_pri;
272         __collate_char_pri_table[$1].sec = sec_pri++;
273 }
274         | CHAR RANGE CHAR {
275         u_int i;
276
277         if ($3 <= $1)
278                 yyerror("Illegal range 0x%02x -- 0x%02x",
279                         $1, $3);
280
281         for (i = $1; i <= $3; i++) {
282                 if (__collate_char_pri_table[(u_char)i].prim)
283                         yyerror("Char 0x%02x duplicated", (u_char)i);
284                 __collate_char_pri_table[(u_char)i].prim = prim_pri;
285                 __collate_char_pri_table[(u_char)i].sec = sec_pri++;
286         }
287 }
288         | chain {
289         if ((__collate_chain_pri_table = realloc(__collate_chain_pri_table,
290              sizeof(*__collate_chain_pri_table) * (chain_index + 1))) == NULL)
291                 yyerror("can't grow chain table");
292         (void)memset(&__collate_chain_pri_table[chain_index], 0,
293                      sizeof(__collate_chain_pri_table[0]));
294         (void)strcpy(__collate_chain_pri_table[chain_index].str, curr_chain);
295         __collate_chain_pri_table[chain_index].prim = prim_pri;
296         __collate_chain_pri_table[chain_index].sec = sec_pri++;
297         chain_index++;
298 }
299 ;
300 %%
301 int
302 main(int ac, char **av)
303 {
304         int ch;
305
306 #ifdef COLLATE_DEBUG
307         while((ch = getopt(ac, av, ":do:I:")) != -1) {
308 #else
309         while((ch = getopt(ac, av, ":o:I:")) != -1) {
310 #endif
311                 switch (ch)
312                 {
313 #ifdef COLLATE_DEBUG
314                   case 'd':
315                         debug++;
316                         break;
317 #endif
318                   case 'o':
319                         out_file = optarg;
320                         break;
321
322                   case 'I':
323                         strlcpy(map_name, optarg, sizeof(map_name));
324                         break;
325
326                   default:
327                         usage();
328                 }
329         }
330         ac -= optind;
331         av += optind;
332         if (ac > 0) {
333                 if ((yyin = fopen(*av, "r")) == NULL)
334                         err(EX_UNAVAILABLE, "can't open source file %s", *av);
335         }
336         for (ch = 0; ch <= UCHAR_MAX; ch++)
337                 __collate_substitute_table[ch][0] = ch;
338         yyparse();
339         return 0;
340 }
341
342 static void
343 usage(void)
344 {
345         fprintf(stderr, "usage: colldef [-I map_dir] [-o out_file] [filename]\n");
346         exit(EX_USAGE);
347 }
348
349 void
350 yyerror(const char *fmt, ...)
351 {
352         va_list ap;
353         char msg[128];
354
355         va_start(ap, fmt);
356         vsnprintf(msg, sizeof(msg), fmt, ap);
357         va_end(ap);
358         errx(EX_UNAVAILABLE, "%s near line %d", msg, line_no);
359 }
360
361 #ifdef COLLATE_DEBUG
362 static void
363 collate_print_tables(void)
364 {
365         int i;
366
367         printf("Substitute table:\n");
368         for (i = 0; i < UCHAR_MAX + 1; i++)
369             if (i != *__collate_substitute_table[i])
370                 printf("\t'%c' --> \"%s\"\n", i,
371                        __collate_substitute_table[i]);
372         printf("Chain priority table:\n");
373         for (i = 0; i < chain_index - 1; i++)
374                 printf("\t\"%s\" : %d %d\n",
375                     __collate_chain_pri_table[i].str,
376                     __collate_chain_pri_table[i].prim,
377                     __collate_chain_pri_table[i].sec);
378         printf("Char priority table:\n");
379         for (i = 0; i < UCHAR_MAX + 1; i++)
380                 printf("\t'%c' : %d %d\n", i, __collate_char_pri_table[i].prim,
381                        __collate_char_pri_table[i].sec);
382 }
383 #endif