xref: /freebsd/usr.bin/gencat/gencat.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
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 <paths.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include "gencat.h"
45 
46 /*
47  * The spec says the syntax is "gencat catfile msgfile...".
48  * We extend it to:
49  * 	gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
50  * Flags are order dependent, we'll take whatever lang was most recently chosen
51  * and use it to generate the next header file.  The header files are generated
52  * at the point in the command line they are listed.  Thus the sequence:
53  *	gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
54  * will put constants from foo.mcs into foo.h and constants from bar.mcs into
55  * bar.h.  Constants are not saved in the catalog file, so nothing will come
56  * from that, even if things have been defined before.  The constants in foo.h
57  * will be in C syntax, in bar.H in C++ syntax.
58  */
59 
60 static void writeIfChanged(char *, int, int);
61 
62 static void
63 usage(void)
64 {
65     fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n"
66                     "              catfile msgfile [-h <header-file>]...\n");
67     exit(1);
68 }
69 
70 int
71 main(int argc, char *argv[])
72 {
73     int		ofd, ifd, i;
74     char	*catfile = NULL;
75     char	*input = NULL;
76     int		lang = MCLangC;
77     int		new = FALSE;
78     int		orConsts = FALSE;
79 
80     for (i = 1; i < argc; ++i) {
81 	if (argv[i][0] == '-') {
82 	    if (strcmp(argv[i], "-lang") == 0) {
83 		++i;
84 		if (strcmp(argv[i], "C") == 0) lang = MCLangC;
85 		else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
86 		else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
87 		else {
88 		    errx(1, "unrecognized language: %s", argv[i]);
89 		}
90 	    } else if (strcmp(argv[i], "-h") == 0) {
91 		if (!input)
92 		    errx(1, "can't write to a header before reading something");
93 		++i;
94 		writeIfChanged(argv[i], lang, orConsts);
95 	    } else if (strcmp(argv[i], "-new") == 0) {
96 		if (catfile)
97 		    errx(1, "you must specify -new before the catalog file name");
98 		new = TRUE;
99 	    } else if (strcmp(argv[i], "-or") == 0) {
100 		orConsts = ~orConsts;
101 	    } else {
102 		usage();
103 	    }
104         } else {
105 	    if (!catfile) {
106 		catfile = argv[i];
107 		if (new) {
108 		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
109 				errx(1, "unable to create a new %s", catfile);
110 		} else if ((ofd = open(catfile, O_RDONLY)) < 0) {
111 		    if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0)
112 				errx(1, "unable to create %s", catfile);
113 		} else {
114 		    MCReadCat(ofd);
115 		    close(ofd);
116 		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0)
117 				errx(1, "unable to truncate %s", catfile);
118 		}
119 	    } else {
120 		input = argv[i];
121 		if ((ifd = open(input, O_RDONLY)) < 0)
122 		    errx(1, "unable to read %s", input);
123 		MCParse(ifd);
124 		close(ifd);
125 	    }
126 	}
127     }
128     if (catfile) {
129 	MCWriteCat(ofd);
130 	exit(0);
131     } else {
132 	usage();
133     }
134     return 0;
135 }
136 
137 static void
138 writeIfChanged(char *fname, int lang, int orConsts)
139 {
140     char	tmpname[] = _PATH_TMP"/gencat.XXXXXX";
141     char	buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
142     int		fd, tfd;
143     int		diff = FALSE;
144     int		len, tlen;
145     struct stat	sbuf;
146 
147     /* If it doesn't exist, just create it */
148     if (stat(fname, &sbuf)) {
149 	if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0)
150 	    errx(1, "unable to create header file %s", fname);
151 	MCWriteConst(fd, lang, orConsts);
152 	close(fd);
153 	return;
154     }
155 
156     /* If it does exist, create a temp file for now */
157     if ((tfd = mkstemp(tmpname)) < 0)
158 		err(1, "mkstemp");
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