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