1 %{/* nlmheader.y - parse NLM header specification keywords. 2 Copyright (C) 1993-2016 Free Software Foundation, Inc. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 /* Written by Ian Lance Taylor <ian (at) cygnus.com>. 22 23 This bison file parses the commands recognized by the NetWare NLM 24 linker, except for lists of object files. It stores the 25 information in global variables. 26 27 This implementation is based on the description in the NetWare Tool 28 Maker Specification manual, edition 1.0. */ 29 30 #include "sysdep.h" 31 #include "safe-ctype.h" 32 #include "bfd.h" 33 #include "nlm/common.h" 34 #include "nlm/internal.h" 35 #include "bucomm.h" 36 #include "nlmconv.h" 37 38 /* Information is stored in the structures pointed to by these 39 variables. */ 40 41 Nlm_Internal_Fixed_Header *fixed_hdr; 42 Nlm_Internal_Variable_Header *var_hdr; 43 Nlm_Internal_Version_Header *version_hdr; 44 Nlm_Internal_Copyright_Header *copyright_hdr; 45 Nlm_Internal_Extended_Header *extended_hdr; 46 47 /* Procedure named by CHECK. */ 48 char *check_procedure; 49 /* File named by CUSTOM. */ 50 char *custom_file; 51 /* Whether to generate debugging information (DEBUG). */ 52 bfd_boolean debug_info; 53 /* Procedure named by EXIT. */ 54 char *exit_procedure; 55 /* Exported symbols (EXPORT). */ 56 struct string_list *export_symbols; 57 /* List of files from INPUT. */ 58 struct string_list *input_files; 59 /* Map file name (MAP, FULLMAP). */ 60 char *map_file; 61 /* Whether a full map has been requested (FULLMAP). */ 62 bfd_boolean full_map; 63 /* File named by HELP. */ 64 char *help_file; 65 /* Imported symbols (IMPORT). */ 66 struct string_list *import_symbols; 67 /* File named by MESSAGES. */ 68 char *message_file; 69 /* Autoload module list (MODULE). */ 70 struct string_list *modules; 71 /* File named by OUTPUT. */ 72 char *output_file; 73 /* File named by SHARELIB. */ 74 char *sharelib_file; 75 /* Start procedure name (START). */ 76 char *start_procedure; 77 /* VERBOSE. */ 78 bfd_boolean verbose; 79 /* RPC description file (XDCDATA). */ 80 char *rpc_file; 81 82 /* The number of serious errors that have occurred. */ 83 int parse_errors; 84 85 /* The current symbol prefix when reading a list of import or export 86 symbols. */ 87 static char *symbol_prefix; 88 89 /* Parser error message handler. */ 90 #define yyerror(msg) nlmheader_error (msg); 91 92 /* Local functions. */ 93 static int yylex (void); 94 static void nlmlex_file_push (const char *); 95 static bfd_boolean nlmlex_file_open (const char *); 96 static int nlmlex_buf_init (void); 97 static char nlmlex_buf_add (int); 98 static long nlmlex_get_number (const char *); 99 static void nlmheader_identify (void); 100 static void nlmheader_warn (const char *, int); 101 static void nlmheader_error (const char *); 102 static struct string_list * string_list_cons (char *, struct string_list *); 103 static struct string_list * string_list_append (struct string_list *, 104 struct string_list *); 105 static struct string_list * string_list_append1 (struct string_list *, 106 char *); 107 static char *xstrdup (const char *); 108 109 %} 110 111 %union 112 { 113 char *string; 114 struct string_list *list; 115 }; 116 117 /* The reserved words. */ 118 119 %token CHECK CODESTART COPYRIGHT CUSTOM DATE DEBUG_K DESCRIPTION EXIT 120 %token EXPORT FLAG_ON FLAG_OFF FULLMAP HELP IMPORT INPUT MAP MESSAGES 121 %token MODULE MULTIPLE OS_DOMAIN OUTPUT PSEUDOPREEMPTION REENTRANT 122 %token SCREENNAME SHARELIB STACK START SYNCHRONIZE 123 %token THREADNAME TYPE VERBOSE VERSIONK XDCDATA 124 125 /* Arguments. */ 126 127 %token <string> STRING 128 %token <string> QUOTED_STRING 129 130 /* Typed non-terminals. */ 131 %type <list> symbol_list_opt symbol_list string_list 132 %type <string> symbol 133 134 %% 135 136 /* Keywords must start in the leftmost column of the file. Arguments 137 may appear anywhere else. The lexer uses this to determine what 138 token to return, so we don't have to worry about it here. */ 139 140 /* The entire file is just a list of commands. */ 141 142 file: 143 commands 144 ; 145 146 /* A possibly empty list of commands. */ 147 148 commands: 149 /* May be empty. */ 150 | command commands 151 ; 152 153 /* A single command. There is where most of the work takes place. */ 154 155 command: 156 CHECK STRING 157 { 158 check_procedure = $2; 159 } 160 | CODESTART STRING 161 { 162 nlmheader_warn (_("CODESTART is not implemented; sorry"), -1); 163 free ($2); 164 } 165 | COPYRIGHT QUOTED_STRING 166 { 167 int len; 168 169 strncpy (copyright_hdr->stamp, "CoPyRiGhT=", 10); 170 len = strlen ($2); 171 if (len >= NLM_MAX_COPYRIGHT_MESSAGE_LENGTH) 172 { 173 nlmheader_warn (_("copyright string is too long"), 174 NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1); 175 len = NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1; 176 } 177 copyright_hdr->copyrightMessageLength = len; 178 strncpy (copyright_hdr->copyrightMessage, $2, len); 179 copyright_hdr->copyrightMessage[len] = '\0'; 180 free ($2); 181 } 182 | CUSTOM STRING 183 { 184 custom_file = $2; 185 } 186 | DATE STRING STRING STRING 187 { 188 /* We don't set the version stamp here, because we use the 189 version stamp to detect whether the required VERSION 190 keyword was given. */ 191 version_hdr->month = nlmlex_get_number ($2); 192 version_hdr->day = nlmlex_get_number ($3); 193 version_hdr->year = nlmlex_get_number ($4); 194 free ($2); 195 free ($3); 196 free ($4); 197 if (version_hdr->month < 1 || version_hdr->month > 12) 198 nlmheader_warn (_("illegal month"), -1); 199 if (version_hdr->day < 1 || version_hdr->day > 31) 200 nlmheader_warn (_("illegal day"), -1); 201 if (version_hdr->year < 1900 || version_hdr->year > 3000) 202 nlmheader_warn (_("illegal year"), -1); 203 } 204 | DEBUG_K 205 { 206 debug_info = TRUE; 207 } 208 | DESCRIPTION QUOTED_STRING 209 { 210 int len; 211 212 len = strlen ($2); 213 if (len > NLM_MAX_DESCRIPTION_LENGTH) 214 { 215 nlmheader_warn (_("description string is too long"), 216 NLM_MAX_DESCRIPTION_LENGTH); 217 len = NLM_MAX_DESCRIPTION_LENGTH; 218 } 219 var_hdr->descriptionLength = len; 220 strncpy (var_hdr->descriptionText, $2, len); 221 var_hdr->descriptionText[len] = '\0'; 222 free ($2); 223 } 224 | EXIT STRING 225 { 226 exit_procedure = $2; 227 } 228 | EXPORT 229 { 230 symbol_prefix = NULL; 231 } 232 symbol_list_opt 233 { 234 export_symbols = string_list_append (export_symbols, $3); 235 } 236 | FLAG_ON STRING 237 { 238 fixed_hdr->flags |= nlmlex_get_number ($2); 239 free ($2); 240 } 241 | FLAG_OFF STRING 242 { 243 fixed_hdr->flags &=~ nlmlex_get_number ($2); 244 free ($2); 245 } 246 | FULLMAP 247 { 248 map_file = ""; 249 full_map = TRUE; 250 } 251 | FULLMAP STRING 252 { 253 map_file = $2; 254 full_map = TRUE; 255 } 256 | HELP STRING 257 { 258 help_file = $2; 259 } 260 | IMPORT 261 { 262 symbol_prefix = NULL; 263 } 264 symbol_list_opt 265 { 266 import_symbols = string_list_append (import_symbols, $3); 267 } 268 | INPUT string_list 269 { 270 input_files = string_list_append (input_files, $2); 271 } 272 | MAP 273 { 274 map_file = ""; 275 } 276 | MAP STRING 277 { 278 map_file = $2; 279 } 280 | MESSAGES STRING 281 { 282 message_file = $2; 283 } 284 | MODULE string_list 285 { 286 modules = string_list_append (modules, $2); 287 } 288 | MULTIPLE 289 { 290 fixed_hdr->flags |= 0x2; 291 } 292 | OS_DOMAIN 293 { 294 fixed_hdr->flags |= 0x10; 295 } 296 | OUTPUT STRING 297 { 298 if (output_file == NULL) 299 output_file = $2; 300 else 301 nlmheader_warn (_("ignoring duplicate OUTPUT statement"), -1); 302 } 303 | PSEUDOPREEMPTION 304 { 305 fixed_hdr->flags |= 0x8; 306 } 307 | REENTRANT 308 { 309 fixed_hdr->flags |= 0x1; 310 } 311 | SCREENNAME QUOTED_STRING 312 { 313 int len; 314 315 len = strlen ($2); 316 if (len >= NLM_MAX_SCREEN_NAME_LENGTH) 317 { 318 nlmheader_warn (_("screen name is too long"), 319 NLM_MAX_SCREEN_NAME_LENGTH); 320 len = NLM_MAX_SCREEN_NAME_LENGTH; 321 } 322 var_hdr->screenNameLength = len; 323 strncpy (var_hdr->screenName, $2, len); 324 var_hdr->screenName[NLM_MAX_SCREEN_NAME_LENGTH] = '\0'; 325 free ($2); 326 } 327 | SHARELIB STRING 328 { 329 sharelib_file = $2; 330 } 331 | STACK STRING 332 { 333 var_hdr->stackSize = nlmlex_get_number ($2); 334 free ($2); 335 } 336 | START STRING 337 { 338 start_procedure = $2; 339 } 340 | SYNCHRONIZE 341 { 342 fixed_hdr->flags |= 0x4; 343 } 344 | THREADNAME QUOTED_STRING 345 { 346 int len; 347 348 len = strlen ($2); 349 if (len >= NLM_MAX_THREAD_NAME_LENGTH) 350 { 351 nlmheader_warn (_("thread name is too long"), 352 NLM_MAX_THREAD_NAME_LENGTH); 353 len = NLM_MAX_THREAD_NAME_LENGTH; 354 } 355 var_hdr->threadNameLength = len; 356 strncpy (var_hdr->threadName, $2, len); 357 var_hdr->threadName[len] = '\0'; 358 free ($2); 359 } 360 | TYPE STRING 361 { 362 fixed_hdr->moduleType = nlmlex_get_number ($2); 363 free ($2); 364 } 365 | VERBOSE 366 { 367 verbose = TRUE; 368 } 369 | VERSIONK STRING STRING STRING 370 { 371 long val; 372 373 strncpy (version_hdr->stamp, "VeRsIoN#", 8); 374 version_hdr->majorVersion = nlmlex_get_number ($2); 375 val = nlmlex_get_number ($3); 376 if (val < 0 || val > 99) 377 nlmheader_warn (_("illegal minor version number (must be between 0 and 99)"), 378 -1); 379 else 380 version_hdr->minorVersion = val; 381 val = nlmlex_get_number ($4); 382 if (val < 0) 383 nlmheader_warn (_("illegal revision number (must be between 0 and 26)"), 384 -1); 385 else if (val > 26) 386 version_hdr->revision = 0; 387 else 388 version_hdr->revision = val; 389 free ($2); 390 free ($3); 391 free ($4); 392 } 393 | VERSIONK STRING STRING 394 { 395 long val; 396 397 strncpy (version_hdr->stamp, "VeRsIoN#", 8); 398 version_hdr->majorVersion = nlmlex_get_number ($2); 399 val = nlmlex_get_number ($3); 400 if (val < 0 || val > 99) 401 nlmheader_warn (_("illegal minor version number (must be between 0 and 99)"), 402 -1); 403 else 404 version_hdr->minorVersion = val; 405 version_hdr->revision = 0; 406 free ($2); 407 free ($3); 408 } 409 | XDCDATA STRING 410 { 411 rpc_file = $2; 412 } 413 ; 414 415 /* A possibly empty list of symbols. */ 416 417 symbol_list_opt: 418 /* Empty. */ 419 { 420 $$ = NULL; 421 } 422 | symbol_list 423 { 424 $$ = $1; 425 } 426 ; 427 428 /* A list of symbols in an import or export list. Prefixes may appear 429 in parentheses. We need to use left recursion here to avoid 430 building up a large import list on the parser stack. */ 431 432 symbol_list: 433 symbol 434 { 435 $$ = string_list_cons ($1, NULL); 436 } 437 | symbol_prefix 438 { 439 $$ = NULL; 440 } 441 | symbol_list symbol 442 { 443 $$ = string_list_append1 ($1, $2); 444 } 445 | symbol_list symbol_prefix 446 { 447 $$ = $1; 448 } 449 ; 450 451 /* A prefix for subsequent symbols. */ 452 453 symbol_prefix: 454 '(' STRING ')' 455 { 456 if (symbol_prefix != NULL) 457 free (symbol_prefix); 458 symbol_prefix = $2; 459 } 460 ; 461 462 /* A single symbol. */ 463 464 symbol: 465 STRING 466 { 467 if (symbol_prefix == NULL) 468 $$ = $1; 469 else 470 { 471 $$ = xmalloc (strlen (symbol_prefix) + strlen ($1) + 2); 472 sprintf ($$, "%s@%s", symbol_prefix, $1); 473 free ($1); 474 } 475 } 476 ; 477 478 /* A list of strings. */ 479 480 string_list: 481 /* May be empty. */ 482 { 483 $$ = NULL; 484 } 485 | STRING string_list 486 { 487 $$ = string_list_cons ($1, $2); 488 } 489 ; 490 491 %% 492 493 /* If strerror is just a macro, we want to use the one from libiberty 494 since it will handle undefined values. */ 495 #undef strerror 496 extern char *strerror (int); 497 498 /* The lexer is simple, too simple for flex. Keywords are only 499 recognized at the start of lines. Everything else must be an 500 argument. A comma is treated as whitespace. */ 501 502 /* The states the lexer can be in. */ 503 504 enum lex_state 505 { 506 /* At the beginning of a line. */ 507 BEGINNING_OF_LINE, 508 /* In the middle of a line. */ 509 IN_LINE 510 }; 511 512 /* We need to keep a stack of files to handle file inclusion. */ 513 514 struct input 515 { 516 /* The file to read from. */ 517 FILE *file; 518 /* The name of the file. */ 519 char *name; 520 /* The current line number. */ 521 int lineno; 522 /* The current state. */ 523 enum lex_state state; 524 /* The next file on the stack. */ 525 struct input *next; 526 }; 527 528 /* The current input file. */ 529 530 static struct input current; 531 532 /* The character which introduces comments. */ 533 #define COMMENT_CHAR '#' 534 535 /* Start the lexer going on the main input file. */ 537 538 bfd_boolean 539 nlmlex_file (const char *name) 540 { 541 current.next = NULL; 542 return nlmlex_file_open (name); 543 } 544 545 /* Start the lexer going on a subsidiary input file. */ 546 547 static void 548 nlmlex_file_push (const char *name) 549 { 550 struct input *push; 551 552 push = (struct input *) xmalloc (sizeof (struct input)); 553 *push = current; 554 if (nlmlex_file_open (name)) 555 current.next = push; 556 else 557 { 558 current = *push; 559 free (push); 560 } 561 } 562 563 /* Start lexing from a file. */ 564 565 static bfd_boolean 566 nlmlex_file_open (const char *name) 567 { 568 current.file = fopen (name, "r"); 569 if (current.file == NULL) 570 { 571 fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno)); 572 ++parse_errors; 573 return FALSE; 574 } 575 current.name = xstrdup (name); 576 current.lineno = 1; 577 current.state = BEGINNING_OF_LINE; 578 return TRUE; 579 } 580 581 /* Table used to turn keywords into tokens. */ 583 584 struct keyword_tokens_struct 585 { 586 const char *keyword; 587 int token; 588 }; 589 590 static struct keyword_tokens_struct keyword_tokens[] = 591 { 592 { "CHECK", CHECK }, 593 { "CODESTART", CODESTART }, 594 { "COPYRIGHT", COPYRIGHT }, 595 { "CUSTOM", CUSTOM }, 596 { "DATE", DATE }, 597 { "DEBUG", DEBUG_K }, 598 { "DESCRIPTION", DESCRIPTION }, 599 { "EXIT", EXIT }, 600 { "EXPORT", EXPORT }, 601 { "FLAG_ON", FLAG_ON }, 602 { "FLAG_OFF", FLAG_OFF }, 603 { "FULLMAP", FULLMAP }, 604 { "HELP", HELP }, 605 { "IMPORT", IMPORT }, 606 { "INPUT", INPUT }, 607 { "MAP", MAP }, 608 { "MESSAGES", MESSAGES }, 609 { "MODULE", MODULE }, 610 { "MULTIPLE", MULTIPLE }, 611 { "OS_DOMAIN", OS_DOMAIN }, 612 { "OUTPUT", OUTPUT }, 613 { "PSEUDOPREEMPTION", PSEUDOPREEMPTION }, 614 { "REENTRANT", REENTRANT }, 615 { "SCREENNAME", SCREENNAME }, 616 { "SHARELIB", SHARELIB }, 617 { "STACK", STACK }, 618 { "STACKSIZE", STACK }, 619 { "START", START }, 620 { "SYNCHRONIZE", SYNCHRONIZE }, 621 { "THREADNAME", THREADNAME }, 622 { "TYPE", TYPE }, 623 { "VERBOSE", VERBOSE }, 624 { "VERSION", VERSIONK }, 625 { "XDCDATA", XDCDATA } 626 }; 627 628 #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0])) 629 630 /* The lexer accumulates strings in these variables. */ 632 static char *lex_buf; 633 static int lex_size; 634 static int lex_pos; 635 636 /* Start accumulating strings into the buffer. */ 637 #define BUF_INIT() \ 638 ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ())) 639 640 static int 641 nlmlex_buf_init (void) 642 { 643 lex_size = 10; 644 lex_buf = xmalloc (lex_size + 1); 645 lex_pos = 0; 646 return 0; 647 } 648 649 /* Finish a string in the buffer. */ 650 #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0')) 651 652 /* Accumulate a character into the buffer. */ 653 #define BUF_ADD(c) \ 654 ((void) (lex_pos < lex_size \ 655 ? lex_buf[lex_pos++] = (c) \ 656 : nlmlex_buf_add (c))) 657 658 static char 659 nlmlex_buf_add (int c) 660 { 661 if (lex_pos >= lex_size) 662 { 663 lex_size *= 2; 664 lex_buf = xrealloc (lex_buf, lex_size + 1); 665 } 666 667 return lex_buf[lex_pos++] = c; 668 } 669 670 /* The lexer proper. This is called by the bison generated parsing 672 code. */ 673 674 static int 675 yylex (void) 676 { 677 int c; 678 679 tail_recurse: 680 681 c = getc (current.file); 682 683 /* Commas are treated as whitespace characters. */ 684 while (ISSPACE (c) || c == ',') 685 { 686 current.state = IN_LINE; 687 if (c == '\n') 688 { 689 ++current.lineno; 690 current.state = BEGINNING_OF_LINE; 691 } 692 c = getc (current.file); 693 } 694 695 /* At the end of the file we either pop to the previous file or 696 finish up. */ 697 if (c == EOF) 698 { 699 fclose (current.file); 700 free (current.name); 701 if (current.next == NULL) 702 return 0; 703 else 704 { 705 struct input *next; 706 707 next = current.next; 708 current = *next; 709 free (next); 710 goto tail_recurse; 711 } 712 } 713 714 /* A comment character always means to drop everything until the 715 next newline. */ 716 if (c == COMMENT_CHAR) 717 { 718 do 719 { 720 c = getc (current.file); 721 } 722 while (c != '\n'); 723 ++current.lineno; 724 current.state = BEGINNING_OF_LINE; 725 goto tail_recurse; 726 } 727 728 /* An '@' introduces an include file. */ 729 if (c == '@') 730 { 731 do 732 { 733 c = getc (current.file); 734 if (c == '\n') 735 ++current.lineno; 736 } 737 while (ISSPACE (c)); 738 BUF_INIT (); 739 while (! ISSPACE (c) && c != EOF) 740 { 741 BUF_ADD (c); 742 c = getc (current.file); 743 } 744 BUF_FINISH (); 745 746 ungetc (c, current.file); 747 748 nlmlex_file_push (lex_buf); 749 goto tail_recurse; 750 } 751 752 /* A non-space character at the start of a line must be the start of 753 a keyword. */ 754 if (current.state == BEGINNING_OF_LINE) 755 { 756 BUF_INIT (); 757 while (ISALNUM (c) || c == '_') 758 { 759 BUF_ADD (TOUPPER (c)); 760 c = getc (current.file); 761 } 762 BUF_FINISH (); 763 764 if (c != EOF && ! ISSPACE (c) && c != ',') 765 { 766 nlmheader_identify (); 767 fprintf (stderr, _("%s:%d: illegal character in keyword: %c\n"), 768 current.name, current.lineno, c); 769 } 770 else 771 { 772 unsigned int i; 773 774 for (i = 0; i < KEYWORD_COUNT; i++) 775 { 776 if (lex_buf[0] == keyword_tokens[i].keyword[0] 777 && strcmp (lex_buf, keyword_tokens[i].keyword) == 0) 778 { 779 /* Pushing back the final whitespace avoids worrying 780 about \n here. */ 781 ungetc (c, current.file); 782 current.state = IN_LINE; 783 return keyword_tokens[i].token; 784 } 785 } 786 787 nlmheader_identify (); 788 fprintf (stderr, _("%s:%d: unrecognized keyword: %s\n"), 789 current.name, current.lineno, lex_buf); 790 } 791 792 ++parse_errors; 793 /* Treat the rest of this line as a comment. */ 794 ungetc (COMMENT_CHAR, current.file); 795 goto tail_recurse; 796 } 797 798 /* Parentheses just represent themselves. */ 799 if (c == '(' || c == ')') 800 return c; 801 802 /* Handle quoted strings. */ 803 if (c == '"' || c == '\'') 804 { 805 int quote; 806 int start_lineno; 807 808 quote = c; 809 start_lineno = current.lineno; 810 811 c = getc (current.file); 812 BUF_INIT (); 813 while (c != quote && c != EOF) 814 { 815 BUF_ADD (c); 816 if (c == '\n') 817 ++current.lineno; 818 c = getc (current.file); 819 } 820 BUF_FINISH (); 821 822 if (c == EOF) 823 { 824 nlmheader_identify (); 825 fprintf (stderr, _("%s:%d: end of file in quoted string\n"), 826 current.name, start_lineno); 827 ++parse_errors; 828 } 829 830 /* FIXME: Possible memory leak. */ 831 yylval.string = xstrdup (lex_buf); 832 return QUOTED_STRING; 833 } 834 835 /* Gather a generic argument. */ 836 BUF_INIT (); 837 while (! ISSPACE (c) 838 && c != ',' 839 && c != COMMENT_CHAR 840 && c != '(' 841 && c != ')') 842 { 843 BUF_ADD (c); 844 c = getc (current.file); 845 } 846 BUF_FINISH (); 847 848 ungetc (c, current.file); 849 850 /* FIXME: Possible memory leak. */ 851 yylval.string = xstrdup (lex_buf); 852 return STRING; 853 } 854 855 /* Get a number from a string. */ 857 858 static long 859 nlmlex_get_number (const char *s) 860 { 861 long ret; 862 char *send; 863 864 ret = strtol (s, &send, 10); 865 if (*send != '\0') 866 nlmheader_warn (_("bad number"), -1); 867 return ret; 868 } 869 870 /* Prefix the nlmconv warnings with a note as to where they come from. 871 We don't use program_name on every warning, because then some 872 versions of the emacs next-error function can't recognize the line 873 number. */ 874 875 static void 876 nlmheader_identify (void) 877 { 878 static int done; 879 880 if (! done) 881 { 882 fprintf (stderr, _("%s: problems in NLM command language input:\n"), 883 program_name); 884 done = 1; 885 } 886 } 887 888 /* Issue a warning. */ 889 890 static void 891 nlmheader_warn (const char *s, int imax) 892 { 893 nlmheader_identify (); 894 fprintf (stderr, "%s:%d: %s", current.name, current.lineno, s); 895 if (imax != -1) 896 fprintf (stderr, " (max %d)", imax); 897 fprintf (stderr, "\n"); 898 } 899 900 /* Report an error. */ 901 902 static void 903 nlmheader_error (const char *s) 904 { 905 nlmheader_warn (s, -1); 906 ++parse_errors; 907 } 908 909 /* Add a string to a string list. */ 910 911 static struct string_list * 912 string_list_cons (char *s, struct string_list *l) 913 { 914 struct string_list *ret; 915 916 ret = (struct string_list *) xmalloc (sizeof (struct string_list)); 917 ret->next = l; 918 ret->string = s; 919 return ret; 920 } 921 922 /* Append a string list to another string list. */ 923 924 static struct string_list * 925 string_list_append (struct string_list *l1, struct string_list *l2) 926 { 927 register struct string_list **pp; 928 929 for (pp = &l1; *pp != NULL; pp = &(*pp)->next) 930 ; 931 *pp = l2; 932 return l1; 933 } 934 935 /* Append a string to a string list. */ 936 937 static struct string_list * 938 string_list_append1 (struct string_list *l, char *s) 939 { 940 struct string_list *n; 941 register struct string_list **pp; 942 943 n = (struct string_list *) xmalloc (sizeof (struct string_list)); 944 n->next = NULL; 945 n->string = s; 946 for (pp = &l; *pp != NULL; pp = &(*pp)->next) 947 ; 948 *pp = n; 949 return l; 950 } 951 952 /* Duplicate a string in memory. */ 953 954 static char * 955 xstrdup (const char *s) 956 { 957 unsigned long len; 958 char *ret; 959 960 len = strlen (s); 961 ret = xmalloc (len + 1); 962 strcpy (ret, s); 963 return ret; 964 } 965