1 %{/* nlmheader.y - parse NLM header specification keywords.
2      Copyright (C) 1993-2014 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@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.  */
536 
537 bfd_boolean
nlmlex_file(const char * name)538 nlmlex_file (const char *name)
539 {
540   current.next = NULL;
541   return nlmlex_file_open (name);
542 }
543 
544 /* Start the lexer going on a subsidiary input file.  */
545 
546 static void
nlmlex_file_push(const char * name)547 nlmlex_file_push (const char *name)
548 {
549   struct input *push;
550 
551   push = (struct input *) xmalloc (sizeof (struct input));
552   *push = current;
553   if (nlmlex_file_open (name))
554     current.next = push;
555   else
556     {
557       current = *push;
558       free (push);
559     }
560 }
561 
562 /* Start lexing from a file.  */
563 
564 static bfd_boolean
nlmlex_file_open(const char * name)565 nlmlex_file_open (const char *name)
566 {
567   current.file = fopen (name, "r");
568   if (current.file == NULL)
569     {
570       fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno));
571       ++parse_errors;
572       return FALSE;
573     }
574   current.name = xstrdup (name);
575   current.lineno = 1;
576   current.state = BEGINNING_OF_LINE;
577   return TRUE;
578 }
579 
580 /* Table used to turn keywords into tokens.  */
581 
582 struct keyword_tokens_struct
583 {
584   const char *keyword;
585   int token;
586 };
587 
588 static struct keyword_tokens_struct keyword_tokens[] =
589 {
590   { "CHECK", CHECK },
591   { "CODESTART", CODESTART },
592   { "COPYRIGHT", COPYRIGHT },
593   { "CUSTOM", CUSTOM },
594   { "DATE", DATE },
595   { "DEBUG", DEBUG_K },
596   { "DESCRIPTION", DESCRIPTION },
597   { "EXIT", EXIT },
598   { "EXPORT", EXPORT },
599   { "FLAG_ON", FLAG_ON },
600   { "FLAG_OFF", FLAG_OFF },
601   { "FULLMAP", FULLMAP },
602   { "HELP", HELP },
603   { "IMPORT", IMPORT },
604   { "INPUT", INPUT },
605   { "MAP", MAP },
606   { "MESSAGES", MESSAGES },
607   { "MODULE", MODULE },
608   { "MULTIPLE", MULTIPLE },
609   { "OS_DOMAIN", OS_DOMAIN },
610   { "OUTPUT", OUTPUT },
611   { "PSEUDOPREEMPTION", PSEUDOPREEMPTION },
612   { "REENTRANT", REENTRANT },
613   { "SCREENNAME", SCREENNAME },
614   { "SHARELIB", SHARELIB },
615   { "STACK", STACK },
616   { "STACKSIZE", STACK },
617   { "START", START },
618   { "SYNCHRONIZE", SYNCHRONIZE },
619   { "THREADNAME", THREADNAME },
620   { "TYPE", TYPE },
621   { "VERBOSE", VERBOSE },
622   { "VERSION", VERSIONK },
623   { "XDCDATA", XDCDATA }
624 };
625 
626 #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0]))
627 
628 /* The lexer accumulates strings in these variables.  */
629 static char *lex_buf;
630 static int lex_size;
631 static int lex_pos;
632 
633 /* Start accumulating strings into the buffer.  */
634 #define BUF_INIT() \
635   ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ()))
636 
637 static int
nlmlex_buf_init(void)638 nlmlex_buf_init (void)
639 {
640   lex_size = 10;
641   lex_buf = xmalloc (lex_size + 1);
642   lex_pos = 0;
643   return 0;
644 }
645 
646 /* Finish a string in the buffer.  */
647 #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0'))
648 
649 /* Accumulate a character into the buffer.  */
650 #define BUF_ADD(c) \
651   ((void) (lex_pos < lex_size \
652 	   ? lex_buf[lex_pos++] = (c) \
653 	   : nlmlex_buf_add (c)))
654 
655 static char
nlmlex_buf_add(int c)656 nlmlex_buf_add (int c)
657 {
658   if (lex_pos >= lex_size)
659     {
660       lex_size *= 2;
661       lex_buf = xrealloc (lex_buf, lex_size + 1);
662     }
663 
664   return lex_buf[lex_pos++] = c;
665 }
666 
667 /* The lexer proper.  This is called by the bison generated parsing
668    code.  */
669 
670 static int
yylex(void)671 yylex (void)
672 {
673   int c;
674 
675 tail_recurse:
676 
677   c = getc (current.file);
678 
679   /* Commas are treated as whitespace characters.  */
680   while (ISSPACE (c) || c == ',')
681     {
682       current.state = IN_LINE;
683       if (c == '\n')
684 	{
685 	  ++current.lineno;
686 	  current.state = BEGINNING_OF_LINE;
687 	}
688       c = getc (current.file);
689     }
690 
691   /* At the end of the file we either pop to the previous file or
692      finish up.  */
693   if (c == EOF)
694     {
695       fclose (current.file);
696       free (current.name);
697       if (current.next == NULL)
698 	return 0;
699       else
700 	{
701 	  struct input *next;
702 
703 	  next = current.next;
704 	  current = *next;
705 	  free (next);
706 	  goto tail_recurse;
707 	}
708     }
709 
710   /* A comment character always means to drop everything until the
711      next newline.  */
712   if (c == COMMENT_CHAR)
713     {
714       do
715 	{
716 	  c = getc (current.file);
717 	}
718       while (c != '\n');
719       ++current.lineno;
720       current.state = BEGINNING_OF_LINE;
721       goto tail_recurse;
722     }
723 
724   /* An '@' introduces an include file.  */
725   if (c == '@')
726     {
727       do
728 	{
729 	  c = getc (current.file);
730 	  if (c == '\n')
731 	    ++current.lineno;
732 	}
733       while (ISSPACE (c));
734       BUF_INIT ();
735       while (! ISSPACE (c) && c != EOF)
736 	{
737 	  BUF_ADD (c);
738 	  c = getc (current.file);
739 	}
740       BUF_FINISH ();
741 
742       ungetc (c, current.file);
743 
744       nlmlex_file_push (lex_buf);
745       goto tail_recurse;
746     }
747 
748   /* A non-space character at the start of a line must be the start of
749      a keyword.  */
750   if (current.state == BEGINNING_OF_LINE)
751     {
752       BUF_INIT ();
753       while (ISALNUM (c) || c == '_')
754 	{
755 	  BUF_ADD (TOUPPER (c));
756 	  c = getc (current.file);
757 	}
758       BUF_FINISH ();
759 
760       if (c != EOF && ! ISSPACE (c) && c != ',')
761 	{
762 	  nlmheader_identify ();
763 	  fprintf (stderr, _("%s:%d: illegal character in keyword: %c\n"),
764 		   current.name, current.lineno, c);
765 	}
766       else
767 	{
768 	  unsigned int i;
769 
770 	  for (i = 0; i < KEYWORD_COUNT; i++)
771 	    {
772 	      if (lex_buf[0] == keyword_tokens[i].keyword[0]
773 		  && strcmp (lex_buf, keyword_tokens[i].keyword) == 0)
774 		{
775 		  /* Pushing back the final whitespace avoids worrying
776 		     about \n here.  */
777 		  ungetc (c, current.file);
778 		  current.state = IN_LINE;
779 		  return keyword_tokens[i].token;
780 		}
781 	    }
782 
783 	  nlmheader_identify ();
784 	  fprintf (stderr, _("%s:%d: unrecognized keyword: %s\n"),
785 		   current.name, current.lineno, lex_buf);
786 	}
787 
788       ++parse_errors;
789       /* Treat the rest of this line as a comment.  */
790       ungetc (COMMENT_CHAR, current.file);
791       goto tail_recurse;
792     }
793 
794   /* Parentheses just represent themselves.  */
795   if (c == '(' || c == ')')
796     return c;
797 
798   /* Handle quoted strings.  */
799   if (c == '"' || c == '\'')
800     {
801       int quote;
802       int start_lineno;
803 
804       quote = c;
805       start_lineno = current.lineno;
806 
807       c = getc (current.file);
808       BUF_INIT ();
809       while (c != quote && c != EOF)
810 	{
811 	  BUF_ADD (c);
812 	  if (c == '\n')
813 	    ++current.lineno;
814 	  c = getc (current.file);
815 	}
816       BUF_FINISH ();
817 
818       if (c == EOF)
819 	{
820 	  nlmheader_identify ();
821 	  fprintf (stderr, _("%s:%d: end of file in quoted string\n"),
822 		   current.name, start_lineno);
823 	  ++parse_errors;
824 	}
825 
826       /* FIXME: Possible memory leak.  */
827       yylval.string = xstrdup (lex_buf);
828       return QUOTED_STRING;
829     }
830 
831   /* Gather a generic argument.  */
832   BUF_INIT ();
833   while (! ISSPACE (c)
834 	 && c != ','
835 	 && c != COMMENT_CHAR
836 	 && c != '('
837 	 && c != ')')
838     {
839       BUF_ADD (c);
840       c = getc (current.file);
841     }
842   BUF_FINISH ();
843 
844   ungetc (c, current.file);
845 
846   /* FIXME: Possible memory leak.  */
847   yylval.string = xstrdup (lex_buf);
848   return STRING;
849 }
850 
851 /* Get a number from a string.  */
852 
853 static long
nlmlex_get_number(const char * s)854 nlmlex_get_number (const char *s)
855 {
856   long ret;
857   char *send;
858 
859   ret = strtol (s, &send, 10);
860   if (*send != '\0')
861     nlmheader_warn (_("bad number"), -1);
862   return ret;
863 }
864 
865 /* Prefix the nlmconv warnings with a note as to where they come from.
866    We don't use program_name on every warning, because then some
867    versions of the emacs next-error function can't recognize the line
868    number.  */
869 
870 static void
nlmheader_identify(void)871 nlmheader_identify (void)
872 {
873   static int done;
874 
875   if (! done)
876     {
877       fprintf (stderr, _("%s: problems in NLM command language input:\n"),
878 	       program_name);
879       done = 1;
880     }
881 }
882 
883 /* Issue a warning.  */
884 
885 static void
nlmheader_warn(const char * s,int imax)886 nlmheader_warn (const char *s, int imax)
887 {
888   nlmheader_identify ();
889   fprintf (stderr, "%s:%d: %s", current.name, current.lineno, s);
890   if (imax != -1)
891     fprintf (stderr, " (max %d)", imax);
892   fprintf (stderr, "\n");
893 }
894 
895 /* Report an error.  */
896 
897 static void
nlmheader_error(const char * s)898 nlmheader_error (const char *s)
899 {
900   nlmheader_warn (s, -1);
901   ++parse_errors;
902 }
903 
904 /* Add a string to a string list.  */
905 
906 static struct string_list *
string_list_cons(char * s,struct string_list * l)907 string_list_cons (char *s, struct string_list *l)
908 {
909   struct string_list *ret;
910 
911   ret = (struct string_list *) xmalloc (sizeof (struct string_list));
912   ret->next = l;
913   ret->string = s;
914   return ret;
915 }
916 
917 /* Append a string list to another string list.  */
918 
919 static struct string_list *
string_list_append(struct string_list * l1,struct string_list * l2)920 string_list_append (struct string_list *l1, struct string_list *l2)
921 {
922   register struct string_list **pp;
923 
924   for (pp = &l1; *pp != NULL; pp = &(*pp)->next)
925     ;
926   *pp = l2;
927   return l1;
928 }
929 
930 /* Append a string to a string list.  */
931 
932 static struct string_list *
string_list_append1(struct string_list * l,char * s)933 string_list_append1 (struct string_list *l, char *s)
934 {
935   struct string_list *n;
936   register struct string_list **pp;
937 
938   n = (struct string_list *) xmalloc (sizeof (struct string_list));
939   n->next = NULL;
940   n->string = s;
941   for (pp = &l; *pp != NULL; pp = &(*pp)->next)
942     ;
943   *pp = n;
944   return l;
945 }
946 
947 /* Duplicate a string in memory.  */
948 
949 static char *
xstrdup(const char * s)950 xstrdup (const char *s)
951 {
952   unsigned long len;
953   char *ret;
954 
955   len = strlen (s);
956   ret = xmalloc (len + 1);
957   strcpy (ret, s);
958   return ret;
959 }
960