Home | History | Annotate | Line # | Download | only in m4
misc.c revision 1.2
      1 /*  File   : misc.c
      2     Author : Ozan Yigit
      3     Updated: 26-Mar-1993
      4     Purpose: Miscellaneous support code for PD M4.
      5 */
      6 
      7 #include "mdef.h"
      8 #include "extr.h"
      9 #include "ourlims.h"
     10 
     11 #ifdef	DUFFCP
     12 
     13 /*  This version of the ANSI standard function memcpy()
     14     uses Duff's Device (tm Tom Duff)  to unroll the copying loop:
     15 	while (count-- > 0) *to++ = *from++;
     16 */
     17 void memcpy(to, from, count)
     18     register char *from, *to;
     19     register int count;
     20     {
     21 	if (count > 0) {
     22 	    register int loops = (count+8-1) >> 3;	/* div 8 round up */
     23 
     24 	    switch (count & (8-1)) {	/* mod 8 */
     25 	        case 0: do {	*to++ = *from++;
     26 		case 7:		*to++ = *from++;
     27 		case 6:		*to++ = *from++;
     28 		case 5:		*to++ = *from++;
     29 		case 4:		*to++ = *from++;
     30 		case 3:		*to++ = *from++;
     31 		case 2:		*to++ = *from++;
     32 		case 1:		*to++ = *from++;
     33 			} while (--loops > 0);
     34 	    }
     35 	}
     36     }
     37 
     38 #endif
     39 
     40 
     41 /*  strsave(s)
     42     return a new malloc()ed copy of s -- same as V.3's strdup().
     43 */
     44 char *strsave(s)
     45     char *s;
     46     {
     47 	register int n = strlen(s)+1;
     48 	char *p = malloc(n);
     49 
     50 	if (p) memcpy(p, s, n);
     51 	return p;
     52     }
     53 
     54 
     55 /*  indx(s1, s2)
     56     if s1 can be decomposed as alpha || s2 || omega, return the length
     57     of the shortest such alpha, otherwise return -1.
     58 */
     59 int indx(s1, s2)
     60     char *s1;
     61     char *s2;
     62     {
     63 	register char *t;
     64 	register char *m;
     65 	register char *p;
     66 
     67 	for (p = s1; *p; p++) {
     68 	    for (t = p, m = s2; *m && *m == *t; m++, t++);
     69 	    if (!*m) return p-s1;
     70 	}
     71 	return -1;
     72     }
     73 
     74 
     75 char pbmsg[] = "m4: too many characters pushed back";
     76 
     77 /*  Xputback(c)
     78     push character c back onto the input stream.
     79     This is now macro putback() in misc.h
     80 */
     81 void Xputback(c)
     82     char c;
     83     {
     84 	if (bp < endpbb) *bp++ = c; else error(pbmsg);
     85     }
     86 
     87 
     88 /*  pbstr(s)
     89     push string s back onto the input stream.
     90     putback() has been unfolded here to improve performance.
     91     Example:
     92 	s = <ABC>
     93 	bp = <more stuff>
     94     After the call:
     95 	bp = <more stuffCBA>
     96     It would be more efficient if we ran the pushback buffer in the
     97     opposite direction
     98 */
     99 void pbstr(s)
    100     register char *s;
    101     {
    102 	register char *es;
    103 	register char *zp;
    104 
    105 	zp = bp;
    106 	for (es = s; *es; ) es++;	/* now es points to terminating NUL */
    107 	bp += es-s;			/* advance bp as far as it should go */
    108 	if (bp >= endpbb) error("m4: too many characters to push back");
    109 	while (es > s) *zp++ = *--es;
    110     }
    111 
    112 
    113 /*  pbqtd(s)
    114     pushes string s back "quoted", doing whatever has to be done to it to
    115     make sure that the result will evaluate to the original value.  As it
    116     happens, we have only to add lquote and rquote.
    117 */
    118 void pbqtd(s)
    119     register char *s;
    120     {
    121 	register char *es;
    122 	register char *zp;
    123 
    124 	zp = bp;
    125 	for (es = s; *es; ) es++;	/* now es points to terminating NUL */
    126 	bp += 2+es-s;			/* advance bp as far as it should go */
    127 	if (bp >= endpbb) error("m4: too many characters to push back");
    128 	*zp++ = rquote;
    129 	while (es > s) *zp++ = *--es;
    130 	*zp++ = lquote;
    131     }
    132 
    133 
    134 /*  pbnum(n)
    135     convert a number to a (decimal) string and push it back.
    136     The original definition did not work for MININT; this does.
    137 */
    138 void pbnum(n)
    139     int n;
    140     {
    141 	register int num;
    142 
    143 	num = n > 0 ? -n : n;	/* MININT <= num <= 0 */
    144 	do {
    145 	    putback('0' - (num % 10));
    146 	} while ((num /= 10) < 0);
    147 	if (n < 0) putback('-');
    148     }
    149 
    150 
    151 /*  pbrad(n, r, m)
    152     converts a number n to base r ([-36..-2] U [2..36]), with at least
    153     m digits.  If r == 10 and m == 1, this is exactly the same as pbnum.
    154     However, this uses the function int2str() from R.A.O'Keefe's public
    155     domain string library, and puts the results of that back.
    156     The Unix System V Release 3 version of m4 accepts radix 1;
    157     THIS VERSION OF M4 DOES NOT ACCEPT RADIX 1 OR -1,
    158     nor do we accept radix < -36 or radix > 36.  At the moment such bad
    159     radices quietly produce nothing.  The V.3 treatment of radix 1 is
    160 	push back abs(n) "1"s, then
    161 	if n < 0, push back one "-".
    162     Until I come across something which uses it, I can't bring myself to
    163     implement this.
    164 
    165     I have, however, found a use for radix 0.  Unsurprisingly, it is
    166     related to radix 0 in Edinburgh Prolog.
    167 	eval('c1c2...cn', 0, m)
    168     pushes back max(m-n,0) blanks and the characters c1...cn.  This can
    169     adjust to any byte size as long as UCHAR_MAX = (1 << CHAR_BIT) - 1.
    170     In particular, eval(c, 0) where 0 < c <= UCHAR_MAX, pushes back the
    171     character with code c.  Note that this has to agree with eval(); so
    172     both of them have to use the same byte ordering.
    173 */
    174 void pbrad(n, r, m)
    175     long int n;
    176     int r, m;
    177     {
    178 	char buffer[34];
    179 	char *p;
    180 	int L;
    181 
    182 	if (r == 0) {
    183 	    unsigned long int x = (unsigned long)n;
    184 	    int n;
    185 
    186 	    for (n = 0; x; x >>= CHAR_BIT, n++) buffer[n] = x & UCHAR_MAX;
    187 	    for (L = n; --L >= 0; ) putback(buffer[L]);
    188 	    for (L = m-n; --L >= 0; ) putback(' ');
    189 	    return;
    190 	}
    191 	L = m - (int2str(p = buffer, -r, n)-buffer);
    192 	if (buffer[0] == '-') L++, p++;
    193 	if (L > 0) {
    194 	    pbstr(p);
    195 	    while (--L >= 0) putback('0');
    196 	    if (p != buffer) putback('-');
    197 	} else {
    198 	    pbstr(buffer);
    199 	}
    200     }
    201 
    202 
    203 char csmsg[] = "m4: string space overflow";
    204 
    205 /*  chrsave(c)
    206     put the character c in the string space.
    207 */
    208 void Xchrsave(c)
    209     char c;
    210     {
    211 #if 0
    212 	if (sp < 0) putc(c, active); else
    213 #endif
    214 	if (ep < endest) *ep++ = c; else
    215 	error(csmsg);
    216     }
    217 
    218 
    219 /*  getdiv(ind)
    220     read in a diversion file and then delete it.
    221 */
    222 void getdiv(ind)
    223     int ind;
    224     {
    225 	register int c;
    226 	register FILE *dfil;
    227 	register FILE *afil;
    228 
    229 	afil = active;
    230 	if (outfile[ind] == afil)
    231 	    error("m4: undivert: diversion still active.");
    232 	(void) fclose(outfile[ind]);
    233 	outfile[ind] = NULL;
    234 	m4temp[UNIQUE] = '0' + ind;
    235 	if ((dfil = fopen(m4temp, "r")) == NULL)
    236 	    error("m4: cannot undivert.");
    237 	while ((c = getc(dfil)) != EOF) putc(c, afil);
    238 	(void) fclose(dfil);
    239 
    240 #if vms
    241 	if (remove(m4temp)) error("m4: cannot unlink.");
    242 #else
    243 	if (unlink(m4temp) == -1) error("m4: cannot unlink.");
    244 #endif
    245     }
    246 
    247 
    248 /*  killdiv()
    249     delete all the diversion files which have been created.
    250 */
    251 void killdiv()
    252     {
    253 	register int n;
    254 
    255 	for (n = 0; n < MAXOUT; n++) {
    256 	    if (outfile[n] != NULL) {
    257 		(void) fclose(outfile[n]);
    258 		m4temp[UNIQUE] = '0' + n;
    259 #if unix
    260 		(void) unlink(m4temp);
    261 #else
    262 		(void) remove(m4temp);
    263 #endif
    264 	    }
    265 	}
    266     }
    267 
    268 
    269 /*  error(s)
    270     close all files, report a fatal error, and quit, letting the caller know.
    271 */
    272 void error(s)
    273     char *s;
    274     {
    275 	killdiv();
    276 	fprintf(stderr, "%s\n", s);
    277 	exit(1);
    278     }
    279 
    280 
    281 /*  Interrupt handling
    282 */
    283 static char *msg = "\ninterrupted.";
    284 
    285 #ifdef	__STDC__
    286 void onintr(int signo)
    287 #else
    288 onintr()
    289 #endif
    290     {
    291 	error(msg);
    292     }
    293 
    294 
    295 void usage()
    296     {
    297 	fprintf(stderr, "Usage: m4 [-e] [-[BHST]int] [-Dname[=val]] [-Uname]\n");
    298 	exit(1);
    299     }
    300 
    301 #ifdef GETOPT
    302 /* Henry Spencer's getopt() - get option letter from argv */
    303 
    304 char *optarg;			/* Global argument pointer. */
    305 int optind = 0;			/* Global argv index. */
    306 
    307 static char *scan = NULL;	/* Private scan pointer. */
    308 
    309 #ifndef	__STDC__
    310 extern	char *index();
    311 #define strchr index
    312 #endif
    313 
    314 int getopt(argc, argv, optstring)
    315     int argc;
    316     char **argv;
    317     char *optstring;
    318     {
    319 	register char c;
    320 	register char *place;
    321 
    322 	optarg = NULL;
    323 
    324 	if (scan == NULL || *scan == '\0') {
    325 	    if (optind == 0) optind++;
    326 	    if (optind >= argc
    327 	     || argv[optind][0] != '-'
    328 	     || argv[optind][1] == '\0')
    329 		return EOF;
    330 	    if (strcmp(argv[optind], "--") == 0) {
    331 		optind++;
    332 		return EOF;
    333 	    }
    334 	    scan = argv[optind]+1;
    335 	    optind++;
    336 	}
    337 	c = *scan++;
    338 	place = strchr(optstring, c);
    339 
    340 	if (place == NULL || c == ':') {
    341 	    fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
    342 	    return '?';
    343 	}
    344 	place++;
    345 	if (*place == ':') {
    346 	    if (*scan != '\0') {
    347 		optarg = scan;
    348 		scan = NULL;
    349 	    } else {
    350 		optarg = argv[optind];
    351 		optind++;
    352 	    }
    353 	}
    354 	return c;
    355     }
    356 #endif
    357 
    358