1219019Sgabor/* $FreeBSD: stable/11/usr.bin/mkesdb/yacc.y 330449 2018-03-05 07:26:05Z eadler $ */
2219019Sgabor/* $NetBSD: yacc.y,v 1.4 2005/06/02 02:09:25 lukem Exp $	*/
3219019Sgabor
4219019Sgabor%{
5219019Sgabor/*-
6330449Seadler * SPDX-License-Identifier: BSD-2-Clause
7330449Seadler *
8219019Sgabor * Copyright (c)2003 Citrus Project,
9219019Sgabor * All rights reserved.
10219019Sgabor *
11219019Sgabor * Redistribution and use in source and binary forms, with or without
12219019Sgabor * modification, are permitted provided that the following conditions
13219019Sgabor * are met:
14219019Sgabor * 1. Redistributions of source code must retain the above copyright
15219019Sgabor *    notice, this list of conditions and the following disclaimer.
16219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
17219019Sgabor *    notice, this list of conditions and the following disclaimer in the
18219019Sgabor *    documentation and/or other materials provided with the distribution.
19219019Sgabor *
20219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23219019Sgabor * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30219019Sgabor * SUCH DAMAGE.
31219019Sgabor */
32219019Sgabor
33219019Sgabor#include <sys/cdefs.h>
34219019Sgabor#include <sys/types.h>
35219019Sgabor#include <sys/queue.h>
36219019Sgabor
37219019Sgabor#include <assert.h>
38219019Sgabor#include <err.h>
39219019Sgabor#include <errno.h>
40219019Sgabor#include <limits.h>
41219019Sgabor#include <stdio.h>
42219019Sgabor#include <stdlib.h>
43219019Sgabor#include <string.h>
44219019Sgabor#include <unistd.h>
45219019Sgabor
46219019Sgabor#include "citrus_namespace.h"
47219019Sgabor#include "citrus_types.h"
48219019Sgabor#include "citrus_region.h"
49219019Sgabor#include "citrus_esdb_file.h"
50219019Sgabor#include "citrus_db_hash.h"
51219019Sgabor#include "citrus_db_factory.h"
52219019Sgabor#include "citrus_lookup_factory.h"
53219019Sgabor
54219019Sgabor#include "ldef.h"
55219019Sgabor
56219019Sgaborextern FILE			*yyin;
57219019Sgabor
58219019Sgaborstatic struct named_csid_list	 named_csids;
59219019Sgaborstatic char			*encoding, *name, *output = NULL, *variable;
60219019Sgaborstatic u_int32_t		 invalid;
61219019Sgaborstatic int			 debug = 0, num_csids = 0, use_invalid = 0;
62219019Sgabor
63219019Sgaborstatic void	 dump_file(void);
64219019Sgaborstatic void	 register_named_csid(char *, u_int32_t);
65219019Sgaborstatic void	 set_invalid(u_int32_t);
66219019Sgaborstatic void	 set_prop_string(const char *, char **, char **);
67219019Sgabor%}
68219019Sgabor%union {
69219019Sgabor	u_int32_t	i_value;
70219019Sgabor	char		*s_value;
71219019Sgabor}
72219019Sgabor
73219019Sgabor%token			R_NAME R_ENCODING R_VARIABLE R_DEFCSID R_INVALID
74219019Sgabor%token			R_LN
75219019Sgabor%token <i_value>	L_IMM
76219019Sgabor%token <s_value>	L_STRING
77219019Sgabor
78219019Sgabor%%
79219019Sgabor
80219019Sgaborfile		: property
81219019Sgabor		{ dump_file(); }
82219019Sgabor
83219019Sgaborproperty	: /* empty */
84219019Sgabor		| property R_LN
85219019Sgabor		| property name R_LN
86219019Sgabor		| property encoding R_LN
87219019Sgabor		| property variable R_LN
88219019Sgabor		| property defcsid R_LN
89219019Sgabor		| property invalid R_LN
90219019Sgabor
91219019Sgaborname		: R_NAME L_STRING
92219019Sgabor		{
93219019Sgabor			set_prop_string("NAME", &name, &$2);
94219019Sgabor		}
95219019Sgabor
96219019Sgaborencoding	: R_ENCODING L_STRING
97219019Sgabor		{
98219019Sgabor			set_prop_string("ENCODING", &encoding, &$2);
99219019Sgabor		}
100219019Sgaborvariable	: R_VARIABLE L_STRING
101219019Sgabor		{
102219019Sgabor			set_prop_string("VARIABLE", &variable, &$2);
103219019Sgabor		}
104219019Sgabordefcsid		: R_DEFCSID L_STRING L_IMM
105219019Sgabor		{
106219019Sgabor			register_named_csid($2, $3);
107219019Sgabor			$2 = NULL;
108219019Sgabor		}
109219019Sgaborinvalid		: R_INVALID L_IMM
110219019Sgabor		{
111219019Sgabor			set_invalid($2);
112219019Sgabor		}
113219019Sgabor%%
114219019Sgabor
115219019Sgaborint
116219019Sgaboryyerror(const char *s)
117219019Sgabor{
118219019Sgabor
119250984Sed	fprintf(stderr, "%s in %d\n", s, linenumber);
120219019Sgabor
121219019Sgabor	return (0);
122219019Sgabor}
123219019Sgabor
124219019Sgabor#define CHKERR(ret, func, a)						\
125219019Sgabordo {									\
126219019Sgabor	ret = func a;							\
127219019Sgabor	if (ret)							\
128219019Sgabor		errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));	\
129219019Sgabor} while (/*CONSTCOND*/0)
130219019Sgaborstatic void
131219019Sgabordump_file(void)
132219019Sgabor{
133219019Sgabor	struct _db_factory *df;
134219019Sgabor	struct _region data;
135219019Sgabor	struct named_csid *csid;
136219019Sgabor	FILE *fp;
137219019Sgabor	char buf[100];
138219019Sgabor	void *serialized;
139219019Sgabor	size_t size;
140219019Sgabor	int i, ret;
141219019Sgabor
142219019Sgabor	ret = 0;
143219019Sgabor	if (!name) {
144219019Sgabor		fprintf(stderr, "NAME is mandatory.\n");
145219019Sgabor		ret = 1;
146219019Sgabor	}
147219019Sgabor	if (!encoding) {
148219019Sgabor		fprintf(stderr, "ENCODING is mandatory.\n");
149219019Sgabor		ret = 1;
150219019Sgabor	}
151219019Sgabor	if (ret)
152219019Sgabor		exit(1);
153219019Sgabor
154219019Sgabor	/*
155219019Sgabor	 * build database
156219019Sgabor	 */
157219019Sgabor	CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
158219019Sgabor
159219019Sgabor	/* store version */
160219019Sgabor	CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_VERSION,
161219019Sgabor	    _CITRUS_ESDB_VERSION));
162219019Sgabor
163219019Sgabor	/* store encoding */
164219019Sgabor	CHKERR(ret, _db_factory_addstr_by_s, (df, _CITRUS_ESDB_SYM_ENCODING,
165219019Sgabor	    encoding));
166219019Sgabor
167219019Sgabor	/* store variable */
168219019Sgabor	if (variable)
169219019Sgabor		CHKERR(ret, _db_factory_addstr_by_s,
170219019Sgabor		    (df, _CITRUS_ESDB_SYM_VARIABLE, variable));
171219019Sgabor
172219019Sgabor	/* store invalid */
173219019Sgabor	if (use_invalid)
174219019Sgabor		CHKERR(ret, _db_factory_add32_by_s, (df,
175219019Sgabor		    _CITRUS_ESDB_SYM_INVALID, invalid));
176219019Sgabor
177219019Sgabor	/* store num of charsets */
178219019Sgabor	CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_NUM_CHARSETS,
179219019Sgabor	    num_csids));
180219019Sgabor	i = 0;
181219019Sgabor	STAILQ_FOREACH(csid, &named_csids, ci_entry) {
182219019Sgabor		snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d",
183219019Sgabor		    i);
184219019Sgabor		CHKERR(ret, _db_factory_addstr_by_s,
185219019Sgabor		    (df, buf, csid->ci_symbol));
186219019Sgabor		snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSID_PREFIX "%d",
187219019Sgabor		    i);
188219019Sgabor		CHKERR(ret, _db_factory_add32_by_s, (df, buf, csid->ci_csid));
189219019Sgabor		i++;
190219019Sgabor	}
191219019Sgabor
192219019Sgabor	/*
193219019Sgabor	 * dump database to file
194219019Sgabor	 */
195219019Sgabor	fp = output ? fopen(output, "wb") : stdout;
196219019Sgabor	if (fp == NULL) {
197219019Sgabor		perror("fopen");
198219019Sgabor		exit(1);
199219019Sgabor	}
200219019Sgabor
201219019Sgabor	/* dump database body */
202219019Sgabor	size = _db_factory_calc_size(df);
203219019Sgabor	serialized = malloc(size);
204219019Sgabor	_region_init(&data, serialized, size);
205219019Sgabor	CHKERR(ret, _db_factory_serialize, (df, _CITRUS_ESDB_MAGIC, &data));
206219019Sgabor	if (fwrite(serialized, size, 1, fp) != 1)
207219019Sgabor		err(EXIT_FAILURE, "fwrite");
208219019Sgabor
209219019Sgabor	fclose(fp);
210219019Sgabor}
211219019Sgabor
212219019Sgaborstatic void
213219019Sgaborset_prop_string(const char *res, char **store, char **data)
214219019Sgabor{
215219019Sgabor	char buf[256];
216219019Sgabor
217219019Sgabor	if (*store) {
218219019Sgabor		snprintf(buf, sizeof(buf),
219219019Sgabor		    "%s is duplicated. ignored the one", res);
220219019Sgabor		yyerror(buf);
221219019Sgabor		return;
222219019Sgabor	}
223219019Sgabor
224219019Sgabor	*store = *data;
225219019Sgabor	*data = NULL;
226219019Sgabor}
227219019Sgabor
228219019Sgaborstatic void
229219019Sgaborset_invalid(u_int32_t inv)
230219019Sgabor{
231219019Sgabor
232219019Sgabor	invalid = inv;
233219019Sgabor	use_invalid = 1;
234219019Sgabor}
235219019Sgabor
236219019Sgaborstatic void
237219019Sgaborregister_named_csid(char *sym, u_int32_t val)
238219019Sgabor{
239219019Sgabor	struct named_csid *csid;
240219019Sgabor
241219019Sgabor	STAILQ_FOREACH(csid, &named_csids, ci_entry) {
242219019Sgabor		if (strcmp(csid->ci_symbol, sym) == 0) {
243219019Sgabor			yyerror("multiply defined CSID");
244219019Sgabor			exit(1);
245219019Sgabor		}
246219019Sgabor	}
247219019Sgabor
248219019Sgabor	csid = malloc(sizeof(*csid));
249219019Sgabor	if (csid == NULL) {
250219019Sgabor		perror("malloc");
251219019Sgabor		exit(1);
252219019Sgabor	}
253219019Sgabor	csid->ci_symbol = sym;
254219019Sgabor	csid->ci_csid = val;
255219019Sgabor	STAILQ_INSERT_TAIL(&named_csids, csid, ci_entry);
256219019Sgabor	num_csids++;
257219019Sgabor}
258219019Sgabor
259219019Sgaborstatic void
260219019Sgabordo_mkdb(FILE *in)
261219019Sgabor{
262219019Sgabor	FILE *out;
263219019Sgabor	int ret;
264219019Sgabor
265219019Sgabor        /* dump DB to file */
266219019Sgabor	out = output ? fopen(output, "wb") : stdout;
267219019Sgabor	if (out == NULL)
268219019Sgabor		err(EXIT_FAILURE, "fopen");
269219019Sgabor
270219019Sgabor	ret = _lookup_factory_convert(out, in);
271219019Sgabor	fclose(out);
272219019Sgabor	if (ret && output)
273219019Sgabor		unlink(output); /* dump failure */
274219019Sgabor	if (ret)
275219019Sgabor		errx(EXIT_FAILURE, "%s\n", strerror(ret));
276219019Sgabor}
277219019Sgabor
278219019Sgaborstatic void
279219019Sgaborusage(void)
280219019Sgabor{
281219019Sgabor	errx(EXIT_FAILURE,
282219019Sgabor	    "usage:\n"
283330325Seadler	    "\t%s [-d] [-o outfile] [infile]\n"
284330325Seadler	    "\t%s -m [-d] [-o outfile] [infile]",
285219019Sgabor	    getprogname(), getprogname());
286219019Sgabor}
287219019Sgabor
288219019Sgaborint
289219019Sgabormain(int argc, char **argv)
290219019Sgabor{
291219019Sgabor	FILE *in = NULL;
292219019Sgabor	int ch, mkdb = 0;
293219019Sgabor
294219019Sgabor	while ((ch = getopt(argc, argv, "do:m")) != EOF) {
295219019Sgabor		switch (ch) {
296219019Sgabor		case 'd':
297219019Sgabor			debug = 1;
298219019Sgabor			break;
299219019Sgabor		case 'o':
300219019Sgabor			output = strdup(optarg);
301219019Sgabor			break;
302219019Sgabor		case 'm':
303219019Sgabor			mkdb = 1;
304219019Sgabor			break;
305219019Sgabor		default:
306219019Sgabor			usage();
307219019Sgabor		}
308219019Sgabor	}
309219019Sgabor
310219019Sgabor	argc -= optind;
311219019Sgabor	argv += optind;
312219019Sgabor	switch (argc) {
313219019Sgabor	case 0:
314219019Sgabor		in = stdin;
315219019Sgabor		break;
316219019Sgabor	case 1:
317219019Sgabor		in = fopen(argv[0], "r");
318219019Sgabor		if (!in)
319219019Sgabor			err(EXIT_FAILURE, "%s", argv[0]);
320219019Sgabor		break;
321219019Sgabor	default:
322219019Sgabor		usage();
323219019Sgabor	}
324219019Sgabor
325219019Sgabor	if (mkdb)
326219019Sgabor		do_mkdb(in);
327219019Sgabor	else {
328219019Sgabor		STAILQ_INIT(&named_csids);
329219019Sgabor		yyin = in;
330219019Sgabor		yyparse();
331219019Sgabor	}
332219019Sgabor
333219019Sgabor	return (0);
334219019Sgabor}
335