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