xref: /openbsd-src/usr.bin/lex/misc.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /*	$OpenBSD: misc.c,v 1.4 1997/07/25 21:05:30 mickey Exp $	*/
2 
3 /* misc - miscellaneous flex routines */
4 
5 /*-
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Vern Paxson.
11  *
12  * The United States Government has rights in this work pursuant
13  * to contract no. DE-AC03-76SF00098 between the United States
14  * Department of Energy and the University of California.
15  *
16  * Redistribution and use in source and binary forms are permitted provided
17  * that: (1) source distributions retain this entire copyright notice and
18  * comment, and (2) distributions including binaries display the following
19  * acknowledgement:  ``This product includes software developed by the
20  * University of California, Berkeley and its contributors'' in the
21  * documentation or other materials provided with the distribution and in
22  * all advertising materials mentioning features or use of this software.
23  * Neither the name of the University nor the names of its contributors may
24  * be used to endorse or promote products derived from this software without
25  * specific prior written permission.
26  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
27  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
28  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  */
30 
31 /* $Header: /home/cvs/src/usr.bin/lex/misc.c,v 1.4 1997/07/25 21:05:30 mickey Exp $ */
32 
33 #include "flexdef.h"
34 
35 
36 void action_define( defname, value )
37 char *defname;
38 int 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 
54 void add_action( new_text )
55 char *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 
83 void *allocate_array( size, element_size )
84 int size;
85 size_t element_size;
86 	{
87 	register 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 
101 int all_lower( str )
102 register char *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 
117 int all_upper( str )
118 register char *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 
146 void bubble( v, n )
147 int v[], n;
148 	{
149 	register 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 
167 void check_char( c )
168 int 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 
184 Char clower( c )
185 register int 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 
193 char *copy_string( str )
194 register const char *str;
195 	{
196 	register const char *c1;
197 	register 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 
222 Char *copy_unsigned_string( str )
223 register Char *str;
224 	{
225 	register 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 
259 void cshell( v, n, special_case_0 )
260 Char v[];
261 int 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 
293 void 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 
308 void 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 
328 void flexerror( msg )
329 const 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 
338 void flexfatal( msg )
339 const 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 
349 int htoi( str )
350 Char 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 
362 void lerrif( msg, arg )
363 const char msg[];
364 int 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 
374 void lerrsf( msg, arg )
375 const 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 
386 void line_directive_out( output_file, do_infile )
387 FILE *output_file;
388 int 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  */
443 void 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  */
455 void 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  */
467 void mk2data( value )
468 int 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  */
494 void mkdata( value )
495 int 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 
517 int myctoi( array )
518 char 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 
530 Char myesc( array )
531 Char 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 #ifdef __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 
610 int otoi( str )
611 Char 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 
624 void out( str )
625 const char str[];
626 	{
627 	fputs( str, stdout );
628 	out_line_count( str );
629 	}
630 
631 void out_dec( fmt, n )
632 const char fmt[];
633 int n;
634 	{
635 	printf( fmt, n );
636 	out_line_count( fmt );
637 	}
638 
639 void out_dec2( fmt, n1, n2 )
640 const char fmt[];
641 int n1, n2;
642 	{
643 	printf( fmt, n1, n2 );
644 	out_line_count( fmt );
645 	}
646 
647 void out_hex( fmt, x )
648 const char fmt[];
649 unsigned int x;
650 	{
651 	printf( fmt, x );
652 	out_line_count( fmt );
653 	}
654 
655 void out_line_count( str )
656 const char str[];
657 	{
658 	register int i;
659 
660 	for ( i = 0; str[i]; ++i )
661 		if ( str[i] == '\n' )
662 			++out_linenum;
663 	}
664 
665 void out_str( fmt, str )
666 const char fmt[], str[];
667 	{
668 	printf( fmt, str );
669 	out_line_count( fmt );
670 	out_line_count( str );
671 	}
672 
673 void out_str3( fmt, s1, s2, s3 )
674 const 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 
683 void out_str_dec( fmt, str, n )
684 const char fmt[], str[];
685 int n;
686 	{
687 	printf( fmt, str, n );
688 	out_line_count( fmt );
689 	out_line_count( str );
690 	}
691 
692 void outc( c )
693 int c;
694 	{
695 	putc( c, stdout );
696 
697 	if ( c == '\n' )
698 		++out_linenum;
699 	}
700 
701 void outn( str )
702 const char str[];
703 	{
704 	puts( str );
705 	out_line_count( str );
706 	++out_linenum;
707 	}
708 
709 
710 /* readable_form - return the the human-readable form of a character
711  *
712  * The returned string is in static storage.
713  */
714 
715 char *readable_form( c )
716 register int 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 #ifdef __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 
757 void *reallocate_array( array, size, element_size )
758 void *array;
759 int size;
760 size_t element_size;
761 	{
762 	register 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  */
779 void 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 
837 void transition_struct_out( element_v, element_n )
838 int 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  */
859 void *yy_flex_xmalloc( size )
860 int 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 
877 void zero_out( region_ptr, size_in_bytes )
878 char *region_ptr;
879 size_t size_in_bytes;
880 	{
881 	register 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