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