Merge from vendor branch DHCP:
[dragonfly.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 /* $DragonFly: src/usr.bin/gencat/gencat.c,v 1.2 2003/06/17 04:29:27 dillon Exp $ */
3
4 /***********************************************************
5 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
6
7                         All Rights Reserved
8
9 Permission to use, copy, modify, and distribute this software and its
10 documentation for any purpose and without fee is hereby granted,
11 provided that the above copyright notice appear in all copies and that
12 both that copyright notice and this permission notice appear in
13 supporting documentation, and that Alfalfa's name not be used in
14 advertising or publicity pertaining to distribution of the software
15 without specific, written prior permission.
16
17 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 SOFTWARE.
24
25 If you make any modifications, bugfixes or other changes to this software
26 we'd appreciate it if you could send a copy to us so we can keep things
27 up-to-date.  Many thanks.
28                                 Kee Hinckley
29                                 Alfalfa Software, Inc.
30                                 267 Allston St., #3
31                                 Cambridge, MA 02139  USA
32                                 nazgul@alfalfa.com
33
34 ******************************************************************/
35
36 #include <sys/types.h>
37 #include <sys/file.h>
38 #include <sys/stat.h>
39 #include <err.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 dependant, 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[32];
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     sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
158     if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0)
159                 errx(1, "unable to open temporary file: %s", tmpname);
160     unlink(tmpname);
161
162     /* Write to the temp file and rewind */
163     MCWriteConst(tfd, lang, orConsts);
164
165     /* Open the real header file */
166     if ((fd = open(fname, O_RDONLY)) < 0)
167                 errx(1, "unable to read header file: %s", fname);
168
169     /* Backup to the start of the temp file */
170     if (lseek(tfd, (off_t)0, L_SET) < 0)
171                 errx(1, "unable to seek in tempfile: %s", tmpname);
172
173     /* Now compare them */
174     while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
175         if ((len = read(fd, buf, BUFSIZ)) != tlen) {
176             diff = TRUE;
177             goto done;
178         }
179         for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
180             if (*tptr != *cptr) {
181                 diff = TRUE;
182                 goto done;
183             }
184         }
185     }
186 done:
187     if (diff) {
188         if (lseek(tfd, (off_t)0, L_SET) < 0)
189             errx(1, "unable to seek in tempfile: %s", tmpname);
190         close(fd);
191         if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0)
192             errx(1, "unable to truncate header file: %s", fname);
193         while ((len = read(tfd, buf, BUFSIZ)) > 0) {
194             if (write(fd, buf, (size_t)len) != len)
195                 warnx("error writing to header file: %s", fname);
196         }
197     }
198     close(fd);
199     close(tfd);
200 }