xref: /freebsd/usr.bin/gencat/gencat.c (revision ee2ea5ceafed78a5bd9810beb9e3ca927180c226)
1 /***********************************************************
2 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
3 
4                         All Rights Reserved
5 
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that Alfalfa's name not be used in
11 advertising or publicity pertaining to distribution of the software
12 without specific, written prior permission.
13 
14 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 SOFTWARE.
21 
22 If you make any modifications, bugfixes or other changes to this software
23 we'd appreciate it if you could send a copy to us so we can keep things
24 up-to-date.  Many thanks.
25 				Kee Hinckley
26 				Alfalfa Software, Inc.
27 				267 Allston St., #3
28 				Cambridge, MA 02139  USA
29 				nazgul@alfalfa.com
30 
31 ******************************************************************/
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
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 dependent, 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 
59 static void writeIfChanged(char *, int, int);
60 
61 static void
62 usage(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 
69 int
70 main(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 
136 static void
137 writeIfChanged(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     }
185 done:
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