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