xref: /openbsd/usr.bin/lex/misc.c (revision 20c29e2b)
1 /*	$OpenBSD: misc.c,v 1.21 2024/11/09 18:03:44 op Exp $	*/
2 
3 /* misc - miscellaneous flex routines */
4 
5 /*  Copyright (c) 1990 The Regents of the University of California. */
6 /*  All rights reserved. */
7 
8 /*  This code is derived from software contributed to Berkeley by */
9 /*  Vern Paxson. */
10 
11 /*  The United States Government has rights in this work pursuant */
12 /*  to contract no. DE-AC03-76SF00098 between the United States */
13 /*  Department of Energy and the University of California. */
14 
15 /*  This file is part of flex. */
16 
17 /*  Redistribution and use in source and binary forms, with or without */
18 /*  modification, are permitted provided that the following conditions */
19 /*  are met: */
20 
21 /*  1. Redistributions of source code must retain the above copyright */
22 /*     notice, this list of conditions and the following disclaimer. */
23 /*  2. Redistributions in binary form must reproduce the above copyright */
24 /*     notice, this list of conditions and the following disclaimer in the */
25 /*     documentation and/or other materials provided with the distribution. */
26 
27 /*  Neither the name of the University nor the names of its contributors */
28 /*  may be used to endorse or promote products derived from this software */
29 /*  without specific prior written permission. */
30 
31 /*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
32 /*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
33 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
34 /*  PURPOSE. */
35 
36 #include "flexdef.h"
37 #include "tables.h"
38 
39 #define CMD_IF_TABLES_SER    "%if-tables-serialization"
40 #define CMD_TABLES_YYDMAP    "%tables-yydmap"
41 #define CMD_DEFINE_YYTABLES  "%define-yytables"
42 #define CMD_IF_CPP_ONLY      "%if-c++-only"
43 #define CMD_IF_C_ONLY        "%if-c-only"
44 #define CMD_IF_C_OR_CPP      "%if-c-or-c++"
45 #define CMD_NOT_FOR_HEADER   "%not-for-header"
46 #define CMD_OK_FOR_HEADER    "%ok-for-header"
47 #define CMD_PUSH             "%push"
48 #define CMD_POP              "%pop"
49 #define CMD_IF_REENTRANT     "%if-reentrant"
50 #define CMD_IF_NOT_REENTRANT "%if-not-reentrant"
51 #define CMD_IF_BISON_BRIDGE  "%if-bison-bridge"
52 #define CMD_IF_NOT_BISON_BRIDGE  "%if-not-bison-bridge"
53 #define CMD_ENDIF            "%endif"
54 
55 /* we allow the skeleton to push and pop. */
56 struct sko_state {
57 	bool dc;		/**< do_copy */
58 };
59 static struct sko_state *sko_stack = 0;
60 static int sko_len = 0, sko_sz = 0;
61 static void
sko_push(bool dc)62 sko_push(bool dc)
63 {
64 	if (!sko_stack) {
65 		sko_sz = 1;
66 		sko_stack = malloc(sizeof(struct sko_state) * sko_sz);
67 		if (!sko_stack)
68 			flexfatal(_("allocation of sko_stack failed"));
69 		sko_len = 0;
70 	}
71 	if (sko_len >= sko_sz) {
72 		sko_sz *= 2;
73 		sko_stack = realloc(sko_stack, sizeof(struct sko_state) * sko_sz);
74 	}
75 	/* initialize to zero and push */
76 	sko_stack[sko_len].dc = dc;
77 	sko_len++;
78 }
79 static void
sko_peek(bool * dc)80 sko_peek(bool * dc)
81 {
82 	if (sko_len <= 0)
83 		flex_die("peek attempt when sko stack is empty");
84 	if (dc)
85 		*dc = sko_stack[sko_len - 1].dc;
86 }
87 static void
sko_pop(bool * dc)88 sko_pop(bool * dc)
89 {
90 	sko_peek(dc);
91 	sko_len--;
92 	if (sko_len < 0)
93 		flex_die("popped too many times in skeleton.");
94 }
95 
96 /* Append "#define defname value\n" to the running buffer. */
97 void
action_define(const char * defname,int value)98 action_define(const char *defname, int value)
99 {
100 	char buf[MAXLINE];
101 	char *cpy;
102 
103 	if ((int) strlen(defname) > MAXLINE / 2) {
104 		format_pinpoint_message(_
105 		    ("name \"%s\" ridiculously long"),
106 		    defname);
107 		return;
108 	}
109 	snprintf(buf, sizeof(buf), "#define %s %d\n", defname, value);
110 	add_action(buf);
111 
112 	/* track #defines so we can undef them when we're done. */
113 	cpy = copy_string(defname);
114 	buf_append(&defs_buf, &cpy, 1);
115 }
116 
117 
118 /* Append "new_text" to the running buffer. */
119 void
add_action(const char * new_text)120 add_action(const char *new_text)
121 {
122 	int len = strlen(new_text);
123 
124 	while (len + action_index >= action_size - 10 /* slop */ ) {
125 		int new_size = action_size * 2;
126 
127 		if (new_size <= 0)
128 			/*
129 			 * Increase just a little, to try to avoid overflow
130 			 * on 16-bit machines.
131 			 */
132 			action_size += action_size / 8;
133 		else
134 			action_size = new_size;
135 
136 		action_array =
137 		    reallocate_character_array(action_array,
138 		    action_size);
139 	}
140 
141 	strlcpy(&action_array[action_index], new_text,
142 	    action_size - action_index);
143 
144 	action_index += len;
145 }
146 
147 
148 /* allocate_array - allocate memory for an integer array of the given size */
149 
150 void *
allocate_array(int size,size_t element_size)151 allocate_array(int size, size_t element_size)
152 {
153 	void *mem;
154 	size_t num_bytes = element_size * size;
155 
156 	mem = malloc(num_bytes);
157 	if (!mem)
158 		flexfatal(_
159 		    ("memory allocation failed in allocate_array()"));
160 
161 	return mem;
162 }
163 
164 
165 /* all_lower - true if a string is all lower-case */
166 
167 int
all_lower(char * str)168 all_lower(char *str)
169 {
170 	while (*str) {
171 		if (!isascii((u_char) * str) || !islower((u_char) * str))
172 			return 0;
173 		++str;
174 	}
175 
176 	return 1;
177 }
178 
179 
180 /* all_upper - true if a string is all upper-case */
181 
182 int
all_upper(char * str)183 all_upper(char *str)
184 {
185 	while (*str) {
186 		if (!isascii((u_char) * str) || !isupper((u_char) * str))
187 			return 0;
188 		++str;
189 	}
190 
191 	return 1;
192 }
193 
194 
195 /* intcmp - compares two integers for use by qsort. */
196 
197 int
intcmp(const void * a,const void * b)198 intcmp(const void *a, const void *b)
199 {
200 	return *(const int *) a - *(const int *) b;
201 }
202 
203 
204 /* check_char - checks a character to make sure it's within the range
205  *		we're expecting.  If not, generates fatal error message
206  *		and exits.
207  */
208 
209 void
check_char(int c)210 check_char(int c)
211 {
212 	if (c >= CSIZE)
213 		lerrsf(_("bad character '%s' detected in check_char()"),
214 		    readable_form(c));
215 
216 	if (c >= csize)
217 		lerrsf(_
218 		    ("scanner requires -8 flag to use the character %s"),
219 		    readable_form(c));
220 }
221 
222 
223 
224 /* clower - replace upper-case letter to lower-case */
225 
226 u_char
clower(int c)227 clower(int c)
228 {
229 	return (u_char) ((isascii(c) && isupper(c)) ? tolower(c) : c);
230 }
231 
232 
233 /* copy_string - returns a dynamically allocated copy of a string */
234 
235 char *
copy_string(const char * str)236 copy_string(const char *str)
237 {
238 	const char *c1;
239 	char *c2;
240 	char *copy;
241 	unsigned int size;
242 
243 	/* find length */
244 	for (c1 = str; *c1; ++c1);
245 
246 	size = (c1 - str + 1) * sizeof(char);
247 
248 	copy = (char *) malloc(size);
249 
250 	if (copy == NULL)
251 		flexfatal(_("dynamic memory failure in copy_string()"));
252 
253 	for (c2 = copy; (*c2++ = *str++) != 0;);
254 
255 	return copy;
256 }
257 
258 
259 /* copy_unsigned_string -
260  *    returns a dynamically allocated copy of a (potentially) unsigned string
261  */
262 
263 u_char *
copy_unsigned_string(unsigned char * str)264 copy_unsigned_string(unsigned char *str)
265 {
266 	u_char *c;
267 	u_char *copy;
268 
269 	/* find length */
270 	for (c = str; *c; ++c);
271 
272 	copy = allocate_Character_array(c - str + 1);
273 
274 	for (c = copy; (*c++ = *str++) != 0;);
275 
276 	return copy;
277 }
278 
279 
280 /* cclcmp - compares two characters for use by qsort with '\0' sorting last. */
281 
282 int
cclcmp(const void * a,const void * b)283 cclcmp(const void *a, const void *b)
284 {
285 	if (!*(const u_char *) a)
286 		return 1;
287 	else if (!*(const u_char *) b)
288 		return -1;
289 	else
290 		return *(const u_char *) a - *(const u_char *) b;
291 }
292 
293 
294 /* dataend - finish up a block of data declarations */
295 
296 void
dataend(void)297 dataend(void)
298 {
299 	/* short circuit any output */
300 	if (gentables) {
301 
302 		if (datapos > 0)
303 			dataflush();
304 
305 		/* add terminator for initialization; { for vi */
306 		outn("    } ;\n");
307 	}
308 	dataline = 0;
309 	datapos = 0;
310 }
311 
312 
313 /* dataflush - flush generated data statements */
314 
315 void
dataflush(void)316 dataflush(void)
317 {
318 	/* short circuit any output */
319 	if (!gentables)
320 		return;
321 
322 	outc('\n');
323 
324 	if (++dataline >= NUMDATALINES) {
325 		/*
326 		 * Put out a blank line so that the table is grouped into
327 		 * large blocks that enable the user to find elements easily.
328 		 */
329 		outc('\n');
330 		dataline = 0;
331 	}
332 	/* Reset the number of characters written on the current line. */
333 	datapos = 0;
334 }
335 
336 
337 /* flexerror - report an error message and terminate */
338 
339 void
flexerror(const char * msg)340 flexerror(const char *msg)
341 {
342 	fprintf(stderr, "%s: %s\n", program_name, msg);
343 	flexend(1);
344 }
345 
346 
347 /* flexfatal - report a fatal error message and terminate */
348 
349 void
flexfatal(const char * msg)350 flexfatal(const char *msg)
351 {
352 	fprintf(stderr, _("%s: fatal internal error, %s\n"),
353 	    program_name, msg);
354 	FLEX_EXIT(1);
355 }
356 
357 
358 /* htoi - convert a hexadecimal digit string to an integer value */
359 
360 int
htoi(unsigned char str[])361 htoi(unsigned char str[])
362 {
363 	unsigned int result;
364 
365 	(void) sscanf((char *) str, "%x", &result);
366 
367 	return result;
368 }
369 
370 
371 /* lerrif - report an error message formatted with one integer argument */
372 
373 void
lerrif(const char * msg,int arg)374 lerrif(const char *msg, int arg)
375 {
376 	char errmsg[MAXLINE];
377 
378 	snprintf(errmsg, sizeof(errmsg), msg, arg);
379 	flexerror(errmsg);
380 }
381 
382 
383 /* lerrsf - report an error message formatted with one string argument */
384 
385 void
lerrsf(const char * msg,const char arg[])386 lerrsf(const char *msg, const char arg[])
387 {
388 	char errmsg[MAXLINE];
389 
390 	snprintf(errmsg, sizeof(errmsg) - 1, msg, arg);
391 	errmsg[sizeof(errmsg) - 1] = 0;	/* ensure NULL termination */
392 	flexerror(errmsg);
393 }
394 
395 
396 /* lerrsf_fatal - as lerrsf, but call flexfatal */
397 
398 void
lerrsf_fatal(const char * msg,const char arg[])399 lerrsf_fatal(const char *msg, const char arg[])
400 {
401 	char errmsg[MAXLINE];
402 
403 	snprintf(errmsg, sizeof(errmsg) - 1, msg, arg);
404 	errmsg[sizeof(errmsg) - 1] = 0;	/* ensure NULL termination */
405 	flexfatal(errmsg);
406 }
407 
408 
409 /* line_directive_out - spit out a "#line" statement */
410 
411 void
line_directive_out(FILE * output_file,int do_infile)412 line_directive_out(FILE *output_file, int do_infile)
413 {
414 	char directive[MAXLINE], filename[MAXLINE];
415 	char *s1, *s2, *s3;
416 	static const char *line_fmt = "#line %d \"%s\"\n";
417 
418 	if (!gen_line_dirs)
419 		return;
420 
421 	s1 = do_infile ? infilename : "M4_YY_OUTFILE_NAME";
422 
423 	if (do_infile && !s1)
424 		s1 = "<stdin>";
425 
426 	s2 = filename;
427 	s3 = &filename[sizeof(filename) - 2];
428 
429 	while (s2 < s3 && *s1) {
430 		if (*s1 == '\\')
431 			/* Escape the '\' */
432 			*s2++ = '\\';
433 
434 		*s2++ = *s1++;
435 	}
436 
437 	*s2 = '\0';
438 
439 	if (do_infile)
440 		snprintf(directive, sizeof(directive), line_fmt, linenum, filename);
441 	else {
442 		snprintf(directive, sizeof(directive), line_fmt, 0, filename);
443 	}
444 
445 	/*
446 	 * If output_file is nil then we should put the directive in the
447 	 * accumulated actions.
448 	 */
449 	if (output_file) {
450 		fputs(directive, output_file);
451 	} else
452 		add_action(directive);
453 }
454 
455 
456 /* mark_defs1 - mark the current position in the action array as
457  *               representing where the user's section 1 definitions end
458  *		 and the prolog begins
459  */
460 void
mark_defs1(void)461 mark_defs1(void)
462 {
463 	defs1_offset = 0;
464 	action_array[action_index++] = '\0';
465 	action_offset = prolog_offset = action_index;
466 	action_array[action_index] = '\0';
467 }
468 
469 
470 /* mark_prolog - mark the current position in the action array as
471  *               representing the end of the action prolog
472  */
473 void
mark_prolog(void)474 mark_prolog(void)
475 {
476 	action_array[action_index++] = '\0';
477 	action_offset = action_index;
478 	action_array[action_index] = '\0';
479 }
480 
481 
482 /* mk2data - generate a data statement for a two-dimensional array
483  *
484  * Generates a data statement initializing the current 2-D array to "value".
485  */
486 void
mk2data(int value)487 mk2data(int value)
488 {
489 	/* short circuit any output */
490 	if (!gentables)
491 		return;
492 
493 	if (datapos >= NUMDATAITEMS) {
494 		outc(',');
495 		dataflush();
496 	}
497 	if (datapos == 0)
498 		/* Indent. */
499 		out("    ");
500 
501 	else
502 		outc(',');
503 
504 	++datapos;
505 
506 	out_dec("%5d", value);
507 }
508 
509 
510 /* mkdata - generate a data statement
511  *
512  * Generates a data statement initializing the current array element to
513  * "value".
514  */
515 void
mkdata(int value)516 mkdata(int value)
517 {
518 	/* short circuit any output */
519 	if (!gentables)
520 		return;
521 
522 	if (datapos >= NUMDATAITEMS) {
523 		outc(',');
524 		dataflush();
525 	}
526 	if (datapos == 0)
527 		/* Indent. */
528 		out("    ");
529 	else
530 		outc(',');
531 
532 	++datapos;
533 
534 	out_dec("%5d", value);
535 }
536 
537 
538 /* myctoi - return the integer represented by a string of digits */
539 
540 int
myctoi(const char * array)541 myctoi(const char *array)
542 {
543 	int val = 0;
544 
545 	(void) sscanf(array, "%d", &val);
546 
547 	return val;
548 }
549 
550 
551 /* myesc - return character corresponding to escape sequence */
552 
553 u_char
myesc(unsigned char array[])554 myesc(unsigned char array[])
555 {
556 	u_char c, esc_char;
557 
558 	switch (array[1]) {
559 	case 'b':
560 		return '\b';
561 	case 'f':
562 		return '\f';
563 	case 'n':
564 		return '\n';
565 	case 'r':
566 		return '\r';
567 	case 't':
568 		return '\t';
569 
570 #if defined (__STDC__)
571 	case 'a':
572 		return '\a';
573 	case 'v':
574 		return '\v';
575 #else
576 	case 'a':
577 		return '\007';
578 	case 'v':
579 		return '\013';
580 #endif
581 
582 	case '0':
583 	case '1':
584 	case '2':
585 	case '3':
586 	case '4':
587 	case '5':
588 	case '6':
589 	case '7':
590 		{		/* \<octal> */
591 			int sptr = 1;
592 
593 			while (isascii(array[sptr]) &&
594 			    isdigit(array[sptr]))
595 				/*
596 				 * Don't increment inside loop control
597 				 * because if isdigit() is a macro it might
598 				 * expand into multiple increments ...
599 				 */
600 				++sptr;
601 
602 			c = array[sptr];
603 			array[sptr] = '\0';
604 
605 			esc_char = otoi(array + 1);
606 
607 			array[sptr] = c;
608 
609 			return esc_char;
610 		}
611 
612 	case 'x':
613 		{		/* \x<hex> */
614 			int sptr = 2;
615 
616 			while (isascii(array[sptr]) &&
617 			    isxdigit(array[sptr]))
618 				/*
619 				 * Don't increment inside loop control
620 				 * because if isdigit() is a macro it might
621 				 * expand into multiple increments ...
622 				 */
623 				++sptr;
624 
625 			c = array[sptr];
626 			array[sptr] = '\0';
627 
628 			esc_char = htoi(array + 2);
629 
630 			array[sptr] = c;
631 
632 			return esc_char;
633 		}
634 
635 	default:
636 		return array[1];
637 	}
638 }
639 
640 
641 /* otoi - convert an octal digit string to an integer value */
642 
643 int
otoi(unsigned char str[])644 otoi(unsigned char str[])
645 {
646 	unsigned int result;
647 
648 	(void) sscanf((char *) str, "%o", &result);
649 	return result;
650 }
651 
652 
653 /* out - various flavors of outputting a (possibly formatted) string for the
654  *	 generated scanner, keeping track of the line count.
655  */
656 
657 void
out(const char * str)658 out(const char *str)
659 {
660 	fputs(str, stdout);
661 }
662 
663 void
out_dec(const char * fmt,int n)664 out_dec(const char *fmt, int n)
665 {
666 	fprintf(stdout, fmt, n);
667 }
668 
669 void
out_dec2(const char * fmt,int n1,int n2)670 out_dec2(const char *fmt, int n1, int n2)
671 {
672 	fprintf(stdout, fmt, n1, n2);
673 }
674 
675 void
out_hex(const char * fmt,unsigned int x)676 out_hex(const char *fmt, unsigned int x)
677 {
678 	fprintf(stdout, fmt, x);
679 }
680 
681 void
out_str(const char * fmt,const char str[])682 out_str(const char *fmt, const char str[])
683 {
684 	fprintf(stdout, fmt, str);
685 }
686 
687 void
out_str3(const char * fmt,const char s1[],const char s2[],const char s3[])688 out_str3(const char *fmt, const char s1[], const char s2[], const char s3[])
689 {
690 	fprintf(stdout, fmt, s1, s2, s3);
691 }
692 
693 void
out_str_dec(const char * fmt,const char str[],int n)694 out_str_dec(const char *fmt, const char str[], int n)
695 {
696 	fprintf(stdout, fmt, str, n);
697 }
698 
699 void
outc(int c)700 outc(int c)
701 {
702 	fputc(c, stdout);
703 }
704 
705 void
outn(const char * str)706 outn(const char *str)
707 {
708 	fputs(str, stdout);
709 	fputc('\n', stdout);
710 }
711 
712 /** Print "m4_define( [[def]], [[val]])m4_dnl\n".
713  * @param def The m4 symbol to define.
714  * @param val The definition; may be NULL.
715  * @return buf
716  */
717 void
out_m4_define(const char * def,const char * val)718 out_m4_define(const char *def, const char *val)
719 {
720 	const char *fmt = "m4_define( [[%s]], [[%s]])m4_dnl\n";
721 	fprintf(stdout, fmt, def, val ? val : "");
722 }
723 
724 
725 /* readable_form - return the human-readable form of a character
726  *
727  * The returned string is in static storage.
728  */
729 
730 char *
readable_form(int c)731 readable_form(int c)
732 {
733 	static char rform[10];
734 
735 	if ((c >= 0 && c < 32) || c >= 127) {
736 		switch (c) {
737 		case '\b':
738 			return "\\b";
739 		case '\f':
740 			return "\\f";
741 		case '\n':
742 			return "\\n";
743 		case '\r':
744 			return "\\r";
745 		case '\t':
746 			return "\\t";
747 
748 #if defined (__STDC__)
749 		case '\a':
750 			return "\\a";
751 		case '\v':
752 			return "\\v";
753 #endif
754 
755 		default:
756 			snprintf(rform, sizeof(rform), "\\%.3o", (unsigned int) c);
757 			return rform;
758 		}
759 	} else if (c == ' ')
760 		return "' '";
761 
762 	else {
763 		rform[0] = c;
764 		rform[1] = '\0';
765 
766 		return rform;
767 	}
768 }
769 
770 
771 /* reallocate_array - increase the size of a dynamic array */
772 
773 void *
reallocate_array(void * array,int size,size_t element_size)774 reallocate_array(void *array, int size, size_t element_size)
775 {
776 	void *new_array;
777 	size_t num_bytes = element_size * size;
778 
779 	new_array = realloc(array, num_bytes);
780 	if (!new_array)
781 		flexfatal(_("attempt to increase array size failed"));
782 
783 	return new_array;
784 }
785 
786 
787 /* skelout - write out one section of the skeleton file
788  *
789  * Description
790  *    Copies skelfile or skel array to stdout until a line beginning with
791  *    "%%" or EOF is found.
792  */
793 void
skelout(void)794 skelout(void)
795 {
796 	char buf_storage[MAXLINE];
797 	char *buf = buf_storage;
798 	bool do_copy = true;
799 
800 	/* "reset" the state by clearing the buffer and pushing a '1' */
801 	if (sko_len > 0)
802 		sko_peek(&do_copy);
803 	sko_len = 0;
804 	sko_push(do_copy = true);
805 
806 
807 	/*
808 	 * Loop pulling lines either from the skelfile, if we're using one,
809 	 * or from the skel[] array.
810 	 */
811 	while (skelfile ?
812 	    (fgets(buf, MAXLINE, skelfile) != NULL) :
813 	    ((buf = (char *) skel[skel_ind++]) != 0)) {
814 
815 		if (skelfile)
816 			chomp(buf);
817 
818 		/* copy from skel array */
819 		if (buf[0] == '%') {	/* control line */
820 			/* print the control line as a comment. */
821 			if (ddebug && buf[1] != '#') {
822 				if (buf[strlen(buf) - 1] == '\\')
823 					out_str("/* %s */\\\n", buf);
824 				else
825 					out_str("/* %s */\n", buf);
826 			}
827 			/*
828 			 * We've been accused of using cryptic markers in the
829 			 * skel. So we'll use
830 			 * emacs-style-hyphenated-commands. We might consider
831 			 * a hash if this if-else-if-else chain gets too
832 			 * large.
833 			 */
834 #define cmd_match(s) (strncmp(buf,(s),strlen(s))==0)
835 
836 			if (buf[1] == '%') {
837 				/* %% is a break point for skelout() */
838 				return;
839 			} else if (cmd_match(CMD_PUSH)) {
840 				sko_push(do_copy);
841 				if (ddebug) {
842 					out_str("/*(state = (%s) */", do_copy ? "true" : "false");
843 				}
844 				out_str("%s\n", buf[strlen(buf) - 1] == '\\' ? "\\" : "");
845 			} else if (cmd_match(CMD_POP)) {
846 				sko_pop(&do_copy);
847 				if (ddebug) {
848 					out_str("/*(state = (%s) */", do_copy ? "true" : "false");
849 				}
850 				out_str("%s\n", buf[strlen(buf) - 1] == '\\' ? "\\" : "");
851 			} else if (cmd_match(CMD_IF_REENTRANT)) {
852 				sko_push(do_copy);
853 				do_copy = reentrant && do_copy;
854 			} else if (cmd_match(CMD_IF_NOT_REENTRANT)) {
855 				sko_push(do_copy);
856 				do_copy = !reentrant && do_copy;
857 			} else if (cmd_match(CMD_IF_BISON_BRIDGE)) {
858 				sko_push(do_copy);
859 				do_copy = bison_bridge_lval && do_copy;
860 			} else if (cmd_match(CMD_IF_NOT_BISON_BRIDGE)) {
861 				sko_push(do_copy);
862 				do_copy = !bison_bridge_lval && do_copy;
863 			} else if (cmd_match(CMD_ENDIF)) {
864 				sko_pop(&do_copy);
865 			} else if (cmd_match(CMD_IF_TABLES_SER)) {
866 				do_copy = do_copy && tablesext;
867 			} else if (cmd_match(CMD_TABLES_YYDMAP)) {
868 				if (tablesext && yydmap_buf.elts)
869 					outn((char *) (yydmap_buf.elts));
870 			} else if (cmd_match(CMD_DEFINE_YYTABLES)) {
871 				out_str("#define YYTABLES_NAME \"%s\"\n",
872 				    tablesname ? tablesname : "yytables");
873 			} else if (cmd_match(CMD_IF_CPP_ONLY)) {
874 				/* only for C++ */
875 				sko_push(do_copy);
876 				do_copy = C_plus_plus;
877 			} else if (cmd_match(CMD_IF_C_ONLY)) {
878 				/* %- only for C */
879 				sko_push(do_copy);
880 				do_copy = !C_plus_plus;
881 			} else if (cmd_match(CMD_IF_C_OR_CPP)) {
882 				/* %* for C and C++ */
883 				sko_push(do_copy);
884 				do_copy = true;
885 			} else if (cmd_match(CMD_NOT_FOR_HEADER)) {
886 				/* %c begin linkage-only (non-header) code. */
887 				OUT_BEGIN_CODE();
888 			} else if (cmd_match(CMD_OK_FOR_HEADER)) {
889 				/* %e end linkage-only code. */
890 				OUT_END_CODE();
891 			} else if (buf[1] == '#') {
892 				/* %# a comment in the skel. ignore. */
893 			} else {
894 				flexfatal(_("bad line in skeleton file"));
895 			}
896 		} else if (do_copy)
897 			outn(buf);
898 	}			/* end while */
899 }
900 
901 
902 /* transition_struct_out - output a yy_trans_info structure
903  *
904  * outputs the yy_trans_info structure with the two elements, element_v and
905  * element_n.  Formats the output with spaces and carriage returns.
906  */
907 
908 void
transition_struct_out(int element_v,int element_n)909 transition_struct_out(int element_v, int element_n)
910 {
911 
912 	/* short circuit any output */
913 	if (!gentables)
914 		return;
915 
916 	out_dec2(" {%4d,%4d },", element_v, element_n);
917 
918 	datapos += TRANS_STRUCT_PRINT_LENGTH;
919 
920 	if (datapos >= 79 - TRANS_STRUCT_PRINT_LENGTH) {
921 		outc('\n');
922 
923 		if (++dataline % 10 == 0)
924 			outc('\n');
925 
926 		datapos = 0;
927 	}
928 }
929 
930 
931 /* The following is only needed when building flex's parser using certain
932  * broken versions of bison.
933  */
934 void *
yy_flex_xmalloc(int size)935 yy_flex_xmalloc(int size)
936 {
937 	void *result = malloc((size_t) size);
938 
939 	if (!result)
940 		flexfatal(_
941 		    ("memory allocation failed in yy_flex_xmalloc()"));
942 
943 	return result;
944 }
945 
946 
947 /* Remove all '\n' and '\r' characters, if any, from the end of str.
948  * str can be any null-terminated string, or NULL.
949  * returns str. */
950 char *
chomp(char * str)951 chomp(char *str)
952 {
953 	char *p = str;
954 
955 	if (!str || !*str)	/* s is null or empty string */
956 		return str;
957 
958 	/* find end of string minus one */
959 	while (*p)
960 		++p;
961 	--p;
962 
963 	/* eat newlines */
964 	while (p >= str && (*p == '\r' || *p == '\n'))
965 		*p-- = 0;
966 	return str;
967 }
968