makestrs.c revision 82275908
1/*
2
3Copyright (c) 1991, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/* Constructs string definitions */
28
29#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
32#include <unistd.h>
33
34typedef struct _TableEnt {
35    struct _TableEnt* next;
36    char* left;
37    char* right;
38    int offset;
39} TableEnt;
40
41typedef struct _Table {
42    struct _Table* next;
43    TableEnt* tableent;
44    TableEnt* tableentcurrent;
45    TableEnt** tableenttail;
46    char* name;
47    int offset;
48} Table;
49
50typedef struct _File {
51    struct _File* next;
52    FILE* tmpl;
53    char* name;
54    Table* table;
55    Table* tablecurrent;
56    Table** tabletail;
57} File;
58
59static File* file = NULL;
60static File* filecurrent = NULL;
61static File** filetail = &file;
62static char* conststr;
63static char* prefixstr = NULL;
64static char* featurestr = NULL;
65static char* ctmplstr = NULL;
66static char* fileprotstr;
67static char* externrefstr;
68static char* externdefstr;
69
70#ifndef FALSE
71# define FALSE 0
72# define TRUE  !(FALSE)
73#endif
74
75static int   solaris_abi_names = FALSE;
76
77#define X_DEFAULT_ABI	0
78#define X_ARRAYPER_ABI	1
79#define X_INTEL_ABI	2
80#define X_INTEL_ABI_BC	3
81#define X_SPARC_ABI	4
82#define X_FUNCTION_ABI	5
83
84#define X_MAGIC_STRING "<<<STRING_TABLE_GOES_HERE>>>"
85
86/* Wrapper for fopen()
87 * Prepend filename with an includedir which can be specified on the
88 * commandline. Needed to separate source and build directories.
89 */
90static char* includedir = NULL;
91static FILE *ifopen(const char *file, const char *mode)
92{
93#ifndef HAVE_ASPRINTF
94    size_t len;
95#endif
96    char *buffer;
97    FILE *ret;
98
99    if (includedir == NULL)
100        return fopen(file, mode);
101
102#ifdef HAVE_ASPRINTF
103    if (asprintf(&buffer, "%s/%s", includedir, file) == -1)
104        return NULL;
105#else
106    len = strlen(file) + strlen(includedir) + 1;
107    buffer = (char*)malloc(len + 1);
108    if (buffer == NULL)
109        return NULL;
110
111    snprintf(buffer, len + 1, "%s/%s", includedir, file);
112#endif
113
114    ret = fopen(buffer, mode);
115
116    free(buffer);
117    return ret;
118}
119
120static void WriteHeaderProlog (FILE *f, File *phile)
121{
122    Table* t;
123    TableEnt* te;
124
125    (void) fprintf (f, "#ifdef %s\n", featurestr);
126    for (t = phile->table; t; t = t->next)
127	for (te = t->tableent; te; te = te->next) {
128	    if (strcmp (te->left, "RAtom") == 0) {
129		(void) fprintf (f,
130			"#ifndef %s%s\n#define %s%s \"%s\"\n#endif\n",
131			prefixstr, te->left, prefixstr, te->left, te->right);
132	    } else {
133		(void) fprintf (f,
134			"#define %s%s \"%s\"\n",
135			prefixstr, te->left, te->right);
136	    }
137	}
138    (void) fprintf (f, "%s", "#else\n");
139}
140
141static void IntelABIWriteHeader (FILE *f, File *phile)
142{
143    Table* t;
144    TableEnt* te;
145
146    WriteHeaderProlog (f, phile);
147
148    for (t = phile->table; t; t = t->next) {
149      (void) fprintf (f, "%s %sConst char %s[];\n",
150		      externrefstr, conststr ? conststr : fileprotstr, t->name);
151	for (te = t->tableent; te; te = te->next)
152	    (void) fprintf (f,
153		"#ifndef %s%s\n#define %s%s ((char*)&%s[%d])\n#endif\n",
154		prefixstr, te->left, prefixstr, te->left, t->name, te->offset);
155    }
156
157    (void) fprintf (f, "#endif /* %s */\n", featurestr);
158}
159
160static void SPARCABIWriteHeader (FILE *f, File *phile)
161{
162    Table* t;
163    TableEnt* te;
164
165    for (t = phile->table; t; t = t->next)
166	for (te = t->tableent; te; te = te->next)
167	    (void) fprintf (f, "#define %s%s \"%s\"\n",
168			    prefixstr, te->left, te->right);
169}
170
171static void FunctionWriteHeader (FILE *f, File *phile)
172{
173    Table* t;
174    TableEnt* te;
175
176    WriteHeaderProlog (f, phile);
177
178    (void) fprintf (f, "%s %sConst char* %s();\n",
179		    externrefstr, conststr ? conststr : fileprotstr,
180		    phile->table->name);
181
182    for (t = phile->table; t; t = t->next)
183	for (te = t->tableent; te; te = te->next)
184	    (void) fprintf (f,
185		"#ifndef %s%s\n#define %s%s (%s(%d))\n#endif\n",
186		prefixstr, te->left, prefixstr, te->left, phile->table->name,
187		te->offset);
188
189    (void) fprintf (f, "#endif /* %s */\n", featurestr);
190}
191
192static void ArrayperWriteHeader (FILE *f, File *phile)
193{
194    Table* t;
195    TableEnt* te;
196
197    WriteHeaderProlog (f, phile);
198
199    for (t = phile->table; t; t = t->next)
200        for (te = t->tableent; te; te = te->next)
201	    (void) fprintf (f,
202			    "#ifndef %s%s\n%s %sConst char %s%s[];\n#endif\n",
203			    prefixstr, te->left,
204			    externrefstr, conststr ? conststr : fileprotstr,
205			    prefixstr, te->left);
206
207    (void) fprintf (f, "#endif /* %s */\n", featurestr);
208}
209
210static void DefaultWriteHeader (FILE *f, File *phile)
211{
212    Table* t;
213    TableEnt* te;
214
215    WriteHeaderProlog (f, phile);
216
217    (void) fprintf (f, "%s %sConst char %s[];\n",
218		    externrefstr, conststr ? conststr : fileprotstr,
219		    phile->table->name);
220
221    for (t = phile->table; t; t = t->next)
222	for (te = t->tableent; te; te = te->next)
223	    (void) fprintf (f,
224		"#ifndef %s%s\n#define %s%s ((char*)&%s[%d])\n#endif\n",
225		prefixstr, te->left, prefixstr, te->left, phile->table->name,
226		te->offset);
227
228    (void) fprintf (f, "#endif /* %s */\n", featurestr);
229}
230
231static void CopyTmplProlog (FILE *tmpl, FILE *f)
232{
233    char buf[1024];
234    static const char* magic_string = X_MAGIC_STRING;
235    int magic_string_len = strlen (magic_string);
236
237    while (fgets (buf, sizeof buf, tmpl)) {
238	if (strncmp (buf, magic_string, magic_string_len) == 0) {
239	    return;
240	}
241	(void) fputs (buf, f);
242    }
243}
244
245static void CopyTmplEpilog (FILE *tmpl, FILE *f)
246{
247    char buf[1024];
248
249    while (fgets (buf, sizeof buf, tmpl))
250	(void) fputs (buf, f);
251}
252
253static const char* abistring[] = {
254    "Default", "Array per string", "Intel", "Intel BC", "SPARC", "Function" };
255
256static void WriteHeader (char *tagline, File *phile, int abi)
257{
258    FILE* f;
259    char* tmp;
260    static void (*headerproc[])(FILE *f, File *phile) = {
261	DefaultWriteHeader, ArrayperWriteHeader,
262	IntelABIWriteHeader, IntelABIWriteHeader,
263	SPARCABIWriteHeader, FunctionWriteHeader };
264
265    if ((f = fopen (phile->name, "w+")) == NULL) exit (1);
266
267    if (phile->tmpl) CopyTmplProlog (phile->tmpl, f);
268
269    (void) fprintf (f,
270	"%s\n%s\n/* %s ABI version -- Do not edit */\n",
271	"/* $Xorg: makestrs.c,v 1.6 2001/02/09 02:03:17 xorgcvs Exp $ */",
272	"/* This file is automatically generated. */",
273	abistring[abi]);
274
275    if (tagline) (void) fprintf (f, "/* %s */\n\n", tagline);
276
277    /* do the right thing for Motif, i.e. avoid _XmXmStrDefs_h_ */
278    if (strcmp (prefixstr, "Xm") == 0) {
279#ifdef HAVE_ASPRINTF
280	if (asprintf (&fileprotstr, "_%s_", phile->name) == -1)
281	    exit (1);
282#else
283	if ((fileprotstr = malloc (strlen (phile->name) + 3)) == NULL)
284	   exit (1);
285	(void) sprintf (fileprotstr, "_%s_", phile->name);
286#endif
287    } else {
288#ifdef HAVE_ASPRINTF
289	if (asprintf (&fileprotstr, "_%s%s_", prefixstr, phile->name) == -1)
290	    exit (1);
291#else
292	if ((fileprotstr = malloc (strlen (phile->name) + strlen (prefixstr) +  3)) == NULL)
293	   exit (1);
294	(void) sprintf (fileprotstr, "_%s%s_", prefixstr, phile->name);
295#endif
296    }
297
298    for (tmp = fileprotstr; *tmp; tmp++) if (*tmp == '.') *tmp = '_';
299
300    (*headerproc[abi])(f, phile);
301
302    if (phile->tmpl) CopyTmplEpilog (phile->tmpl, f);
303
304    (void) free (fileprotstr);
305    (void) fclose (phile->tmpl);
306    (void) fclose (f);
307}
308
309static void WriteSourceLine (TableEnt *te, int abi, int fudge)
310{
311    char* c;
312
313    for (c = te->right; *c; c++) (void) printf ("'%c',", *c);
314    (void) printf ("%c", '0');
315    if (te->next || fudge) (void) printf ("%c", ',');
316    (void) printf ("%s", "\n");
317}
318
319static const char* const_string = "%s %sConst char %s[] = {\n";
320
321static void IntelABIWriteSource (int abi)
322{
323    File* phile;
324
325    for (phile = file; phile; phile = phile->next) {
326	Table* t;
327	TableEnt* te;
328
329	for (t = phile->table; t; t = t->next) {
330	    (void) printf (const_string, externdefstr,
331			   conststr ? conststr : "", t->name);
332	    for (te = t->tableent; te; te = te->next)
333		WriteSourceLine (te, abi, 0);
334	    (void) printf ("%s\n\n", "};");
335	}
336    }
337}
338
339static void IntelABIBCWriteSource (int abi)
340{
341    File* phile;
342
343    for (phile = file; phile; phile = phile->next) {
344	Table* t;
345	TableEnt* te;
346
347	(void) printf (const_string, externdefstr,
348		       conststr ? conststr : "", phile->table->name);
349
350	for (t = phile->table; t; t = t->next)
351	    for (te = t->tableent; te; te = te->next)
352		WriteSourceLine (te, abi, t->next ? 1 : 0);
353	(void) printf ("%s\n\n", "};");
354
355	if (phile->table->next) {
356	    (void) printf (const_string, externdefstr,
357			   conststr ? conststr : "", phile->table->next->name);
358	    for (t = phile->table->next; t; t = t->next)
359		for (te = t->tableent; te; te = te->next)
360		    WriteSourceLine (te, abi, 0);
361	    (void) printf ("%s\n\n", "};");
362	}
363    }
364}
365
366static void FunctionWriteSource (int abi)
367{
368    File* phile;
369
370    for (phile = file; phile; phile = phile->next) {
371	Table* t;
372	TableEnt* te;
373
374	(void) printf ("static %sConst char _%s[] = {\n",
375		       conststr ? conststr : "", phile->table->name);
376
377	for (t = phile->table; t; t = t->next)
378	    for (te = t->tableent; te; te = te->next)
379		WriteSourceLine (te, abi, t->next ? 1 : 0);
380	(void) printf ("%s\n\n", "};");
381
382	(void) printf ("%sConst char* %s(index)\n    int index;\n{\n    return &_%s[index];\n}\n\n",
383		       conststr ? conststr : "",
384		       phile->table->name, phile->table->name);
385    }
386}
387
388static void ArrayperWriteSource (int abi)
389{
390    File* phile;
391    static int done_atom;
392
393    for (phile = file; phile; phile = phile->next) {
394	Table* t;
395	TableEnt* te;
396
397	for (t = phile->table; t; t = t->next)
398	    for (te = t->tableent; te; te = te->next) {
399		if (strcmp (te->left, "RAtom") == 0) {
400		    if (done_atom) return;
401		    done_atom = 1;
402		}
403		(void) printf ("%s %sConst char %s%s[] = \"%s\";\n",
404			       externdefstr, conststr ? conststr : "",
405			       prefixstr,
406			       te->left, te->right);
407	    }
408    }
409}
410
411static void DefaultWriteSource (int abi)
412{
413    File* phile;
414
415    for (phile = file; phile; phile = phile->next) {
416	Table* t;
417	TableEnt* te;
418
419	(void) printf (const_string, externdefstr, conststr ? conststr : "",
420		       phile->table->name);
421
422	for (t = phile->table; t; t = t->next)
423	    for (te = t->tableent; te; te = te->next)
424		WriteSourceLine (te, abi, t->next ? 1 : 0);
425	(void) printf ("%s\n\n", "};");
426    }
427}
428
429static void WriteSource(char *tagline, int abi)
430{
431    static void (*sourceproc[])(int) = {
432	DefaultWriteSource, ArrayperWriteSource,
433	IntelABIWriteSource, IntelABIBCWriteSource,
434	DefaultWriteSource, FunctionWriteSource };
435
436    FILE* tmpl;
437
438    if (ctmplstr) {
439	tmpl = ifopen (ctmplstr, "r");
440
441	if (tmpl) CopyTmplProlog (tmpl, stdout);
442	else {
443	    (void) fprintf (stderr, "Expected template %s, not found\n",
444			    ctmplstr);
445	    exit (1);
446	}
447    } else
448	tmpl = NULL;
449
450
451    (void) printf ("%s\n%s\n/* %s ABI version -- Do not edit */\n",
452		   "/* $Xorg: makestrs.c,v 1.6 2001/02/09 02:03:17 xorgcvs Exp $ */",
453		   "/* This file is automatically generated. */",
454		   abistring[abi]);
455
456    if (tagline) (void) printf ("/* %s */\n\n", tagline);
457
458    (*sourceproc[abi])(abi);
459
460    if (tmpl) CopyTmplEpilog (tmpl, stdout);
461}
462
463static void DoLine(char *buf)
464{
465#define X_NO_TOKEN 0
466#define X_FILE_TOKEN 1
467#define X_TABLE_TOKEN 2
468#define X_PREFIX_TOKEN 3
469#define X_FEATURE_TOKEN 4
470#define X_EXTERNREF_TOKEN 5
471#define X_EXTERNDEF_TOKEN 6
472#define X_CTMPL_TOKEN 7
473#define X_HTMPL_TOKEN 8
474#define X_CONST_TOKEN 9
475
476    int token;
477    char lbuf[1024];
478    static const char* file_str = "#file";
479    static const char* table_str = "#table";
480    static const char* prefix_str = "#prefix";
481    static const char* feature_str = "#feature";
482    static const char* externref_str = "#externref";
483    static const char* externdef_str = "#externdef";
484    static const char* ctmpl_str = "#ctmpl";
485    static const char* htmpl_str = "#htmpl";
486    static const char* const_str = "#const";
487
488    if (strncmp (buf, file_str, strlen (file_str)) == 0)
489	token = X_FILE_TOKEN;
490    else if (strncmp (buf, table_str, strlen (table_str)) == 0)
491	token = X_TABLE_TOKEN;
492    else if (strncmp (buf, prefix_str, strlen (prefix_str)) == 0)
493	token = X_PREFIX_TOKEN;
494    else if (strncmp (buf, feature_str, strlen (feature_str)) == 0)
495	token = X_FEATURE_TOKEN;
496    else if (strncmp (buf, externref_str, strlen (externref_str)) == 0)
497	token = X_EXTERNREF_TOKEN;
498    else if (strncmp (buf, externdef_str, strlen (externdef_str)) == 0)
499	token = X_EXTERNDEF_TOKEN;
500    else if (strncmp (buf, ctmpl_str, strlen (ctmpl_str)) == 0)
501	token = X_CTMPL_TOKEN;
502    else if (strncmp (buf, htmpl_str, strlen (htmpl_str)) == 0)
503	token = X_HTMPL_TOKEN;
504    else if (strncmp (buf, const_str, strlen (const_str)) == 0)
505	token = X_CONST_TOKEN;
506    else
507        token = X_NO_TOKEN;
508
509    switch (token) {
510    case X_FILE_TOKEN:
511	{
512	    File* phile;
513
514	    if ((phile = (File*) malloc (sizeof(File))) == NULL)
515		exit(1);
516	    if ((phile->name = strdup (buf + strlen (file_str) + 1)) == NULL)
517		exit(1);
518	    phile->table = NULL;
519	    phile->tablecurrent = NULL;
520	    phile->tabletail = &phile->table;
521	    phile->next = NULL;
522	    phile->tmpl = NULL;
523
524	    *filetail = phile;
525	    filetail = &phile->next;
526	    filecurrent = phile;
527	}
528	break;
529    case X_TABLE_TOKEN:
530	{
531	    Table* table;
532	    if ((table = (Table*) malloc (sizeof(Table))) == NULL)
533		exit(1);
534	    if ((table->name = strdup (buf + strlen (table_str) + 1)) == NULL)
535		exit(1);
536	    if (solaris_abi_names) {
537		if (strcmp(table->name, "XtStringsR6") == 0) {
538		    strcpy(table->name, "XtR6Strings");
539		} else if (strcmp(table->name, "XtShellStringsR6") == 0) {
540		    strcpy(table->name, "XtR6ShellStrings");
541		}
542	    }
543	    table->tableent = NULL;
544	    table->tableentcurrent = NULL;
545	    table->tableenttail = &table->tableent;
546	    table->next = NULL;
547	    table->offset = 0;
548
549	    *filecurrent->tabletail = table;
550	    filecurrent->tabletail = &table->next;
551	    filecurrent->tablecurrent = table;
552	}
553	break;
554    case X_PREFIX_TOKEN:
555	if ((prefixstr = strdup (buf + strlen (prefix_str) + 1)) == NULL)
556	    exit(1);
557	break;
558    case X_FEATURE_TOKEN:
559	if ((featurestr = strdup (buf + strlen (feature_str) + 1)) == NULL)
560	    exit(1);
561	break;
562    case X_EXTERNREF_TOKEN:
563	if ((externrefstr = strdup (buf + strlen (externref_str) + 1)) == NULL)
564	    exit(1);
565	break;
566    case X_EXTERNDEF_TOKEN:
567	if ((externdefstr = strdup (buf + strlen (externdef_str) + 1)) == NULL)
568	    exit(1);
569	break;
570    case X_CTMPL_TOKEN:
571	if ((ctmplstr = strdup (buf + strlen (ctmpl_str) + 1)) == NULL)
572	    exit(1);
573	break;
574    case X_HTMPL_TOKEN:
575	if ((filecurrent->tmpl = ifopen (buf + strlen (htmpl_str) + 1, "r")) == NULL) {
576	    (void) fprintf (stderr,
577			    "Expected template %s, not found\n", htmpl_str);
578	    exit (1);
579	}
580	break;
581    case X_CONST_TOKEN:
582	if ((conststr = strdup (buf + strlen (const_str) + 1)) == NULL)
583	    exit(1);
584	break;
585    default:
586	{
587	    char* right;
588	    TableEnt* tableent;
589	    int llen;
590	    int rlen;
591	    int len;
592
593	    if ((right = strchr(buf, ' ')))
594		*right++ = 0;
595	    else
596		right = buf + 1;
597	    if (buf[0] == 'H') {
598		snprintf (lbuf, sizeof(lbuf), "%s%s", prefixstr, right);
599		right = lbuf;
600	    }
601
602	    llen = len = strlen(buf) + 1;
603	    rlen = strlen(right) + 1;
604	    if (right != buf + 1) len += rlen;
605	    if ((tableent = (TableEnt*)malloc(sizeof(TableEnt) + len)) == NULL)
606		exit(1);
607	    tableent->left = (char *)(tableent + 1);
608	    strcpy(tableent->left, buf);
609	    if (llen != len) {
610		tableent->right = tableent->left + llen;
611		strcpy(tableent->right, right);
612	    } else {
613		tableent->right = tableent->left + 1;
614	    }
615	    tableent->next = NULL;
616
617	    *filecurrent->tablecurrent->tableenttail = tableent;
618	    filecurrent->tablecurrent->tableenttail = &tableent->next;
619	    filecurrent->tablecurrent->tableentcurrent = tableent;
620	}
621	break;
622    }
623}
624
625static void IntelABIIndexEntries (File *file)
626{
627    Table* t;
628    TableEnt* te;
629
630    for (t = file->table; t; t = t->next)
631	for (te = t->tableent; te; te = te->next) {
632	    te->offset = t->offset;
633	    t->offset += strlen (te->right);
634	    t->offset++;
635    }
636}
637
638static void DefaultIndexEntries (File *file)
639{
640    Table* t;
641    TableEnt* te;
642    int offset = 0;
643
644    for (t = file->table; t; t = t->next)
645	for (te = t->tableent; te; te = te->next) {
646	    te->offset = offset;
647	    offset += strlen (te->right);
648	    offset++;
649    }
650}
651
652static void IndexEntries (File *file, int abi)
653{
654    switch (abi) {
655    case X_SPARC_ABI:
656	break;
657    case X_INTEL_ABI:
658    case X_INTEL_ABI_BC:
659	IntelABIIndexEntries (file);
660	break;
661    default:
662	DefaultIndexEntries (file);
663	break;
664    }
665}
666
667static char* DoComment (char *line)
668{
669    char* tag;
670    char* eol;
671    char* ret;
672    int len;
673
674    /* assume that the first line with two '$' in it is the RCS tag line */
675    if ((tag = strchr (line, '$')) == NULL) return NULL;
676    if ((eol = strchr (tag + 1, '$')) == NULL) return NULL;
677    len = eol - tag;
678    if ((ret = malloc (len)) == NULL)
679	exit (1);
680    (void) strncpy (ret, tag + 1, len - 1);
681    ret[len - 2] = 0;
682    return ret;
683}
684
685int main(int argc, char *argv[])
686{
687    int len, i;
688    char* tagline = NULL;
689    File* phile;
690    FILE *f;
691    char buf[1024];
692    int abi =
693#ifndef ARRAYPERSTR
694	X_DEFAULT_ABI;
695#else
696	X_ARRAYPER_ABI;
697#endif
698
699    f = stdin;
700    if (argc > 1) {
701	for (i = 1; i < argc; i++) {
702	    if (strcmp (argv[i], "-f") == 0) {
703		if (++i < argc)
704		    f = fopen (argv[i], "r");
705		else
706		    return 1;
707	    }
708	    if (strcmp (argv[i], "-i") == 0) {
709		if (++i < argc)
710		    includedir = argv[i];
711		else
712		    return 1;
713	    }
714	    if (strcmp (argv[i], "-sparcabi") == 0)
715		abi = X_SPARC_ABI;
716	    if (strcmp (argv[i], "-intelabi") == 0)
717		abi = X_INTEL_ABI;
718	    if (strcmp (argv[i], "-functionabi") == 0)
719		abi = X_FUNCTION_ABI;
720	    if (strcmp (argv[i], "-earlyR6bc") == 0 && abi == X_INTEL_ABI)
721		abi = X_INTEL_ABI_BC;
722	    if (strcmp (argv[i], "-arrayperabi") == 0)
723		abi = X_ARRAYPER_ABI;
724#ifdef ARRAYPERSTR
725	    if (strcmp (argv[i], "-defaultabi") == 0)
726		abi = X_DEFAULT_ABI;
727#endif
728	    if (strcmp (argv[i], "-solarisabinames") == 0)
729		solaris_abi_names = TRUE;
730	}
731    }
732
733    if (f == NULL) return 1;
734    while (fgets(buf, sizeof buf, f)) {
735	if (!buf[0] || buf[0] == '\n')
736	    continue;
737	if (buf[0] == '!') {
738	    if (tagline) continue;
739	    tagline = DoComment (buf);
740	    continue;
741	}
742	if (buf[(len = strlen (buf) - 1)] == '\n') buf[len] = '\0';
743	DoLine(buf);
744    }
745    for (phile = file; phile; phile = phile->next) {
746	if (abi != X_ARRAYPER_ABI) IndexEntries (phile, abi);
747	WriteHeader (tagline, phile, abi);
748    }
749    WriteSource(tagline, abi);
750    return 0;
751}
752
753