source: vendor/binutils/2.14/binutils/nlmheader.y

Last change on this file was 609, checked in by bird, 22 years ago

binutils v2.14 - offical sources.

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