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 are permitted provided 15 * that: (1) source distributions retain this entire copyright notice and 16 * comment, and (2) distributions including binaries display the following 17 * acknowledgement: ``This product includes software developed by the 18 * University of California, Berkeley and its contributors'' in the 19 * documentation or other materials provided with the distribution and in 20 * all advertising materials mentioning features or use of this software. 21 * Neither the name of the University nor the names of its contributors may 22 * be used to endorse or promote products derived from this software without 23 * 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#include <sys/cdefs.h> 31__FBSDID("$FreeBSD$"); 32 33#include "flexdef.h" 34 35 36void action_define( defname, value ) 37char *defname; 38int 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 54void add_action( new_text ) 55char *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 83void *allocate_array( size, element_size ) 84int size; 85size_t element_size; 86 { 87 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 101int all_lower( str ) 102char *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 117int all_upper( str ) 118char *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 146void bubble( v, n ) 147int v[], n; 148 { 149 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 167void check_char( c ) 168int 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 184Char clower( c ) 185int 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 193char *copy_string( str ) 194const char *str; 195 { 196 const char *c1; 197 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 222Char *copy_unsigned_string( str ) 223Char *str; 224 { 225 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 259void cshell( v, n, special_case_0 ) 260Char v[]; 261int 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 293void 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 308void 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 328void flexerror( msg ) 329const 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 338void flexfatal( msg ) 339const 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 349int htoi( str ) 350Char 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 362void lerrif( msg, arg ) 363const char msg[]; 364int 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 374void lerrsf( msg, arg ) 375const 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 386void line_directive_out( output_file, do_infile ) 387FILE *output_file; 388int 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 */ 443void 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 */ 455void 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 */ 467void mk2data( value ) 468int 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 */ 494void mkdata( value ) 495int 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 517int myctoi( array ) 518char 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 530Char myesc( array ) 531Char 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#if __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 610int otoi( str ) 611Char 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 624void out( str ) 625const char str[]; 626 { 627 fputs( str, stdout ); 628 out_line_count( str ); 629 } 630 631void out_dec( fmt, n ) 632const char fmt[]; 633int n; 634 { 635 printf( fmt, n ); 636 out_line_count( fmt ); 637 } 638 639void out_dec2( fmt, n1, n2 ) 640const char fmt[]; 641int n1, n2; 642 { 643 printf( fmt, n1, n2 ); 644 out_line_count( fmt ); 645 } 646 647void out_hex( fmt, x ) 648const char fmt[]; 649unsigned int x; 650 { 651 printf( fmt, x ); 652 out_line_count( fmt ); 653 } 654 655void out_line_count( str ) 656const char str[]; 657 { 658 int i; 659 660 for ( i = 0; str[i]; ++i ) 661 if ( str[i] == '\n' ) 662 ++out_linenum; 663 } 664 665void out_str( fmt, str ) 666const char fmt[], str[]; 667 { 668 printf( fmt, str ); 669 out_line_count( fmt ); 670 out_line_count( str ); 671 } 672 673void out_str3( fmt, s1, s2, s3 ) 674const 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 683void out_str_dec( fmt, str, n ) 684const char fmt[], str[]; 685int n; 686 { 687 printf( fmt, str, n ); 688 out_line_count( fmt ); 689 out_line_count( str ); 690 } 691 692void outc( c ) 693int c; 694 { 695 putc( c, stdout ); 696 697 if ( c == '\n' ) 698 ++out_linenum; 699 } 700 701void outn( str ) 702const char str[]; 703 { 704 puts( str ); 705 out_line_count( str ); 706 ++out_linenum; 707 } 708 709 710/* readable_form - return the human-readable form of a character 711 * 712 * The returned string is in static storage. 713 */ 714 715char *readable_form( c ) 716int 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#if __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 757void *reallocate_array( array, size, element_size ) 758void *array; 759int size; 760size_t element_size; 761 { 762 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 */ 779void 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 837void transition_struct_out( element_v, element_n ) 838int 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 */ 859void *yy_flex_xmalloc( size ) 860int 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 877void zero_out( region_ptr, size_in_bytes ) 878char *region_ptr; 879size_t size_in_bytes; 880 { 881 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