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