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