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
nlmlex_file(const char * name)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
nlmlex_file_push(const char * name)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
nlmlex_file_open(const char * name)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
nlmlex_buf_init(void)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
nlmlex_buf_add(int c)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
yylex(void)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
nlmlex_get_number(const char * s)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
nlmheader_identify(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
nlmheader_warn(const char * s,int imax)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
nlmheader_error(const char * s)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 *
string_list_cons(char * s,struct string_list * l)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 *
string_list_append(struct string_list * l1,struct string_list * l2)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 *
string_list_append1(struct string_list * l,char * s)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 *
xstrdup(const char * s)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