xref: /freebsd/usr.bin/gencat/gencat.c (revision d82e286489da73321a47e329d98a98817b0438b6)
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 <stdio.h>
44 #include <sys/types.h>
45 #include <unistd.h>
46 #ifdef SYSV
47 #include <sys/fcntl.h>
48 #define L_SET SEEK_SET
49 #define L_INCR SEEK_CUR
50 #endif
51 #include <sys/file.h>
52 #include <sys/stat.h>
53 #include "gencat.h"
54 
55 /*
56  * The spec says the syntax is "gencat catfile msgfile...".
57  * We extend it to:
58  * 	gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
59  * Flags are order dependant, we'll take whatever lang was most recently chosen
60  * and use it to generate the next header file.  The header files are generated
61  * at the point in the command line they are listed.  Thus the sequence:
62  *	gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
63  * will put constants from foo.mcs into foo.h and constants from bar.mcs into
64  * bar.h.  Constants are not saved in the catalog file, so nothing will come
65  * from that, even if things have been defined before.  The constants in foo.h
66  * will be in C syntax, in bar.H in C++ syntax.
67  */
68 
69 #if ANSI_C || defined(__cplusplus)
70 # define P_(x) x
71 #else
72 # define P_(x) /**/
73 #endif
74 
75 static void writeIfChanged P_((char *fname, int lang, int orConsts));
76 
77 #undef P_
78 
79 void usage() {
80     fprintf(stderr, "Use: gencat [-new] [-or] [-lang C|C++|ANSIC]\n");
81     fprintf(stderr, "            catfile msgfile [-h <header-file>]...\n");
82 }
83 
84 void main(
85 #if ANSI_C || defined(__cplusplus)
86 		int argc, char *argv[])
87 #else
88 		argc, argv)
89 int argc;
90 char *argv[];
91 #endif
92 {
93     int		ofd, ifd, i;
94     FILE	*fptr;
95     char	*catfile = NULL;
96     char	*input = NULL;
97     int		lang = MCLangC;
98     int		new = False;
99     int		orConsts = False;
100 
101     for (i = 1; i < argc; ++i) {
102 	if (argv[i][0] == '-') {
103 	    if (strcmp(argv[i], "-lang") == 0) {
104 		++i;
105 		if (strcmp(argv[i], "C") == 0) lang = MCLangC;
106 		else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
107 		else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
108 		else {
109 		    fprintf(stderr, "gencat: Unrecognized language: %s\n", argv[i]);
110 		    exit(1);
111 		}
112 	    } else if (strcmp(argv[i], "-h") == 0) {
113 		if (!input) {
114 		    fprintf(stderr, "gencat: Can't write to a header before reading something.\n");
115 		    exit(1);
116 		}
117 		++i;
118 		writeIfChanged(argv[i], lang, orConsts);
119 	    } else if (strcmp(argv[i], "-new") == 0) {
120 		if (catfile) {
121 		    fprintf(stderr, "gencat: You must specify -new before the catalog file name\n");
122 		    exit(1);
123 		}
124 		new = True;
125 	    } else if (strcmp(argv[i], "-or") == 0) {
126 		orConsts = ~orConsts;
127 	    } else {
128 		usage();
129 		exit(1);
130 	    }
131         } else {
132 	    if (!catfile) {
133 		catfile = argv[i];
134 		if (new) {
135 		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
136 			fprintf(stderr, "gencat: Unable to create a new %s.\n", catfile);
137 			exit(1);
138 		    }
139 		} else if ((ofd = open(catfile, O_RDONLY)) < 0) {
140 		    if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0) {
141 			fprintf(stderr, "gencat: Unable to create %s.\n", catfile);
142 			exit(1);
143 		    }
144 		} else {
145 		    MCReadCat(ofd);
146 		    close(ofd);
147 		    if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0) {
148 			fprintf(stderr, "gencat: Unable to truncate %s.\n", catfile);
149 			exit(1);
150 		    }
151 		}
152 	    } else {
153 		input = argv[i];
154 		if ((ifd = open(input, O_RDONLY)) < 0) {
155 		    fprintf(stderr, "gencat: Unable to read %s\n", input);
156 		    exit(1);
157 		}
158 		MCParse(ifd);
159 		close(ifd);
160 	    }
161 	}
162     }
163     if (catfile) {
164 	MCWriteCat(ofd);
165 	exit(0);
166     } else {
167 	usage();
168 	exit(1);
169     }
170 }
171 
172 static void writeIfChanged(
173 #if ANSI_C || defined(__cplusplus)
174 		char *fname, int lang, int orConsts)
175 #else
176 		fname, lang, orConsts)
177 char *fname;
178 int lang;
179 int orConsts;
180 #endif
181 {
182     char	tmpname[32];
183     char	buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
184     int		fd, tfd;
185     int		diff = False;
186     int		c, len, tlen;
187     struct stat	sbuf;
188 
189     /* If it doesn't exist, just create it */
190     if (stat(fname, &sbuf)) {
191 	if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) {
192 	    fprintf(stderr, "gencat: Unable to create header file %s.\n", fname);
193 	    exit(1);
194 	}
195 	MCWriteConst(fd, lang, orConsts);
196 	close(fd);
197 	return;
198     }
199 
200     /* If it does exist, create a temp file for now */
201     sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
202     if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0) {
203 	fprintf(stderr, "gencat: Unable to open temporary file: %s\n", tmpname);
204 	exit(1);
205     }
206     unlink(tmpname);
207 
208     /* Write to the temp file and rewind */
209     MCWriteConst(tfd, lang, orConsts);
210 
211     /* Open the real header file */
212     if ((fd = open(fname, O_RDONLY)) < 0) {
213 	fprintf(stderr, "gencat: Unable to read header file: %s\n", fname);
214 	exit(1);
215     }
216 
217     /* Backup to the start of the temp file */
218     if (lseek(tfd, 0L, L_SET) < 0) {
219 	fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
220 	exit(1);
221     }
222 
223     /* Now compare them */
224     while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
225 	if ((len = read(fd, buf, BUFSIZ)) != tlen) {
226 	    diff = True;
227 	    goto done;
228 	}
229 	for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
230 	    if (*tptr != *cptr) {
231 		diff = True;
232 		goto done;
233 	    }
234 	}
235     }
236 done:
237     if (diff) {
238 	if (lseek(tfd, 0L, L_SET) < 0) {
239 	    fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
240 	    exit(1);
241 	}
242 	close(fd);
243 	if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) {
244 	    fprintf(stderr, "gencat: Unable to truncate header file: %s\n", fname);
245 	    exit(1);
246 	}
247 	while ((len = read(tfd, buf, BUFSIZ)) > 0) {
248 	    if (write(fd, buf, len) != len) {
249 		fprintf(stderr, "gencat: Error writing to header file: %s\n", fname);
250 	    }
251 	}
252     }
253     close(fd);
254     close(tfd);
255 }
256