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