386BSD 0.1 development
[unix-history] / usr / src / usr.bin / lex / misc.c
CommitLineData
86041518
WJ
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Vern Paxson of Lawrence Berkeley Laboratory.
7 *
8 * The United States Government has rights in this work pursuant
9 * to contract no. DE-AC03-76SF00098 between the United States
10 * Department of Energy and the University of California.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#ifndef lint
42static char sccsid[] = "@(#)misc.c 5.3 (Berkeley) 2/26/91";
43#endif /* not lint */
44
45/* misc - miscellaneous flex routines */
46
47#include <ctype.h>
48#include <stdlib.h>
49#include "flexdef.h"
50
51/* ANSI C does not guarantee that isascii() is defined */
52#ifndef isascii
53#define isascii(c) ((c) <= 0177)
54#endif
55
56
57
58/* declare functions that have forward references */
59
60void dataflush PROTO(());
61int otoi PROTO((Char []));
62
63
64/* action_out - write the actions from the temporary file to lex.yy.c
65 *
66 * synopsis
67 * action_out();
68 *
69 * Copies the action file up to %% (or end-of-file) to lex.yy.c
70 */
71
72void action_out()
73
74 {
75 char buf[MAXLINE];
76
77 while ( fgets( buf, MAXLINE, temp_action_file ) != NULL )
78 if ( buf[0] == '%' && buf[1] == '%' )
79 break;
80 else
81 fputs( buf, stdout );
82 }
83
84
85/* allocate_array - allocate memory for an integer array of the given size */
86
87void *allocate_array( size, element_size )
88int size, element_size;
89
90 {
91 register void *mem;
92
93 /* on 16-bit int machines (e.g., 80286) we might be trying to
94 * allocate more than a signed int can hold, and that won't
95 * work. Cheap test:
96 */
97 if ( element_size * size <= 0 )
98 flexfatal( "request for < 1 byte in allocate_array()" );
99
100 mem = (void *) malloc( (unsigned) (element_size * size) );
101
102 if ( mem == NULL )
103 flexfatal( "memory allocation failed in allocate_array()" );
104
105 return ( mem );
106 }
107
108
109/* all_lower - true if a string is all lower-case
110 *
111 * synopsis:
112 * Char *str;
113 * int all_lower();
114 * true/false = all_lower( str );
115 */
116
117int all_lower( str )
118register Char *str;
119
120 {
121 while ( *str )
122 {
123 if ( ! isascii( *str ) || ! islower( *str ) )
124 return ( 0 );
125 ++str;
126 }
127
128 return ( 1 );
129 }
130
131
132/* all_upper - true if a string is all upper-case
133 *
134 * synopsis:
135 * Char *str;
136 * int all_upper();
137 * true/false = all_upper( str );
138 */
139
140int all_upper( str )
141register Char *str;
142
143 {
144 while ( *str )
145 {
146 if ( ! isascii( *str ) || ! isupper( (char) *str ) )
147 return ( 0 );
148 ++str;
149 }
150
151 return ( 1 );
152 }
153
154
155/* bubble - bubble sort an integer array in increasing order
156 *
157 * synopsis
158 * int v[n], n;
159 * bubble( v, n );
160 *
161 * description
162 * sorts the first n elements of array v and replaces them in
163 * increasing order.
164 *
165 * passed
166 * v - the array to be sorted
167 * n - the number of elements of 'v' to be sorted */
168
169void bubble( v, n )
170int v[], n;
171
172 {
173 register int i, j, k;
174
175 for ( i = n; i > 1; --i )
176 for ( j = 1; j < i; ++j )
177 if ( v[j] > v[j + 1] ) /* compare */
178 {
179 k = v[j]; /* exchange */
180 v[j] = v[j + 1];
181 v[j + 1] = k;
182 }
183 }
184
185
186/* clower - replace upper-case letter to lower-case
187 *
188 * synopsis:
189 * Char clower();
190 * int c;
191 * c = clower( c );
192 */
193
194Char clower( c )
195register int c;
196
197 {
198 return ( (isascii( c ) && isupper( c )) ? tolower( c ) : c );
199 }
200
201
202/* copy_string - returns a dynamically allocated copy of a string
203 *
204 * synopsis
205 * char *str, *copy, *copy_string();
206 * copy = copy_string( str );
207 */
208
209char *copy_string( str )
210register char *str;
211
212 {
213 register char *c;
214 char *copy;
215
216 /* find length */
217 for ( c = str; *c; ++c )
218 ;
219
220 copy = malloc( (unsigned) ((c - str + 1) * sizeof( char )) );
221
222 if ( copy == NULL )
223 flexfatal( "dynamic memory failure in copy_string()" );
224
225 for ( c = copy; (*c++ = *str++); )
226 ;
227
228 return ( copy );
229 }
230
231
232/* copy_unsigned_string -
233 * returns a dynamically allocated copy of a (potentially) unsigned string
234 *
235 * synopsis
236 * Char *str, *copy, *copy_unsigned_string();
237 * copy = copy_unsigned_string( str );
238 */
239
240Char *copy_unsigned_string( str )
241register Char *str;
242
243 {
244 register Char *c;
245 Char *copy;
246
247 /* find length */
248 for ( c = str; *c; ++c )
249 ;
250
251 copy = (Char *) malloc( (unsigned) ((c - str + 1) * sizeof( Char )) );
252
253 if ( copy == NULL )
254 flexfatal( "dynamic memory failure in copy_unsigned_string()" );
255
256 for ( c = copy; (*c++ = *str++); )
257 ;
258
259 return ( copy );
260 }
261
262
263/* cshell - shell sort a character array in increasing order
264 *
265 * synopsis
266 *
267 * Char v[n];
268 * int n, special_case_0;
269 * cshell( v, n, special_case_0 );
270 *
271 * description
272 * does a shell sort of the first n elements of array v.
273 * If special_case_0 is true, then any element equal to 0
274 * is instead assumed to have infinite weight.
275 *
276 * passed
277 * v - array to be sorted
278 * n - number of elements of v to be sorted
279 */
280
281void cshell( v, n, special_case_0 )
282Char v[];
283int n, special_case_0;
284
285 {
286 int gap, i, j, jg;
287 Char k;
288
289 for ( gap = n / 2; gap > 0; gap = gap / 2 )
290 for ( i = gap; i < n; ++i )
291 for ( j = i - gap; j >= 0; j = j - gap )
292 {
293 jg = j + gap;
294
295 if ( special_case_0 )
296 {
297 if ( v[jg] == 0 )
298 break;
299
300 else if ( v[j] != 0 && v[j] <= v[jg] )
301 break;
302 }
303
304 else if ( v[j] <= v[jg] )
305 break;
306
307 k = v[j];
308 v[j] = v[jg];
309 v[jg] = k;
310 }
311 }
312
313
314/* dataend - finish up a block of data declarations
315 *
316 * synopsis
317 * dataend();
318 */
319
320void dataend()
321
322 {
323 if ( datapos > 0 )
324 dataflush();
325
326 /* add terminator for initialization */
327 puts( " } ;\n" );
328
329 dataline = 0;
330 datapos = 0;
331 }
332
333
334
335/* dataflush - flush generated data statements
336 *
337 * synopsis
338 * dataflush();
339 */
340
341void dataflush()
342
343 {
344 putchar( '\n' );
345
346 if ( ++dataline >= NUMDATALINES )
347 {
348 /* put out a blank line so that the table is grouped into
349 * large blocks that enable the user to find elements easily
350 */
351 putchar( '\n' );
352 dataline = 0;
353 }
354
355 /* reset the number of characters written on the current line */
356 datapos = 0;
357 }
358
359
360/* flexerror - report an error message and terminate
361 *
362 * synopsis
363 * char msg[];
364 * flexerror( msg );
365 */
366
367void flexerror( msg )
368char msg[];
369
370 {
371 fprintf( stderr, "%s: %s\n", program_name, msg );
372
373 flexend( 1 );
374 }
375
376
377/* flexfatal - report a fatal error message and terminate
378 *
379 * synopsis
380 * char msg[];
381 * flexfatal( msg );
382 */
383
384void flexfatal( msg )
385char msg[];
386
387 {
388 fprintf( stderr, "%s: fatal internal error, %s\n", program_name, msg );
389 flexend( 1 );
390 }
391
392
393/* flex_gettime - return current time
394 *
395 * synopsis
396 * char *flex_gettime(), *time_str;
397 * time_str = flex_gettime();
398 *
399 * note
400 * the routine name has the "flex_" prefix because of name clashes
401 * with Turbo-C
402 */
403
404/* include sys/types.h to use time_t and make lint happy */
405
406#ifndef MS_DOS
407#ifndef VMS
408#include <sys/types.h>
409#else
410#include <types.h>
411#endif
412#endif
413
414#ifdef MS_DOS
415#include <time.h>
416typedef long time_t;
417#endif
418
419char *flex_gettime()
420
421 {
422 time_t t, time();
423 char *result, *ctime(), *copy_string();
424
425 t = time( (long *) 0 );
426
427 result = copy_string( ctime( &t ) );
428
429 /* get rid of trailing newline */
430 result[24] = '\0';
431
432 return ( result );
433 }
434
435
436/* lerrif - report an error message formatted with one integer argument
437 *
438 * synopsis
439 * char msg[];
440 * int arg;
441 * lerrif( msg, arg );
442 */
443
444void lerrif( msg, arg )
445char msg[];
446int arg;
447
448 {
449 char errmsg[MAXLINE];
450 (void) sprintf( errmsg, msg, arg );
451 flexerror( errmsg );
452 }
453
454
455/* lerrsf - report an error message formatted with one string argument
456 *
457 * synopsis
458 * char msg[], arg[];
459 * lerrsf( msg, arg );
460 */
461
462void lerrsf( msg, arg )
463char msg[], arg[];
464
465 {
466 char errmsg[MAXLINE];
467
468 (void) sprintf( errmsg, msg, arg );
469 flexerror( errmsg );
470 }
471
472
473/* htoi - convert a hexadecimal digit string to an integer value
474 *
475 * synopsis:
476 * int val, htoi();
477 * Char str[];
478 * val = htoi( str );
479 */
480
481int htoi( str )
482Char str[];
483
484 {
485 int result;
486
487 (void) sscanf( (char *) str, "%x", &result );
488
489 return ( result );
490 }
491
492
493/* line_directive_out - spit out a "# line" statement */
494
495void line_directive_out( output_file_name )
496FILE *output_file_name;
497
498 {
499 if ( infilename && gen_line_dirs )
500 fprintf( output_file_name, "# line %d \"%s\"\n", linenum, infilename );
501 }
502
503
504/* mk2data - generate a data statement for a two-dimensional array
505 *
506 * synopsis
507 * int value;
508 * mk2data( value );
509 *
510 * generates a data statement initializing the current 2-D array to "value"
511 */
512void mk2data( value )
513int value;
514
515 {
516 if ( datapos >= NUMDATAITEMS )
517 {
518 putchar( ',' );
519 dataflush();
520 }
521
522 if ( datapos == 0 )
523 /* indent */
524 fputs( " ", stdout );
525
526 else
527 putchar( ',' );
528
529 ++datapos;
530
531 printf( "%5d", value );
532 }
533
534
535/* mkdata - generate a data statement
536 *
537 * synopsis
538 * int value;
539 * mkdata( value );
540 *
541 * generates a data statement initializing the current array element to
542 * "value"
543 */
544void mkdata( value )
545int value;
546
547 {
548 if ( datapos >= NUMDATAITEMS )
549 {
550 putchar( ',' );
551 dataflush();
552 }
553
554 if ( datapos == 0 )
555 /* indent */
556 fputs( " ", stdout );
557
558 else
559 putchar( ',' );
560
561 ++datapos;
562
563 printf( "%5d", value );
564 }
565
566
567/* myctoi - return the integer represented by a string of digits
568 *
569 * synopsis
570 * Char array[];
571 * int val, myctoi();
572 * val = myctoi( array );
573 *
574 */
575
576int myctoi( array )
577Char array[];
578
579 {
580 int val = 0;
581
582 (void) sscanf( (char *) array, "%d", &val );
583
584 return ( val );
585 }
586
587
588/* myesc - return character corresponding to escape sequence
589 *
590 * synopsis
591 * Char array[], c, myesc();
592 * c = myesc( array );
593 *
594 */
595
596Char myesc( array )
597Char array[];
598
599 {
600 switch ( array[1] )
601 {
602 case 'a': return ( '\a' );
603 case 'b': return ( '\b' );
604 case 'f': return ( '\f' );
605 case 'n': return ( '\n' );
606 case 'r': return ( '\r' );
607 case 't': return ( '\t' );
608 case 'v': return ( '\v' );
609
610 case 'x':
611 /* fall through */
612
613 case '0':
614 case '1':
615 case '2':
616 case '3':
617 case '4':
618 case '5':
619 case '6':
620 case '7':
621 case '8':
622 case '9':
623
624 { /* \<octal> or \x<hex> */
625 Char c, esc_char;
626 register int sptr = 1;
627
628 if ( array[1] == 'x' )
629 ++sptr;
630
631 while ( isascii( array[sptr] ) && isdigit( array[sptr] ) )
632 /* don't increment inside loop control because if
633 * isdigit() is a macro it will expand it to two
634 * increments ...
635 */
636 ++sptr;
637
638 c = array[sptr];
639 array[sptr] = '\0';
640
641 if ( array[1] == 'x' )
642 esc_char = htoi( array + 2 );
643 else
644 esc_char = otoi( array + 1 );
645
646 array[sptr] = c;
647
648 return ( esc_char );
649 }
650
651 default:
652 return ( array[1] );
653 }
654 }
655
656
657/* otoi - convert an octal digit string to an integer value
658 *
659 * synopsis:
660 * int val, otoi();
661 * Char str[];
662 * val = otoi( str );
663 */
664
665int otoi( str )
666Char str[];
667
668 {
669 int result;
670
671 (void) sscanf( (char *) str, "%o", &result );
672
673 return ( result );
674 }
675
676
677/* readable_form - return the the human-readable form of a character
678 *
679 * synopsis:
680 * int c;
681 * char *readable_form();
682 * <string> = readable_form( c );
683 *
684 * The returned string is in static storage.
685 */
686
687char *readable_form( c )
688register int c;
689
690 {
691 static char rform[10];
692
693 if ( (c >= 0 && c < 32) || c >= 127 )
694 {
695 switch ( c )
696 {
697 case '\n': return ( "\\n" );
698 case '\t': return ( "\\t" );
699 case '\f': return ( "\\f" );
700 case '\r': return ( "\\r" );
701 case '\b': return ( "\\b" );
702
703 default:
704 (void) sprintf( rform, "\\%.3o", c );
705 return ( rform );
706 }
707 }
708
709 else if ( c == ' ' )
710 return ( "' '" );
711
712 else
713 {
714 rform[0] = c;
715 rform[1] = '\0';
716
717 return ( rform );
718 }
719 }
720
721
722/* reallocate_array - increase the size of a dynamic array */
723
724void *reallocate_array( array, size, element_size )
725void *array;
726int size, element_size;
727
728 {
729 register void *new_array;
730
731 /* same worry as in allocate_array(): */
732 if ( size * element_size <= 0 )
733 flexfatal( "attempt to increase array size by less than 1 byte" );
734
735 new_array =
736 (void *) realloc( (char *)array, (unsigned) (size * element_size ));
737
738 if ( new_array == NULL )
739 flexfatal( "attempt to increase array size failed" );
740
741 return ( new_array );
742 }
743
744
745/* skelout - write out one section of the skeleton file
746 *
747 * synopsis
748 * skelout();
749 *
750 * DESCRIPTION
751 * Copies from skelfile to stdout until a line beginning with "%%" or
752 * EOF is found.
753 */
754void skelout()
755
756 {
757 char buf[MAXLINE];
758
759 while ( fgets( buf, MAXLINE, skelfile ) != NULL )
760 if ( buf[0] == '%' && buf[1] == '%' )
761 break;
762 else
763 fputs( buf, stdout );
764 }
765
766
767/* transition_struct_out - output a yy_trans_info structure
768 *
769 * synopsis
770 * int element_v, element_n;
771 * transition_struct_out( element_v, element_n );
772 *
773 * outputs the yy_trans_info structure with the two elements, element_v and
774 * element_n. Formats the output with spaces and carriage returns.
775 */
776
777void transition_struct_out( element_v, element_n )
778int element_v, element_n;
779
780 {
781 printf( "%7d, %5d,", element_v, element_n );
782
783 datapos += TRANS_STRUCT_PRINT_LENGTH;
784
785 if ( datapos >= 75 )
786 {
787 putchar( '\n' );
788
789 if ( ++dataline % 10 == 0 )
790 putchar( '\n' );
791
792 datapos = 0;
793 }
794 }