|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T e
Length: 29514 (0x734a)
Types: TextFile
Names: »extra.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
└─⟦c319c2751⟧ »unix3.0/TeX3.0.tar.Z«
└─⟦036c765ac⟧
└─⟦this⟧ »TeX3.0/mf/extra.c«
/* This file contains the C routines that implement most of the
system-dependent parts of Metafont.
This code was originally written by Tim Morgan, drawing from other
Unix ports of Metafont. */
#include <stdio.h>
#define EXTERN extern /* Don't instantiate data. */
#include "mfd.h" /* Includes "site.h" via "mf.h". */
#ifdef SYSV
#define index strchr
extern int sprintf ();
#else
extern char *sprintf ();
#endif /* SYSV */
/* C library routines. */
extern char *malloc (), *getenv ();
extern char *index (), *rindex ();
/* Place to save the command line arguments. */
static int gargc;
static char **gargv;
/* The name we are invoked as. */
static char *progname = NULL;
/* ``Open the terminal for input.'' Actually, copy any commandline
arguments for processing. If nothing is available, or we've been
called already (and hence, gargc==0), we return with last==first. */
void
topenin ()
{
register int i;
buffer[first] = '\0'; /* So the first strcat will work. */
#ifndef INIMF
/* If no format file specified, use progname as the default */
if ((gargc < 2 || gargv[1][0] != '&') && progname != NULL)
(void) sprintf ((char *) &buffer[first], "&%s ", progname);
progname = NULL;
#endif /* ! INIMF */
if (gargc > 1)
{ /* There are commandline arguments. */
for (i = 1; i < gargc; i++)
{
(void) strcat ((char *) &buffer[first], gargv[i]);
(void) strcat ((char *) &buffer[first], " ");
}
gargc = 0; /* Don't do this again */
}
/* Make last index 1 past the last non-blank character in buffer[]. */
for (last = first; buffer[last]; ++last) ;
for (--last; last >= first && buffer[last] == ' '; --last) ;
++last;
}
/* The entry point. Set up for rescanning the command line, then call
Metafont's main body. */
main (argc, argv)
int argc;
char *argv[];
{
#ifndef INIMF
if (readyalready != 314159)
{
if ((progname = rindex (argv[0], '/')) == NULL)
progname = argv[0];
else
++progname;
if (strcmp (progname, "virmf") == 0)
progname = NULL;
}
#endif /* !INIMF */
gargc = argc;
gargv = argv;
main_body ();
/*NOTREACHED*/
}
/* Return the integer absolute value. */
integer
zabs (x)
integer x;
{
if (x >= 0)
return (x);
return (-x);
}
/* Return the nth program argument into the string pointed at by s */
argv (n, s)
integer n;
char *s;
{
(void) sprintf (s + 1, "%s ", gargv[n - 1]);
}
/* Return true on end of line or eof of file, else false */
eoln (f)
FILE *f;
{
register int c;
if (feof (f))
return (1);
c = getc (f);
if (c != EOF)
(void) ungetc (c, f);
return (c == '\n' || c == EOF);
}
/* Open a file. Don't return unless successful. */
FILE *
Fopen (name, mode)
char *name, *mode;
{
FILE *result;
char *index (), *cp, my_name[FILENAMESIZE];
register int i = 0;
for (cp = name; *cp && *cp != ' ';)
my_name[i++] = *cp++;
my_name[i] = '\0';
result = fopen (my_name, mode);
if (!result)
{
perror (my_name);
exit (1);
}
return (result);
}
#ifdef sequent
/*
* On a Sequent Balance system under Dynix 2.1.1, if u and v are unsigned
* shorts or chars, then "(int) u - (int) v" does not perform a signed
* subtraction. Hence we have to call this routine to force the compiler
* to treat u and v as ints instead of unsigned ints. Sequent knows about
* the problem, but they don't seem to be in a hurry to fix it.
*/
integer
ztoint (x)
{
return (x);
}
#endif
/*
* Read a line of input as efficiently as possible while still
* looking like Pascal.
* Sets last=first and returns FALSE if eof is hit.
* Otherwise, TRUE is returned and either last==first or buffer[last-1]!=' ';
* that is, last == first + length(line except trailing whitespace).
*/
zinputln (f)
FILE *f;
{
register int i;
last = first;
#ifdef BSD
if (f == stdin)
clearerr (stdin);
#endif
while (last < bufsize && ((i = getc (f)) != EOF) && i != '\n')
{
#ifdef NONASCII
buffer[last++] = i;
#else
buffer[last++] = (i > 127 || i < 0) ? ' ' : i;
#endif
}
if (i == EOF && last == first)
return (false);
if (i != EOF && i != '\n')
{
/* We didn't get whole line because of lack of buffer space */
(void) fprintf (stderr, "\nUnable to read an entire line---bufsize=%d\n",
bufsize);
exit (1);
}
buffer[last] = ' ';
if (last >= maxbufstack)
maxbufstack = last; /* Record keeping */
/* Trim trailing whitespace by decrementing "last" */
while (last > first && (buffer[last - 1] == ' ' || buffer[last - 1] == '\t'))
--last;
/* Now, either last==first or buffer[last-1] != ' ' (or tab) */
/*
* If we're running on a system with ASCII characters like TeX's
* internal character set, we can save some time by not executing
* this loop.
*/
#ifdef NOTASCII
for (i = first; i <= last; i++)
buffer[i] = xord[buffer[i]];
#endif
return (true);
}
\f
/*
* Byte output routines.
*
* Tim Morgan 4/8/88
*/
#define aputc(x, f) \
if ((eightbits) putc(((x) & 255), f) != ((x) & 255)) \
perror("putc"), exit(1)
zbwrite2bytes (f, b)
FILE *f;
integer b;
{
aputc ((b >> 8), f);
aputc ((b & 255), f);
}
zbwrite4bytes (f, b)
FILE *f;
integer b;
{
aputc ((b >> 24), f);
aputc ((b >> 16), f);
aputc ((b >> 8), f);
aputc (b, f);
}
zbwritebuf (f, buf, first, last)
FILE *f;
eightbits buf[];
integer first, last;
{
if (!fwrite ((char *) &buf[first], sizeof (buf[0]),
(int) (last - first + 1), f))
{
perror ("fwrite");
exit (1);
}
}
\f
/* Switch-to-editor routine.
The following procedure is due to sjc@s1-c, and it doesn't work with
the new string pool any more. Most likely only a very simple change
is needed.
Metafont can call this to implement the 'e' feature in error-recovery
mode, invoking a text editor on the erroneous source file.
You should pass to "filename" the first character of the packed array
containing the filename, and to "fnlength" the size of the filename.
Ordinarily, this invokes what is defined in site.h. If you want a
different editor, create a shell environment variable MFEDIT
containing the string that invokes that editor, with "%s" indicating
where the filename goes and "%d" indicating where the decimal
linenumber (if any) goes. For example, a MFEDIT string for a variant
copy of "vi" might be:
setenv MFEDIT "/usr/local/bin/vi +%d %s"
*/
char *mfeditvalue = EDITOR;
calledit (filename, fnstart, fnlength, linenumber)
ASCIIcode *filename;
poolpointer fnstart;
integer fnlength, linenumber;
{
char *temp, *command, c;
int sdone, ddone, i;
sdone = ddone = 0;
filename += fnstart;
/* Close any open input files */
for (i = 1; i <= inopen; i++)
(void) fclose (inputfile[i]);
/* Replace default with environment variable if possible. */
if (NULL != (temp = (char *) getenv ("MFEDIT")))
mfeditvalue = temp;
/* Make command string containing envvalue, filename, and linenumber */
if (!(command = malloc ((unsigned) (strlen (mfeditvalue) + fnlength + 25))))
{
fprintf (stderr, "! Not enough memory to issue editor command\n");
exit (1);
}
temp = command;
while ((c = *mfeditvalue++) != '\0')
{
if (c == '%')
{
switch (c = *mfeditvalue++)
{
case 'd':
if (ddone)
{
fprintf (stderr,
"! Line number cannot appear twice in editor command\n");
exit (1);
}
(void) sprintf (temp, "%d", linenumber);
while (*temp != '\0')
temp++;
ddone = 1;
break;
case 's':
if (sdone)
{
fprintf (stderr,
"! Filename cannot appear twice in editor command\n");
exit (1);
}
i = 0;
while (i < fnlength)
*temp++ = filename[i++] & 0x7F;
sdone = 1;
break;
case '\0':
*temp++ = '%';
mfeditvalue--; /* Back up to \0 to force termination. */
break;
default:
*temp++ = '%';
*temp++ = c;
break;
}
}
else
*temp++ = c;
}
*temp = '\0';
/* Execute command. */
if (system (command) != 0)
fprintf (stderr, "! Trouble executing command `%s'.\n", command);
/* Quit, indicating Metafont had found an error before you typed "e". */
exit (1);
}
\f
/* Interrupt handling and date/time routines. */
#include <signal.h>
#ifdef BSD
#include <sys/time.h>
#else
#include <time.h>
#endif
/* Defined in mf.p; nonzero means an interrupt request is pending. */
extern integer interrupt;
/* Gets called when the user hits his interrupt key. Sets the global
``interrupt'' nonzero, then sets it up so that the next interrupt will
also be caught here. */
void
catchint ()
{
interrupt = 1;
(void) signal (SIGINT, catchint);
}
/* Stores minutes since midnight, current day, month and year into
*time, *day, *month and *year, respectively.
It also sets things up so that catchint() will get control on
interrupts. */
void
ydateandtime (minutes, day, month, year)
integer *minutes, *day, *month, *year;
{
long clock, time ();
struct tm *tmptr, *localtime ();
static SIGNAL_HANDLER_RETURN_TYPE (*psig) ();
clock = time ((long *) 0);
tmptr = localtime (&clock);
*minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
*day = tmptr->tm_mday;
*month = tmptr->tm_mon + 1;
*year = tmptr->tm_year + 1900;
if ((psig = signal (SIGINT, catchint)) != SIG_DFL)
(void) signal (SIGINT, psig);
}
\f
/* Faster arithmetic.
* These functions account for a significant percentage of the processing
* time used by Metafont, and have been recoded in assembly language for
* some classes of machines.
*
* User BEWARE! These codings make assumptions as to how the Pascal
* compiler passes arguments to external subroutines, which should not
* be ignored if you take this code to a different environment than
* it was originally designed and tested on! You have been warned!
*
* function makefraction(p, q: integer): fraction;
* { Calculate the function floor( (p * 2^28) / q + 0.5 ) }
* { if both p and q are positive. If not, then the value }
* { of makefraction is calculated as though both *were* }
* { positive, then the result sign adjusted. }
* { (e.g. makefraction ALWAYS rounds away from zero) }
* { In case of an overflow, return the largest possible }
* { value (2^32-1) with the correct sign, and set global }
* { variable "aritherror" to 1. Note that -2^32 is }
* { considered to be an illegal product for this type of }
* { arithmetic! }
*
* function takefraction(f: fraction; q: integer): integer;
* { Calculate the function floor( (p * q) / 2^28 + 0.5 ) }
* { takefraction() rounds in a similar manner as }
* { makefraction() above. }
*
*/
#define EL_GORDO 0x7fffffff /* 2^31-1 */
#define FRACTION_ONE 0x10000000 /* 2^28 */
#define FRACTION_HALF 0x08000000 /* 2^27 */
#define FRACTION_FOUR 0x40000000 /* 2^30 */
/* This code makes Metafont fail the trap test on my Vax 11/750 running
4.3bsd. Be sure to try the trap test yourself if you turn it on. */
#if defined(VAX4_2) || defined(VAX4_3) || defined(PYRAMID)
#if defined(VAX4_2) || defined(VAX4_3)
/*
* DEC VAX-11 class systems running 4.2 or 4.3 BSD Unix and Berkeley PC
*
* In the VAX assembler code that follows, remember, REMEMBER that
* a quad result addressed in Rn has most significant longword
* in Rn+1, NOT Rn!
*/
fraction
zmakefraction (p, q)
integer p, q;
{
register r11;
asm (" movl 8(ap),r0 "); /* q */
asm (" xorl3 4(ap),r0,r11 "); /* sign of prod */
asm (" jgeq Lmf1 ");
asm (" mnegl r0,r0 "); /* abs(q)*sign(p) */
asm ("Lmf1: ");
asm (" divl2 $2,r0 "); /* div 2 (signed) */
asm (" emul 4(ap),$0x10000000,r0,r0 "); /* p*2^28+(sign(p)*(q/2)) */
asm (" ediv 8(ap),r0,r0,r1 "); /*((p*2^28)+ */
asm (" jvs Lmf2 "); /* sign(p)*(q/2))/q */
asm (" mnegl r0,r1 "); /* check for 2^32 */
asm (" jvc Lmf3 ");
asm ("Lmf2: ");
asm (" movl $1,_aritherror ");
asm (" movl $0x7fffffff,r0 "); /* EL_GORDO */
asm (" tstl r11 ");
asm (" jgeq Lmf3 ");
asm (" mnegl r0,r0 ");
asm ("Lmf3: ");
asm (" ret ");
}
integer
ztakefraction (q, f)
integer q;
fraction f;
{
register r11;
asm (" movl $0x8000000,r0 "); /* 2^27 */
asm (" xorl3 4(ap),8(ap),r11 "); /* sign of prod */
asm (" jgeq Ltf1 ");
asm (" mnegl r0,r0 "); /* 2^27*sgn(prod) */
asm ("Ltf1: ");
asm (" emul 4(ap),8(ap),r0,r0 "); /* q*f+sgn(prod)*2^27 */
asm (" ediv $0x10000000,r0,r0,r1 "); /* div 2^28 (signed!) */
asm (" jvs Ltf2 ");
asm (" mnegl r0,r1 "); /* check for -2^32 */
asm (" jvc Ltf3 ");
asm ("Ltf2: ");
asm (" movl $1,_aritherror ");
asm (" movl $0x7fffffff,r0 "); /* EL_GORDO */
asm (" tstl r11 ");
asm (" jgeq Ltf3 ");
asm (" mnegl r0,r0 ");
asm ("Ltf3: ");
asm (" ret ");
}
#endif /* VAX */
#if defined(PYRAMID)
/*
* Pyramid 90x class of machines, running Pyramid's PASCAL
*/
fraction
zmakefraction (p, q)
integer p, q;
{
asm (" movw $0,lr0 "); /* high word of 64 bit accum */
asm (" mabsw pr0,lr1 "); /* lr1 = abs(p) */
asm (" mabsw pr1,lr2 "); /* lr2 = abs(q) */
asm (" ashll $29,lr0 "); /* lr0'lr1 = abs(p)*2^29 */
asm (" addw lr2,lr1 "); /* abs(p)*2^29 + abs(q) */
asm (" addwc $0,lr0 ");
asm (" ashrl $1,lr0 "); /* (abs(p)*2^28 + abs(q/2)) */
asm (" ediv lr2,lr0 "); /* (abs(p)*2^28 / abs(q)) + .5 */
asm (" bvc L1 ");
asm (" movw $1,_aritherror ");
asm (" movw $0x7fffffff,lr0 "); /* EL_GORDO */
asm ("L1: ");
asm (" xorw pr0,pr1 "); /* determine sign of result */
asm (" blt L2 ");
asm (" movw lr0,pr0 ");
asm (" ret ");
asm ("L2: ");
asm (" mnegw lr0,pr0 "); /* negative */
asm (" ret ");
}
integer
ztakefraction (q, f)
integer q;
fraction f;
{
asm (" movw $0,lr0 "); /* high word of 64 bit accum */
asm (" mabsw pr0,lr1 "); /* lr1 = abs(q) */
asm (" mabsw pr1,lr2 "); /* lr2 = abs(f) */
asm (" emul lr2,lr0 "); /* lr0'lr1 = abs(q) * abs(f) */
asm (" addw $0x08000000,lr1 "); /* (abs(q)*abs(f))+2^27 */
asm (" addwc $0,lr0 ");
asm (" ashll $4,lr0 "); /* lr0=(abs(q)*abs(f))/2^28 + .5 */
asm (" bvc L3 ");
asm (" movw $1,_aritherror ");
asm (" movw $0x7fffffff,lr0 "); /* EL_GORDO */
asm ("L3: ");
asm (" xorw pr0,pr1 "); /* construct sign of product */
asm (" blt L4 ");
asm (" movw lr0,pr0 ");
asm (" ret ");
asm ("L4: ");
asm (" mnegw lr0,pr0 "); /* negative */
asm (" ret ");
}
#endif /* PYRAMID */
#else /* the machine isn't anything special */
/* Here is essentially a verbatim copy of the WEB routines, with the
hope that the C compiler may do better than the Pascal on code
quality. */
fraction
zmakefraction (p, q)
register integer p, q;
{
int negative;
register int be_careful;
register fraction f;
int n;
if (p < 0)
{
negative = 1;
p = -p;
}
else
negative = 0;
if (q < 0)
{
negative = !negative;
q = -q;
}
n = p / q;
p = p % q;
if (n >= 8)
{
aritherror = true;
return (negative ? -EL_GORDO : EL_GORDO);
}
n = (n - 1) * FRACTION_ONE;
f = 1;
do
{
be_careful = p - q;
p = be_careful + p;
if (p >= 0)
{
f = f + f + 1;
}
else
{
f <<= 1;
p += q;
}
} while (f < FRACTION_ONE);
be_careful = p - q;
if ((be_careful + p) >= 0)
f += 1;
return (negative ? -(f + n) : (f + n));
}
integer
ztakefraction (q, f)
register integer q;
register fraction f;
{
int n, negative;
register int p, be_careful;
if (f < 0)
{
negative = 1;
f = -f;
}
else
negative = 0;
if (q < 0)
{
negative = !negative;
q = -q;
}
if (f < FRACTION_ONE)
n = 0;
else
{
n = f / FRACTION_ONE;
f = f % FRACTION_ONE;
if (q < (EL_GORDO / n))
n = n * q;
else
{
aritherror = true;
n = EL_GORDO;
}
}
f += FRACTION_ONE;
p = FRACTION_HALF;
if (q < FRACTION_FOUR)
do
{
if (f & 0x1)
p = (p + q) >> 1;
else
p >>= 1;
f >>= 1;
} while (f > 1);
else
do
{
if (f & 0x1)
p = p + ((q - p) >> 1);
else
p >>= 1;
f >>= 1;
} while (f > 1);
be_careful = n - EL_GORDO;
if ((be_careful + p) > 0)
{
aritherror = true;
n = EL_GORDO - p;
}
return (negative ? -(n + p) : (n + p));
}
#endif /* ! (VAX4_2 || PYRAMID) */
\f
/* File routines.
procedure setpaths;
{ initialize path database from environment variables }
function testaccess(
var filename: packed array of char;
var realfilename: packed array of char;
accessmode: integer;
filepath: integer ): boolean;
{ check file whose name is in array filename to see }
{ if it can be accessed using mode specified in accessmode. }
{ use the path selected by filepath to try to find file }
{ NB: >>> side effect <<< is to set array realfilename }
{ to complete path name of located file. }
{ Returns "TRUE" if found and can be accessed, else "FALSE" }
*/
#define R_OK 4
#undef close /* We're going to use the Unix close call */
/* These routines reference the following global variables and constants
from Metafont and its associated utilities. If the name or type of
these variables is changed in the Pascal source, be sure to make them
match here! */
#define READACCESS 4 /* args to test_access() */
#define WRITEACCESS 2
#define NOFILEPATH 0
#define TEXINPUTFILEPATH 1
#define TEXREADFILEPATH 2
#define TEXFONTFILEPATH 3
#define TEXFORMATFILEPATH 4
#define TEXPOOLFILEPATH 5
#define MFINPUTFILEPATH 6
#define MFBASEFILEPATH 7
#define MFPOOLFILEPATH 8
/* Fixed arrays are used to hold the paths, to avoid any possible
problems involving interaction of malloc and undump. */
char TeXinputpath[MAXPATHLENGTH] = TEXINPUTS;
char TeXfontpath[MAXPATHLENGTH] = TEXFONTS;
char TeXformatpath[MAXPATHLENGTH] = TEXFORMATS;
char TeXpoolpath[MAXPATHLENGTH] = TEXPOOL;
char MFinputpath[MAXPATHLENGTH] = MFINPUTS;
char MFbasepath[MAXPATHLENGTH] = MFBASES;
char MFpoolpath[MAXPATHLENGTH] = MFPOOL;
/* This copies at most n characters (including the null) from string s2
to string s1, giving an error message for paths that are too long,
identifying the PATH name. */
static void
path_copypath (s1, s2, n, pathname)
register char *s1, *s2, *pathname;
register int n;
{
while ((*s1++ = *s2++) != '\0')
if (--n == 0)
{
fprintf (stderr, "! Environment search path `%s' is too big.\n",
pathname);
*--s1 = '\0';
return; /* let user continue with truncated path */
}
}
/* This returns a char* pointer to the string selected by the path
specifier, or NULL if no path or an illegal path selected. */
static char *
path_select (pathsel)
integer pathsel;
{
char *pathstring = NULL;
switch (pathsel)
{
case TEXINPUTFILEPATH:
case TEXREADFILEPATH:
pathstring = TeXinputpath;
break;
case TEXFONTFILEPATH:
pathstring = TeXfontpath;
break;
case TEXFORMATFILEPATH:
pathstring = TeXformatpath;
break;
case TEXPOOLFILEPATH:
pathstring = TeXpoolpath;
break;
case MFINPUTFILEPATH:
pathstring = MFinputpath;
break;
case MFBASEFILEPATH:
pathstring = MFbasepath;
break;
case MFPOOLFILEPATH:
pathstring = MFpoolpath;
break;
default:
pathstring = NULL;
}
return (pathstring);
}
/*
path_buildname(filename, buffername, cpp)
makes buffername contain the directory at *cpp,
followed by '/', followed by the characters in filename
up until the first blank there, and finally a '\0'.
The cpp pointer is left pointing at the next directory
in the path.
But: if *cpp == NULL, then we are supposed to use filename as is.
*/
void
path_buildname (filename, buffername, cpp)
char *filename, *buffername;
char **cpp;
{
register char *p, *realname;
realname = buffername;
if ((p = *cpp) != NULL)
{
while ((*p != ':') && (*p != '\0'))
{
*realname++ = *p++;
if (realname >= &(buffername[FILENAMESIZE - 1]))
break;
}
if (*p == '\0')
*cpp = NULL; /* at end of path now */
else
*cpp = p + 1; /* else get past ':' */
*realname++ = '/'; /* separate the area from the name to follow */
}
/* now append filename to buffername... */
p = filename;
if (*p == 0)
p++;
while (*p != ' ' && *p != 0)
{
if (realname >= &(buffername[FILENAMESIZE - 1]))
{
fprintf (stderr, "! Full file name is too long\n");
break;
}
*realname++ = *p++;
}
*realname = '\0';
}
/*
setpaths is called to set up the default path arrays as follows:
if the user's environment has a value for the appropriate value,
then use it; otherwise, leave the current value of the array
(which may be the default path, or it may be the result of
a call to setpaths on a previous run that was made the subject of
an undump: this will give the maker of a preloaded Metafont the
option of providing a new set of "default" paths.
Note that we have to copy the string from the environment area, since
that will change on the next run (which matters if this is for a
preloaded Metafont).
*/
void
setpaths ()
{
register char *envpath;
if ((envpath = getenv ("TEXINPUTS")) != NULL)
path_copypath (TeXinputpath, envpath, MAXPATHLENGTH, "TEXINPUTS");
if ((envpath = getenv ("TEXFONTS")) != NULL)
path_copypath (TeXfontpath, envpath, MAXPATHLENGTH, "TEXFONTS");
if ((envpath = getenv ("TEXFORMATS")) != NULL)
path_copypath (TeXformatpath, envpath, MAXPATHLENGTH, "TEXFORMATS");
if ((envpath = getenv ("TEXPOOL")) != NULL)
path_copypath (TeXpoolpath, envpath, MAXPATHLENGTH, "TEXPOOL");
if ((envpath = getenv ("MFINPUTS")) != NULL)
path_copypath (MFinputpath, envpath, MAXPATHLENGTH, "MFINPUTS");
if ((envpath = getenv ("MFBASES")) != NULL)
path_copypath (MFbasepath, envpath, MAXPATHLENGTH, "MFBASES");
if ((envpath = getenv ("MFPOOL")) != NULL)
path_copypath (MFpoolpath, envpath, MAXPATHLENGTH, "MFPOOL");
}
/*
testaccess(filename, realfilename, amode, filepath)
Test whether or not the file whose name is in filename
can be opened for reading (if mode=READACCESS)
or writing (if mode=WRITEACCESS).
The filepath argument is one of the ...FILEPATH constants
defined above. If the filename given in filename does not
begin with '/', we try prepending all the ':'-separated directory
names in the appropriate path to the filename until access
can be made, if it ever can.
The realfilename array will contain the name that
yielded an access success.
*/
int
ztestaccess (filename, realfilename, amode, filepath)
char *filename, *realfilename;
integer amode, filepath;
{
register boolean ok;
register char *p;
char *curpathplace;
int f;
filename++;
realfilename++;
curpathplace = (*filename == '/') ? NULL : path_select (filepath);
do
{
path_buildname (filename, realfilename, &curpathplace);
if (amode == READACCESS)
{
/* use system call "access" to see if we could read it */
if (access (realfilename, 04) == 0)
ok = true;
else
ok = false;
}
else
{
/* WRITEACCESS: use creat to see if we could create it, but close
the file again if we're OK, to let pc open it for real */
if ((f = creat (realfilename, 0666)) >= 0)
{
ok = true;
(void) close (f);
}
else
ok = false;
}
} while (!ok && curpathplace != NULL);
if (ok)
{ /* pad realnameoffile with blanks, as Pascal wants */
for (p = realfilename; *p != '\0'; p++)
; /* nothing: find end of string */
while (p <= &(realfilename[FILENAMESIZE - 1]))
*p++ = ' ';
}
return (ok);
}
\f
/* On-line display routines. Here we use a dispatch table indexed by
the TERM environment variable to select the graphics routines
appropriate to the user's terminal. stdout must be connected to a
terminal for us to do any graphics. */
/* We don't want any other window routines screwing us up if we're
trying to do the trap test. We could have written another device for
the trap test, but the terminal type conditionals in initscreen argue
against that. */
#ifdef TRAP
#undef SUNWIN
#undef HP2627WIN
#undef X10WIN
#undef X11WIN
#undef TEKTRONIXWIN
#endif
#ifdef HP2627WIN
extern mf_hp2627_initscreen (), mf_hp2627_updatescreen ();
extern mf_hp2627_blankrectangle (), mf_hp2627_paintrow ();
#endif
#ifdef SUNWIN
extern mf_sun_initscreen (), mf_sun_updatescreen ();
extern mf_sun_blankrectangle (), mf_sun_paintrow ();
#endif
#ifdef TEKTRONIXWIN
extern mf_tektronix_initscreen (), mf_tektronix_updatescreen ();
extern mf_tektronix_blankrectangle (), mf_tektronix_paintrow ();
#endif
#ifdef X10WIN
extern mf_x10_initscreen (), mf_x10_updatescreen ();
extern mf_x10_blankrectangle (), mf_x10_paintrow ();
#endif
#ifdef X11WIN
extern mf_x11_initscreen (), mf_x11_updatescreen ();
extern mf_x11_blankrectangle (), mf_x11_paintrow ();
#endif
/* `mfwsw' contains the dispatch tables for each terminal. We map the
Pascal calls to the routines `init_screen', `update_screen',
`blank_rectangle', and `paint_row' into the appropriate entry point
for the specific terminal that MF is being run on. */
struct mfwin_sw
{
char *mfwsw_type; /* Name of terminal a la TERMCAP. */
int (*mfwsw_initscreen) ();
int (*mfwsw_updatescrn) ();
int (*mfwsw_blankrect) ();
int (*mfwsw_paintrow) ();
} mfwsw[] =
/* Now we have a long structure which initializes this array of
``Metafont window switches''. */
{
#ifdef HP2627WIN
{ "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
mf_hp2627_blankrectangle, mf_hp2627_paintrow },
#endif
#ifdef SUNWIN
{ "sun", mf_sun_initscreen, mf_sun_updatescreen,
mf_sun_blankrectangle, mf_sun_paintrow },
#endif
#ifdef TEKTRONIXWIN
{ "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
mf_tektronix_blankrectangle, mf_tektronix_paintrow },
#endif
#ifdef X10WIN
{ "xterm", mf_x10_initscreen, mf_x10_updatescreen,
mf_x10_blankrectangle, mf_x10_paintrow },
#endif
#ifdef X11WIN
{ "xterm",
mf_x11_initscreen, mf_x11_updatescreen,
mf_x11_blankrectangle, mf_x11_paintrow },
#endif
{ "Irrelevant", NULL, NULL, NULL, NULL },
/* Finally, we must have an entry with a terminal type of NULL. */
{ NULL, NULL, NULL, NULL, NULL }
}; /* End of the array initialization. */
/* This is a pointer to current mfwsw[] entry. */
static struct mfwin_sw *mfwp;
/* The following are routines that just jump to the correct
terminal-specific graphics code. If none of the routines in the
dispatch table exist, or they fail, we produce trap-compatible
output, i.e., the same words and punctuation that the unchanged
mf.web would produce. */
/* This returns true if window operations legal, else false. */
initscreen ()
{
#ifndef TRAP
register char *ttytype;
if ((ttytype = getenv ("TERM")) == NULL || !(isatty (fileno (stdout))))
return (0);
for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++)
if (!strncmp (mfwp->mfwsw_type, ttytype, strlen (mfwp->mfwsw_type))
|| !strcmp (ttytype, "emacs"))
if (mfwp->mfwsw_initscreen)
return ((*mfwp->mfwsw_initscreen) ());
else
{ /* Test terminal type */
printf ("Could not init_screen for `%s'.\n", ttytype);
return 1;
}
return 0;
#else /* TRAP */
return 1;
#endif
}
/* Initialize things. */
updatescreen ()
{
#ifndef TRAP
if (mfwp->mfwsw_updatescrn)
((*mfwp->mfwsw_updatescrn) ());
else
{
printf ("Updatescreen called\n");
}
#else /* TRAP */
fprintf (logfile, "Calling UPDATESCREEN\n");
#endif
}
/* This sets the rectangle bounded by ([left,right], [top,bottom]) to
the background color. */
blankrectangle (left, right, top, bottom)
screencol left, right;
screenrow top, bottom;
{
#ifndef TRAP
if (mfwp->mfwsw_blankrect)
((*mfwp->mfwsw_blankrect) (left, right, top, bottom));
else
{
printf ("Blankrectangle l=%d r=%d t=%d b=%d\n",
left, right, top, bottom);
}
#else /* TRAP */
fprintf (logfile, "\nCalling BLANKRECTANGLE(%d,%d,%d,%d)\n", left,
right, top, bottom);
#endif
}
/* This paints ROW, starting with the color INIT_COLOR.
TRANSITION_VECTOR then specifies the length of the run; then we
switch colors. This goes on for VECTOR_SIZE transitions. */
zpaintrow (row, init_color, transition_vector, vector_size)
screenrow row;
pixelcolor init_color;
transspec transition_vector;
screencol vector_size;
{
#ifndef TRAP
if (mfwp->mfwsw_paintrow)
((*mfwp->mfwsw_paintrow) (row, init_color,
transition_vector, vector_size));
else
{
printf ("Paintrow r=%d c=%d v=");
while (vector_size-- > 0)
printf ("%d ", transition_vector++);
printf ("\n");
}
#else /* TRAP */
unsigned k;
fprintf (logfile, "Calling PAINTROW(%d,%d;", row, init_color);
for (k = 0; k <= vector_size; k++)
{
fprintf (logfile, "%d", transition_vector[k]);
if (k != vector_size)
fprintf (logfile, ",");
}
fprintf (logfile, ")\n");
#endif
}