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