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