2b78b893e10c07260bd2c39852c2b40cbbda2aaf
[deliverable/binutils-gdb.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 }
This page took 0.04946 seconds and 4 git commands to generate.