1/*	$OpenBSD: misc.c,v 1.20 2022/12/26 19:16:01 jmc 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. */
56struct sko_state {
57	bool dc;		/**< do_copy */
58};
59static struct sko_state *sko_stack = 0;
60static int sko_len = 0, sko_sz = 0;
61static void
62sko_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}
79static void
80sko_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}
87static void
88sko_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. */
97void
98action_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 */
124void
125action_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. */
142void
143add_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
174void *
175allocate_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
193int
194all_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
209int
210all_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
225int
226intcmp(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
237void
238check_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
255u_char
256clower(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
265char *
266copy_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
294u_char *
295copy_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
314int
315cclcmp(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
328void
329dataend()
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
347void
348dataflush()
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
371void
372flexerror(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
382void
383flexfatal(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
394int
395htoi(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
408void
409lerrif(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
422void
423lerrsf(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
436void
437lerrsf_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
450void
451line_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 */
501void
502mark_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 */
514void
515mark_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 */
527void
528mk2data(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 */
557void
558mkdata(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
583int
584myctoi(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
597u_char
598myesc(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
688int
689otoi(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 outputting a (possibly formatted) string for the
700 *	 generated scanner, keeping track of the line count.
701 */
702
703void
704out(str)
705	const char *str;
706{
707	fputs(str, stdout);
708}
709
710void
711out_dec(fmt, n)
712	const char *fmt;
713	int n;
714{
715	fprintf(stdout, fmt, n);
716}
717
718void
719out_dec2(fmt, n1, n2)
720	const char *fmt;
721	int n1, n2;
722{
723	fprintf(stdout, fmt, n1, n2);
724}
725
726void
727out_hex(fmt, x)
728	const char *fmt;
729	unsigned int x;
730{
731	fprintf(stdout, fmt, x);
732}
733
734void
735out_str(fmt, str)
736	const char *fmt, str[];
737{
738	fprintf(stdout, fmt, str);
739}
740
741void
742out_str3(fmt, s1, s2, s3)
743	const char *fmt, s1[], s2[], s3[];
744{
745	fprintf(stdout, fmt, s1, s2, s3);
746}
747
748void
749out_str_dec(fmt, str, n)
750	const char *fmt, str[];
751	int n;
752{
753	fprintf(stdout, fmt, str, n);
754}
755
756void
757outc(c)
758	int c;
759{
760	fputc(c, stdout);
761}
762
763void
764outn(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 */
776void
777out_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
789char *
790readable_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
833void *
834reallocate_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 */
856void
857skelout()
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
971void
972transition_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 */
998void *
999yy_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. */
1015char *
1016chomp(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