5af12dca5e435e93ebdd8b83c3d14aa36065ae1b
[dragonfly.git] / usr.bin / mkesdb / yacc.y
1 /*      $NetBSD: src/usr.bin/mkesdb/yacc.y,v 1.3 2004/01/02 12:09:48 itojun Exp $       */
2
3 %{
4 /*-
5  * Copyright (c)2003 Citrus Project,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/types.h>
31 #include <sys/queue.h>
32 #include <assert.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "citrus_namespace.h"
42 #include "citrus_types.h"
43 #include "citrus_region.h"
44 #include "citrus_esdb_file.h"
45 #include "citrus_db_hash.h"
46 #include "citrus_db_factory.h"
47 #include "citrus_lookup_factory.h"
48
49 #include "ldef.h"
50
51 extern FILE     *yyin;
52
53 static int                      debug = 0, num_csids = 0;
54 static char                     *output = NULL;
55 static char                     *name, *encoding, *variable;
56 static uint32_t                 invalid;
57 static int                      use_invalid = 0;
58 static struct named_csid_list   named_csids;
59
60 static void     dump_file(void);
61 static void     register_named_csid(char *, uint32_t);
62 static void     set_prop_string(const char *, char **, char **);
63 static void     set_invalid(uint32_t);
64
65 int yylex (void);
66 %}
67 %union {
68         uint32_t        i_value;
69         char            *s_value;
70 }
71
72 %token                  R_NAME R_ENCODING R_VARIABLE R_DEFCSID R_INVALID
73 %token                  R_LN
74 %token <i_value>        L_IMM
75 %token <s_value>        L_STRING
76
77 %%
78
79 file            : property
80                 { dump_file(); }
81
82 property        : /* empty */
83                 | property R_LN
84                 | property name R_LN
85                 | property encoding R_LN
86                 | property variable R_LN
87                 | property defcsid R_LN
88                 | property invalid R_LN
89
90 name            : R_NAME L_STRING
91                 {
92                         set_prop_string("NAME", &name, &$2);
93                 }
94
95 encoding        : R_ENCODING L_STRING
96                 {
97                         set_prop_string("ENCODING", &encoding, &$2);
98                 }
99 variable        : R_VARIABLE L_STRING
100                 {
101                         set_prop_string("VARIABLE", &variable, &$2);
102                 }
103 defcsid         : R_DEFCSID L_STRING L_IMM
104                 {
105                         register_named_csid($2, $3);
106                         $2 = NULL;
107                 }
108 invalid         : R_INVALID L_IMM
109                 {
110                         set_invalid($2);
111                 }
112 %%
113
114 int
115 yyerror(const char *s)
116 {
117         fprintf(stderr, "%s in %d\n", s, aline_number);
118
119         return (0);
120 }
121
122 #define CHKERR(ret, func, a)                                            \
123 do {                                                                    \
124         ret = func a;                                                   \
125         if (ret)                                                        \
126                 errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));     \
127 } while (/*CONSTCOND*/0)
128 static void
129 dump_file(void)
130 {
131         int ret;
132         FILE *fp;
133         struct _db_factory *df;
134         struct _region data;
135         struct named_csid *csid;
136         char buf[100];
137         int i;
138         void *serialized;
139         size_t size;
140
141         ret = 0;
142         if (!name) {
143                 fprintf(stderr, "NAME is mandatory.\n");
144                 ret = 1;
145         }
146         if (!encoding) {
147                 fprintf(stderr, "ENCODING is mandatory.\n");
148                 ret = 1;
149         }
150         if (ret)
151                 exit(1);
152
153         /*
154          * build database
155          */
156         CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
157
158         /* store version */
159         CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_VERSION,
160                                              _CITRUS_ESDB_VERSION));
161
162         /* store encoding */
163         CHKERR(ret, _db_factory_addstr_by_s, (df, _CITRUS_ESDB_SYM_ENCODING,
164                                               encoding));
165
166         /* store variable */
167         if (variable)
168                 CHKERR(ret, _db_factory_addstr_by_s,
169                        (df, _CITRUS_ESDB_SYM_VARIABLE, variable));
170
171         /* store invalid */
172         if (use_invalid)
173                 CHKERR(ret, _db_factory_add32_by_s, (df,
174                                                      _CITRUS_ESDB_SYM_INVALID,
175                                                      invalid));
176
177         /* store num of charsets */
178         CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_NUM_CHARSETS,
179                                              num_csids));
180         i=0;
181         STAILQ_FOREACH(csid, &named_csids, ci_entry) {
182                 snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d",
183                     i);
184                 CHKERR(ret, _db_factory_addstr_by_s,
185                        (df, buf, csid->ci_symbol));
186                 snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSID_PREFIX "%d",
187                     i);
188                 CHKERR(ret, _db_factory_add32_by_s, (df, buf, csid->ci_csid));
189                 i++;
190         }
191
192         /*
193          * dump database to file
194          */
195         if (output)
196                 fp = fopen(output, "wb");
197         else
198                 fp = stdout;
199
200         if (fp == NULL) {
201                 perror("fopen");
202                 exit(1);
203         }
204
205         /* dump database body */
206         size = _db_factory_calc_size(df);
207         serialized = malloc(size);
208         _region_init(&data, serialized, size);
209         CHKERR(ret, _db_factory_serialize, (df, _CITRUS_ESDB_MAGIC, &data));
210         if (fwrite(serialized, size, 1, fp) != 1)
211                 err(EXIT_FAILURE, "fwrite");
212
213         fclose(fp);
214 }
215
216 static void
217 set_prop_string(const char *res, char **store, char **data)
218 {
219         char buf[256];
220
221         if (*store) {
222                 snprintf(buf, sizeof(buf),
223                          "%s is duplicated. ignored the one", res);
224                 yyerror(buf);
225                 return;
226         }
227
228         *store = *data;
229         *data = NULL;
230 }
231
232 static void
233 set_invalid(uint32_t inv)
234 {
235         invalid = inv;
236         use_invalid = 1;
237 }
238
239 static void
240 register_named_csid(char *sym, uint32_t val)
241 {
242         struct named_csid *csid;
243
244         STAILQ_FOREACH(csid, &named_csids, ci_entry) {
245                 if (strcmp(csid->ci_symbol, sym) == 0) {
246                         yyerror("multiply defined CSID");
247                         exit(1);
248                 }
249         }
250
251         csid = malloc(sizeof(*csid));
252         if (csid == NULL) {
253                 perror("malloc");
254                 exit(1);
255         }
256         csid->ci_symbol = sym;
257         csid->ci_csid = val;
258         STAILQ_INSERT_TAIL(&named_csids, csid, ci_entry);
259         num_csids++;
260 }
261
262 static void
263 do_mkdb(FILE *in)
264 {
265         int ret;
266         FILE *out;
267
268         /* dump DB to file */
269         if (output)
270                 out = fopen(output, "wb");
271         else
272                 out = stdout;
273
274         if (out==NULL)
275                 err(EXIT_FAILURE, "fopen");
276
277         ret = _lookup_factory_convert(out, in);
278         fclose(out);
279         if (ret && output)
280                 unlink(output); /* dump failure */
281         if (ret)
282                 errx(EXIT_FAILURE, "%s\n", strerror(ret));
283 }
284
285 static void
286 usage(void)
287 {
288         errx(EXIT_FAILURE,
289              "usage:\n"
290              "\t%s [-o outfile] [infile]\n"
291              "\t%s -m [-o outfile] [infile]",
292              getprogname(), getprogname());
293 }
294
295 int
296 main(int argc, char **argv)
297 {
298         int ch;
299         FILE *in = NULL;
300         int mkdb = 0;
301
302         while ((ch=getopt(argc, argv, "do:m")) != -1) {
303                 switch (ch) {
304                 case 'd':
305                         debug = 1;
306                         break;
307                 case 'o':
308                         output = strdup(optarg);
309                         break;
310                 case 'm':
311                         mkdb = 1;
312                         break;
313                 default:
314                         usage();
315                 }
316         }
317
318         argc-=optind;
319         argv+=optind;
320         switch (argc) {
321         case 0:
322                 in = stdin;
323                 break;
324         case 1:
325                 in = fopen(argv[0], "r");
326                 if (!in)
327                         err(EXIT_FAILURE, argv[0]);
328                 break;
329         default:
330                 usage();
331         }
332
333         if (mkdb)
334                 do_mkdb(in);
335         else {
336                 STAILQ_INIT(&named_csids);
337                 yyin=in;
338                 yyparse();
339         }
340
341         return (0);
342 }