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