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