1%{/* nlmheader.y - parse NLM header specification keywords.
2     Copyright 1993, 1994, 1995, 1997, 1998, 2001, 2002, 2003
3     Free Software Foundation, Inc.
4
5This file is part of GNU Binutils.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software
19Foundation, 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
42Nlm_Internal_Fixed_Header *fixed_hdr;
43Nlm_Internal_Variable_Header *var_hdr;
44Nlm_Internal_Version_Header *version_hdr;
45Nlm_Internal_Copyright_Header *copyright_hdr;
46Nlm_Internal_Extended_Header *extended_hdr;
47
48/* Procedure named by CHECK.  */
49char *check_procedure;
50/* File named by CUSTOM.  */
51char *custom_file;
52/* Whether to generate debugging information (DEBUG).  */
53bfd_boolean debug_info;
54/* Procedure named by EXIT.  */
55char *exit_procedure;
56/* Exported symbols (EXPORT).  */
57struct string_list *export_symbols;
58/* List of files from INPUT.  */
59struct string_list *input_files;
60/* Map file name (MAP, FULLMAP).  */
61char *map_file;
62/* Whether a full map has been requested (FULLMAP).  */
63bfd_boolean full_map;
64/* File named by HELP.  */
65char *help_file;
66/* Imported symbols (IMPORT).  */
67struct string_list *import_symbols;
68/* File named by MESSAGES.  */
69char *message_file;
70/* Autoload module list (MODULE).  */
71struct string_list *modules;
72/* File named by OUTPUT.  */
73char *output_file;
74/* File named by SHARELIB.  */
75char *sharelib_file;
76/* Start procedure name (START).  */
77char *start_procedure;
78/* VERBOSE.  */
79bfd_boolean verbose;
80/* RPC description file (XDCDATA).  */
81char *rpc_file;
82
83/* The number of serious errors that have occurred.  */
84int parse_errors;
85
86/* The current symbol prefix when reading a list of import or export
87   symbols.  */
88static char *symbol_prefix;
89
90/* Parser error message handler.  */
91#define yyerror(msg) nlmheader_error (msg);
92
93/* Local functions.  */
94static int yylex (void);
95static void nlmlex_file_push (const char *);
96static bfd_boolean nlmlex_file_open (const char *);
97static int nlmlex_buf_init (void);
98static char nlmlex_buf_add (int);
99static long nlmlex_get_number (const char *);
100static void nlmheader_identify (void);
101static void nlmheader_warn (const char *, int);
102static void nlmheader_error (const char *);
103static struct string_list * string_list_cons (char *, struct string_list *);
104static struct string_list * string_list_append (struct string_list *,
105						struct string_list *);
106static struct string_list * string_list_append1 (struct string_list *,
107						 char *);
108static 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
143file:
144	  commands
145	;
146
147/* A possibly empty list of commands.  */
148
149commands:
150	  /* May be empty.  */
151	| command commands
152	;
153
154/* A single command.  There is where most of the work takes place.  */
155
156command:
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
418symbol_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
433symbol_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
454symbol_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
465symbol:
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
481string_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
497extern 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
505enum 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
515struct 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
531static 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
538bfd_boolean
539nlmlex_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
547static void
548nlmlex_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
565static bfd_boolean
566nlmlex_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
583struct keyword_tokens_struct
584{
585  const char *keyword;
586  int token;
587};
588
589static 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.  */
630static char *lex_buf;
631static int lex_size;
632static 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
638static int
639nlmlex_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
656static char
657nlmlex_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
671static int
672yylex (void)
673{
674  int c;
675
676tail_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
854static long
855nlmlex_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
871static void
872nlmheader_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
886static void
887nlmheader_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
898static void
899nlmheader_error (const char *s)
900{
901  nlmheader_warn (s, -1);
902  ++parse_errors;
903}
904
905/* Add a string to a string list.  */
906
907static struct string_list *
908string_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
920static struct string_list *
921string_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
933static struct string_list *
934string_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
950static char *
951xstrdup (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