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