1 /* $NetBSD: misc.c,v 1.4 2018/12/23 16:27:17 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.4 2018/12/23 16:27:17 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 #if HAVE_REALLOCARRAY 151 /* reallocarray has built-in overflow detection */ 152 mem = reallocarray(NULL, (size_t) size, element_size); 153 #else 154 size_t num_bytes = (size_t) size * element_size; 155 mem = (size && SIZE_MAX / (size_t) size < element_size) ? NULL : 156 malloc(num_bytes); 157 #endif 158 if (!mem) 159 flexfatal (_ 160 ("memory allocation failed in allocate_array()")); 161 162 return mem; 163 } 164 165 166 /* all_lower - true if a string is all lower-case */ 167 168 int all_lower (char *str) 169 { 170 while (*str) { 171 if (!isascii ((unsigned char) * str) || !islower ((unsigned char) * str)) 172 return 0; 173 ++str; 174 } 175 176 return 1; 177 } 178 179 180 /* all_upper - true if a string is all upper-case */ 181 182 int all_upper (char *str) 183 { 184 while (*str) { 185 if (!isascii ((unsigned char) * str) || !isupper ((unsigned char) * str)) 186 return 0; 187 ++str; 188 } 189 190 return 1; 191 } 192 193 194 /* intcmp - compares two integers for use by qsort. */ 195 196 int intcmp (const void *a, const void *b) 197 { 198 return *(const int *) a - *(const int *) b; 199 } 200 201 202 /* check_char - checks a character to make sure it's within the range 203 * we're expecting. If not, generates fatal error message 204 * and exits. 205 */ 206 207 void check_char (int c) 208 { 209 if (c >= CSIZE) 210 lerr (_("bad character '%s' detected in check_char()"), 211 readable_form (c)); 212 213 if (c >= csize) 214 lerr (_ 215 ("scanner requires -8 flag to use the character %s"), 216 readable_form (c)); 217 } 218 219 220 221 /* clower - replace upper-case letter to lower-case */ 222 223 unsigned char clower (int c) 224 { 225 return (unsigned char) ((isascii (c) && isupper (c)) ? tolower (c) : c); 226 } 227 228 229 char *xstrdup(const char *s) 230 { 231 char *s2; 232 233 if ((s2 = strdup(s)) == NULL) 234 flexfatal (_("memory allocation failure in xstrdup()")); 235 236 return s2; 237 } 238 239 240 /* cclcmp - compares two characters for use by qsort with '\0' sorting last. */ 241 242 int cclcmp (const void *a, const void *b) 243 { 244 if (!*(const unsigned char *) a) 245 return 1; 246 else 247 if (!*(const unsigned char *) b) 248 return - 1; 249 else 250 return *(const unsigned char *) a - *(const unsigned char *) b; 251 } 252 253 254 /* dataend - finish up a block of data declarations */ 255 256 void dataend (void) 257 { 258 /* short circuit any output */ 259 if (gentables) { 260 261 if (datapos > 0) 262 dataflush (); 263 264 /* add terminator for initialization; { for vi */ 265 outn (" } ;\n"); 266 } 267 dataline = 0; 268 datapos = 0; 269 } 270 271 272 /* dataflush - flush generated data statements */ 273 274 void dataflush (void) 275 { 276 /* short circuit any output */ 277 if (!gentables) 278 return; 279 280 outc ('\n'); 281 282 if (++dataline >= NUMDATALINES) { 283 /* Put out a blank line so that the table is grouped into 284 * large blocks that enable the user to find elements easily. 285 */ 286 outc ('\n'); 287 dataline = 0; 288 } 289 290 /* Reset the number of characters written on the current line. */ 291 datapos = 0; 292 } 293 294 295 /* flexerror - report an error message and terminate */ 296 297 void flexerror (const char *msg) 298 { 299 fprintf (stderr, "%s: %s\n", program_name, msg); 300 flexend (1); 301 } 302 303 304 /* flexfatal - report a fatal error message and terminate */ 305 306 void flexfatal (const char *msg) 307 { 308 fprintf (stderr, _("%s: fatal internal error, %s\n"), 309 program_name, msg); 310 FLEX_EXIT (1); 311 } 312 313 314 /* lerr - report an error message */ 315 316 void lerr (const char *msg, ...) 317 { 318 char errmsg[MAXLINE]; 319 va_list args; 320 321 va_start(args, msg); 322 vsnprintf (errmsg, sizeof(errmsg), msg, args); 323 va_end(args); 324 flexerror (errmsg); 325 } 326 327 328 /* lerr_fatal - as lerr, but call flexfatal */ 329 330 void lerr_fatal (const char *msg, ...) 331 { 332 char errmsg[MAXLINE]; 333 va_list args; 334 va_start(args, msg); 335 336 vsnprintf (errmsg, sizeof(errmsg), msg, args); 337 va_end(args); 338 flexfatal (errmsg); 339 } 340 341 342 /* line_directive_out - spit out a "#line" statement */ 343 344 void line_directive_out (FILE *output_file, int do_infile) 345 { 346 char directive[MAXLINE], filename[MAXLINE]; 347 char *s1, *s2, *s3; 348 static const char line_fmt[] = "#line %d \"%s\"\n"; 349 350 if (!gen_line_dirs) 351 return; 352 353 s1 = do_infile ? infilename : "M4_YY_OUTFILE_NAME"; 354 355 if (do_infile && !s1) 356 s1 = "<stdin>"; 357 358 s2 = filename; 359 s3 = &filename[sizeof (filename) - 2]; 360 361 while (s2 < s3 && *s1) { 362 if (*s1 == '\\' || *s1 == '"') 363 /* Escape the '\' or '"' */ 364 *s2++ = '\\'; 365 366 *s2++ = *s1++; 367 } 368 369 *s2 = '\0'; 370 371 if (do_infile) 372 snprintf (directive, sizeof(directive), line_fmt, linenum, filename); 373 else { 374 snprintf (directive, sizeof(directive), line_fmt, 0, filename); 375 } 376 377 /* If output_file is nil then we should put the directive in 378 * the accumulated actions. 379 */ 380 if (output_file) { 381 fputs (directive, output_file); 382 } 383 else 384 add_action (directive); 385 } 386 387 388 /* mark_defs1 - mark the current position in the action array as 389 * representing where the user's section 1 definitions end 390 * and the prolog begins 391 */ 392 void mark_defs1 (void) 393 { 394 defs1_offset = 0; 395 action_array[action_index++] = '\0'; 396 action_offset = prolog_offset = action_index; 397 action_array[action_index] = '\0'; 398 } 399 400 401 /* mark_prolog - mark the current position in the action array as 402 * representing the end of the action prolog 403 */ 404 void mark_prolog (void) 405 { 406 action_array[action_index++] = '\0'; 407 action_offset = action_index; 408 action_array[action_index] = '\0'; 409 } 410 411 412 /* mk2data - generate a data statement for a two-dimensional array 413 * 414 * Generates a data statement initializing the current 2-D array to "value". 415 */ 416 void mk2data (int value) 417 { 418 /* short circuit any output */ 419 if (!gentables) 420 return; 421 422 if (datapos >= NUMDATAITEMS) { 423 outc (','); 424 dataflush (); 425 } 426 427 if (datapos == 0) 428 /* Indent. */ 429 out (" "); 430 431 else 432 outc (','); 433 434 ++datapos; 435 436 out_dec ("%5d", value); 437 } 438 439 440 /* mkdata - generate a data statement 441 * 442 * Generates a data statement initializing the current array element to 443 * "value". 444 */ 445 void mkdata (int value) 446 { 447 /* short circuit any output */ 448 if (!gentables) 449 return; 450 451 if (datapos >= NUMDATAITEMS) { 452 outc (','); 453 dataflush (); 454 } 455 456 if (datapos == 0) 457 /* Indent. */ 458 out (" "); 459 else 460 outc (','); 461 462 ++datapos; 463 464 out_dec ("%5d", value); 465 } 466 467 468 /* myctoi - return the integer represented by a string of digits */ 469 470 int myctoi (const char *array) 471 { 472 int val = 0; 473 474 (void) sscanf (array, "%d", &val); 475 476 return val; 477 } 478 479 480 /* myesc - return character corresponding to escape sequence */ 481 482 unsigned char myesc (unsigned char array[]) 483 { 484 unsigned char c, esc_char; 485 486 switch (array[1]) { 487 case 'b': 488 return '\b'; 489 case 'f': 490 return '\f'; 491 case 'n': 492 return '\n'; 493 case 'r': 494 return '\r'; 495 case 't': 496 return '\t'; 497 case 'a': 498 return '\a'; 499 case 'v': 500 return '\v'; 501 case '0': 502 case '1': 503 case '2': 504 case '3': 505 case '4': 506 case '5': 507 case '6': 508 case '7': 509 { /* \<octal> */ 510 int sptr = 1; 511 512 while (sptr <= 3 && 513 array[sptr] >= '0' && array[sptr] <= '7') { 514 ++sptr; 515 } 516 517 c = array[sptr]; 518 array[sptr] = '\0'; 519 520 esc_char = (unsigned char) strtoul ((const char *)array + 1, NULL, 8); 521 522 array[sptr] = c; 523 524 return esc_char; 525 } 526 527 case 'x': 528 { /* \x<hex> */ 529 int sptr = 2; 530 531 while (sptr <= 3 && isxdigit (array[sptr])) { 532 /* Don't increment inside loop control 533 * because if isxdigit() is a macro it might 534 * expand into multiple increments ... 535 */ 536 ++sptr; 537 } 538 539 c = array[sptr]; 540 array[sptr] = '\0'; 541 542 esc_char = (unsigned char) strtoul ((const char *)array + 2, NULL, 16); 543 544 array[sptr] = c; 545 546 return esc_char; 547 } 548 549 default: 550 return array[1]; 551 } 552 } 553 554 555 /* out - various flavors of outputing a (possibly formatted) string for the 556 * generated scanner, keeping track of the line count. 557 */ 558 559 void out (const char *str) 560 { 561 fputs (str, stdout); 562 } 563 564 void out_dec (const char *fmt, int n) 565 { 566 fprintf (stdout, fmt, n); 567 } 568 569 void out_dec2 (const char *fmt, int n1, int n2) 570 { 571 fprintf (stdout, fmt, n1, n2); 572 } 573 574 void out_hex (const char *fmt, unsigned int x) 575 { 576 fprintf (stdout, fmt, x); 577 } 578 579 void out_str (const char *fmt, const char str[]) 580 { 581 fprintf (stdout,fmt, str); 582 } 583 584 void out_str3 (const char *fmt, const char s1[], const char s2[], const char s3[]) 585 { 586 fprintf (stdout,fmt, s1, s2, s3); 587 } 588 589 void out_str_dec (const char *fmt, const char str[], int n) 590 { 591 fprintf (stdout,fmt, str, n); 592 } 593 594 void outc (int c) 595 { 596 fputc (c, stdout); 597 } 598 599 void outn (const char *str) 600 { 601 fputs (str,stdout); 602 fputc('\n',stdout); 603 } 604 605 /** Print "m4_define( [[def]], [[val]])m4_dnl\n". 606 * @param def The m4 symbol to define. 607 * @param val The definition; may be NULL. 608 */ 609 void out_m4_define (const char* def, const char* val) 610 { 611 const char * fmt = "m4_define( [[%s]], [[%s]])m4_dnl\n"; 612 fprintf(stdout, fmt, def, val?val:""); 613 } 614 615 616 /* readable_form - return the the human-readable form of a character 617 * 618 * The returned string is in static storage. 619 */ 620 621 char *readable_form (int c) 622 { 623 static char rform[20]; 624 625 if ((c >= 0 && c < 32) || c >= 127) { 626 switch (c) { 627 case '\b': 628 return "\\b"; 629 case '\f': 630 return "\\f"; 631 case '\n': 632 return "\\n"; 633 case '\r': 634 return "\\r"; 635 case '\t': 636 return "\\t"; 637 case '\a': 638 return "\\a"; 639 case '\v': 640 return "\\v"; 641 default: 642 if(trace_hex) 643 snprintf (rform, sizeof(rform), "\\x%.2x", (unsigned int) c); 644 else 645 snprintf (rform, sizeof(rform), "\\%.3o", (unsigned int) c); 646 return rform; 647 } 648 } 649 650 else if (c == ' ') 651 return "' '"; 652 653 else { 654 rform[0] = (char) c; 655 rform[1] = '\0'; 656 657 return rform; 658 } 659 } 660 661 662 /* reallocate_array - increase the size of a dynamic array */ 663 664 void *reallocate_array (void *array, int size, size_t element_size) 665 { 666 void *new_array; 667 #if HAVE_REALLOCARRAY 668 /* reallocarray has built-in overflow detection */ 669 new_array = reallocarray(array, (size_t) size, element_size); 670 #else 671 size_t num_bytes = (size_t) size * element_size; 672 new_array = (size && SIZE_MAX / (size_t) size < element_size) ? NULL : 673 realloc(array, num_bytes); 674 #endif 675 if (!new_array) 676 flexfatal (_("attempt to increase array size failed")); 677 678 return new_array; 679 } 680 681 682 /* skelout - write out one section of the skeleton file 683 * 684 * Description 685 * Copies skelfile or skel array to stdout until a line beginning with 686 * "%%" or EOF is found. 687 */ 688 void skelout (void) 689 { 690 char buf_storage[MAXLINE]; 691 char *buf = buf_storage; 692 bool do_copy = true; 693 694 /* "reset" the state by clearing the buffer and pushing a '1' */ 695 if(sko_len > 0) 696 sko_peek(&do_copy); 697 sko_len = 0; 698 sko_push(do_copy=true); 699 700 701 /* Loop pulling lines either from the skelfile, if we're using 702 * one, or from the skel[] array. 703 */ 704 while (skelfile ? 705 (fgets (buf, MAXLINE, skelfile) != NULL) : 706 ((buf = (char *) skel[skel_ind++]) != 0)) { 707 708 if (skelfile) 709 chomp (buf); 710 711 /* copy from skel array */ 712 if (buf[0] == '%') { /* control line */ 713 /* print the control line as a comment. */ 714 if (ddebug && buf[1] != '#') { 715 if (buf[strlen (buf) - 1] == '\\') 716 out_str ("/* %s */\\\n", buf); 717 else 718 out_str ("/* %s */\n", buf); 719 } 720 721 /* We've been accused of using cryptic markers in the skel. 722 * So we'll use emacs-style-hyphenated-commands. 723 * We might consider a hash if this if-else-if-else 724 * chain gets too large. 725 */ 726 #define cmd_match(s) (strncmp(buf,(s),strlen(s))==0) 727 728 if (buf[1] == '%') { 729 /* %% is a break point for skelout() */ 730 return; 731 } 732 else if (cmd_match (CMD_PUSH)){ 733 sko_push(do_copy); 734 if(ddebug){ 735 out_str("/*(state = (%s) */",do_copy?"true":"false"); 736 } 737 out_str("%s\n", buf[strlen (buf) - 1] =='\\' ? "\\" : ""); 738 } 739 else if (cmd_match (CMD_POP)){ 740 sko_pop(&do_copy); 741 if(ddebug){ 742 out_str("/*(state = (%s) */",do_copy?"true":"false"); 743 } 744 out_str("%s\n", buf[strlen (buf) - 1] =='\\' ? "\\" : ""); 745 } 746 else if (cmd_match (CMD_IF_REENTRANT)){ 747 sko_push(do_copy); 748 do_copy = reentrant && do_copy; 749 } 750 else if (cmd_match (CMD_IF_NOT_REENTRANT)){ 751 sko_push(do_copy); 752 do_copy = !reentrant && do_copy; 753 } 754 else if (cmd_match(CMD_IF_BISON_BRIDGE)){ 755 sko_push(do_copy); 756 do_copy = bison_bridge_lval && do_copy; 757 } 758 else if (cmd_match(CMD_IF_NOT_BISON_BRIDGE)){ 759 sko_push(do_copy); 760 do_copy = !bison_bridge_lval && do_copy; 761 } 762 else if (cmd_match (CMD_ENDIF)){ 763 sko_pop(&do_copy); 764 } 765 else if (cmd_match (CMD_IF_TABLES_SER)) { 766 do_copy = do_copy && tablesext; 767 } 768 else if (cmd_match (CMD_TABLES_YYDMAP)) { 769 if (tablesext && yydmap_buf.elts) 770 outn ((char *) (yydmap_buf.elts)); 771 } 772 else if (cmd_match (CMD_DEFINE_YYTABLES)) { 773 out_str("#define YYTABLES_NAME \"%s\"\n", 774 tablesname?tablesname:"yytables"); 775 } 776 else if (cmd_match (CMD_IF_CPP_ONLY)) { 777 /* only for C++ */ 778 sko_push(do_copy); 779 do_copy = C_plus_plus; 780 } 781 else if (cmd_match (CMD_IF_C_ONLY)) { 782 /* %- only for C */ 783 sko_push(do_copy); 784 do_copy = !C_plus_plus; 785 } 786 else if (cmd_match (CMD_IF_C_OR_CPP)) { 787 /* %* for C and C++ */ 788 sko_push(do_copy); 789 do_copy = true; 790 } 791 else if (cmd_match (CMD_NOT_FOR_HEADER)) { 792 /* %c begin linkage-only (non-header) code. */ 793 OUT_BEGIN_CODE (); 794 } 795 else if (cmd_match (CMD_OK_FOR_HEADER)) { 796 /* %e end linkage-only code. */ 797 OUT_END_CODE (); 798 } 799 else { 800 flexfatal (_("bad line in skeleton file")); 801 } 802 } 803 804 else if (do_copy) 805 outn (buf); 806 } /* end while */ 807 } 808 809 810 /* transition_struct_out - output a yy_trans_info structure 811 * 812 * outputs the yy_trans_info structure with the two elements, element_v and 813 * element_n. Formats the output with spaces and carriage returns. 814 */ 815 816 void transition_struct_out (int element_v, int element_n) 817 { 818 819 /* short circuit any output */ 820 if (!gentables) 821 return; 822 823 out_dec2 (" {%4d,%4d },", element_v, element_n); 824 825 datapos += TRANS_STRUCT_PRINT_LENGTH; 826 827 if (datapos >= 79 - TRANS_STRUCT_PRINT_LENGTH) { 828 outc ('\n'); 829 830 if (++dataline % 10 == 0) 831 outc ('\n'); 832 833 datapos = 0; 834 } 835 } 836 837 838 /* The following is only needed when building flex's parser using certain 839 * broken versions of bison. 840 * 841 * XXX: this is should go soon 842 */ 843 void *yy_flex_xmalloc (int size) 844 { 845 void *result; 846 847 result = malloc((size_t) size); 848 if (!result) 849 flexfatal (_ 850 ("memory allocation failed in yy_flex_xmalloc()")); 851 852 return result; 853 } 854 855 856 /* Remove all '\n' and '\r' characters, if any, from the end of str. 857 * str can be any null-terminated string, or NULL. 858 * returns str. */ 859 char *chomp (char *str) 860 { 861 char *p = str; 862 863 if (!str || !*str) /* s is null or empty string */ 864 return str; 865 866 /* find end of string minus one */ 867 while (*p) 868 ++p; 869 --p; 870 871 /* eat newlines */ 872 while (p >= str && (*p == '\r' || *p == '\n')) 873 *p-- = 0; 874 return str; 875 } 876