xref: /freebsd/usr.bin/mkcsmapper/yacc.y (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
1 /* $FreeBSD$ */
2 /* $NetBSD: yacc.y,v 1.7 2006/09/09 14:35:17 tnozaki Exp $	*/
3 
4 %{
5 /*-
6  * Copyright (c)2003, 2006 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/cdefs.h>
32 #include <sys/types.h>
33 
34 #include <assert.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <arpa/inet.h>
43 
44 #include "ldef.h"
45 
46 #ifndef __packed
47 #define __packed
48 #endif
49 
50 #include "citrus_namespace.h"
51 #include "citrus_types.h"
52 #include "citrus_mapper_std_file.h"
53 #include "citrus_region.h"
54 #include "citrus_db_factory.h"
55 #include "citrus_db_hash.h"
56 #include "citrus_lookup_factory.h"
57 #include "citrus_pivot_factory.h"
58 
59 extern FILE		*yyin;
60 
61 int			 debug = 0;
62 
63 static linear_zone_t	 rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX];
64 static char		*map_name;
65 static char		*output = NULL;
66 static void		*table = NULL;
67 static size_t		 rowcol_len = 0;
68 static size_t		 table_size;
69 static u_int32_t	 done_flag = 0;
70 static u_int32_t	 dst_ilseq, dst_invalid, dst_unit_bits, oob_mode;
71 static u_int32_t	 rowcol_bits = 0, rowcol_mask = 0;
72 static u_int32_t	 src_next;
73 static int		 map_type;
74 static void		 (*putfunc)(void *, size_t, u_int32_t) = NULL;
75 
76 #define DF_TYPE			0x00000001
77 #define DF_NAME			0x00000002
78 #define DF_SRC_ZONE		0x00000004
79 #define DF_DST_INVALID		0x00000008
80 #define DF_DST_ILSEQ		0x00000010
81 #define DF_DST_UNIT_BITS	0x00000020
82 #define DF_OOB_MODE		0x00000040
83 
84 static void	dump_file(void);
85 static void	setup_map(void);
86 static void	set_type(int);
87 static void	set_name(char *);
88 static void	set_src_zone(u_int32_t);
89 static void	set_dst_invalid(u_int32_t);
90 static void	set_dst_ilseq(u_int32_t);
91 static void	set_dst_unit_bits(u_int32_t);
92 static void	set_oob_mode(u_int32_t);
93 static int	check_src(u_int32_t, u_int32_t);
94 static void	store(const linear_zone_t *, u_int32_t, int);
95 static void	put8(void *, size_t, u_int32_t);
96 static void	put16(void *, size_t, u_int32_t);
97 static void	put32(void *, size_t, u_int32_t);
98 static void	set_range(u_int32_t, u_int32_t);
99 static void	set_src(linear_zone_t *, u_int32_t, u_int32_t);
100 %}
101 
102 %union {
103 	u_int32_t	 i_value;
104 	char		*s_value;
105 	linear_zone_t	 lz_value;
106 }
107 
108 %token			R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS
109 %token			R_DST_INVALID R_DST_ILSEQ
110 %token			R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL
111 %token			R_ILSEQ R_OOB_MODE
112 %token			R_LN
113 %token <i_value>	L_IMM
114 %token <s_value>	L_STRING
115 
116 %type <lz_value>	src
117 %type <i_value>		dst types oob_mode_sel zone
118 
119 %%
120 
121 file		: property mapping lns
122 		{ dump_file(); }
123 
124 property	: /* empty */
125 		| property R_LN
126 		| property name
127 		| property type
128 		| property src_zone
129 		| property dst_invalid
130 		| property dst_ilseq
131 		| property dst_unit_bits
132 		| property oob_mode
133 
134 name		: R_NAME L_STRING { set_name($2); $2 = NULL; }
135 type		: R_TYPE types { set_type($2); }
136 types		: R_ROWCOL { $$ = R_ROWCOL; }
137 range		: L_IMM '-' L_IMM { set_range($1, $3); }
138 
139 ranges		: /* empty */
140 		| ranges range '/'
141 
142 src_zone	: R_SRC_ZONE zone { set_src_zone($2); }
143 zone		: range {
144 			$$ = 32;
145 		}
146 		| range '/' range '/' ranges L_IMM {
147 			$$ = $6;
148 		}
149 
150 dst_invalid	: R_DST_INVALID L_IMM { set_dst_invalid($2); }
151 dst_ilseq	: R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
152 dst_unit_bits	: R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
153 oob_mode	: R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
154 
155 oob_mode_sel	: R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
156 		| R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
157 
158 mapping		: begin_map map_elems R_END_MAP
159 begin_map	: R_BEGIN_MAP lns { setup_map(); }
160 
161 map_elems	: /* empty */
162 		| map_elems map_elem lns
163 
164 map_elem	: src '=' dst
165 		{ store(&$1, $3, 0); }
166 		| src '=' L_IMM '-'
167 		{ store(&$1, $3, 1); }
168 dst		: L_IMM
169 		{
170 			$$ = $1;
171 		}
172 		| R_INVALID
173 		{
174 			$$ = dst_invalid;
175 		}
176 		| R_ILSEQ
177 		{
178 			$$ = dst_ilseq;
179 		}
180 
181 src		: /* empty */
182 		{
183 			set_src(&$$, src_next, src_next);
184 		}
185 		| L_IMM
186 		{
187 			set_src(&$$, $1, $1);
188 		}
189 		| L_IMM '-' L_IMM
190 		{
191 			set_src(&$$, $1, $3);
192 		}
193 		| '-' L_IMM
194 		{
195 			set_src(&$$, src_next, $2);
196 		}
197 lns		: R_LN
198 		| lns R_LN
199 
200 %%
201 
202 static void
203 warning(const char *s)
204 {
205 
206 	fprintf(stderr, "%s in %d\n", s, linenumber);
207 }
208 
209 int
210 yyerror(const char *s)
211 {
212 
213 	warning(s);
214 	exit(1);
215 }
216 
217 void
218 put8(void *ptr, size_t ofs, u_int32_t val)
219 {
220 
221 	*((u_int8_t *)ptr + ofs) = val;
222 }
223 
224 void
225 put16(void *ptr, size_t ofs, u_int32_t val)
226 {
227 
228 	u_int16_t oval = htons(val);
229 	memcpy((u_int16_t *)ptr + ofs, &oval, 2);
230 }
231 
232 void
233 put32(void *ptr, size_t ofs, u_int32_t val)
234 {
235 
236 	u_int32_t oval = htonl(val);
237 	memcpy((u_int32_t *)ptr + ofs, &oval, 4);
238 }
239 
240 static void
241 alloc_table(void)
242 {
243 	linear_zone_t *p;
244 	size_t i;
245 	uint32_t val = 0;
246 
247 	i = rowcol_len;
248 	p = &rowcol[--i];
249 	table_size = p->width;
250 	while (i > 0) {
251 		p = &rowcol[--i];
252 		table_size *= p->width;
253 	}
254 	table = (void *)malloc(table_size * dst_unit_bits / 8);
255 	if (table == NULL) {
256 		perror("malloc");
257 		exit(1);
258 	}
259 
260 	switch (oob_mode) {
261 	case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
262 		val = dst_invalid;
263 		break;
264 	case _CITRUS_MAPPER_STD_OOB_ILSEQ:
265 		val = dst_ilseq;
266 		break;
267 	default:
268 		break;
269 	}
270 	for (i = 0; i < table_size; i++)
271 		(*putfunc)(table, i, val);
272 }
273 
274 static void
275 setup_map(void)
276 {
277 
278 	if ((done_flag & DF_SRC_ZONE)==0) {
279 		fprintf(stderr, "SRC_ZONE is mandatory.\n");
280 		exit(1);
281 	}
282 	if ((done_flag & DF_DST_UNIT_BITS)==0) {
283 		fprintf(stderr, "DST_UNIT_BITS is mandatory.\n");
284 		exit(1);
285 	}
286 
287 	if ((done_flag & DF_DST_INVALID) == 0)
288 		dst_invalid = 0xFFFFFFFF;
289 	if ((done_flag & DF_DST_ILSEQ) == 0)
290 		dst_ilseq = 0xFFFFFFFE;
291 	if ((done_flag & DF_OOB_MODE) == 0)
292 		oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
293 
294 	alloc_table();
295 }
296 
297 static void
298 create_rowcol_info(struct _region *r)
299 {
300 	void *ptr;
301 	size_t i, len, ofs;
302 
303 	ofs = 0;
304 	ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
305 	if (ptr == NULL)
306 		err(EXIT_FAILURE, "malloc");
307 	put32(ptr, ofs, rowcol_bits); ofs++;
308 	put32(ptr, ofs, dst_invalid); ofs++;
309 
310 	/* XXX: keep backward compatibility */
311 	switch (rowcol_len) {
312 	case 1:
313 		put32(ptr, ofs, 0); ofs++;
314 		put32(ptr, ofs, 0); ofs++;
315 	/*FALLTHROUGH*/
316 	case 2:
317 		len = 0;
318 		break;
319 	default:
320 		len = rowcol_len;
321 	}
322 	for (i = 0; i < rowcol_len; ++i) {
323 		put32(ptr, ofs, rowcol[i].begin); ofs++;
324 		put32(ptr, ofs, rowcol[i].end); ofs++;
325 	}
326 	put32(ptr, ofs, dst_unit_bits); ofs++;
327 	put32(ptr, ofs, len); ofs++;
328 
329 	_region_init(r, ptr, ofs * 4);
330 }
331 
332 
333 static void
334 create_rowcol_ext_ilseq_info(struct _region *r)
335 {
336 	void *ptr;
337 	size_t ofs;
338 
339 	ofs = 0;
340 	ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
341 	if (ptr == NULL)
342 		err(EXIT_FAILURE, "malloc");
343 
344 	put32(ptr, ofs, oob_mode); ofs++;
345 	put32(ptr, ofs, dst_ilseq); ofs++;
346 
347 	_region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
348 }
349 
350 #define CHKERR(ret, func, a)						\
351 do {									\
352 	ret = func a;							\
353 	if (ret)							\
354 		errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));	\
355 } while (/*CONSTCOND*/0)
356 
357 static void
358 dump_file(void)
359 {
360 	struct _db_factory *df;
361 	struct _region data;
362 	void *serialized;
363 	FILE *fp;
364 	size_t size;
365 	int ret;
366 
367 	/*
368 	 * build database
369 	 */
370 	CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
371 
372 	/* store type */
373 	CHKERR(ret, _db_factory_addstr_by_s,
374 	    (df, _CITRUS_MAPPER_STD_SYM_TYPE, _CITRUS_MAPPER_STD_TYPE_ROWCOL));
375 
376 	/* store info */
377 	create_rowcol_info(&data);
378 	CHKERR(ret, _db_factory_add_by_s,
379 	    (df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1));
380 
381 	/* ilseq extension */
382 	create_rowcol_ext_ilseq_info(&data);
383 	CHKERR(ret, _db_factory_add_by_s,
384 	    (df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1));
385 
386 	/* store table */
387 	_region_init(&data, table, table_size*dst_unit_bits/8);
388 	CHKERR(ret, _db_factory_add_by_s,
389 	    (df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1));
390 
391 	/*
392 	 * dump database to file
393 	 */
394 	fp = output ? fopen(output, "wb") : stdout;
395 
396 	if (fp == NULL) {
397 		perror("fopen");
398 		exit(1);
399 	}
400 
401 	/* dump database body */
402 	size = _db_factory_calc_size(df);
403 	serialized = malloc(size);
404 	_region_init(&data, serialized, size);
405 	CHKERR(ret, _db_factory_serialize,
406 	    (df, _CITRUS_MAPPER_STD_MAGIC, &data));
407 	if (fwrite(serialized, size, 1, fp) != 1)
408 		err(EXIT_FAILURE, "fwrite");
409 
410 	fclose(fp);
411 }
412 
413 static void
414 /*ARGSUSED*/
415 set_type(int type)
416 {
417 
418 	if (done_flag & DF_TYPE) {
419 		warning("TYPE is duplicated. ignored this one");
420 		return;
421 	}
422 
423 	map_type = type;
424 
425 	done_flag |= DF_TYPE;
426 }
427 
428 static void
429 /*ARGSUSED*/
430 set_name(char *str)
431 {
432 
433 	if (done_flag & DF_NAME) {
434 		warning("NAME is duplicated. ignored this one");
435 		return;
436 	}
437 
438 	map_name = str;
439 
440 	done_flag |= DF_NAME;
441 }
442 
443 static void
444 set_src_zone(u_int32_t val)
445 {
446 	linear_zone_t *p;
447 	size_t i;
448 
449 	if (done_flag & DF_SRC_ZONE) {
450 		warning("SRC_ZONE is duplicated. ignored this one");
451 		return;
452 	}
453 	rowcol_bits = val;
454 
455 	/* sanity check */
456 	switch (rowcol_bits) {
457 	case 8: case 16: case 32:
458 		if (rowcol_len <= 32 / rowcol_bits)
459 			break;
460 	/*FALLTHROUGH*/
461 	default:
462 		goto bad;
463 	}
464 	rowcol_mask = 1 << (rowcol_bits - 1);
465 	rowcol_mask |= rowcol_mask - 1;
466 	for (i = 0; i < rowcol_len; ++i) {
467 		p = &rowcol[i];
468 		if (p->end > rowcol_mask)
469 			goto bad;
470 	}
471 	done_flag |= DF_SRC_ZONE;
472 	return;
473 
474 bad:
475 	yyerror("Illegal argument for SRC_ZONE");
476 }
477 
478 static void
479 set_dst_invalid(u_int32_t val)
480 {
481 
482 	if (done_flag & DF_DST_INVALID) {
483 		warning("DST_INVALID is duplicated. ignored this one");
484 		return;
485 	}
486 
487 	dst_invalid = val;
488 
489 	done_flag |= DF_DST_INVALID;
490 }
491 
492 static void
493 set_dst_ilseq(u_int32_t val)
494 {
495 
496 	if (done_flag & DF_DST_ILSEQ) {
497 		warning("DST_ILSEQ is duplicated. ignored this one");
498 		return;
499 	}
500 
501 	dst_ilseq = val;
502 
503 	done_flag |= DF_DST_ILSEQ;
504 }
505 
506 static void
507 set_oob_mode(u_int32_t val)
508 {
509 
510 	if (done_flag & DF_OOB_MODE) {
511 		warning("OOB_MODE is duplicated. ignored this one");
512 		return;
513 	}
514 
515 	oob_mode = val;
516 
517 	done_flag |= DF_OOB_MODE;
518 }
519 
520 static void
521 set_dst_unit_bits(u_int32_t val)
522 {
523 
524 	if (done_flag & DF_DST_UNIT_BITS) {
525 		warning("DST_UNIT_BITS is duplicated. ignored this one");
526 		return;
527 	}
528 
529 	switch (val) {
530 	case 8:
531 		putfunc = &put8;
532 		dst_unit_bits = val;
533 		break;
534 	case 16:
535 		putfunc = &put16;
536 		dst_unit_bits = val;
537 		break;
538 	case 32:
539 		putfunc = &put32;
540 		dst_unit_bits = val;
541 		break;
542 	default:
543 		yyerror("Illegal argument for DST_UNIT_BITS");
544 	}
545 	done_flag |= DF_DST_UNIT_BITS;
546 }
547 
548 static int
549 check_src(u_int32_t begin, u_int32_t end)
550 {
551 	linear_zone_t *p;
552 	size_t i;
553 	u_int32_t m, n;
554 
555 	if (begin > end)
556 		return (1);
557 	if (begin < end) {
558 		m = begin & ~rowcol_mask;
559 		n = end & ~rowcol_mask;
560 		if (m != n)
561 			return (1);
562 	}
563 	for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
564 		i -= rowcol_bits;
565 		m = (begin >> i) & rowcol_mask;
566 		if (m < p->begin || m > p->end)
567 			return (1);
568 	}
569 	if (begin < end) {
570 		n = end & rowcol_mask;
571 		--p;
572 		if (n < p->begin || n > p->end)
573 			return (1);
574 	}
575 	return (0);
576 }
577 
578 static void
579 store(const linear_zone_t *lz, u_int32_t dst, int inc)
580 {
581 	linear_zone_t *p;
582 	size_t i, ofs;
583 	u_int32_t n;
584 
585 	ofs = 0;
586 	for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
587 		i -= rowcol_bits;
588 		n = ((lz->begin >> i) & rowcol_mask) - p->begin;
589 		ofs = (ofs * p->width) + n;
590 	}
591 	n = lz->width;
592 	while (n-- > 0) {
593 		(*putfunc)(table, ofs++, dst);
594 		if (inc)
595 			dst++;
596 	}
597 }
598 
599 static void
600 set_range(u_int32_t begin, u_int32_t end)
601 {
602 	linear_zone_t *p;
603 
604 	if (rowcol_len >= _CITRUS_MAPPER_STD_ROWCOL_MAX)
605 		goto bad;
606 	p = &rowcol[rowcol_len++];
607 
608 	if (begin > end)
609 		goto bad;
610 	p->begin = begin, p->end = end;
611 	p->width = end - begin + 1;
612 
613 	return;
614 
615 bad:
616 	yyerror("Illegal argument for SRC_ZONE");
617 }
618 
619 static void
620 set_src(linear_zone_t *lz, u_int32_t begin, u_int32_t end)
621 {
622 
623 	if (check_src(begin, end) != 0)
624 		yyerror("illegal zone");
625 
626 	lz->begin = begin, lz->end = end;
627 	lz->width = end - begin + 1;
628 
629 	src_next = end + 1;
630 }
631 
632 static void
633 do_mkdb(FILE *in)
634 {
635 	FILE *out;
636 	int ret;
637 
638         /* dump DB to file */
639 	out = output ? fopen(output, "wb") : stdout;
640 
641 	if (out == NULL)
642 		err(EXIT_FAILURE, "fopen");
643 
644 	ret = _lookup_factory_convert(out, in);
645 	fclose(out);
646 	if (ret && output)
647 		unlink(output); /* dump failure */
648 }
649 
650 static void
651 do_mkpv(FILE *in)
652 {
653 	FILE *out;
654 	int ret;
655 
656         /* dump pivot to file */
657 	out = output ? fopen(output, "wb") : stdout;
658 
659 	if (out == NULL)
660 		err(EXIT_FAILURE, "fopen");
661 
662 	ret = _pivot_factory_convert(out, in);
663 	fclose(out);
664 	if (ret && output)
665 		unlink(output); /* dump failure */
666 	if (ret)
667 		errx(EXIT_FAILURE, "%s\n", strerror(ret));
668 }
669 
670 static void
671 usage(void)
672 {
673 	warnx("usage: \n"
674 	    "\t%s [-d] [-o outfile] [infile]\n"
675 	    "\t%s -m [-d] [-o outfile] [infile]\n"
676 	    "\t%s -p [-d] [-o outfile] [infile]\n",
677 	    getprogname(), getprogname(), getprogname());
678 	exit(1);
679 }
680 
681 int
682 main(int argc, char **argv)
683 {
684 	FILE *in = NULL;
685 	int ch, mkdb = 0, mkpv = 0;
686 
687 	while ((ch = getopt(argc, argv, "do:mp")) != EOF) {
688 		switch (ch) {
689 		case 'd':
690 			debug = 1;
691 			break;
692 		case 'o':
693 			output = strdup(optarg);
694 			break;
695 		case 'm':
696 			mkdb = 1;
697 			break;
698 		case 'p':
699 			mkpv = 1;
700 			break;
701 		default:
702 			usage();
703 		}
704 	}
705 
706 	argc -= optind;
707 	argv += optind;
708 	switch (argc) {
709 	case 0:
710 		in = stdin;
711 		break;
712 	case 1:
713 		in = fopen(argv[0], "r");
714 		if (!in)
715 			err(EXIT_FAILURE, "%s", argv[0]);
716 		break;
717 	default:
718 		usage();
719 	}
720 
721 	if (mkdb)
722 		do_mkdb(in);
723 	else if (mkpv)
724 		do_mkpv(in);
725 	else {
726 		yyin = in;
727 		yyparse();
728 	}
729 
730 	return (0);
731 }
732