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