1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ozan Yigit. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)serv.c 5.2 (Berkeley) 06/01/90"; 13 #endif /* not lint */ 14 15 /* 16 * serv.c 17 * Facility: m4 macro processor 18 * by: oz 19 */ 20 21 #include "mdef.h" 22 #include "extr.h" 23 24 extern ndptr lookup(); 25 extern ndptr addent(); 26 extern char *strsave(); 27 28 char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */ 29 30 /* 31 * expand - user-defined macro expansion 32 * 33 */ 34 expand(argv, argc) 35 register char *argv[]; 36 register int argc; 37 { 38 register char *t; 39 register char *p; 40 register int n; 41 register int argno; 42 43 t = argv[0]; /* defn string as a whole */ 44 p = t; 45 while (*p) 46 p++; 47 p--; /* last character of defn */ 48 while (p > t) { 49 if (*(p-1) != ARGFLAG) 50 putback(*p); 51 else { 52 switch (*p) { 53 54 case '#': 55 pbnum(argc-2); 56 break; 57 case '0': 58 case '1': 59 case '2': 60 case '3': 61 case '4': 62 case '5': 63 case '6': 64 case '7': 65 case '8': 66 case '9': 67 if ((argno = *p - '0') < argc-1) 68 pbstr(argv[argno+1]); 69 break; 70 case '*': 71 for (n = argc - 1; n > 2; n--) { 72 pbstr(argv[n]); 73 putback(','); 74 } 75 pbstr(argv[2]); 76 break; 77 default : 78 putback(*p); 79 break; 80 } 81 p--; 82 } 83 p--; 84 } 85 if (p == t) /* do last character */ 86 putback(*p); 87 } 88 89 /* 90 * dodefine - install definition in the table 91 * 92 */ 93 dodefine(name, defn) 94 register char *name; 95 register char *defn; 96 { 97 register ndptr p; 98 99 if (!*name) 100 error("m4: null definition."); 101 if (strcmp(name, defn) == 0) 102 error("m4: recursive definition."); 103 if ((p = lookup(name)) == nil) 104 p = addent(name); 105 else if (p->defn != null) 106 free(p->defn); 107 if (!*defn) 108 p->defn = null; 109 else 110 p->defn = strsave(defn); 111 p->type = MACRTYPE; 112 } 113 114 /* 115 * dodefn - push back a quoted definition of 116 * the given name. 117 */ 118 119 dodefn(name) 120 char *name; 121 { 122 register ndptr p; 123 124 if ((p = lookup(name)) != nil && p->defn != null) { 125 putback(rquote); 126 pbstr(p->defn); 127 putback(lquote); 128 } 129 } 130 131 /* 132 * dopushdef - install a definition in the hash table 133 * without removing a previous definition. Since 134 * each new entry is entered in *front* of the 135 * hash bucket, it hides a previous definition from 136 * lookup. 137 */ 138 dopushdef(name, defn) 139 register char *name; 140 register char *defn; 141 { 142 register ndptr p; 143 144 if (!*name) 145 error("m4: null definition"); 146 if (strcmp(name, defn) == 0) 147 error("m4: recursive definition."); 148 p = addent(name); 149 if (!*defn) 150 p->defn = null; 151 else 152 p->defn = strsave(defn); 153 p->type = MACRTYPE; 154 } 155 156 /* 157 * dodumpdef - dump the specified definitions in the hash 158 * table to stderr. If nothing is specified, the entire 159 * hash table is dumped. 160 * 161 */ 162 dodump(argv, argc) 163 register char *argv[]; 164 register int argc; 165 { 166 register int n; 167 ndptr p; 168 169 if (argc > 2) { 170 for (n = 2; n < argc; n++) 171 if ((p = lookup(argv[n])) != nil) 172 fprintf(stderr, dumpfmt, p->name, 173 p->defn); 174 } 175 else { 176 for (n = 0; n < HASHSIZE; n++) 177 for (p = hashtab[n]; p != nil; p = p->nxtptr) 178 fprintf(stderr, dumpfmt, p->name, 179 p->defn); 180 } 181 } 182 183 /* 184 * doifelse - select one of two alternatives - loop. 185 * 186 */ 187 doifelse(argv,argc) 188 register char *argv[]; 189 register int argc; 190 { 191 cycle { 192 if (strcmp(argv[2], argv[3]) == 0) 193 pbstr(argv[4]); 194 else if (argc == 6) 195 pbstr(argv[5]); 196 else if (argc > 6) { 197 argv += 3; 198 argc -= 3; 199 continue; 200 } 201 break; 202 } 203 } 204 205 /* 206 * doinclude - include a given file. 207 * 208 */ 209 doincl(ifile) 210 char *ifile; 211 { 212 if (ilevel+1 == MAXINP) 213 error("m4: too many include files."); 214 if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) { 215 ilevel++; 216 return (1); 217 } 218 else 219 return (0); 220 } 221 222 #ifdef EXTENDED 223 /* 224 * dopaste - include a given file without any 225 * macro processing. 226 */ 227 dopaste(pfile) 228 char *pfile; 229 { 230 FILE *pf; 231 register int c; 232 233 if ((pf = fopen(pfile, "r")) != NULL) { 234 while((c = getc(pf)) != EOF) 235 putc(c, active); 236 (void) fclose(pf); 237 return(1); 238 } 239 else 240 return(0); 241 } 242 #endif 243 244 /* 245 * dochq - change quote characters 246 * 247 */ 248 dochq(argv, argc) 249 register char *argv[]; 250 register int argc; 251 { 252 if (argc > 2) { 253 if (*argv[2]) 254 lquote = *argv[2]; 255 if (argc > 3) { 256 if (*argv[3]) 257 rquote = *argv[3]; 258 } 259 else 260 rquote = lquote; 261 } 262 else { 263 lquote = LQUOTE; 264 rquote = RQUOTE; 265 } 266 } 267 268 /* 269 * dochc - change comment characters 270 * 271 */ 272 dochc(argv, argc) 273 register char *argv[]; 274 register int argc; 275 { 276 if (argc > 2) { 277 if (*argv[2]) 278 scommt = *argv[2]; 279 if (argc > 3) { 280 if (*argv[3]) 281 ecommt = *argv[3]; 282 } 283 else 284 ecommt = ECOMMT; 285 } 286 else { 287 scommt = SCOMMT; 288 ecommt = ECOMMT; 289 } 290 } 291 292 /* 293 * dodivert - divert the output to a temporary file 294 * 295 */ 296 dodiv(n) 297 register int n; 298 { 299 if (n < 0 || n >= MAXOUT) 300 n = 0; /* bitbucket */ 301 if (outfile[n] == NULL) { 302 m4temp[UNIQUE] = n + '0'; 303 if ((outfile[n] = fopen(m4temp, "w")) == NULL) 304 error("m4: cannot divert."); 305 } 306 oindex = n; 307 active = outfile[n]; 308 } 309 310 /* 311 * doundivert - undivert a specified output, or all 312 * other outputs, in numerical order. 313 */ 314 doundiv(argv, argc) 315 register char *argv[]; 316 register int argc; 317 { 318 register int ind; 319 register int n; 320 321 if (argc > 2) { 322 for (ind = 2; ind < argc; ind++) { 323 n = atoi(argv[ind]); 324 if (n > 0 && n < MAXOUT && outfile[n] != NULL) 325 getdiv(n); 326 327 } 328 } 329 else 330 for (n = 1; n < MAXOUT; n++) 331 if (outfile[n] != NULL) 332 getdiv(n); 333 } 334 335 /* 336 * dosub - select substring 337 * 338 */ 339 dosub (argv, argc) 340 register char *argv[]; 341 register int argc; 342 { 343 register char *ap, *fc, *k; 344 register int nc; 345 346 if (argc < 5) 347 nc = MAXTOK; 348 else 349 #ifdef EXPR 350 nc = expr(argv[4]); 351 #else 352 nc = atoi(argv[4]); 353 #endif 354 ap = argv[2]; /* target string */ 355 #ifdef EXPR 356 fc = ap + expr(argv[3]); /* first char */ 357 #else 358 fc = ap + atoi(argv[3]); /* first char */ 359 #endif 360 if (fc >= ap && fc < ap+strlen(ap)) 361 for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--) 362 putback(*k); 363 } 364 365 /* 366 * map: 367 * map every character of s1 that is specified in from 368 * into s3 and replace in s. (source s1 remains untouched) 369 * 370 * This is a standard implementation of map(s,from,to) function of ICON 371 * language. Within mapvec, we replace every character of "from" with 372 * the corresponding character in "to". If "to" is shorter than "from", 373 * than the corresponding entries are null, which means that those 374 * characters dissapear altogether. Furthermore, imagine 375 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 376 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 377 * ultimately maps to `*'. In order to achieve this effect in an efficient 378 * manner (i.e. without multiple passes over the destination string), we 379 * loop over mapvec, starting with the initial source character. if the 380 * character value (dch) in this location is different than the source 381 * character (sch), sch becomes dch, once again to index into mapvec, until 382 * the character value stabilizes (i.e. sch = dch, in other words 383 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 384 * character, it will stabilize, since mapvec[0] == 0 at all times. At the 385 * end, we restore mapvec* back to normal where mapvec[n] == n for 386 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 387 * about 5 times faster than any algorithm that makes multiple passes over 388 * destination string. 389 * 390 */ 391 392 map(dest,src,from,to) 393 register char *dest; 394 register char *src; 395 register char *from; 396 register char *to; 397 { 398 register char *tmp; 399 register char sch, dch; 400 static char mapvec[128] = { 401 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 402 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 403 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 404 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 405 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 406 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 407 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 408 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 409 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 410 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 411 120, 121, 122, 123, 124, 125, 126, 127 412 }; 413 414 if (*src) { 415 tmp = from; 416 /* 417 * create a mapping between "from" and "to" 418 */ 419 while (*from) 420 mapvec[*from++] = (*to) ? *to++ : (char) 0; 421 422 while (*src) { 423 sch = *src++; 424 dch = mapvec[sch]; 425 while (dch != sch) { 426 sch = dch; 427 dch = mapvec[sch]; 428 } 429 if (*dest = dch) 430 dest++; 431 } 432 /* 433 * restore all the changed characters 434 */ 435 while (*tmp) { 436 mapvec[*tmp] = *tmp; 437 tmp++; 438 } 439 } 440 *dest = (char) 0; 441 } 442