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