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