gencat.c revision 78717
1/* $FreeBSD: head/usr.bin/gencat/gencat.c 78717 2001-06-24 19:41:18Z dd $ */
2
3/***********************************************************
4Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
5
6                        All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and its
9documentation for any purpose and without fee is hereby granted,
10provided that the above copyright notice appear in all copies and that
11both that copyright notice and this permission notice appear in
12supporting documentation, and that Alfalfa's name not be used in
13advertising or publicity pertaining to distribution of the software
14without specific, written prior permission.
15
16ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22SOFTWARE.
23
24If you make any modifications, bugfixes or other changes to this software
25we'd appreciate it if you could send a copy to us so we can keep things
26up-to-date.  Many thanks.
27				Kee Hinckley
28				Alfalfa Software, Inc.
29				267 Allston St., #3
30				Cambridge, MA 02139  USA
31				nazgul@alfalfa.com
32
33******************************************************************/
34
35#include <sys/types.h>
36#include <sys/file.h>
37#include <sys/stat.h>
38#include <err.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include "gencat.h"
44
45/*
46 * The spec says the syntax is "gencat catfile msgfile...".
47 * We extend it to:
48 * 	gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
49 * Flags are order dependant, we'll take whatever lang was most recently chosen
50 * and use it to generate the next header file.  The header files are generated
51 * at the point in the command line they are listed.  Thus the sequence:
52 *	gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
53 * will put constants from foo.mcs into foo.h and constants from bar.mcs into
54 * bar.h.  Constants are not saved in the catalog file, so nothing will come
55 * from that, even if things have been defined before.  The constants in foo.h
56 * will be in C syntax, in bar.H in C++ syntax.
57 */
58
59static void writeIfChanged(char *, int, int);
60
61static void
62usage(void)
63{
64    fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n"
65                    "              catfile msgfile [-h <header-file>]...\n");
66    exit(1);
67}
68
69int
70main(int argc, char *argv[])
71{
72    int		ofd, ifd, i;
73    char	*catfile = NULL;
74    char	*input = NULL;
75    int		lang = MCLangC;
76    int		new = FALSE;
77    int		orConsts = FALSE;
78
79    for (i = 1; i < argc; ++i) {
80	if (argv[i][0] == '-') {
81	    if (strcmp(argv[i], "-lang") == 0) {
82		++i;
83		if (strcmp(argv[i], "C") == 0) lang = MCLangC;
84		else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
85		else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
86		else {
87		    errx(1, "unrecognized language: %s", argv[i]);
88		}
89	    } else if (strcmp(argv[i], "-h") == 0) {
90		if (!input)
91		    errx(1, "can't write to a header before reading something");
92		++i;
93		writeIfChanged(argv[i], lang, orConsts);
94	    } else if (strcmp(argv[i], "-new") == 0) {
95		if (catfile)
96		    errx(1, "you must specify -new before the catalog file name");
97		new = TRUE;
98	    } else if (strcmp(argv[i], "-or") == 0) {
99		orConsts = ~orConsts;
100	    } else {
101		usage();
102	    }
103        } else {
104	    if (!catfile) {
105		catfile = argv[i];
106		if (new) {
107		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
108				errx(1, "unable to create a new %s", catfile);
109		} else if ((ofd = open(catfile, O_RDONLY)) < 0) {
110		    if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0)
111				errx(1, "unable to create %s", catfile);
112		} else {
113		    MCReadCat(ofd);
114		    close(ofd);
115		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0)
116				errx(1, "unable to truncate %s", catfile);
117		}
118	    } else {
119		input = argv[i];
120		if ((ifd = open(input, O_RDONLY)) < 0)
121		    errx(1, "unable to read %s", input);
122		MCParse(ifd);
123		close(ifd);
124	    }
125	}
126    }
127    if (catfile) {
128	MCWriteCat(ofd);
129	exit(0);
130    } else {
131	usage();
132    }
133    return 0;
134}
135
136static void
137writeIfChanged(char *fname, int lang, int orConsts)
138{
139    char	tmpname[32];
140    char	buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
141    int		fd, tfd;
142    int		diff = FALSE;
143    int		len, tlen;
144    struct stat	sbuf;
145
146    /* If it doesn't exist, just create it */
147    if (stat(fname, &sbuf)) {
148	if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0)
149	    errx(1, "unable to create header file %s", fname);
150	MCWriteConst(fd, lang, orConsts);
151	close(fd);
152	return;
153    }
154
155    /* If it does exist, create a temp file for now */
156    sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
157    if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0)
158		errx(1, "unable to open temporary file: %s", tmpname);
159    unlink(tmpname);
160
161    /* Write to the temp file and rewind */
162    MCWriteConst(tfd, lang, orConsts);
163
164    /* Open the real header file */
165    if ((fd = open(fname, O_RDONLY)) < 0)
166		errx(1, "unable to read header file: %s", fname);
167
168    /* Backup to the start of the temp file */
169    if (lseek(tfd, (off_t)0, L_SET) < 0)
170		errx(1, "unable to seek in tempfile: %s", tmpname);
171
172    /* Now compare them */
173    while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
174	if ((len = read(fd, buf, BUFSIZ)) != tlen) {
175	    diff = TRUE;
176	    goto done;
177	}
178	for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
179	    if (*tptr != *cptr) {
180		diff = TRUE;
181		goto done;
182	    }
183	}
184    }
185done:
186    if (diff) {
187	if (lseek(tfd, (off_t)0, L_SET) < 0)
188	    errx(1, "unable to seek in tempfile: %s", tmpname);
189	close(fd);
190	if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0)
191	    errx(1, "unable to truncate header file: %s", fname);
192	while ((len = read(tfd, buf, BUFSIZ)) > 0) {
193	    if (write(fd, buf, (size_t)len) != len)
194		warnx("error writing to header file: %s", fname);
195	}
196    }
197    close(fd);
198    close(tfd);
199}
200