1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 static const char copyright[] = 34 "@(#) Copyright (c) 1980, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 #endif /* not lint */ 40 41 #include <sys/cdefs.h> 42 #include <err.h> 43 #include <errno.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 48 #define ungetchar(c) ungetc(c, stdin) 49 50 /* 51 * mkstr - create a string error message file by massaging C source 52 * 53 * Bill Joy UCB August 1977 54 * 55 * Modified March 1978 to hash old messages to be able to recompile 56 * without addding messages to the message file (usually) 57 * 58 * Based on an earlier program conceived by Bill Joy and Chuck Haley 59 * 60 * Program to create a string error message file 61 * from a group of C programs. Arguments are the name 62 * of the file where the strings are to be placed, the 63 * prefix of the new files where the processed source text 64 * is to be placed, and the files to be processed. 65 * 66 * The program looks for 'error("' in the source stream. 67 * Whenever it finds this, the following characters from the '"' 68 * to a '"' are replaced by 'seekpt' where seekpt is a 69 * pointer into the error message file. 70 * If the '(' is not immediately followed by a '"' no change occurs. 71 * 72 * The optional '-' causes strings to be added at the end of the 73 * existing error message file for recompilation of single routines. 74 */ 75 76 static FILE *mesgread, *mesgwrite; 77 static char name[100], *np; 78 79 void copystr(void); 80 int fgetNUL(char *, int, FILE *); 81 unsigned hashit(char *, int, unsigned); 82 void inithash(void); 83 int match(const char *); 84 int octdigit(char); 85 void process(void); 86 void usage(void); 87 88 int 89 main(int argc, char *argv[]) 90 { 91 char addon = 0; 92 size_t namelen; 93 94 argc--, argv++; 95 if (argc > 1 && argv[0][0] == '-') 96 addon++, argc--, argv++; 97 if (argc < 3) 98 usage(); 99 mesgwrite = fopen(argv[0], addon ? "a" : "w"); 100 if (mesgwrite == NULL) 101 err(1, "%s", argv[0]); 102 mesgread = fopen(argv[0], "r"); 103 if (mesgread == NULL) 104 err(1, "%s", argv[0]); 105 inithash(); 106 argc--, argv++; 107 namelen = strlcpy(name, argv[0], sizeof(name)); 108 if (namelen >= sizeof(name)) { 109 errno = ENAMETOOLONG; 110 err(1, "%s", argv[0]); 111 } 112 np = name + namelen; 113 argc--, argv++; 114 do { 115 if (strlcpy(np, argv[0], sizeof(name) - namelen) >= 116 sizeof(name) - namelen) { 117 errno = ENAMETOOLONG; 118 err(1, "%s%s", name, argv[0]); 119 } 120 if (freopen(name, "w", stdout) == NULL) 121 err(1, "%s", name); 122 if (freopen(argv[0], "r", stdin) == NULL) 123 err(1, "%s", argv[0]); 124 process(); 125 argc--, argv++; 126 } while (argc > 0); 127 exit(0); 128 } 129 130 void 131 usage(void) 132 { 133 fprintf(stderr, "usage: mkstr [-] mesgfile prefix file ...\n"); 134 exit(1); 135 } 136 137 void 138 process(void) 139 { 140 int c; 141 142 for (;;) { 143 c = getchar(); 144 if (c == EOF) 145 return; 146 if (c != 'e') { 147 putchar(c); 148 continue; 149 } 150 if (match("error(")) { 151 printf("error("); 152 c = getchar(); 153 if (c != '"') 154 putchar(c); 155 else 156 copystr(); 157 } 158 } 159 } 160 161 int 162 match(const char *ocp) 163 { 164 const char *cp; 165 int c; 166 167 for (cp = ocp + 1; *cp; cp++) { 168 c = getchar(); 169 if (c != *cp) { 170 while (ocp < cp) 171 putchar(*ocp++); 172 ungetchar(c); 173 return (0); 174 } 175 } 176 return (1); 177 } 178 179 void 180 copystr(void) 181 { 182 int c, ch; 183 char buf[512]; 184 char *cp = buf; 185 186 for (;;) { 187 if (cp == buf + sizeof(buf) - 2) 188 errx(1, "message too long"); 189 c = getchar(); 190 if (c == EOF) 191 break; 192 switch (c) { 193 194 case '"': 195 *cp++ = 0; 196 goto out; 197 case '\\': 198 c = getchar(); 199 switch (c) { 200 201 case 'b': 202 c = '\b'; 203 break; 204 case 't': 205 c = '\t'; 206 break; 207 case 'r': 208 c = '\r'; 209 break; 210 case 'n': 211 c = '\n'; 212 break; 213 case '\n': 214 continue; 215 case 'f': 216 c = '\f'; 217 break; 218 case '0': 219 c = 0; 220 break; 221 case '\\': 222 break; 223 default: 224 if (!octdigit(c)) 225 break; 226 c -= '0'; 227 ch = getchar(); 228 if (!octdigit(ch)) 229 break; 230 c <<= 7, c += ch - '0'; 231 ch = getchar(); 232 if (!octdigit(ch)) 233 break; 234 c <<= 3, c+= ch - '0', ch = -1; 235 break; 236 } 237 } 238 *cp++ = c; 239 } 240 out: 241 *cp = 0; 242 printf("%d", hashit(buf, 1, 0)); 243 } 244 245 int 246 octdigit(char c) 247 { 248 249 return (c >= '0' && c <= '7'); 250 } 251 252 void 253 inithash(void) 254 { 255 char buf[512]; 256 int mesgpt = 0; 257 258 rewind(mesgread); 259 while (fgetNUL(buf, sizeof buf, mesgread) != 0) { 260 hashit(buf, 0, mesgpt); 261 mesgpt += strlen(buf) + 2; 262 } 263 } 264 265 #define NBUCKETS 511 266 267 static struct hash { 268 long hval; 269 unsigned hpt; 270 struct hash *hnext; 271 } *bucket[NBUCKETS]; 272 273 unsigned 274 hashit(char *str, int really, unsigned fakept) 275 { 276 int i; 277 struct hash *hp; 278 char buf[512]; 279 long hashval = 0; 280 char *cp; 281 282 if (really) 283 fflush(mesgwrite); 284 for (cp = str; *cp;) 285 hashval = (hashval << 1) + *cp++; 286 i = hashval % NBUCKETS; 287 if (i < 0) 288 i += NBUCKETS; 289 if (really != 0) 290 for (hp = bucket[i]; hp != 0; hp = hp->hnext) 291 if (hp->hval == hashval) { 292 fseek(mesgread, (long) hp->hpt, 0); 293 fgetNUL(buf, sizeof buf, mesgread); 294 /* 295 fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf); 296 */ 297 if (strcmp(buf, str) == 0) 298 break; 299 } 300 if (!really || hp == 0) { 301 hp = (struct hash *) calloc(1, sizeof *hp); 302 if (hp == NULL) 303 err(1, NULL); 304 hp->hnext = bucket[i]; 305 hp->hval = hashval; 306 hp->hpt = really ? ftell(mesgwrite) : fakept; 307 if (really) { 308 fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite); 309 fwrite("\n", sizeof (char), 1, mesgwrite); 310 } 311 bucket[i] = hp; 312 } 313 /* 314 fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt); 315 */ 316 return (hp->hpt); 317 } 318 319 int 320 fgetNUL(char *obuf, int rmdr, FILE *file) 321 { 322 int c; 323 char *buf = obuf; 324 325 while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) 326 *buf++ = c; 327 *buf++ = 0; 328 getc(file); 329 return ((feof(file) || ferror(file)) ? 0 : 1); 330 } 331