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 #include <err.h> 33 #include <errno.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #define ungetchar(c) ungetc(c, stdin) 39 40 /* 41 * mkstr - create a string error message file by massaging C source 42 * 43 * Bill Joy UCB August 1977 44 * 45 * Modified March 1978 to hash old messages to be able to recompile 46 * without addding messages to the message file (usually) 47 * 48 * Based on an earlier program conceived by Bill Joy and Chuck Haley 49 * 50 * Program to create a string error message file 51 * from a group of C programs. Arguments are the name 52 * of the file where the strings are to be placed, the 53 * prefix of the new files where the processed source text 54 * is to be placed, and the files to be processed. 55 * 56 * The program looks for 'error("' in the source stream. 57 * Whenever it finds this, the following characters from the '"' 58 * to a '"' are replaced by 'seekpt' where seekpt is a 59 * pointer into the error message file. 60 * If the '(' is not immediately followed by a '"' no change occurs. 61 * 62 * The optional '-' causes strings to be added at the end of the 63 * existing error message file for recompilation of single routines. 64 */ 65 66 static FILE *mesgread, *mesgwrite; 67 static char name[100], *np; 68 69 void copystr(void); 70 int fgetNUL(char *, int, FILE *); 71 unsigned hashit(char *, int, unsigned); 72 void inithash(void); 73 int match(const char *); 74 int octdigit(char); 75 void process(void); 76 void usage(void); 77 78 int 79 main(int argc, char *argv[]) 80 { 81 char addon = 0; 82 size_t namelen; 83 84 argc--, argv++; 85 if (argc > 1 && argv[0][0] == '-') 86 addon++, argc--, argv++; 87 if (argc < 3) 88 usage(); 89 mesgwrite = fopen(argv[0], addon ? "a" : "w"); 90 if (mesgwrite == NULL) 91 err(1, "%s", argv[0]); 92 mesgread = fopen(argv[0], "r"); 93 if (mesgread == NULL) 94 err(1, "%s", argv[0]); 95 inithash(); 96 argc--, argv++; 97 namelen = strlcpy(name, argv[0], sizeof(name)); 98 if (namelen >= sizeof(name)) { 99 errno = ENAMETOOLONG; 100 err(1, "%s", argv[0]); 101 } 102 np = name + namelen; 103 argc--, argv++; 104 do { 105 if (strlcpy(np, argv[0], sizeof(name) - namelen) >= 106 sizeof(name) - namelen) { 107 errno = ENAMETOOLONG; 108 err(1, "%s%s", name, argv[0]); 109 } 110 if (freopen(name, "w", stdout) == NULL) 111 err(1, "%s", name); 112 if (freopen(argv[0], "r", stdin) == NULL) 113 err(1, "%s", argv[0]); 114 process(); 115 argc--, argv++; 116 } while (argc > 0); 117 exit(0); 118 } 119 120 void 121 usage(void) 122 { 123 fprintf(stderr, "usage: mkstr [-] mesgfile prefix file ...\n"); 124 exit(1); 125 } 126 127 void 128 process(void) 129 { 130 int c; 131 132 for (;;) { 133 c = getchar(); 134 if (c == EOF) 135 return; 136 if (c != 'e') { 137 putchar(c); 138 continue; 139 } 140 if (match("error(")) { 141 printf("error("); 142 c = getchar(); 143 if (c != '"') 144 putchar(c); 145 else 146 copystr(); 147 } 148 } 149 } 150 151 int 152 match(const char *ocp) 153 { 154 const char *cp; 155 int c; 156 157 for (cp = ocp + 1; *cp; cp++) { 158 c = getchar(); 159 if (c != *cp) { 160 while (ocp < cp) 161 putchar(*ocp++); 162 ungetchar(c); 163 return (0); 164 } 165 } 166 return (1); 167 } 168 169 void 170 copystr(void) 171 { 172 int c, ch; 173 char buf[512]; 174 char *cp = buf; 175 176 for (;;) { 177 if (cp == buf + sizeof(buf) - 2) 178 errx(1, "message too long"); 179 c = getchar(); 180 if (c == EOF) 181 break; 182 switch (c) { 183 184 case '"': 185 *cp++ = 0; 186 goto out; 187 case '\\': 188 c = getchar(); 189 switch (c) { 190 191 case 'b': 192 c = '\b'; 193 break; 194 case 't': 195 c = '\t'; 196 break; 197 case 'r': 198 c = '\r'; 199 break; 200 case 'n': 201 c = '\n'; 202 break; 203 case '\n': 204 continue; 205 case 'f': 206 c = '\f'; 207 break; 208 case '0': 209 c = 0; 210 break; 211 case '\\': 212 break; 213 default: 214 if (!octdigit(c)) 215 break; 216 c -= '0'; 217 ch = getchar(); 218 if (!octdigit(ch)) 219 break; 220 c <<= 7, c += ch - '0'; 221 ch = getchar(); 222 if (!octdigit(ch)) 223 break; 224 c <<= 3, c+= ch - '0', ch = -1; 225 break; 226 } 227 } 228 *cp++ = c; 229 } 230 out: 231 *cp = 0; 232 printf("%d", hashit(buf, 1, 0)); 233 } 234 235 int 236 octdigit(char c) 237 { 238 239 return (c >= '0' && c <= '7'); 240 } 241 242 void 243 inithash(void) 244 { 245 char buf[512]; 246 int mesgpt = 0; 247 248 rewind(mesgread); 249 while (fgetNUL(buf, sizeof buf, mesgread) != 0) { 250 hashit(buf, 0, mesgpt); 251 mesgpt += strlen(buf) + 2; 252 } 253 } 254 255 #define NBUCKETS 511 256 257 static struct hash { 258 long hval; 259 unsigned hpt; 260 struct hash *hnext; 261 } *bucket[NBUCKETS]; 262 263 unsigned 264 hashit(char *str, int really, unsigned fakept) 265 { 266 int i; 267 struct hash *hp; 268 char buf[512]; 269 long hashval = 0; 270 char *cp; 271 272 if (really) 273 fflush(mesgwrite); 274 for (cp = str; *cp;) 275 hashval = (hashval << 1) + *cp++; 276 i = hashval % NBUCKETS; 277 if (i < 0) 278 i += NBUCKETS; 279 if (really != 0) 280 for (hp = bucket[i]; hp != 0; hp = hp->hnext) 281 if (hp->hval == hashval) { 282 fseek(mesgread, (long) hp->hpt, 0); 283 fgetNUL(buf, sizeof buf, mesgread); 284 /* 285 fprintf(stderr, "Got (from %d) %s\n", hp->hpt, buf); 286 */ 287 if (strcmp(buf, str) == 0) 288 break; 289 } 290 if (!really || hp == 0) { 291 hp = (struct hash *) calloc(1, sizeof *hp); 292 if (hp == NULL) 293 err(1, NULL); 294 hp->hnext = bucket[i]; 295 hp->hval = hashval; 296 hp->hpt = really ? ftell(mesgwrite) : fakept; 297 if (really) { 298 fwrite(str, sizeof (char), strlen(str) + 1, mesgwrite); 299 fwrite("\n", sizeof (char), 1, mesgwrite); 300 } 301 bucket[i] = hp; 302 } 303 /* 304 fprintf(stderr, "%s hashed to %ld at %d\n", str, hp->hval, hp->hpt); 305 */ 306 return (hp->hpt); 307 } 308 309 int 310 fgetNUL(char *obuf, int rmdr, FILE *file) 311 { 312 int c; 313 char *buf = obuf; 314 315 while (--rmdr > 0 && (c = getc(file)) != 0 && c != EOF) 316 *buf++ = c; 317 *buf++ = 0; 318 getc(file); 319 return ((feof(file) || ferror(file)) ? 0 : 1); 320 } 321