Annotation of src/usr.bin/m4/serv.c, Revision 1.1
1.1 ! deraadt 1: /* $NetBSD: serv.c,v 1.7 1995/09/28 05:37:47 tls Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1989
! 5: * The Regents of the University of California. All rights reserved.
! 6: * (c) UNIX System Laboratories, Inc.
! 7: * All or some portions of this file are derived from material licensed
! 8: * to the University of California by American Telephone and Telegraph
! 9: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
! 10: * the permission of UNIX System Laboratories, Inc.
! 11: *
! 12: * This code is derived from software contributed to Berkeley by
! 13: * Ozan Yigit.
! 14: *
! 15: * Redistribution and use in source and binary forms, with or without
! 16: * modification, are permitted provided that the following conditions
! 17: * are met:
! 18: * 1. Redistributions of source code must retain the above copyright
! 19: * notice, this list of conditions and the following disclaimer.
! 20: * 2. Redistributions in binary form must reproduce the above copyright
! 21: * notice, this list of conditions and the following disclaimer in the
! 22: * documentation and/or other materials provided with the distribution.
! 23: * 3. All advertising materials mentioning features or use of this software
! 24: * must display the following acknowledgement:
! 25: * This product includes software developed by the University of
! 26: * California, Berkeley and its contributors.
! 27: * 4. Neither the name of the University nor the names of its contributors
! 28: * may be used to endorse or promote products derived from this software
! 29: * without specific prior written permission.
! 30: *
! 31: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 32: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 33: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 34: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 35: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 36: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 37: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 38: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 39: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 40: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 41: * SUCH DAMAGE.
! 42: */
! 43:
! 44: #ifndef lint
! 45: #if 0
! 46: static char sccsid[] = "@(#)serv.c 5.4 (Berkeley) 1/21/94";
! 47: #else
! 48: static char rcsid[] = "$NetBSD: serv.c,v 1.7 1995/09/28 05:37:47 tls Exp $";
! 49: #endif
! 50: #endif /* not lint */
! 51:
! 52: /*
! 53: * serv.c
! 54: * Facility: m4 macro processor
! 55: * by: oz
! 56: */
! 57:
! 58: #include <stdio.h>
! 59: #include <stdlib.h>
! 60: #include <string.h>
! 61: #include "mdef.h"
! 62: #include "extr.h"
! 63: #include "pathnames.h"
! 64:
! 65: extern ndptr lookup();
! 66: extern ndptr addent();
! 67:
! 68: char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
! 69:
! 70: /*
! 71: * expand - user-defined macro expansion
! 72: *
! 73: */
! 74: expand(argv, argc)
! 75: register char *argv[];
! 76: register int argc;
! 77: {
! 78: register char *t;
! 79: register char *p;
! 80: register int n;
! 81: register int argno;
! 82:
! 83: t = argv[0]; /* defn string as a whole */
! 84: p = t;
! 85: while (*p)
! 86: p++;
! 87: p--; /* last character of defn */
! 88: while (p > t) {
! 89: if (*(p-1) != ARGFLAG)
! 90: putback(*p);
! 91: else {
! 92: switch (*p) {
! 93:
! 94: case '#':
! 95: pbnum(argc-2);
! 96: break;
! 97: case '0':
! 98: case '1':
! 99: case '2':
! 100: case '3':
! 101: case '4':
! 102: case '5':
! 103: case '6':
! 104: case '7':
! 105: case '8':
! 106: case '9':
! 107: if ((argno = *p - '0') < argc-1)
! 108: pbstr(argv[argno+1]);
! 109: break;
! 110: case '*':
! 111: for (n = argc - 1; n > 2; n--) {
! 112: pbstr(argv[n]);
! 113: putback(',');
! 114: }
! 115: pbstr(argv[2]);
! 116: break;
! 117: default :
! 118: putback(*p);
! 119: break;
! 120: }
! 121: p--;
! 122: }
! 123: p--;
! 124: }
! 125: if (p == t) /* do last character */
! 126: putback(*p);
! 127: }
! 128:
! 129: /*
! 130: * dodefine - install definition in the table
! 131: *
! 132: */
! 133: dodefine(name, defn)
! 134: register char *name;
! 135: register char *defn;
! 136: {
! 137: register ndptr p;
! 138:
! 139: if (!*name)
! 140: error("m4: null definition.");
! 141: if (strcmp(name, defn) == 0)
! 142: error("m4: recursive definition.");
! 143: if ((p = lookup(name)) == nil)
! 144: p = addent(name);
! 145: else if (p->defn != null)
! 146: free(p->defn);
! 147: if (!*defn)
! 148: p->defn = null;
! 149: else
! 150: p->defn = strdup(defn);
! 151: p->type = MACRTYPE;
! 152: }
! 153:
! 154: /*
! 155: * dodefn - push back a quoted definition of
! 156: * the given name.
! 157: */
! 158:
! 159: dodefn(name)
! 160: char *name;
! 161: {
! 162: register ndptr p;
! 163:
! 164: if ((p = lookup(name)) != nil && p->defn != null) {
! 165: putback(rquote);
! 166: pbstr(p->defn);
! 167: putback(lquote);
! 168: }
! 169: }
! 170:
! 171: /*
! 172: * dopushdef - install a definition in the hash table
! 173: * without removing a previous definition. Since
! 174: * each new entry is entered in *front* of the
! 175: * hash bucket, it hides a previous definition from
! 176: * lookup.
! 177: */
! 178: dopushdef(name, defn)
! 179: register char *name;
! 180: register char *defn;
! 181: {
! 182: register ndptr p;
! 183:
! 184: if (!*name)
! 185: error("m4: null definition");
! 186: if (strcmp(name, defn) == 0)
! 187: error("m4: recursive definition.");
! 188: p = addent(name);
! 189: if (!*defn)
! 190: p->defn = null;
! 191: else
! 192: p->defn = strdup(defn);
! 193: p->type = MACRTYPE;
! 194: }
! 195:
! 196: /*
! 197: * dodumpdef - dump the specified definitions in the hash
! 198: * table to stderr. If nothing is specified, the entire
! 199: * hash table is dumped.
! 200: *
! 201: */
! 202: dodump(argv, argc)
! 203: register char *argv[];
! 204: register int argc;
! 205: {
! 206: register int n;
! 207: ndptr p;
! 208:
! 209: if (argc > 2) {
! 210: for (n = 2; n < argc; n++)
! 211: if ((p = lookup(argv[n])) != nil)
! 212: fprintf(stderr, dumpfmt, p->name,
! 213: p->defn);
! 214: }
! 215: else {
! 216: for (n = 0; n < HASHSIZE; n++)
! 217: for (p = hashtab[n]; p != nil; p = p->nxtptr)
! 218: fprintf(stderr, dumpfmt, p->name,
! 219: p->defn);
! 220: }
! 221: }
! 222:
! 223: /*
! 224: * doifelse - select one of two alternatives - loop.
! 225: *
! 226: */
! 227: doifelse(argv,argc)
! 228: register char *argv[];
! 229: register int argc;
! 230: {
! 231: cycle {
! 232: if (strcmp(argv[2], argv[3]) == 0)
! 233: pbstr(argv[4]);
! 234: else if (argc == 6)
! 235: pbstr(argv[5]);
! 236: else if (argc > 6) {
! 237: argv += 3;
! 238: argc -= 3;
! 239: continue;
! 240: }
! 241: break;
! 242: }
! 243: }
! 244:
! 245: /*
! 246: * doinclude - include a given file.
! 247: *
! 248: */
! 249: doincl(ifile)
! 250: char *ifile;
! 251: {
! 252: if (ilevel+1 == MAXINP)
! 253: error("m4: too many include files.");
! 254: if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
! 255: ilevel++;
! 256: return (1);
! 257: }
! 258: else
! 259: return (0);
! 260: }
! 261:
! 262: #ifdef EXTENDED
! 263: /*
! 264: * dopaste - include a given file without any
! 265: * macro processing.
! 266: */
! 267: dopaste(pfile)
! 268: char *pfile;
! 269: {
! 270: FILE *pf;
! 271: register int c;
! 272:
! 273: if ((pf = fopen(pfile, "r")) != NULL) {
! 274: while((c = getc(pf)) != EOF)
! 275: putc(c, active);
! 276: (void) fclose(pf);
! 277: return(1);
! 278: }
! 279: else
! 280: return(0);
! 281: }
! 282: #endif
! 283:
! 284: /*
! 285: * dochq - change quote characters
! 286: *
! 287: */
! 288: dochq(argv, argc)
! 289: register char *argv[];
! 290: register int argc;
! 291: {
! 292: if (argc > 2) {
! 293: if (*argv[2])
! 294: lquote = *argv[2];
! 295: if (argc > 3) {
! 296: if (*argv[3])
! 297: rquote = *argv[3];
! 298: }
! 299: else
! 300: rquote = lquote;
! 301: }
! 302: else {
! 303: lquote = LQUOTE;
! 304: rquote = RQUOTE;
! 305: }
! 306: }
! 307:
! 308: /*
! 309: * dochc - change comment characters
! 310: *
! 311: */
! 312: dochc(argv, argc)
! 313: register char *argv[];
! 314: register int argc;
! 315: {
! 316: if (argc > 2) {
! 317: if (*argv[2])
! 318: scommt = *argv[2];
! 319: if (argc > 3) {
! 320: if (*argv[3])
! 321: ecommt = *argv[3];
! 322: }
! 323: else
! 324: ecommt = ECOMMT;
! 325: }
! 326: else {
! 327: scommt = SCOMMT;
! 328: ecommt = ECOMMT;
! 329: }
! 330: }
! 331:
! 332: /*
! 333: * dodivert - divert the output to a temporary file
! 334: *
! 335: */
! 336: dodiv(n)
! 337: register int n;
! 338: {
! 339: if (n < 0 || n >= MAXOUT)
! 340: n = 0; /* bitbucket */
! 341: if (outfile[n] == NULL) {
! 342: m4temp[UNIQUE] = n + '0';
! 343: if ((outfile[n] = fopen(m4temp, "w")) == NULL)
! 344: error("m4: cannot divert.");
! 345: }
! 346: oindex = n;
! 347: active = outfile[n];
! 348: }
! 349:
! 350: /*
! 351: * doundivert - undivert a specified output, or all
! 352: * other outputs, in numerical order.
! 353: */
! 354: doundiv(argv, argc)
! 355: register char *argv[];
! 356: register int argc;
! 357: {
! 358: register int ind;
! 359: register int n;
! 360:
! 361: if (argc > 2) {
! 362: for (ind = 2; ind < argc; ind++) {
! 363: n = atoi(argv[ind]);
! 364: if (n > 0 && n < MAXOUT && outfile[n] != NULL)
! 365: getdiv(n);
! 366:
! 367: }
! 368: }
! 369: else
! 370: for (n = 1; n < MAXOUT; n++)
! 371: if (outfile[n] != NULL)
! 372: getdiv(n);
! 373: }
! 374:
! 375: /*
! 376: * dosub - select substring
! 377: *
! 378: */
! 379: dosub (argv, argc)
! 380: register char *argv[];
! 381: register int argc;
! 382: {
! 383: register char *ap, *fc, *k;
! 384: register int nc;
! 385:
! 386: if (argc < 5)
! 387: nc = MAXTOK;
! 388: else
! 389: #ifdef EXPR
! 390: nc = expr(argv[4]);
! 391: #else
! 392: nc = atoi(argv[4]);
! 393: #endif
! 394: ap = argv[2]; /* target string */
! 395: #ifdef EXPR
! 396: fc = ap + expr(argv[3]); /* first char */
! 397: #else
! 398: fc = ap + atoi(argv[3]); /* first char */
! 399: #endif
! 400: if (fc >= ap && fc < ap+strlen(ap))
! 401: for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
! 402: putback(*k);
! 403: }
! 404:
! 405: /*
! 406: * map:
! 407: * map every character of s1 that is specified in from
! 408: * into s3 and replace in s. (source s1 remains untouched)
! 409: *
! 410: * This is a standard implementation of map(s,from,to) function of ICON
! 411: * language. Within mapvec, we replace every character of "from" with
! 412: * the corresponding character in "to". If "to" is shorter than "from",
! 413: * than the corresponding entries are null, which means that those
! 414: * characters dissapear altogether. Furthermore, imagine
! 415: * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
! 416: * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
! 417: * ultimately maps to `*'. In order to achieve this effect in an efficient
! 418: * manner (i.e. without multiple passes over the destination string), we
! 419: * loop over mapvec, starting with the initial source character. if the
! 420: * character value (dch) in this location is different than the source
! 421: * character (sch), sch becomes dch, once again to index into mapvec, until
! 422: * the character value stabilizes (i.e. sch = dch, in other words
! 423: * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
! 424: * character, it will stabilize, since mapvec[0] == 0 at all times. At the
! 425: * end, we restore mapvec* back to normal where mapvec[n] == n for
! 426: * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
! 427: * about 5 times faster than any algorithm that makes multiple passes over
! 428: * destination string.
! 429: *
! 430: */
! 431:
! 432: map(dest,src,from,to)
! 433: register char *dest;
! 434: register char *src;
! 435: register char *from;
! 436: register char *to;
! 437: {
! 438: register char *tmp;
! 439: register char sch, dch;
! 440: static char mapvec[128] = {
! 441: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
! 442: 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
! 443: 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
! 444: 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
! 445: 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
! 446: 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
! 447: 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
! 448: 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
! 449: 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
! 450: 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
! 451: 120, 121, 122, 123, 124, 125, 126, 127
! 452: };
! 453:
! 454: if (*src) {
! 455: tmp = from;
! 456: /*
! 457: * create a mapping between "from" and "to"
! 458: */
! 459: while (*from)
! 460: mapvec[*from++] = (*to) ? *to++ : (char) 0;
! 461:
! 462: while (*src) {
! 463: sch = *src++;
! 464: dch = mapvec[sch];
! 465: while (dch != sch) {
! 466: sch = dch;
! 467: dch = mapvec[sch];
! 468: }
! 469: if (*dest = dch)
! 470: dest++;
! 471: }
! 472: /*
! 473: * restore all the changed characters
! 474: */
! 475: while (*tmp) {
! 476: mapvec[*tmp] = *tmp;
! 477: tmp++;
! 478: }
! 479: }
! 480: *dest = (char) 0;
! 481: }