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