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