xref: /freebsd/usr.bin/gencat/gencat.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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 int 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     return 0;
159 }
160 
161 static void writeIfChanged(
162 #if ANSI_C || defined(__cplusplus)
163 		char *fname, int lang, int orConsts)
164 #else
165 		fname, lang, orConsts)
166 char *fname;
167 int lang;
168 int orConsts;
169 #endif
170 {
171     char	tmpname[32];
172     char	buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
173     int		fd, tfd;
174     int		diff = False;
175     int		len, tlen;
176     struct stat	sbuf;
177 
178     /* If it doesn't exist, just create it */
179     if (stat(fname, &sbuf)) {
180 	if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0)
181 	    errx(1, "unable to create header file %s", fname);
182 	MCWriteConst(fd, lang, orConsts);
183 	close(fd);
184 	return;
185     }
186 
187     /* If it does exist, create a temp file for now */
188     sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
189     if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0)
190 		errx(1, "unable to open temporary file: %s", tmpname);
191     unlink(tmpname);
192 
193     /* Write to the temp file and rewind */
194     MCWriteConst(tfd, lang, orConsts);
195 
196     /* Open the real header file */
197     if ((fd = open(fname, O_RDONLY)) < 0)
198 		errx(1, "unable to read header file: %s", fname);
199 
200     /* Backup to the start of the temp file */
201     if (lseek(tfd, 0L, L_SET) < 0)
202 		errx(1, "unable to seek in tempfile: %s", tmpname);
203 
204     /* Now compare them */
205     while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
206 	if ((len = read(fd, buf, BUFSIZ)) != tlen) {
207 	    diff = True;
208 	    goto done;
209 	}
210 	for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
211 	    if (*tptr != *cptr) {
212 		diff = True;
213 		goto done;
214 	    }
215 	}
216     }
217 done:
218     if (diff) {
219 	if (lseek(tfd, 0L, L_SET) < 0)
220 	    errx(1, "unable to seek in tempfile: %s", tmpname);
221 	close(fd);
222 	if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0)
223 	    errx(1, "unable to truncate header file: %s", fname);
224 	while ((len = read(tfd, buf, BUFSIZ)) > 0) {
225 	    if (write(fd, buf, len) != len)
226 			warnx("error writing to header file: %s", fname);
227 	}
228     }
229     close(fd);
230     close(tfd);
231 }
232