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