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