1 /* $FreeBSD$ */ 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 <unistd.h> 41 #include "gencat.h" 42 43 /* 44 * The spec says the syntax is "gencat catfile msgfile...". 45 * We extend it to: 46 * gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]... 47 * Flags are order dependant, we'll take whatever lang was most recently chosen 48 * and use it to generate the next header file. The header files are generated 49 * at the point in the command line they are listed. Thus the sequence: 50 * gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H 51 * will put constants from foo.mcs into foo.h and constants from bar.mcs into 52 * bar.h. Constants are not saved in the catalog file, so nothing will come 53 * from that, even if things have been defined before. The constants in foo.h 54 * will be in C syntax, in bar.H in C++ syntax. 55 */ 56 57 static void writeIfChanged(char *, int, int); 58 59 static void 60 usage(void) 61 { 62 fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n" 63 " catfile msgfile [-h <header-file>]...\n"); 64 exit(1); 65 } 66 67 int 68 main(int argc, char *argv[]) 69 { 70 int ofd, ifd, i; 71 char *catfile = NULL; 72 char *input = NULL; 73 int lang = MCLangC; 74 int new = FALSE; 75 int orConsts = FALSE; 76 77 for (i = 1; i < argc; ++i) { 78 if (argv[i][0] == '-') { 79 if (strcmp(argv[i], "-lang") == 0) { 80 ++i; 81 if (strcmp(argv[i], "C") == 0) lang = MCLangC; 82 else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus; 83 else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC; 84 else { 85 errx(1, "unrecognized language: %s", argv[i]); 86 } 87 } else if (strcmp(argv[i], "-h") == 0) { 88 if (!input) 89 errx(1, "can't write to a header before reading something"); 90 ++i; 91 writeIfChanged(argv[i], lang, orConsts); 92 } else if (strcmp(argv[i], "-new") == 0) { 93 if (catfile) 94 errx(1, "you must specify -new before the catalog file name"); 95 new = TRUE; 96 } else if (strcmp(argv[i], "-or") == 0) { 97 orConsts = ~orConsts; 98 } else { 99 usage(); 100 } 101 } else { 102 if (!catfile) { 103 catfile = argv[i]; 104 if (new) { 105 if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) 106 errx(1, "unable to create a new %s", catfile); 107 } else if ((ofd = open(catfile, O_RDONLY)) < 0) { 108 if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0) 109 errx(1, "unable to create %s", catfile); 110 } else { 111 MCReadCat(ofd); 112 close(ofd); 113 if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0) 114 errx(1, "unable to truncate %s", catfile); 115 } 116 } else { 117 input = argv[i]; 118 if ((ifd = open(input, O_RDONLY)) < 0) 119 errx(1, "unable to read %s", input); 120 MCParse(ifd); 121 close(ifd); 122 } 123 } 124 } 125 if (catfile) { 126 MCWriteCat(ofd); 127 exit(0); 128 } else { 129 usage(); 130 } 131 return 0; 132 } 133 134 static void 135 writeIfChanged(char *fname, int lang, int orConsts) 136 { 137 char tmpname[32]; 138 char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr; 139 int fd, tfd; 140 int diff = FALSE; 141 int len, tlen; 142 struct stat sbuf; 143 144 /* If it doesn't exist, just create it */ 145 if (stat(fname, &sbuf)) { 146 if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) 147 errx(1, "unable to create header file %s", fname); 148 MCWriteConst(fd, lang, orConsts); 149 close(fd); 150 return; 151 } 152 153 /* If it does exist, create a temp file for now */ 154 sprintf(tmpname, "/tmp/gencat.%d", (int) getpid()); 155 if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0) 156 errx(1, "unable to open temporary file: %s", tmpname); 157 unlink(tmpname); 158 159 /* Write to the temp file and rewind */ 160 MCWriteConst(tfd, lang, orConsts); 161 162 /* Open the real header file */ 163 if ((fd = open(fname, O_RDONLY)) < 0) 164 errx(1, "unable to read header file: %s", fname); 165 166 /* Backup to the start of the temp file */ 167 if (lseek(tfd, (off_t)0, L_SET) < 0) 168 errx(1, "unable to seek in tempfile: %s", tmpname); 169 170 /* Now compare them */ 171 while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) { 172 if ((len = read(fd, buf, BUFSIZ)) != tlen) { 173 diff = TRUE; 174 goto done; 175 } 176 for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) { 177 if (*tptr != *cptr) { 178 diff = TRUE; 179 goto done; 180 } 181 } 182 } 183 done: 184 if (diff) { 185 if (lseek(tfd, (off_t)0, L_SET) < 0) 186 errx(1, "unable to seek in tempfile: %s", tmpname); 187 close(fd); 188 if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) 189 errx(1, "unable to truncate header file: %s", fname); 190 while ((len = read(tfd, buf, BUFSIZ)) > 0) { 191 if (write(fd, buf, (size_t)len) != len) 192 warnx("error writing to header file: %s", fname); 193 } 194 } 195 close(fd); 196 close(tfd); 197 } 198