NetBSD/usr.bin/m4/misc.c

358 lines
7.5 KiB
C
Raw Normal View History

/* File : misc.c
Author : Ozan Yigit
Updated: 26-Mar-1993
Purpose: Miscellaneous support code for PD M4.
*/
1993-03-21 12:45:37 +03:00
#include "mdef.h"
#include "extr.h"
#include "ourlims.h"
#ifdef DUFFCP
/* This version of the ANSI standard function memcpy()
uses Duff's Device (tm Tom Duff) to unroll the copying loop:
while (count-- > 0) *to++ = *from++;
*/
void memcpy(to, from, count)
register char *from, *to;
register int count;
{
if (count > 0) {
register int loops = (count+8-1) >> 3; /* div 8 round up */
switch (count & (8-1)) { /* mod 8 */
case 0: do { *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
} while (--loops > 0);
}
}
}
#endif
/* strsave(s)
return a new malloc()ed copy of s -- same as V.3's strdup().
*/
char *strsave(s)
char *s;
{
register int n = strlen(s)+1;
char *p = malloc(n);
if (p) memcpy(p, s, n);
return p;
}
/* indx(s1, s2)
if s1 can be decomposed as alpha || s2 || omega, return the length
of the shortest such alpha, otherwise return -1.
*/
int indx(s1, s2)
char *s1;
char *s2;
{
register char *t;
register char *m;
register char *p;
for (p = s1; *p; p++) {
for (t = p, m = s2; *m && *m == *t; m++, t++);
if (!*m) return p-s1;
}
return -1;
}
char pbmsg[] = "m4: too many characters pushed back";
/* Xputback(c)
push character c back onto the input stream.
This is now macro putback() in misc.h
*/
void Xputback(c)
char c;
{
if (bp < endpbb) *bp++ = c; else error(pbmsg);
}
/* pbstr(s)
push string s back onto the input stream.
putback() has been unfolded here to improve performance.
Example:
s = <ABC>
bp = <more stuff>
After the call:
bp = <more stuffCBA>
It would be more efficient if we ran the pushback buffer in the
opposite direction
*/
void pbstr(s)
register char *s;
{
register char *es;
register char *zp;
zp = bp;
for (es = s; *es; ) es++; /* now es points to terminating NUL */
bp += es-s; /* advance bp as far as it should go */
if (bp >= endpbb) error("m4: too many characters to push back");
while (es > s) *zp++ = *--es;
}
/* pbqtd(s)
pushes string s back "quoted", doing whatever has to be done to it to
make sure that the result will evaluate to the original value. As it
happens, we have only to add lquote and rquote.
*/
void pbqtd(s)
register char *s;
{
register char *es;
1993-03-21 12:45:37 +03:00
register char *zp;
zp = bp;
for (es = s; *es; ) es++; /* now es points to terminating NUL */
bp += 2+es-s; /* advance bp as far as it should go */
if (bp >= endpbb) error("m4: too many characters to push back");
*zp++ = rquote;
while (es > s) *zp++ = *--es;
*zp++ = lquote;
}
/* pbnum(n)
convert a number to a (decimal) string and push it back.
The original definition did not work for MININT; this does.
*/
void pbnum(n)
int n;
{
register int num;
num = n > 0 ? -n : n; /* MININT <= num <= 0 */
do {
putback('0' - (num % 10));
} while ((num /= 10) < 0);
if (n < 0) putback('-');
}
/* pbrad(n, r, m)
converts a number n to base r ([-36..-2] U [2..36]), with at least
m digits. If r == 10 and m == 1, this is exactly the same as pbnum.
However, this uses the function int2str() from R.A.O'Keefe's public
domain string library, and puts the results of that back.
The Unix System V Release 3 version of m4 accepts radix 1;
THIS VERSION OF M4 DOES NOT ACCEPT RADIX 1 OR -1,
nor do we accept radix < -36 or radix > 36. At the moment such bad
radices quietly produce nothing. The V.3 treatment of radix 1 is
push back abs(n) "1"s, then
if n < 0, push back one "-".
Until I come across something which uses it, I can't bring myself to
implement this.
I have, however, found a use for radix 0. Unsurprisingly, it is
related to radix 0 in Edinburgh Prolog.
eval('c1c2...cn', 0, m)
pushes back max(m-n,0) blanks and the characters c1...cn. This can
adjust to any byte size as long as UCHAR_MAX = (1 << CHAR_BIT) - 1.
In particular, eval(c, 0) where 0 < c <= UCHAR_MAX, pushes back the
character with code c. Note that this has to agree with eval(); so
both of them have to use the same byte ordering.
*/
void pbrad(n, r, m)
long int n;
int r, m;
{
char buffer[34];
char *p;
int L;
1993-03-21 12:45:37 +03:00
if (r == 0) {
unsigned long int x = (unsigned long)n;
int n;
for (n = 0; x; x >>= CHAR_BIT, n++) buffer[n] = x & UCHAR_MAX;
for (L = n; --L >= 0; ) putback(buffer[L]);
for (L = m-n; --L >= 0; ) putback(' ');
return;
}
L = m - (int2str(p = buffer, -r, n)-buffer);
if (buffer[0] == '-') L++, p++;
if (L > 0) {
pbstr(p);
while (--L >= 0) putback('0');
if (p != buffer) putback('-');
} else {
pbstr(buffer);
}
}
char csmsg[] = "m4: string space overflow";
/* chrsave(c)
put the character c in the string space.
*/
void Xchrsave(c)
char c;
{
#if 0
if (sp < 0) putc(c, active); else
#endif
if (ep < endest) *ep++ = c; else
error(csmsg);
}
/* getdiv(ind)
read in a diversion file and then delete it.
*/
void getdiv(ind)
int ind;
{
register int c;
register FILE *dfil;
register FILE *afil;
afil = active;
if (outfile[ind] == afil)
error("m4: undivert: diversion still active.");
(void) fclose(outfile[ind]);
outfile[ind] = NULL;
m4temp[UNIQUE] = '0' + ind;
if ((dfil = fopen(m4temp, "r")) == NULL)
error("m4: cannot undivert.");
while ((c = getc(dfil)) != EOF) putc(c, afil);
(void) fclose(dfil);
#if vms
if (remove(m4temp)) error("m4: cannot unlink.");
#else
if (unlink(m4temp) == -1) error("m4: cannot unlink.");
#endif
}
/* killdiv()
delete all the diversion files which have been created.
*/
void killdiv()
{
register int n;
for (n = 0; n < MAXOUT; n++) {
if (outfile[n] != NULL) {
(void) fclose(outfile[n]);
m4temp[UNIQUE] = '0' + n;
#if unix
(void) unlink(m4temp);
#else
(void) remove(m4temp);
#endif
}
}
}
/* error(s)
close all files, report a fatal error, and quit, letting the caller know.
*/
void error(s)
char *s;
{
killdiv();
fprintf(stderr, "%s\n", s);
exit(1);
}
/* Interrupt handling
*/
1993-03-21 12:45:37 +03:00
static char *msg = "\ninterrupted.";
#ifdef __STDC__
void onintr(int signo)
#else
onintr()
#endif
{
error(msg);
}
void usage()
{
fprintf(stderr, "Usage: m4 [-e] [-[BHST]int] [-Dname[=val]] [-Uname]\n");
exit(1);
}
#ifdef GETOPT
/* Henry Spencer's getopt() - get option letter from argv */
char *optarg; /* Global argument pointer. */
int optind = 0; /* Global argv index. */
static char *scan = NULL; /* Private scan pointer. */
#ifndef __STDC__
extern char *index();
#define strchr index
#endif
int getopt(argc, argv, optstring)
int argc;
char **argv;
char *optstring;
{
register char c;
register char *place;
optarg = NULL;
if (scan == NULL || *scan == '\0') {
if (optind == 0) optind++;
if (optind >= argc
|| argv[optind][0] != '-'
|| argv[optind][1] == '\0')
return EOF;
if (strcmp(argv[optind], "--") == 0) {
optind++;
return EOF;
}
scan = argv[optind]+1;
optind++;
}
c = *scan++;
place = strchr(optstring, c);
if (place == NULL || c == ':') {
fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
return '?';
}
place++;
if (*place == ':') {
if (*scan != '\0') {
optarg = scan;
scan = NULL;
} else {
optarg = argv[optind];
optind++;
}
}
return c;
}
#endif