1 /* lwpp.c: A lightweight text preprocessor.
2  * created 1999-Mar-12 16:42 jmk
3  * autodate: 1999-Aug-15 18:46
4  *
5  * by Jim Knoble <http://www.pobox.com/~jmknoble/>
6  * Copyright 1999 Jim Knoble
7  *
8  * Adapted for use with HuskyPnt by Sascha Silbe <Sascha.Silbe@ldknet.org>
9  *
10  * Disclaimer:
11  *
12  * The software is provided "as is", without warranty of any kind,
13  * express or implied, including but not limited to the warranties of
14  * merchantability, fitness for a particular purpose and
15  * noninfringement. In no event shall the author(s) be liable for any
16  * claim, damages or other liability, whether in an action of
17  * contract, tort or otherwise, arising from, out of or in connection
18  * with the software or the use or other dealings in the software.
19  */
20 
21 #define VERSION "1.0hp"
22 #define DATE "2000-Apr-22"
23 
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #define MAX_LINE_LEN		1024
30 
31 #define KEYWORD_NONE		0
32 #define KEYWORD_DEFINE		1
33 #define KEYWORD_UNDEF		2
34 #define KEYWORD_IFDEF		3
35 #define KEYWORD_ELSE		4
36 #define KEYWORD_ENDIF		5
37 #define KEYWORD_IFNDEF		6
38 #define KEYWORD_IFEQ		7
39 #define KEYWORD_IFNEQ		8
40 
41 #define STATUS_OK		1
42 #define STATUS_UNKNOWN_KEYWORD	0
43 #define STATUS_DEFINE_ERROR	-1
44 #define STATUS_UNDEF_ERROR	-2
45 #define STATUS_MISSING_TOKEN	-3
46 #define STATUS_MISSING_VALUE	-4
47 #define STATUS_ELSE_WITHOUT_IF	-5
48 #define STATUS_ENDIF_WITHOUT_IF	-6
49 #define STATUS_MISSING_ENDIF	-7
50 #define STATUS_STACK_UNDERFLOW	-10
51 
52 typedef struct KeywordStruct
53 {
54    char *token;
55    int id;
56    char *text;
57    char *help_text;
58 } Keyword;
59 
60 static Keyword keyword_table[] =
61 {
62    { "define",	KEYWORD_DEFINE, "=",
63 "    define <token> [<value>]  Define <token> to have value <value>.\n"
64 "                              If <value> is omitted, defaults to `1'.\n"
65 "\n"
66    },
67    { "undef",	KEYWORD_UNDEF, NULL,
68 "    undef <token>             Undefine <token>.\n"
69 "\n"
70    },
71    { "ifdef",	KEYWORD_IFDEF, "defined",
72 "    ifdef <token>             If <token> is defined, print the following\n"
73 "                              lines on the output, until the next `else'\n"
74 "                              or `endif' directive.\n"
75 "\n"
76    },
77    { "else",	KEYWORD_ELSE, NULL,
78 "    else                      If the prior `if' directive evaluated to\n"
79 "                              false, print the following lines on the\n"
80 "                              output.\n"
81 "\n"
82    },
83    { "endif",	KEYWORD_ENDIF, NULL,
84 "    endif                     Conclude the preceding `if ... [else ...]'.\n"
85 "\n"
86    },
87    { "ifndef",	KEYWORD_IFNDEF, "!defined",
88 "    ifndef <token>            If <token> is *not* defined, print the\n"
89 "                              following lines on the output, until the\n"
90 "                              next `else' or `endif' directive.\n"
91 "\n"
92    },
93    { "ifeq",	KEYWORD_IFEQ, "==",
94 "    ifeq <token> <value>      If <token> is lexically equal to <value>,\n"
95 "                              print the following lines on the output,\n"
96 "                              until the next `else' or `endif' directive.\n"
97 "\n"
98    },
99    { "ifneq",	KEYWORD_IFNEQ, "!=",
100 "    ifneq <token> <value>     If <token> is *not* lexically equal to\n"
101 "                              <value>, print the following lines on the\n"
102 "                              output, until the next `else' or `endif'\n"
103 "                              directive.\n"
104 "\n"
105    },
106    { NULL,	KEYWORD_NONE, NULL, NULL }
107 };
108 
109 typedef struct FileStateStruct
110 {
111    int in_if;
112    int in_else;
113    int condition;
114    int parent_condition;
115    char *text;
116 } FileState;
117 
118 #define STACK_SIZE_INCREMENT	64
119 typedef struct StackStateStruct
120 {
121    FileState *bottom;
122    int size;
123    int count;
124 } StackState;
125 
126 #define DEF_PREFIX	"@"
127 #define DEF_VALUE	"1"
128 static char *prefix = NULL;
129 static int prefix_len = 0;
130 
131 char *prog_name = NULL;
132 int verbose = 0;
133 
134 char version_info[] = ""
135 "lwpp version " VERSION " (" DATE ")\n"
136 "by Jim Knoble <http://www.pobox.com/~jmknoble/>\n"
137 "Provided as is with no warranty of any kind, etc., etc.\n"
138 ;
139 
140 char usage_info[] =
141 "\n"
142 "Usage: %s [-p <text>] [-D<token>[=<val>]] [-U<token>] [-v] [<filename>]\n"
143 "\n"
144 "Preprocess <filename>, sending the result to the standard output.\n"
145 "If <filename> is not specified, read from the standard input.\n"
146 "\n"
147 "Options:\n"
148 "    -p<text>                  Preprocessor directives are prefixed with\n"
149 "    --prefix <text>           <text>.  Defaults to `" DEF_PREFIX "'.\n"
150 "\n"
151 "    -D<token>[=<val>]         Define <token> to have value <val>.  If\n"
152 "    --define <token>[=<val>]  <val> is omitted, defaults to `" DEF_VALUE "'.\n"
153 "\n"
154 "    -U<token>                 Undefine <token>.\n"
155 "    --undef <token>\n"
156 "\n"
157 "    -v                        Be verbose.\n"
158 "    --verbose\n"
159 "\n"
160 "    -V                        Show version information.\n"
161 "    --version\n"
162 "\n"
163 "Preprocessing Directives:\n"
164 ;
165 
166 /**********************************************************************/
out_of_memory(int line_num)167 void out_of_memory(int line_num)
168 {
169    fprintf(stderr, "%s:line %d: Out of memory\n", prog_name, line_num);
170    exit(1);
171 }
172 
init_stack(StackState * stack)173 void init_stack(StackState *stack)
174 {
175    stack->bottom = NULL;
176    stack->size = 0;
177    stack->count = 0;
178 }
179 
increase_stack_size(StackState * stack)180 void increase_stack_size(StackState *stack)
181 {
182    stack->size += STACK_SIZE_INCREMENT;
183    stack->bottom = realloc(stack->bottom, stack->size * sizeof(FileState));
184    if (NULL == stack->bottom)
185     {
186        out_of_memory(__LINE__);
187     }
188 }
189 
init_file_state(FileState * state)190 void init_file_state(FileState *state)
191 {
192    state->in_if = 0;
193    state->in_else = 0;
194    state->condition = 1;
195    state->parent_condition = 1;
196    state->text = NULL;
197 }
198 
copy_file_state(FileState * dst,FileState * src)199 void copy_file_state(FileState *dst, FileState *src)
200 {
201    dst->in_if = src->in_if;
202    dst->in_else = src->in_else;
203    dst->condition = src->condition;
204    dst->parent_condition = src->parent_condition;
205    dst->text = src->text;
206 }
207 
push_file_state(StackState * stack,FileState * state)208 void push_file_state(StackState *stack, FileState *state)
209 {
210    FileState *top;
211 
212    if (stack->count == stack->size)
213     {
214        increase_stack_size(stack);
215     }
216    top = (stack->bottom + stack->count);
217    (stack->count)++;
218    copy_file_state(top, state);
219 }
220 
pop_file_state(StackState * stack,FileState * state)221 int pop_file_state(StackState *stack, FileState *state)
222 {
223    int status = STATUS_STACK_UNDERFLOW;
224    FileState *top;
225 
226    if (0 < stack->count)
227     {
228        status = STATUS_OK;
229        (stack->count)--;
230        top = (stack->bottom + stack->count);
231        copy_file_state(state, top);
232     }
233    return(status);
234 }
235 
find_keyword(char * token)236 Keyword *find_keyword(char *token)
237 {
238    Keyword *kw = keyword_table;
239 
240    while (NULL != kw->token)
241     {
242        if (0 == strcmp(token, kw->token))
243 	{
244 	   break;
245 	}
246        kw++;
247     }
248    return(kw);
249 }
250 
lookup_definition(char * token)251 char *lookup_definition(char *token)
252 {
253    char *value = NULL;
254 
255    if (NULL != token)
256     {
257        value = getenv(token);
258     }
259    return(value);
260 }
261 
262 #ifndef USE_PUTENV
create_definition(char * token,char * value)263 int create_definition(char *token, char *value)
264 {
265    int status = 0;
266 
267    if ((NULL != token) && (0 < strlen(token)) && (NULL != value))
268     {
269        status = (0 == setenv(token, value, 1));
270     }
271    return(status);
272 }
273 
remove_definition(char * token)274 int remove_definition(char *token)
275 {
276    unsetenv(token);
277    return(1);
278 }
279 #else /* USE_PUTENV */
create_definition(char * token,char * value)280 int create_definition(char *token, char *value)
281 {
282    int status = 0;
283    char *definition;
284    int n;
285 
286    if (NULL != token)
287     {
288        n = strlen(token);
289        if (0 < n)
290 	{
291 	   if (NULL == value)
292 	    {
293 	       status = (0 == putenv(token));
294 	    }
295 	   else
296 	    {
297 	       n += strlen(value);
298 	       definition = malloc(n + 2);
299 	       if (NULL == definition)
300 		{
301 		   out_of_memory(__LINE__);
302 		}
303 	       strcpy(definition, token);
304 	       strcat(definition, "=");
305 	       if (NULL != value)
306 		{
307 		   strcat(definition, value);
308 		}
309 	       status = (0 == putenv(definition));
310 	       free(definition);
311 	    }
312 	}
313     }
314    return(status);
315 }
316 
remove_definition(char * token)317 int remove_definition(char *token)
318 {
319    int status = create_definition(token, NULL);
320    return(status);
321 }
322 #endif /* !USE_PUTENV */
323 
is_defined(char * token)324 int is_defined(char *token)
325 {
326    int status = 0;
327    char *value;
328 
329    if (NULL != token)
330     {
331       value = getenv(token);
332       return ((value != NULL) && (strlen(value) > 0));
333     }
334    return(status);
335 }
336 
is_prefixed_line(char * line)337 int is_prefixed_line(char *line)
338 {
339    int status = 0;
340 
341    if (NULL != line)
342     {
343        status = (0 == strncmp(line, prefix, prefix_len));
344     }
345    return(status);
346 }
347 
skip_white(char * line)348 char *skip_white(char *line)
349 {
350    char *c = line;
351 
352    if (NULL != c)
353     {
354        while (isspace(*c))
355 	{
356 	   c++;
357 	}
358     }
359    return(c);
360 }
361 
skip_prefix(char * line)362 char *skip_prefix(char *line)
363 {
364    char *new_line = line;
365    int i;
366 
367    for (i = 0; i < prefix_len; i++)
368     {
369        if ('\0' == *new_line)
370 	{
371 	   break;
372 	}
373        new_line++;
374     }
375    new_line = skip_white(new_line);
376 
377    return(new_line);
378 }
379 
skip_quoted_string(char ** line,int * n)380 char *skip_quoted_string(char **line, int *n)
381 {
382    char *c = *line;
383    char quote;
384 
385    if (NULL != c)
386     {
387        quote = *c;
388        (*line)++;
389        c++;
390        while (('\0' != *c) && (quote != *c))
391 	{
392 	   (*n)++;
393 	   c++;
394 	}
395     }
396    return(c);
397 }
398 
extract_next_token(char ** line)399 char *extract_next_token(char **line)
400 {
401    int n = 0;
402    char *c = *line;
403    char *token = NULL;
404 
405    if (NULL != c)
406     {
407        if (('"' == *c) || ('\'' == *c))
408 	{
409 	   c = skip_quoted_string(line, &n);
410 	}
411        else
412 	{
413 	   while (('\0' != *c) && !isspace(*c))
414 	    {
415 	       n++;
416 	       c++;
417 	    }
418 	}
419        if (0 < n)
420 	{
421 	   token = malloc(n + 1);
422 	   if (NULL == token)
423 	    {
424 	       out_of_memory(__LINE__);
425 	    }
426 	   strncpy(token, *line, n);
427 	   token[n] = '\0';
428 	   if (('"' == *c) || ('\'' == *c))
429 	    {
430 	       c++;
431 	    }
432 	   *line = skip_white(c);
433 	}
434     }
435    return(token);
436 }
437 
print_warning(int status,char * filename,char * keyword,char * token,int line_num)438 void print_warning(int status, char *filename, char *keyword, char *token,
439 		   int line_num)
440 {
441    char *msg;
442    int need_keyword = 0;
443    int need_token = 0;
444 
445    switch (status)
446     {
447      case STATUS_OK:
448        msg = "Oops ... no error.  This shouldn't happen.";
449        break;
450      case STATUS_UNKNOWN_KEYWORD:
451        msg = "Unknown keyword";
452        need_token = 1;
453        break;
454      case STATUS_DEFINE_ERROR:
455        msg = "Error defining token";
456        need_token = 1;
457        break;
458      case STATUS_UNDEF_ERROR:
459        msg = "Error undefining token";
460        need_token = 1;
461        break;
462      case STATUS_MISSING_TOKEN:
463        msg = "Missing token for keyword";
464        need_keyword = 1;
465        break;
466      case STATUS_MISSING_VALUE:
467        msg = "Missing comparison value for expression";
468        need_keyword = 1;
469        break;
470      case STATUS_ELSE_WITHOUT_IF:
471        msg = "else without if";
472        break;
473      case STATUS_ENDIF_WITHOUT_IF:
474        msg = "endif without if";
475        break;
476      case STATUS_MISSING_ENDIF:
477        msg = "missing endif";
478        need_keyword = 1;
479        break;
480      case STATUS_STACK_UNDERFLOW:
481        msg = "File state stack underflow";
482        break;
483      default:
484        msg = "Unknown error";
485        break;
486     }
487    if (need_keyword && need_token)
488     {
489        fprintf(stderr, "%s:%d: %s: `%s %s'\n", filename, line_num, msg,
490 	       keyword, token);
491     }
492    else if (need_keyword)
493     {
494        fprintf(stderr, "%s:%d: %s: `%s'\n", filename, line_num, msg, keyword);
495     }
496    else if (need_token)
497     {
498        fprintf(stderr, "%s:%d: %s: `%s'\n", filename, line_num, msg, token);
499     }
500    else
501     {
502        fprintf(stderr, "%s:%d: %s\n", filename, line_num, msg);
503     }
504 }
505 
process_line(char * infilename,FILE * outfile,StackState * stack,FileState * state,char * buf,int line_num)506 int process_line(char *infilename, FILE *outfile,
507 		 StackState *stack, FileState *state,
508 		 char *buf, int line_num)
509 {
510    int status = STATUS_OK;
511    char *line = buf;
512    char *keyword = NULL;
513    Keyword *kw = NULL;
514    char *token = NULL;
515    char *value = NULL;
516    char *default_value = DEF_VALUE;
517    char *txt = NULL;
518 
519    if (!is_prefixed_line(line))
520     {
521        if ((state->condition) && (state->parent_condition))
522 	{
523 	   fputs(line, outfile);
524 	}
525     }
526    else
527     {
528        line = skip_prefix(line);
529        keyword = extract_next_token(&line);
530        kw = find_keyword(keyword);
531        switch (kw->id)
532 	{
533 	 case KEYWORD_DEFINE:
534 	   token = extract_next_token(&line);
535 	   value = extract_next_token(&line);
536 	   if (NULL == value)
537 	    {
538 	       status = create_definition(token, default_value);
539 	       txt = default_value;
540 	    }
541 	   else
542 	    {
543 	       status = create_definition(token, value);
544 	       txt = value;
545 	    }
546 	   if (verbose)
547 	    {
548 	       fprintf(stderr, "%s:%d: define (\"%s\" %s \"%s\")\n",
549 		       infilename, line_num, token, kw->text, txt);
550 	    }
551 	   if (!status)
552 	    {
553 	       status = STATUS_DEFINE_ERROR;
554 	    }
555 	   break;
556 	 case KEYWORD_UNDEF:
557 	   token = extract_next_token(&line);
558 	   status = remove_definition(token);
559 	   if (verbose)
560 	    {
561 	       fprintf(stderr, "%s:%d: undef  (\"%s\")\n",
562 		       infilename, line_num, token);
563 	    }
564 	   if (!status)
565 	    {
566 	       status = STATUS_UNDEF_ERROR;
567 	    }
568 	   break;
569 	 case KEYWORD_IFDEF:
570 	   /* Fall through */
571 	 case KEYWORD_IFNDEF:
572 	   token = extract_next_token(&line);
573 	   if (NULL == token)
574 	    {
575 	       status = STATUS_MISSING_TOKEN;
576 	    }
577 	   else
578 	    {
579 	       int n;
580 
581 	       push_file_state(stack, state);
582 	       state->in_if = 1;
583 	       state->in_else = 0;
584 	       state->parent_condition = state->condition;
585 	       if (state->parent_condition)
586 		{
587 		   if (KEYWORD_IFDEF == kw->id)
588 		    {
589 		       state->condition = is_defined(token);
590 		    }
591 		   else
592 		    {
593 		       state->condition = !is_defined(token);
594 		    }
595 		}
596 	       n = strlen(kw->text) + 1 + strlen(token) + 2 + 1;
597 	       state->text = malloc(n);
598 	       if (NULL == state->text)
599 		{
600 		   out_of_memory(__LINE__);
601 		}
602 	       sprintf(state->text, "%s \"%s\"", kw->text, token);
603 	       if (verbose)
604 		{
605 		   fprintf(stderr, "%s:%d: if     (%s): %s\n",
606 			   infilename, line_num, state->text,
607 			   (state->condition ? "true" : "false"));
608 		}
609 	    }
610 	   break;
611 	 case KEYWORD_ELSE:
612 	   if (!state->in_if)
613 	    {
614 	       status = STATUS_ELSE_WITHOUT_IF;
615 	    }
616 	   else
617 	    {
618 	       state->in_if = 0;
619 	       state->in_else = 1;
620 	       state->condition = !(state->condition);
621 	       if (verbose)
622 		{
623 		   fprintf(stderr, "%s:%d: else   (%s): %s\n",
624 			   infilename, line_num, state->text,
625 			   (state->condition ? "true" : "false"));
626 		}
627 	    }
628 	   break;
629 	 case KEYWORD_ENDIF:
630 	   if (!(state->in_if) && !(state->in_else))
631 	    {
632 	       status = STATUS_ENDIF_WITHOUT_IF;
633 	    }
634 	   else
635 	    {
636 	       if (verbose)
637 		{
638 		   fprintf(stderr, "%s:%d: endif  (%s)\n",
639 			   infilename, line_num, state->text);
640 		}
641 	       if (NULL != state->text)
642 		{
643 		   free(state->text);
644 		}
645 	       status = pop_file_state(stack, state);
646 	    }
647 	   break;
648 	 case KEYWORD_IFEQ:
649 	   /* Fall through */
650 	 case KEYWORD_IFNEQ:
651 	   token = extract_next_token(&line);
652 	   if (NULL == token)
653 	    {
654 	       status = STATUS_MISSING_TOKEN;
655 	    }
656 	   else
657 	    {
658 	       value = extract_next_token(&line);
659 	       if (NULL == value)
660 		{
661 		   status = STATUS_MISSING_VALUE;
662 		}
663 	       else
664 		{
665 		   int n;
666 
667 		   push_file_state(stack, state);
668 		   state->in_if = 1;
669 		   state->in_else = 0;
670 		   state->parent_condition = state->condition;
671 		   if (state->parent_condition)
672 		    {
673 		       char *def = lookup_definition(token);
674 		       if (KEYWORD_IFEQ == kw->id)
675 			{
676 			   state->condition = ((NULL != def) &&
677 					       (0 == strcmp(def, value)));
678 			}
679 		       else
680 			{
681 			   state->condition = ((NULL != def) &&
682 					       (0 != strcmp(def, value)));
683 			}
684 		    }
685 		   n = strlen(token) + 2 + 1 + strlen(kw->text) + 1 +
686 		      strlen(value) + 2 + 1;
687 		   state->text = malloc(n);
688 		   if (NULL == state->text)
689 		    {
690 		       out_of_memory(__LINE__);
691 		    }
692 		   sprintf(state->text, "\"%s\" %s \"%s\"",
693 			   token, kw->text, value);
694 		   if (verbose)
695 		    {
696 		       fprintf(stderr, "%s:%d: if     (%s): %s\n",
697 			       infilename, line_num, state->text,
698 			       (state->condition ? "true" : "false"));
699 		    }
700 		}
701 	    }
702 	   break;
703 	 default:
704 	   status = STATUS_UNKNOWN_KEYWORD;
705 	   break;
706 	}
707        if (status < STATUS_OK)
708 	{
709 	   print_warning(status, infilename, keyword, token, line_num);
710 	}
711        if (NULL != keyword)
712 	{
713 	   free(keyword);
714 	}
715        if (NULL != token)
716 	{
717 	   free(token);
718 	}
719        if (NULL != value)
720 	{
721 	   free(value);
722 	}
723     }
724    return(status);
725 }
726 
process_input_file(char * infilename,char * outfilename)727 int process_input_file(char *infilename, char *outfilename)
728 {
729    int status = 1;
730    FILE *infile = stdin;
731    FILE *outfile = stdout;
732    int using_stdin = 1;
733    int using_stdout = 1;
734    char *munged_infilename = "stdin";
735    char *munged_outfilename = "stdout";
736    char buffer[MAX_LINE_LEN];
737    char *line;
738    int line_num = 0;
739    StackState stack;
740    FileState state;
741 
742    if (0 != strcmp(infilename, "-"))
743     {
744        using_stdin = 0;
745        munged_infilename = infilename;
746        infile = fopen(infilename, "r");
747        if (NULL == infile)
748 	{
749 	   perror(infilename);
750 	   return(0);
751 	}
752     }
753    if (0 != strcmp(outfilename, "-"))
754     {
755        using_stdout = 0;
756        munged_outfilename = outfilename;
757        outfile = fopen(outfilename, "w");
758        if (NULL == outfile)
759 	{
760 	   perror(outfilename);
761 	   if (!using_stdin)
762 	    {
763 	       fclose(infile);
764 	    }
765 	   return(0);
766 	}
767     }
768    if (verbose)
769     {
770        fprintf(stderr, "Processing %s ...\n", munged_infilename);
771     }
772 
773    init_stack(&stack);
774    init_file_state(&state);
775    while(NULL != fgets(buffer, sizeof(buffer), infile))
776     {
777        line = buffer;
778        line_num++;
779        status = process_line(munged_infilename, outfile,
780 			     &stack, &state, line, line_num);
781     }
782    if (stack.count > 0)
783     {
784        print_warning(STATUS_MISSING_ENDIF, munged_infilename, state.text,
785 		     NULL, line_num);
786     }
787    putc('\n', outfile);
788    if (!using_stdin)
789     {
790        fclose(infile);
791     }
792    if (!using_stdout)
793     {
794        fclose(outfile);
795     }
796    return(status);
797 }
798 
usage(void)799 void usage(void)
800 {
801    Keyword *kw;
802 
803    fprintf(stderr, usage_info, prog_name);
804    kw = keyword_table;
805    while (NULL != kw->token)
806     {
807        fprintf(stderr, kw->help_text);
808        kw++;
809     }
810    exit(1);
811 }
812 
show_version(void)813 void show_version(void)
814 {
815    fprintf(stderr, version_info);
816 }
817 
process_args(int argc,char ** argv)818 int process_args(int argc, char **argv)
819 {
820    int i;
821    char *t;
822    char *v;
823 
824    for (i = 1; i < argc; i++)
825     {
826        if ('-' != argv[i][0])
827 	{
828 	   break;
829 	}
830        else if ((0 == strcmp(argv[i], "-h")) ||
831 		(0 == strcmp(argv[i], "--help")))
832 	{
833 	   show_version();
834 	   usage();
835 	}
836        else if ((0 == strncmp(argv[i], "-p", 2)) ||
837 		(0 == strcmp(argv[i], "--prefix")))
838 	{
839 	   if (2 <= strlen(argv[i]))
840 	    {
841 	       t = (argv[i] + 2);
842 	    }
843 	   else if (i >= argc)
844 	    {
845 	       break;
846 	    }
847 	   else
848 	    {
849 	       t = argv[++i];
850 	    }
851 	   prefix = t;
852 	}
853        else if ((0 == strcmp(argv[i], "-v")) ||
854 		(0 == strcmp(argv[i], "--verbose")))
855 	{
856 	   verbose = 1;
857 	}
858        else if ((0 == strcmp(argv[i], "-V")) ||
859 		(0 == strcmp(argv[i], "--version")))
860 	{
861 	   show_version();
862 	   exit(1);
863 	}
864        else if ((0 == strncmp(argv[i], "-D", 2)) ||
865 		(0 == strcmp(argv[i], "--define")))
866 	{
867 	   if (2 <= strlen(argv[i]))
868 	    {
869 	       t = (argv[i] + 2);
870 	    }
871 	   else if (i >= argc)
872 	    {
873 	       break;
874 	    }
875 	   else
876 	    {
877 	       t = argv[++i];
878 	    }
879 	   v = strchr(t, '=');
880 	   if (NULL == v)
881 	    {
882 	       create_definition(t, DEF_VALUE);
883 	    }
884 	   else
885 	    {
886 	       *(v++) = '\0';
887 	       create_definition(t, v);
888 	    }
889 	   if (verbose)
890 	    {
891 	       fprintf(stderr, "Defined token `%s' with value `%s'\n",
892 		       t, lookup_definition(t));
893 	    }
894 	}
895        else if ((0 == strncmp(argv[i], "-U", 2)) ||
896 		(0 == strcmp(argv[i], "--undef")))
897 	{
898 	   if (2 <= strlen(argv[i]))
899 	    {
900 	       t = (argv[i] + 2);
901 	    }
902 	   else if (i >= argc)
903 	    {
904 	       break;
905 	    }
906 	   else
907 	    {
908 	       t = argv[++i];
909 	    }
910 	   remove_definition(t);
911 	   if (verbose)
912 	    {
913 	       fprintf(stderr, "Undefined token `%s'\n", t);
914 	    }
915 	}
916        else if (0 == strcmp(argv[i], "-"))
917 	{
918 	   /* '-' is a filename meaning stdin;
919 	    * leave it in the list of files to process.
920 	    */
921 	   break;
922 	}
923        else if (0 == strcmp(argv[i], "--"))
924 	{
925 	   /* End of options. */
926 	   i++;
927 	   break;
928 	}
929        else
930 	{
931 	   fprintf(stderr, "%s: Unknown option `%s'\n", prog_name, argv[i]);
932 	   usage();
933 	}
934     }
935    return(i);
936 }
937 
main(int argc,char ** argv)938 int main(int argc, char **argv)
939 {
940    int i;
941    int status;
942    char *outfilename = "-";
943 
944    prog_name = argv[0];
945 
946    i = process_args(argc, argv);
947 
948    if (NULL == prefix)
949     {
950        prefix = DEF_PREFIX;
951     }
952    prefix_len = strlen(prefix);
953 
954    if (i >= argc)
955     {
956        /* No files specified on command line; use stdin. */
957        status = process_input_file("-", outfilename);
958     }
959    else
960     {
961        status = process_input_file(argv[i], outfilename);
962     }
963 
964    return(status ? 0 : 1);
965 }
966 
967