1
2/***********************************************************
3Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that Alfalfa's name not be used in
12advertising or publicity pertaining to distribution of the software
13without specific, written prior permission.
14
15ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
22
23If you make any modifications, bugfixes or other changes to this software
24we'd appreciate it if you could send a copy to us so we can keep things
25up-to-date.  Many thanks.
26				Kee Hinckley
27				Alfalfa Software, Inc.
28				267 Allston St., #3
29				Cambridge, MA 02139  USA
30				nazgul@alfalfa.com
31
32******************************************************************/
33
34/* Edit History
35
3601/18/91   3 hamilton	#if not reparsed
3701/12/91   2 schulert	conditionally use prototypes
3812/23/90   2 hamilton	Fix fd == NULL to fd < 0
3911/03/90   1 hamilton	Alphalpha->Alfalfa & OmegaMail->Poste
4008/13/90   1 schulert	move from ua to omu
41*/
42
43#include <stdio.h>
44#include <sys/types.h>
45#ifdef SYSV
46#include <sys/fcntl.h>
47#include <string.h>
48#else
49#include <strings.h>
50#endif
51#include <sys/file.h>
52#include <sys/stat.h>
53#include "gencat.h"
54
55#ifndef L_SET
56#define L_SET SEEK_SET
57#endif
58
59#ifndef L_INCR
60#define L_INCR SEEK_CUR
61#endif
62
63/*
64 * The spec says the syntax is "gencat catfile msgfile...".
65 * We extend it to:
66 * 	gencat [-new] [-or] [-lang C|C++|ANSIC] catfile msgfile
67 *	       [-h <header-file>]...
68 * Flags are order dependant, we'll take whatever lang was most recently chosen
69 * and use it to generate the next header file.  The header files are generated
70 * at the point in the command line they are listed.  Thus the sequence:
71 *	gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
72 * will put constants from foo.mcs into foo.h and constants from bar.mcs into
73 * bar.h.  Constants are not saved in the catalog file, so nothing will come
74 * from that, even if things have been defined before.  The constants in foo.h
75 * will be in C syntax, in bar.H in C++ syntax.
76 */
77
78static void writeIfChanged(
79#if defined(__STDC__) || defined(__cplusplus)
80		char *fname, int lang, int orConsts
81#endif
82);
83
84void usage() {
85    fprintf(stderr, "Use: gencat [-new] [-or] [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...\n");
86}
87
88int main(
89#if defined(__STDC__) || defined(__cplusplus)
90		int argc, char *argv[])
91#else
92		argc, argv)
93int argc;
94char *argv[];
95#endif
96{
97    int		ofd, ifd, i;
98    FILE	*fptr;
99    char	*catfile = NULL;
100    char	*input = NULL;
101    int		lang = MCLangC;
102    int		new = False;
103    int		orConsts = False;
104
105    for (i = 1; i < argc; ++i) {
106	if (argv[i][0] == '-') {
107	    if (strcmp(argv[i], "-lang") == 0) {
108		++i;
109		if (strcmp(argv[i], "C") == 0) lang = MCLangC;
110		else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
111		else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
112		else {
113		    fprintf(stderr, "gencat: Unrecognized language: %s\n", argv[i]);
114		    exit(1);
115		}
116	    } else if (strncmp(argv[i], "-h", 2) == 0) {
117		if (!input) {
118		    fprintf(stderr, "gencat: Can't write to a header before reading something.\n");
119		    exit(1);
120		}
121		++i;
122		writeIfChanged(argv[i], lang, orConsts);
123	    } else if (strncmp(argv[i], "-new", 4) == 0) {
124		if (catfile) {
125		    fprintf(stderr, "gencat: You must specify -new before the catalog file name\n");
126		    exit(1);
127		}
128		new = True;
129	    } else if (strncmp(argv[i], "-or", 3) == 0) {
130		orConsts = ~orConsts;
131	    } else {
132		usage();
133		exit(1);
134	    }
135        } else {
136	    if (!catfile) {
137		catfile = argv[i];
138		if (new) {
139		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
140			fprintf(stderr, "gencat: Unable to create a new %s.\n", catfile);
141			exit(1);
142		    }
143		} else if ((ofd = open(catfile, O_RDONLY)) < 0) {
144		    if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0) {
145			fprintf(stderr, "gencat: Unable to create %s.\n", catfile);
146			exit(1);
147		    }
148		} else {
149		    MCReadCat(ofd);
150		    close(ofd);
151		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0) {
152			fprintf(stderr, "gencat: Unable to truncate %s.\n", catfile);
153			exit(1);
154		    }
155		}
156	    } else {
157		input = argv[i];
158		if ((ifd = open(input, O_RDONLY)) < 0) {
159		    fprintf(stderr, "gencat: Unable to read %s\n", input);
160		    exit(1);
161		}
162		MCParse(ifd);
163		close(ifd);
164	    }
165	}
166    }
167    if (catfile) {
168	MCWriteCat(ofd);
169	exit(0);
170    } else {
171	usage();
172	exit(1);
173    }
174    return 0; /* just for gcc */
175}
176
177static void writeIfChanged(
178#if defined(__STDC__) || defined(__cplusplus)
179		char *fname, int lang, int orConsts)
180#else
181		fname, lang, orConsts)
182char *fname;
183int lang;
184int orConsts;
185#endif
186{
187    char	tmpname[32];
188    char	buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
189    int		fd, tfd;
190    int		diff = False;
191    int		c, len, tlen;
192    struct stat	sbuf;
193
194    /* If it doesn't exist, just create it */
195    if (stat(fname, &sbuf)) {
196	if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) {
197	    fprintf(stderr, "gencat: Unable to create header file %s.\n", fname);
198	    exit(1);
199	}
200	MCWriteConst(fd, lang, orConsts);
201	close(fd);
202	return;
203    }
204
205    /* If it does exist, create a temp file for now */
206    sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
207    if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0) {
208	fprintf(stderr, "gencat: Unable to open temporary file: %s\n", tmpname);
209	exit(1);
210    }
211    unlink(tmpname);
212
213    /* Write to the temp file and rewind */
214    MCWriteConst(tfd, lang, orConsts);
215
216    /* Open the real header file */
217    if ((fd = open(fname, O_RDONLY)) < 0) {
218	fprintf(stderr, "gencat: Unable to read header file: %s\n", fname);
219	exit(1);
220    }
221
222    /* Backup to the start of the temp file */
223    if (lseek(tfd, 0L, L_SET) < 0) {
224	fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
225	exit(1);
226    }
227
228    /* Now compare them */
229    while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
230	if ((len = read(fd, buf, BUFSIZ)) != tlen) {
231	    diff = True;
232	    goto done;
233	}
234	for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
235	    if (*tptr != *cptr) {
236		diff = True;
237		goto done;
238	    }
239	}
240    }
241done:
242    if (diff) {
243	if (lseek(tfd, 0L, L_SET) < 0) {
244	    fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
245	    exit(1);
246	}
247	close(fd);
248	if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) {
249	    fprintf(stderr, "gencat: Unable to truncate header file: %s\n", fname);
250	    exit(1);
251	}
252	while ((len = read(tfd, buf, BUFSIZ)) > 0) {
253	    if (write(fd, buf, len) != len) {
254		fprintf(stderr, "gencat: Error writing to header file: %s\n", fname);
255	    }
256	}
257    }
258    close(fd);
259    close(tfd);
260}
261