diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /systems/knuth/local/mf-sparc |
Initial commit
Diffstat (limited to 'systems/knuth/local/mf-sparc')
-rw-r--r-- | systems/knuth/local/mf-sparc/Makefile | 73 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/ext.c | 457 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/ext.h | 38 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/gftype.in | 2 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/ini_to_trap | 38 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/inimf.ch | 1505 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/mf.pool | 824 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/mf_arith.c | 142 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/mf_sunwin.c | 90 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/mf_window.h | 15 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/plain.base | bin | 0 -> 56640 bytes | |||
-rw-r--r-- | systems/knuth/local/mf-sparc/plain.log | 16 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/trap1.in | 3 | ||||
-rw-r--r-- | systems/knuth/local/mf-sparc/trap2.in | 1 |
14 files changed, 3204 insertions, 0 deletions
diff --git a/systems/knuth/local/mf-sparc/Makefile b/systems/knuth/local/mf-sparc/Makefile new file mode 100644 index 0000000000..2bdb6536d4 --- /dev/null +++ b/systems/knuth/local/mf-sparc/Makefile @@ -0,0 +1,73 @@ +# Make executable files for this workstation, using the master TeX sources + +PFLAGS= -I.. +CFLAGS= -g -I.. -I/usr/openwin/include +#CFLAGS= -O -I.. -I/usr/openwin/include +#LIBS= -lsuntool -lsunwindow -lpixrect +LIBS= -L/usr/openwin/lib -lxview -lolgx -lX11 + +PC= time pc + +all: inimf + +traptest: trapmf + -trapmf < trap1.in + mv trap.log trapin.log + -trapmf < trap2.in | tee trap.fot + gftype trap.72270gf trap.typ < gftype.in + tftopl trap.tfm trap.pl + rm -f *.dif + -diff trapin.log ../../dist/mf/trapin.log > trapin.log.dif + -diff trap.log ../../dist/mf/trap.log > trap.log.dif + -diff trap.fot ../../dist/mf/trap.fot > trap.fot.dif + -diff trap.typ ../../dist/mf/trap.typ > trap.typ.dif + -diff trap.pl ../../dist/mf/trap.pl > trap.pl.dif + more trapin.log.dif trap.log.dif trap.typ.dif trap.fot.dif trap.pl.dif + +%.p: %.ch + tangle ../../dist/mf/mf.web $*.ch + mv ../../dist/mf/mf.pool . + mv ../../dist/mf/mf.p $*.p + +inimf.ch: ../../dist/mf/mf.web + +trapmf.ch: inimf.ch ini_to_trap + ini_to_trap inimf.ch trapmf.ch + +%.o: %.p + ${PC} ${PFLAGS} -c $*.p + +trapmf.o: trapmf.p + ${PC} -g ${PFLAGS} -c trapmf.p + +inimf: inimf.o ext.o mf_arith.o mf_sunwin.o + pc ${PFLAGS} -o inimf inimf.o ext.o mf_arith.o mf_sunwin.o ${LIBS} + +trapmf: trapmf.o ext.o mf_arith.o + pc -g ${PFLAGS} -o trapmf trapmf.o ext.o mf_arith.o + cp ../../dist/mf/trap.mf . + +ext.o: ext.c ext.h ../h00vars.h ../mfpaths.h + cc ${CFLAGS} -c ext.c + +mf_arith.o: mf_arith.c +mf_sunwin.o: mf_sunwin.c + +plain.base: ../../dist/lib/plain.mf ../lib/local.mf + -inimf plain \\input local \\dump + +install: # doit make install + mv inimf /usr/local/bin + rm /usr/local/bin/mf + ln /usr/local/bin/inimf /usr/local/bin/mf + make plain.base + +installtrap: # when the trap test is satisfactory + mv trap.mf trapin.log trap.log trap.fot trap.typ trap.pl ../../dist/mf + +clean: + rm -f *.p *.o *~ *.mf trapmf* trap.* trapin* + @echo "Remaining files should be:" + @echo "Makefile gftype.in mf.pool mf_window.h trap1.in" + @echo "ext.c ini_to_trap* mf_arith.c plain.base trap2.in" + @echo "ext.h inimf.ch mf_sunwin.c plain.log" diff --git a/systems/knuth/local/mf-sparc/ext.c b/systems/knuth/local/mf-sparc/ext.c new file mode 100644 index 0000000000..dfbf0b2bbb --- /dev/null +++ b/systems/knuth/local/mf-sparc/ext.c @@ -0,0 +1,457 @@ +/* external procedures called by MF */ +#include <sys/signal.h> +#include <sys/time.h> +#include "mfpaths.h" /* defines MAXINPATHCHARS, defaultinputpath, etc. */ +#include "h00vars.h" + +/* The following are for closing files */ + +closea(f) + int *f; /* actually, file pointer, but it doesn't matter */ +{ + close1(f); +} + +closeb(f) + int *f; /* actually, file pointer, but it doesn't matter */ +{ + close1(f); +} + +closew(f) + int *f; /* actually, file pointer, but it doesn't matter */ +{ + close1(f); +} + +extern int interrupt; /* To be made nonzero to tell MF about interrupts */ + +/* +** catchint() +** +** 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. +** +*/ + +catchint() +{ + interrupt = 1; + signal(SIGINT,catchint); +} + +/* +** dateandtime(time, day, month, year) +** +** Stores minutes since midnight, current day, month and year into +** *time, *day, *month and *year, respectively. +** +** Also, set things up so that catchint() will get control on interrupts. +** +*/ + +dateandtime(minutes, day, month, year) +int *minutes, *day, *month, *year; +{ + long clock; + struct tm *tmptr, *localtime(); + + clock = time(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; + signal(SIGINT,catchint); +} + + +/* fixed arrays are used to hold the paths, to avoid any possible problems + involving interaction of malloc and undump */ + +char inputpath[MAXINPATHCHARS] = defaultinputpath; +char basepath[MAXOTHPATHCHARS] = defaultbasepath; +char poolpath[MAXOTHPATHCHARS] = defaultpoolpath; + +char *getenv(); + +/* + * setpaths is called to set up the arrays inputpath, basepath, and + * poolpath 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 MF 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 MF). + */ +setpaths() +{ + register char *envpath; + + if ((envpath = getenv("MFINPUTS")) != NULL) + excopypath(inputpath,envpath,MAXINPATHCHARS); + if ((envpath = getenv("MFBASES")) != NULL) + excopypath(basepath,envpath,MAXOTHPATHCHARS); + if ((envpath = getenv("MFPOOL")) != NULL) + excopypath(poolpath,envpath,MAXOTHPATHCHARS); +} + +/* + * excopypath(s1,s2,n) copies at most n characters (including the null) + * from string s2 to string s1, giving an error message for paths + * that are too long. + */ +excopypath(s1,s2,n) + register char *s1,*s2; + register int n; +{ + while ((*s1++ = *s2++) != '\0') + if (--n == 0) { + fprintf(stderr, "! Environment search path is too big\n"); + *--s1 = '\0'; + return; /* let user continue with truncated path */ + } +} + +extern short buffer[],xord[]; +extern short last,first; /* pointers into buffer */ + +/* + * lineread reads from the Pascal text file with iorec pointer filep + * into buffer[first], buffer[first+1],..., buffer[last-1] (and + * setting "last"). + * Characters are read until a newline is found (which isn't put in the + * buffer) or until the next character would go into buffer[lastlim]. + * The characters need to be translated, so really xord[c] is put into + * the buffer when c is read. + * If end-of-file is encountered, the funit field of *filep is set + * appropriately. + */ +lineread(filep, lastlim) +struct iorec *filep; +int lastlim; +{ + register c; + register short *cs; /* pointer into buffer where next char goes */ + register FILE *iop; /* stdio-style FILE pointer */ + int l; /* how many more chars are allowed before buffer overflow */ + short *bf; /* hold address of buffer[first] */ + + iop = filep->fbuf; + bf = cs = &(buffer[first]); + l = lastlim-first; + /* overflow when next char would go into buffer[lastlim] */ + while (--l>=0 && (c = getc(iop)) != EOF && c!='\n') + *cs++ = xord[c]; + if (c == EOF) + filep->funit |= EOFF; /* we hit end-of-file */ + last = first+cs-bf; +} + +#define filenamesize 1024 /* should agree with inimf.ch */ +extern char nameoffile[],realnameoffile[]; /* these have size filenamesize */ + +/* + * testaccess(amode,filepath) + * + * Test whether or not the file whose name is in the global nameoffile + * can be opened for reading (if mode=READACCESS) + * or writing (if mode=WRITEACCESS). + * + * The filepath argument is one of the ...FILEPATH constants defined below. + * If the filename given in nameoffile does not begin with '/', we try + * prepending all the ':'-separated areanames in the appropriate path to the + * filename until access can be made, if it ever can. + * + * The realnameoffile global array will contain the name that yielded an + * access success. + */ + +#define READACCESS 4 +#define WRITEACCESS 2 + +#define NOFILEPATH 0 +#define INPUTFILEPATH 1 +#define READFILEPATH 2 +#define BASEFILEPATH 4 +#define POOLFILEPATH 5 + +bool +testaccess(amode,filepath) + int amode,filepath; +{ + register bool ok; + register char *p; + char *curpathplace; + int f; + + switch(filepath) { + case NOFILEPATH: curpathplace = NULL; break; + case INPUTFILEPATH: case READFILEPATH: + curpathplace = inputpath; break; + case BASEFILEPATH: curpathplace = basepath; break; + case POOLFILEPATH: curpathplace = poolpath; break; + } + if (nameoffile[0]=='/') /* file name has absolute path */ + curpathplace = NULL; + do { + packrealnameoffile(&curpathplace); + if (amode==READACCESS) + /* use system call "access" to see if we could read it */ + if (access(realnameoffile,READACCESS)==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 */ + f = creat(realnameoffile,0666); + if (f>=0) ok = TRUE; + else ok = FALSE; + if (ok) + close(f); + } + } while (!ok && curpathplace != NULL); + if (ok) { /* pad realnameoffile with blanks, as Pascal wants */ + for (p = realnameoffile; *p != '\0'; p++) + /* nothing: find end of string */ ; + while (p < &(realnameoffile[filenamesize])) + *p++ = ' '; + } + return (ok); +} + +/* + * packrealnameoffile(cpp) makes realnameoffile contain the directory at *cpp, + * followed by '/', followed by the characters in nameoffile 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 nameoffile as is. + */ +packrealnameoffile(cpp) + char **cpp; +{ + register char *p,*realname; + + realname = realnameoffile; + if ((p = *cpp)!=NULL) { + while ((*p != ':') && (*p != '\0')) { + *realname++ = *p++; + if (realname == &(realnameoffile[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 nameoffile to realname... */ + p = nameoffile; + while (*p != ' ') { + if (realname >= &(realnameoffile[filenamesize-1])) { + fprintf(stderr,"! Full file name is too long\n"); + break; + } + *realname++ = *p++; + } + *realname = '\0'; +} + +/* +** testeof(filep) +** +** Test whether or not the Pascal text file with iorec pointer filep +** has reached end-of-file (when the only I/O on it is done with +** lineread, above). +** We may have to read the next character and unget it to see if perhaps +** the end-of-file is next. +*/ + +bool +testeof(filep) +register struct iorec *filep; +{ + register char c; + register FILE *iop; /* stdio-style FILE pointer */ + if (filep->funit & EOFF) + return(TRUE); + else { /* check to see if next is EOF */ + iop = filep->fbuf; + c = getc(iop); + if (c == EOF) + return(TRUE); + else { + ungetc(c,iop); + return(FALSE); + } + } +} + + +/* +** writegf(a,b) +** +** writegf is called to write gfbuf[a..b] to gffile +** Unfortunately, gfbuf is declared as eight_bits, which in our +** implementation means that two bytes are taken by each entry. +** We only want to output the low order (first) byte of each pair. +*/ +extern struct iorec gffile; +extern short gfbuf[]; +writegf (a,b) + int a,b; +{ + register short *ptr,*final; + register FILE *iop; + + iop=gffile.fbuf; + ptr= &(gfbuf[a]); + final= &(gfbuf[b]); + while (ptr<=final) { + putc((char) (*ptr & 0377), iop); + ptr += 1; + } + /* Note: The above code used to be machine dependent. By changing + * the declarations from "char *" to "short *" we get the machine + * to do its own byte ordering of the de-reference of "ptr" above. + * Then we AND off the low bits (now that it's been pulled from + * memory correctly) and cast it into a "char" for putc(). + * --Peter Kessler's idea; explanation, AND, cast a la clp. + */ +} + + +/* +** close1(filep) +** close1 does the proper things to pc's runtime system file data structure +** to close a file +*/ +close1(filep) + + register struct iorec *filep; +{ + register struct iorec *next; + + if (filep->fbuf != 0) { + if ((filep->funit & FDEF) == 0) { + next = (struct iorec *) &_fchain; + while (next->fchain != FILNIL + && next->fchain != filep) + next = next->fchain; + if (next->fchain != FILNIL) + next->fchain = next->fchain->fchain; + + if (filep->fblk > PREDEF) { + fflush(filep->fbuf); + setbuf(filep->fbuf, NULL); + } + fclose(filep->fbuf); + if (ferror(filep->fbuf)) { +/* ERROR("%s: Close failed\n", + filep->pfname); */ + return; + } + filep->fbuf=0; + } + if ((filep->funit & TEMP) != 0 && + unlink(filep->pfname)) { +/* PERROR("Could not remove ", filep->pfname); */ + return; + } + } +} + +/* +** The following procedure is due to sjc@s1-c. +** +** calledit(filename, fnlength, linenumber) +** +** MF84 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 emacs. 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 "vi" might be: +** +** setenv MFEDIT "/usr/bin/vi +%d %s" +** +*/ + + char dvalue[] = "emacs +%d %s"; + char *mfeditvalue = &dvalue[0]; + + calledit(filename, fnlength, linenumber) + char *filename; + int fnlength, linenumber; + { + char *temp, *command, c; + int sdone, ddone, i; + + sdone = ddone = 0; + + /* Replace default with environment variable if possible. */ + if (NULL != (temp = (char *) getenv("MFEDIT"))) + mfeditvalue = temp; + + /* Make command string containing envvalue, filename, and linenumber */ + if (NULL == + (command = (char *) malloc(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); + } + 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++] ^ 0x80; /* changed for 8-bit MF */ + 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 (0 != system(command)) + fprintf(stderr, "! Trouble executing command %s\n", command); + + /* Quit, indicating MF had found an error before you typed "e". */ + exit(1); + } diff --git a/systems/knuth/local/mf-sparc/ext.h b/systems/knuth/local/mf-sparc/ext.h new file mode 100644 index 0000000000..7ff0e3bfdc --- /dev/null +++ b/systems/knuth/local/mf-sparc/ext.h @@ -0,0 +1,38 @@ +procedure exit(x : integer); + external; + +procedure closea(var f:text); + external; + +procedure closeb(var f:bytefile); + external; + +procedure closew(var f:wordfile); + external; + +procedure dateandtime(var minutes, day, month, year : integer); + external; + +procedure setpaths; + external; + +function testaccess(accessmode:integer; filepath:integer): boolean; + external; + +function testeof(var f: text): boolean; + external; + +procedure lineread(var f: text; lastlim: integer); + external; + +procedure writegf(a,b:integer); + external; + +procedure calledit(var filename: packedASCIIcode; fnlength, linenumber: integer); + external; + +function makefraction(p,q:integer):fraction; + external; + +function takefraction(q:integer;f:fraction):integer; + external; diff --git a/systems/knuth/local/mf-sparc/gftype.in b/systems/knuth/local/mf-sparc/gftype.in new file mode 100644 index 0000000000..9b48ee4cf9 --- /dev/null +++ b/systems/knuth/local/mf-sparc/gftype.in @@ -0,0 +1,2 @@ +y +y diff --git a/systems/knuth/local/mf-sparc/ini_to_trap b/systems/knuth/local/mf-sparc/ini_to_trap new file mode 100644 index 0000000000..c18984179f --- /dev/null +++ b/systems/knuth/local/mf-sparc/ini_to_trap @@ -0,0 +1,38 @@ +#! /bin/csh +# A shell script to perform modifications on the changefile for inimf +# to make a changefile for trapmf (used to test mf). +# +# To use it, say +# ini_to_trap inimf.ch trapmf.ch +# +ed - $1 <<edscriptend +/debug=/ +// +s/@{//p +/gubed=/ +s/@t@>@}//p +/@!mem_max=/ +// +s/[0-9][0-9]*/3000/p +/@!error_line=/ +s/[0-9][0-9]*/64/p +/@!half_error_line=/ +s/[0-9][0-9]*/32/p +/@!max_print_line=/ +s/[0-9][0-9]*/72/p +/@!screen_width=/ +s/[0-9][0-9]*/100/p +/@!screen_depth=/ +s/[0-9][0-9]*/200/p +/@!gf_buf_size=/ +s/[0-9][0-9]*/8/p +/@d mem_min=/ +// +s/-[0-9]*/0/p +/@d mem_top==/ +s/[0-9][0-9]*/3000/p +/% BEGIN HOOK FOR THE TRAP TEST/ +.+1,.+5s/%// +.+1,/% END HOOK FOR THE TRAP TEST/d +w $2 +edscriptend diff --git a/systems/knuth/local/mf-sparc/inimf.ch b/systems/knuth/local/mf-sparc/inimf.ch new file mode 100644 index 0000000000..271532c7b6 --- /dev/null +++ b/systems/knuth/local/mf-sparc/inimf.ch @@ -0,0 +1,1505 @@ +% Derived from INITEX.CH for Berkeley Unix TeX 1.1, by Howard Trickey +% and Pavel Curtis + +% Modification History: +% +% brought up to version 2.7182 on 8/8/98 --- don +% brought up to version 2.718 on 3/8/95 --- don +% UNIXexit convention switched 2/21/93 --- don +% tfm_out needed to be corrected for new Pascal compiler 7/18/92 --- don +% brought up to version 2.71 on 9/20/91 --- don +% brought up to version 2.7 on 9/6/90 --- don +% fixed max_buf_stack logic (it was one too high) on 1/22/90 --- don +% brought up to version 1.9 on 12/20/89 --- don +% brought up to version 1.8 on 10/14/89 --- don +% 8-bit modifications made 9/11/89 --- don +% +% don adapted everything for SunOS, MF Version 1.7, on 8/12/89 +% Module numbers changed to match Volume D +% Changes made more consistent with initex.ch +% Window code merged in, with hooks to remove it for the TRAP test +% +% Revision 1.3 87/03/07 21:15:21 mackay +% +% Minor changes found on archive version on SCORE +% (max_in_open increased to 10. -- 88/02/07 PAM) +% +% Revision 1.2 86/09/29 21:46:43 mackay +% +% Made no-debug the default, and changed version number +% to correspond with improved mf.web file +% (Got rid of debug code to avoid bug in range check +% code of VAX4.3 BSD and SUN3 version 3.x Os pc interpreter) +% +% Revision 1.0 86/01/31 15:46:08 richards +% Released for MF 1.0; +% +% Incorporates: New binary I/O library, separate optimized +% arithmetic for takefraction/makefraction, new graphics interface +% +% Revision 0.999999.1.2 86/01/28 19:49:38 richards +% Added: +% variable "dummy" to routine initterm() because SUN PC compiler +% loops with only i,j,k defined. Argh! +% +% Revision 0.999999.1.1 86/01/21 23:05:16 richards +% First cut for MF 1.0 +% +% Revision 0.999999 86/01/13 00:40:25 richards +% Released for 0.999999: +% added OTHERCASES sentinel +% revised WINDOW interface and include files +% +% Revision 0.99999 85/12/09 20:23:35 richards +% Version for 0.99999 +% +% Revision 0.9999 85/10/21 20:48:24 richards +% Released for MF version 0.9999 +% +% Revision 0.999 85/10/18 21:33:44 richards +% Version that works with 0.999 MF (Never released) +% +% Revision 0.91 85/05/16 10:58:13 richards +% Released for MF version 0.91 +% +% Revision 0.81 85/05/05 12:24:08 richards +% Released for MF version 0.81 +% +% Revision 0.77 85/03/11 20:23:37 richards +% Released for MF version 0.77 +% +% Revision 0.6.1.1 85/02/12 20:12:32 richards +% First edit for 0.76 +% +% Revision 0.6 85/02/08 00:52:40 richards +% Distribution version for MF 0.6 +% +% Revision 0.0.2.1 84/12/06 03:43:33 richards +% Edited to work with 0.4 -- still needs to have section numbers re-done +% before release. +% +% Revision 0.0 84/11/05 00:50:38 richards +% Base version (first cut) for MetaFont 0.0 +% +% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [0] WEAVE: only print changes +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in} +@y +\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in} +\let\maybe=\iffalse +\def\title{{\logo opqrstuq} changes for SunOS} +\def\glob{13}\def\gglob{20, 25} % these are defined in module 1 +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.2] banner line +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d banner=='This is METAFONT, Version 2.7182' {printed when \MF\ starts} +@y +@d banner=='This is METAFONT, Version 2.7182 for SunOS' + {printed when \MF\ starts} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.4] program header, include ext.h for C routine linkage +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +Actually the heading shown here is not quite normal: The |program| line +does not mention any |output| file, because \ph\ would ask the \MF\ user +to specify a file name if |output| were specified here. +@^system dependencies@> + +@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:} +@y +@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:} +@d standard_input==i@&n@&p@&u@&t {and another} +@z +@x +program MF; {all file names are defined dynamically} +@y +program MF(standard_input,output); {other file names are defined dynamically} +@z +@x +var @<Global variables@>@/ +@y +var @<Global variables@>@/ +@# +@\@=#include "ext.h"@>@\ {declarations for external C procedures} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.7] debug..gubed, stat..tats +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging} +@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging} +@y +@d debug==@{ +@d gubed==@t@>@} +@z +% (I will use the debug code only in the trap test) +@x +@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering + usage statistics} +@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering + usage statistics} +@y +@d stat== +@d tats== +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.8] init..tini +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version} +@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version} +@y +@d init== +@d tini== +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.9] compiler directives +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} +@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} +@y +@=(*$C-*)@> {no range check} +@!debug @=(*$C+*)@> @+ gubed {but turn everything on when debugging} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.10] othercases, feature of Sun Pascal +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d othercases == others: {default for cases not listed explicitly} +@y +@d othercases == otherwise {default for cases not listed explicitly} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.11] compile-time constants +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@<Constants...@>= +@!mem_max=30000; {greatest index in \MF's internal |mem| array; + must be strictly less than |max_halfword|; + must be equal to |mem_top| in \.{INIMF}, otherwise |>=mem_top|} +@!max_internal=100; {maximum number of internal quantities} +@!buf_size=500; {maximum number of characters simultaneously present in + current lines of open files; must not exceed |max_halfword|} +@!error_line=72; {width of context lines on terminal error messages} +@!half_error_line=42; {width of first lines of contexts in terminal + error messages; should be between 30 and |error_line-15|} +@!max_print_line=79; {width of longest text lines output; should be at least 60} +@!screen_width=768; {number of pixels in each row of screen display} +@!screen_depth=1024; {number of pixels in each column of screen display} +@!stack_size=30; {maximum number of simultaneous input sources} +@!max_strings=2000; {maximum number of strings; must not exceed |max_halfword|} +@!string_vacancies=8000; {the minimum number of characters that should be + available for the user's identifier names and strings, + after \MF's own error messages are stored} +@!pool_size=32000; {maximum number of characters in strings, including all + error messages and help texts, and the names of all identifiers; + must exceed |string_vacancies| by the total + length of \MF's own strings, which is currently about 22000} +@!move_size=5000; {space for storing moves in a single octant} +@!max_wiggle=300; {number of autorounded points per cycle} +@!gf_buf_size=800; {size of the output buffer, must be a multiple of 8} +@!file_name_size=40; {file names shouldn't be longer than this} +@!pool_name='MFbases:MF.POOL '; + {string of length |file_name_size|; tells where the string pool appears} +@y +@<Constants...@>= +@!mem_max=30000; {greatest index in \MF's internal |mem| array; + must be strictly less than |max_halfword|; + must be equal to |mem_top| in \.{INIMF}, otherwise |>=mem_top|} +@!max_internal=100; {maximum number of internal quantities} +@!buf_size=500; {maximum number of characters simultaneously present in + current lines of open files; must not exceed |max_halfword|} +@!error_line=79; {width of context lines on terminal error messages} +@!half_error_line=50; {width of first lines of contexts in terminal + error messages; should be between 30 and |error_line-15|} +@!max_print_line=79; {width of longest text lines output; should be at least 60} +@!screen_width=1024; {number of pixels in each row of screen display} +@!screen_depth=800; {number of pixels in each column of screen display} +@!stack_size=30; {maximum number of simultaneous input sources} +@!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|} +@!string_vacancies=18000; {the minimum number of characters that should be + available for the user's identifier names and strings, + after \MF's own error messages are stored} +@!pool_size=42000; {maximum number of characters in strings, including all + error messages and help texts, and the names of all identifiers; + must exceed |string_vacancies| by the total + length of \MF's own strings, which is currently about 22000} +@!move_size=5000; {space for storing moves in a single octant} +@!max_wiggle=300; {number of autorounded points per cycle} +@!gf_buf_size=800; {size of the output buffer, must be a multiple of 8} +@!file_name_size=1024; {file names shouldn't be longer than this} +@!pool_name='mf.pool'; + {string of length |file_name_size|; tells where the string pool appears} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.12] sensitive compile-time constants +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d mem_min=0 {smallest index in the |mem| array, must not be less + than |min_halfword|} +@d mem_top==30000 {largest index in the |mem| array dumped by \.{INIMF}; + must be substantially larger than |mem_min| + and not greater than |mem_max|} +@d hash_size=2100 {maximum number of symbolic tokens, + must be less than |max_halfword-3*param_size|} +@d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|} +@d max_in_open=6 {maximum number of input files and error insertions that + can be going on simultaneously} +@d param_size=150 {maximum number of simultaneous macro parameters} +@y +@d mem_min==-30000 {smallest index in the |mem| array, must not be less + than |min_halfword|} +@d mem_top==30000 {largest index in the |mem| array dumped by \.{INIMF}; + must be substantially larger than |mem_min| + and not greater than |mem_max|} +@d hash_size=2100 {maximum number of symbolic tokens, + must be less than |max_halfword-3*param_size|} +@d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|} +@d max_in_open=10 {maximum number of input files and error insertions that + can be going on simultaneously. Enlarged for Silvio Levy's Greek} +@d param_size=150 {maximum number of simultaneous macro parameters} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [1.22] Permissive input +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@^character set dependencies@> +@^system dependencies@> + +@<Set init...@>= +for i:=0 to @'37 do xchr[i]:=' '; +for i:=@'177 to @'377 do xchr[i]:=' '; +@y +@^character set dependencies@> +@^system dependencies@> + +@d tab = @'11 { ASCII horizontal tab } +@d form_feed = @'14 { ASCII form-feed } + +@<Set init...@>= +for i:=0 to @'37 do xchr[i]:=chr(i); +for i:=@'177 to @'377 do xchr[i]:=chr(i); +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.24] file types +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +The program actually makes use also of a third kind of file, called a +@y +The pc compiler on Berkeley {\mc UNIX} won't pack a range into one byte unless +the lower bound is |-128| or more, and the upper bound is |127| or less. +This applies to files, too. To make the program work with compiler range +checking turned on, we'll have to adjust |eight_bits| codes by sometimes +adding or subtracting |256|. +Note that |eight_bits| really takes 16 bits here. + +The program actually makes use also of a third kind of file, called a +@z +@x +@!alpha_file=packed file of text_char; {files that contain textual data} +@!byte_file=packed file of eight_bits; {files that contain binary data} +@y +@!alpha_file=t@&e@&x@&t; {files that contain textual data} +@!byte_file=packed file of -128..127; {files that contain binary data} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.25] add real_name_of_file array for search path resolution +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +is crucial for our purposes. We shall assume that |name_of_file| is a variable +of an appropriate type such that the \PASCAL\ run-time system being used to +implement \MF\ can open a file whose external name is specified by +|name_of_file|. +@^system dependencies@> + +@<Glob...@>= +@!name_of_file:packed array[1..file_name_size] of char;@;@/ + {on some systems this may be a \&{record} variable} +@!name_length:0..file_name_size;@/{this many characters are actually + relevant in |name_of_file| (the rest are blank)} +@y +is crucial for our purposes. We shall assume that |name_of_file| is a variable +of an appropriate type such that the \PASCAL\ run-time system being used to +implement \MF\ can open a file whose external name is specified by +|name_of_file|. +The Berkeley {\mc UNIX} version uses search paths to look for files to open. +We use |real_name_of_file| to hold the |name_of_file| with a directory +name from the path in front of it. +@^system dependencies@> + +@<Glob...@>= +@!name_of_file,@!real_name_of_file:packed array[1..file_name_size] of char; +@;@/ +@!name_length:0..file_name_size;@/{this many characters are actually + relevant in |name_of_file| (the rest are blank)} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.26] file opening +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ The \ph\ compiler with which the present version of \MF\ was prepared has +extended the rules of \PASCAL\ in a very convenient way. To open file~|f|, +we can write +$$\vbox{\halign{#\hfil\qquad&#\hfil\cr +|reset(f,@t\\{name}@>,'/O')|&for input;\cr +|rewrite(f,@t\\{name}@>,'/O')|&for output.\cr}}$$ +The `\\{name}' parameter, which is of type `\ignorespaces|packed +array[@t\<\\{any}>@>] of text_char|', stands for the name of +the external file that is being opened for input or output. +Blank spaces that might appear in \\{name} are ignored. + +The `\.{/O}' parameter tells the operating system not to issue its own +error messages if something goes wrong. If a file of the specified name +cannot be found, or if such a file cannot be opened for some other reason +(e.g., someone may already be trying to write the same file), we will have +|@!erstat(f)<>0| after an unsuccessful |reset| or |rewrite|. This allows +\MF\ to undertake appropriate corrective action. +@:PASCAL H}{\ph@> +@^system dependencies@> + +\MF's file-opening procedures return |false| if no file identified by +|name_of_file| could be opened. + +@d reset_OK(#)==erstat(#)=0 +@d rewrite_OK(#)==erstat(#)=0 + +@p function a_open_in(var @!f:alpha_file):boolean; + {open a text file for input} +begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f); +end; +@# +function a_open_out(var @!f:alpha_file):boolean; + {open a text file for output} +begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f); +end; +@# +function b_open_out(var @!f:byte_file):boolean; + {open a binary file for output} +begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f); +end; +@# +function w_open_in(var @!f:word_file):boolean; + {open a word file for input} +begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f); +end; +@# +function w_open_out(var @!f:word_file):boolean; + {open a word file for output} +begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f); +end; +@y +@ The \ph\ compiler with which the present version of \MF\ was prepared has +extended the rules of \PASCAL\ in a very convenient way for file opening. +Berkeley {\mc UNIX} \PASCAL\ isn't nearly as nice as \ph. +Normally, it bombs out if a file open fails. +An external C procedure, |test_access| is used to check whether or not the +open will work. It is declared in the ``ext.h'' include file, and it returns +|true| or |false|. The |name_of_file| global holds the file name whose access +is to be tested. +The first parameter for |test_access| is the access mode, +one of |read_access_mode| or |write_access_mode|. + +We also implement path searching in |test_access|: its second parameter is +one of the ``file path'' constants defined below. If |name_of_file| +doesn't start with |'/'| then |test_access| tries prepending pathnames +from the appropriate path list until success or the end of path list +is reached. +On return, |real_name_of_file| contains the original name with the path +that succeeded (if any) prepended. It is the name used in the various +open procedures. + +Note that |a_open_in| has been redefined to take an additional argument, +which should be one of the ``file path'' specifiers. +Path searching is not done for output files. + +@d read_access_mode=4 {``read'' mode for |test_access|} +@d write_access_mode=2 {``write'' mode for |test_access|} + +@d no_file_path=0 {no path searching should be done} +@d input_file_path=1 {path specifier for \.{\\input} files} +@d base_file_path=4 {path specifier for base files} +@d pool_file_path=5 {path specifier for the pool file} + +@p function a_open_in(var @!f:alpha_file;@!path_specifier:integer):boolean; + {open a text file for input} +var @!ok:boolean; +begin +if test_access(read_access_mode,path_specifier) then + begin reset(f,real_name_of_file); ok:=true@+end +else + ok:=false; +a_open_in:=ok; +end; +@# +function a_open_out(var @!f:alpha_file):boolean; + {open a text file for output} +var @!ok:boolean; +begin +if test_access(write_access_mode,no_file_path) then + begin rewrite(f,real_name_of_file); ok:=true @+end +else ok:=false; +a_open_out:=ok; +end; +@# +function b_open_out(var f:byte_file):boolean; + {open a binary file for output} +var @!ok:boolean; +begin +if test_access(write_access_mode,no_file_path) then + begin rewrite(f,real_name_of_file); ok:=true @+end +else ok:=false; +b_open_out:=ok; +end; +@# +function w_open_in(var @!f:word_file):boolean; + {open a word file for input} +var @!ok:boolean; +begin +if test_access(read_access_mode,base_file_path) then + begin reset(f,real_name_of_file); ok:=true @+end +else ok:=false; +w_open_in:=ok; +end; +@# +function w_open_out(var @!f:word_file):boolean; + {open a word file for output} +var @!ok:boolean; +begin +if test_access(write_access_mode,no_file_path) then + begin rewrite(f,name_of_file); ok:=true @+end +else ok:=false; +w_open_out:=ok; +end; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.27] file closing +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +This makes |f| available to be opened again, if desired; and if |f| was used for +output, the |close| operation makes the corresponding external file appear +on the user's area, ready to be read. + +@p procedure a_close(var @!f:alpha_file); {close a text file} +begin close(f); +end; +@# +procedure b_close(var @!f:byte_file); {close a binary file} +begin close(f); +end; +@# +procedure w_close(var @!f:word_file); {close a word file} +begin close(f); +end; +@y +This makes |f| available to be opened again, if desired; and if |f| was used for +output, the |close| operation makes the corresponding external file appear +on the user's area, ready to be read. + +With the pc library, files will be automatically closed when the program stops +and when one reopens them. +There is, however, the problem of opening a file and writing it, and then +wanting to read it again, but from a different file variable. +For this purpose we use external procedures |close_a|, |close_b|, and +|close_w|. + +@p procedure a_close(var f:alpha_file); {close a text file} +begin close_a(f); +end; +@# +procedure b_close(var f:byte_file); {close a binary file} +begin close_b(f); +end; +@# +procedure w_close(var f:word_file); {close a word file} +begin close_w(f); +end; + +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.30] faster version of input_ln +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +Standard \PASCAL\ says that a file should have |eoln| immediately +before |eof|, but \MF\ needs only a weaker restriction: If |eof| +occurs in the middle of a line, the system function |eoln| should return +a |true| result (even though |f^| will be undefined). + +@p function input_ln(var @!f:alpha_file;@!bypass_eoln:boolean):boolean; + {inputs the next line or returns |false|} +var @!last_nonblank:0..buf_size; {|last| with trailing blanks removed} +begin if bypass_eoln then if not eof(f) then get(f); + {input the first character of the line into |f^|} +last:=first; {cf.\ Matthew 19\thinspace:\thinspace30} +if eof(f) then input_ln:=false +else begin last_nonblank:=first; + while not eoln(f) do + begin if last>=max_buf_stack then + begin max_buf_stack:=last+1; + if max_buf_stack=buf_size then + @<Report overflow of the input buffer, and abort@>; + end; + buffer[last]:=xord[f^]; get(f); incr(last); + if buffer[last-1]<>" " then last_nonblank:=last; + end; + last:=last_nonblank; input_ln:=true; + end; +end; +@y +Standard \PASCAL\ says that a file should have |eoln| immediately +before |eof|, but \MF\ needs only a weaker restriction: If |eof| +occurs in the middle of a line, the system function |eoln| should return +a |true| result (even though |f^| will be undefined). + +With Berkeley {\mc UNIX} we call an external C procedure, |line_read|. +That routine fills |buffer| from |first| onwards with the |xord|'ed values +of the next line, setting |last| appropriately. It will stop if +|last=buf_size|, and the following will cause an ``overflow'' abort. +We ignore the |bypass_eoln| argument, since the |line_read| procedure +will have handled bypassing the end-of-line in its previous call, if +there was one. + +If one uses |input_ln| on a file, the normal |read| +and |get| routines shouldn't be used, nor the |eof| and |eoln| tests. +End of file can be tested with the external function |test_eof|. + +@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean; + {inputs the next line or returns |false|} +label done; +begin +last:=first; {cf.\ Matthew 19\thinspace:\thinspace30} +if test_eof(f) then input_ln:=false +else begin last:=first; + line_read(f,buf_size); + if last>max_buf_stack then begin + max_buf_stack:=last; + if max_buf_stack>=buf_size then + @<Report overflow of the input buffer, and abort@>; + end; + loop@+ begin if last=first then goto done; + if buffer[last-1]<>" " then goto done; + decr(last); + end; +done: input_ln:=true; + end; +end; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.31] term_in/out are input,output +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ The user's terminal acts essentially like other files of text, except +that it is used both for input and for output. When the terminal is +considered an input file, the file variable is called |term_in|, and when it +is considered an output file the file variable is |term_out|. +@^system dependencies@> + +@<Glob...@>= +@!term_in:alpha_file; {the terminal as an input file} +@!term_out:alpha_file; {the terminal as an output file} +@y +@ The user's terminal acts essentially like other files of text, except +that it is used both for input and for output. When the terminal is +considered an input file, the file is called |term_in|, and when it +is considered an output file the file is |term_out|. +For Berkeley {\mc UNIX} we use |standard_input| and |output| for these +files, as were declared in the program header. The former name +|standard_input| was defined using a web trick so that ``input'' is +produced in the Pascal file. + +@d term_in==standard_input {the terminal as an input file} +@d term_out==output {the terminal as an output file} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.32] don't need to open terminal files +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ Here is how to open the terminal files +in \ph. The `\.{/I}' switch suppresses the first |get|. +@^system dependencies@> + +@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input} +@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output} +@y +@ Here is how to open the terminal files---do nothing. + +@d t_open_in == {input already open for text input} +@d t_open_out == {output already open for text output} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.33] flushing output +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +these operations can be specified in \ph: +@^system dependencies@> + +@d update_terminal == break(term_out) {empty the terminal output buffer} +@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer} +@d wake_up_terminal == do_nothing {cancel the user's cancellation of output} +@y +these operations can be specified with Berkeley {\mc UNIX}: +@^system dependencies@> + +@d update_terminal == flush(output) +@d clear_terminal == {nothing necessary on UNIX} +@d wake_up_terminal == {nothing necessary on UNIX} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [3.36] rescanning the command line +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ The following program does the required initialization +without retrieving a possible command line. +It should be clear how to modify this routine to deal with command lines, +if the system permits them. +@^system dependencies@> + +@p function init_terminal:boolean; {gets the terminal input started} +label exit; +begin t_open_in; +loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal; +@.**@> + if not input_ln(term_in,true) then {this shouldn't happen} + begin write_ln(term_out); + write(term_out,'! End of file on the terminal... why?'); +@.End of file on the terminal@> + init_terminal:=false; return; + end; + loc:=first; + while (loc<last)and(buffer[loc]=" ") do incr(loc); + if loc<last then + begin init_terminal:=true; + return; {return unless the line was all blank} + end; + write_ln(term_out,'Please type the name of your input file.'); + end; +exit:end; +@y +@ The following program does the required initialization +and also retrieves a possible command line. +@^system dependencies@> + +@p +function init_terminal:boolean; {gets the terminal input started} +label exit; + +var + dummy, i, j, k: integer; + arg: packed array[1..100] of char; + +begin + t_open_in; + if argc > 1 then begin + last := first; + for i := 1 to argc - 1 do begin + argv(i, arg); + j := 1; + k := 100; {find last non-blank char in arg} + while (k > 1) and (arg[k] = ' ') do@/ + decr(k); + while (j <= k) do begin + buffer[last] := xord[arg[j]]; + incr(j); incr(last); + end; + if k > 1 then begin + buffer[last] := xord[' ']; + incr(last); + end; + end; + if last > first then begin + loc := first; + init_terminal := true; + return; + end; + end; + loop@+begin + wake_up_terminal; write(term_out, '**'); update_terminal; +@.**@> + if not input_ln(term_in,true) then begin {this shouldn't happen} + write_ln(term_out); + write_ln(term_out, '! End of file on the terminal... why?'); +@.End of file on the terminal@> + init_terminal:=false; + return; + end; + + loc:=first; + while (loc<last)and(buffer[loc]=" ") do + incr(loc); + + if loc<last then begin + init_terminal:=true; + return; {return unless the line was all blank} + end; + write_ln(term_out, 'Please type the name of your input file.'); +@.Please type the name...@> + end; +exit: +end; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [4.51] a_open_in of pool file needs path specifier +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +if a_open_in(pool_file) then +@y +if a_open_in(pool_file,pool_file_path) then +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [4.51,52,53] make MF.POOL lowercase in messages +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +else bad_pool('! I can''t read MF.POOL.') +@y +else bad_pool('! I can''t read mf.pool.') +@z +@x +begin if eof(pool_file) then bad_pool('! MF.POOL has no check sum.'); +@y +begin if eof(pool_file) then bad_pool('! mf.pool has no check sum.'); +@z +@x + bad_pool('! MF.POOL line doesn''t begin with two digits.'); +@y + bad_pool('! mf.pool line doesn''t begin with two digits.'); +@z +@x + bad_pool('! MF.POOL check sum doesn''t have nine digits.'); +@y + bad_pool('! mf.pool check sum doesn''t have nine digits.'); +@z +@x +done: if a<>@$ then bad_pool('! MF.POOL doesn''t match; TANGLE me again.'); +@y +done: if a<>@$ then bad_pool('! mf.pool doesn''t match; tangle me again.'); +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [6.79] switch-to-editor option +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +line ready to be edited. But such an extension requires some system +wizardry, so the present implementation simply types out the name of the +file that should be +edited and the relevant line number. +@^system dependencies@> + +There is a secret `\.D' option available when the debugging routines haven't +been commented~out. +@^debugging@> +@y +line ready to be edited. +We do this by calling the external procedure |calledit| with a pointer to +the filename, its length, and the line number. +However, here we just set up the variables that will be used as arguments, +since we don't want to do the switch-to-editor until after \MF\ has closed +its files. +@^system dependencies@> + +There is a secret `\.D' option available when the debugging routines have +not been commented out. +@^debugging@> +@d edit_file==input_stack[file_ptr] +@z +@x +"E": if file_ptr>0 then + begin print_nl("You want to edit file "); +@.You want to edit file x@> + slow_print(input_stack[file_ptr].name_field); + print(" at line "); print_int(line);@/ + interaction:=scroll_mode; jump_out; +@y +"E": if file_ptr>0 then + begin + ed_name_start:=str_start[edit_file.name_field]; + ed_name_length:=str_start[edit_file.name_field+1] - + str_start[edit_file.name_field]; + edit_line:=line; + jump_out; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [7.107,108] replace make_fraction with external routine +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@p function make_fraction(@!p,@!q:integer):fraction; +var @!f:integer; {the fraction bits, with a leading 1 bit} +@!n:integer; {the integer part of $\vert p/q\vert$} +@!negative:boolean; {should the result be negated?} +@!be_careful:integer; {disables certain compiler optimizations} +begin if p>=0 then negative:=false +else begin negate(p); negative:=true; + end; +if q<=0 then + begin debug if q=0 then confusion("/");@;@+gubed@;@/ +@:this can't happen /}{\quad \./@> + negate(q); negative:=not negative; + end; +n:=p div q; p:=p mod q; +if n>=8 then + begin arith_error:=true; + if negative then make_fraction:=-el_gordo@+else make_fraction:=el_gordo; + end +else begin n:=(n-1)*fraction_one; + @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>; + if negative then make_fraction:=-(f+n)@+else make_fraction:=f+n; + end; +end; + +@ The |repeat| loop here preserves the following invariant relations +between |f|, |p|, and~|q|: +(i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and +$p_0$ is the original value of~$p$. + +Notice that the computation specifies +|(p-q)+p| instead of |(p+p)-q|, because the latter could overflow. +Let us hope that optimizing compilers do not miss this point; a +special variable |be_careful| is used to emphasize the necessary +order of computation. Optimizing compilers should keep |be_careful| +in a register, not store it in memory. +@^inner loop@> + +@<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>= +f:=1; +repeat be_careful:=p-q; p:=be_careful+p; +if p>=0 then f:=f+f+1 +else begin double(f); p:=p+q; + end; +until f>=fraction_one; +be_careful:=p-q; +if be_careful+p>=0 then incr(f) + +@y +Under {\mc UNIX} \MF, we have replaced the \PASCAL\ version of |make_fraction| +with either a C or assembly language equivalent for efficiency. + +@ This section was deleted when |make_fraction| was removed. + +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [7.109,110,111] replace take_fraction with external version +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@p function take_fraction(@!q:integer;@!f:fraction):integer; +var @!p:integer; {the fraction so far} +@!negative:boolean; {should the result be negated?} +@!n:integer; {additional multiple of $q$} +@!be_careful:integer; {disables certain compiler optimizations} +begin @<Reduce to the case that |f>=0| and |q>0|@>; +if f<fraction_one then n:=0 +else begin n:=f div fraction_one; f:=f mod fraction_one; + if q<=el_gordo div n then n:=n*q + else begin arith_error:=true; n:=el_gordo; + end; + end; +f:=f+fraction_one; +@<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>; +be_careful:=n-el_gordo; +if be_careful+p>0 then + begin arith_error:=true; n:=el_gordo-p; + end; +if negative then take_fraction:=-(n+p) +else take_fraction:=n+p; +end; + +@ @<Reduce to the case that |f>=0| and |q>0|@>= +if f>=0 then negative:=false +else begin negate(f); negative:=true; + end; +if q<0 then + begin negate(q); negative:=not negative; + end; + +@ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor +=\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and +$f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$. +@^inner loop@> + +@<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>= +p:=fraction_half; {that's $2^{27}$; the invariants hold now with $k=28$} +if q<fraction_four then + repeat if odd(f) then p:=half(p+q)@+else p:=half(p); + f:=half(f); + until f=1 +else repeat if odd(f) then p:=p+half(q-p)@+else p:=half(p); + f:=half(f); + until f=1 + +@y +Function |take_fraction| has also been replaced by an external routine. + +@ @<Reduce to the case that |f>=0| and |q>0|@>= +if f>=0 then negative:=false +else begin negate(f); negative:=true; + end; +if q<0 then + begin negate(q); negative:=not negative; + end; + +@ This section was deleted when |take_fraction| was replaced by an +external routine. (But the previous section was left in, because +it is part of |take_scaled|, which follows.) + +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [9.153] ranges for quarter,half words +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +can get 256 values into a quarterword only if the subrange is `|-128..127|'. + +The present implementation tries to accommodate as many variations as possible, +so it makes few assumptions. If integers having the subrange +`|min_quarterword..max_quarterword|' can be packed into a quarterword, +and if integers having the subrange `|min_halfword..max_halfword|' +can be packed into a halfword, everything should work satisfactorily. + +It is usually most efficient to have |min_quarterword=min_halfword=0|, +so one should try to achieve this unless it causes a severe problem. +The values defined here are recommended for most 32-bit computers. + +@d min_quarterword=0 {smallest allowable value in a |quarterword|} +@d max_quarterword=255 {largest allowable value in a |quarterword|} +@d min_halfword==0 {smallest allowable value in a |halfword|} +@d max_halfword==65535 {largest allowable value in a |halfword|} +@y +can get 256 values into a quarterword only if the subrange is `|-128..127|'. + +For Berkeley {\mc UNIX} we need to do the |-128..127| kind of range. + +@d min_quarterword=-128 {smallest allowable value in a |quarterword|} +@d max_quarterword=127 {largest allowable value in a |quarterword|} +@d min_halfword==-32768 {smallest allowable value in a |halfword|} +@d max_halfword==32767 {largest allowable value in a |halfword|} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [11.178] fix the word "free" so that it doesn't conflict with a runtime proc +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +been included. (You may want to decrease the size of |mem| while you +@^debugging@> +are debugging.) +@y +been included. (You may want to decrease the size of |mem| while you +@^debugging@> +are debugging.) + +@d free==free_arr +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [12.194] fix_date_and_time +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ The following procedure, which is called just before \MF\ initializes its +input and output, establishes the initial values of the date and time. +@^system dependencies@> +Since standard \PASCAL\ cannot provide such information, something special +is needed. The program here simply specifies July 4, 1776, at noon; but +users probably want a better approximation to the truth. + +Note that the values are |scaled| integers. Hence \MF\ can no longer +be used after the year 32767. + +@p procedure fix_date_and_time; +begin internal[time]:=12*60*unity; {minutes since midnight} +internal[day]:=4*unity; {fourth day of the month} +internal[month]:=7*unity; {seventh month of the year} +internal[year]:=1776*unity; {Anno Domini} +end; +@y +@ The following procedure, which is called just before \MF\ initializes its +input and output, establishes the initial values of the date and time. +It is calls an externally defined |date_and_time|, even though it could +be done from Pascal. +The external procedure also sets up interrupt catching. +@^system dependencies@> + +Note that the values are |scaled| integers. Hence \MF\ can no longer +be used after the year 32767. + +@p procedure fix_date_and_time; +begin + date_and_time(internal[time],internal[day],internal[month],internal[year]); + internal[time] := internal[time] * unity; + internal[day] := internal[day] * unity; + internal[month] := internal[month] * unity; + internal[year] := internal[year] * unity; +end; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [12.199] allow <tab> and <ff> as input +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +for k:=0 to " "-1 do char_class[k]:=invalid_class; +for k:=127 to 255 do char_class[k]:=invalid_class; +@y +for k:=0 to " "-1 do char_class[k]:=invalid_class; +for k:=127 to 255 do char_class[k]:=invalid_class; +char_class[tab]:=space_class; +char_class[form_feed]:=space_class; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [27.564] init_screen and update_screen are external C procs +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% BEGIN HOOK FOR THE TRAP TEST +%@x +%begin init_screen:=false; +%@y +%begin init_screen:=true; +%@z +@x +The \PASCAL\ code here is a minimum version of |init_screen| and +|update_screen|, usable on \MF\ installations that don't +support screen output. If |init_screen| is changed to return |true| +instead of |false|, the other routines will simply log the fact +that they have been called; they won't really display anything. +The standard test routines for \MF\ use this log information to check +that \MF\ is working properly, but the |wlog| instructions should be +removed from production versions of \MF. + +@p function init_screen:boolean; +begin init_screen:=false; +end; +@# +procedure update_screen; {will be called only if |init_screen| returns |true|} +begin @!init wlog_ln('Calling UPDATESCREEN');@+tini {for testing only} +end; + +@y +We declare the screen functions +for the {\mc UNIX} version of \MF\ in the following header file. + +@p +@\@=#include "mf_window.h"@>@\ {declarations for external C procedures} + +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [27.559] blank_rectangle is an external C proc +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +The commented-out code in the following procedure is for illustrative +purposes only. +@^system dependencies@> + +@p procedure blank_rectangle(@!left_col,@!right_col:screen_col; + @!top_row,@!bot_row:screen_row); +var @!r:screen_row; +@!c:screen_col; +begin @{@+for r:=top_row to bot_row-1 do + for c:=left_col to right_col-1 do + screen_pixel[r,c]:=white;@+@}@/ +@!init wlog_cr; {this will be done only after |init_screen=true|} +wlog_ln('Calling BLANKRECTANGLE(',left_col:1,',', + right_col:1,',',top_row:1,',',bot_row:1,')');@+tini +end; + +@y +@^system dependencies@> + +The procedure |blank_rectangle| has been declared an external routine +for the {\mc UNIX} version of \MF\ in the header file above. + +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [27.560] paint_row is an external C proc +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +The general idea is to paint blocks of pixels in alternate colors; +the precise details are best conveyed by means of a \PASCAL\ +program (see the commented-out code below). +@^system dependencies@> + +@p procedure paint_row(@!r:screen_row;@!b:pixel_color;var @!a:trans_spec; + @!n:screen_col); +var @!k:screen_col; {an index into |a|} +@!c:screen_col; {an index into |screen_pixel|} +begin @{ k:=0; c:=a[0]; +repeat incr(k); + repeat screen_pixel[r,c]:=b; incr(c); + until c=a[k]; + b:=black-b; {$|black|\swap|white|$} + until k=n;@+@}@/ +@!init wlog('Calling PAINTROW(',r:1,',',b:1,';'); + {this is done only after |init_screen=true|} +for k:=0 to n do + begin wlog(a[k]:1); if k<>n then wlog(','); + end; +wlog_ln(')');@+tini +end; + +@y +@^system dependencies@> + +|Paint_row| has been declared an external routine in the {\mc UNIX} version +of \MF\ in the header file above. + +@z +% END HOOK FOR THE TRAP TEST +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.768] area and extension rules +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ The file names we shall deal with for illustrative purposes have the +following structure: If the name contains `\.>' or `\.:', the file area +consists of all characters up to and including the final such character; +otherwise the file area is null. If the remaining file name contains +`\..', the file extension consists of all such characters from the first +remaining `\..' to the end, otherwise the file extension is null. +@^system dependencies@> + +We can scan such file names easily by using two global variables that keep track +of the occurrences of area and extension delimiters: + +@<Glob...@>= +@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any} +@!ext_delimiter:pool_pointer; {the relevant `\..', if any} +@y +@ The file names we shall deal with for SunOS have the +following structure: If the name contains `\./', the file area +consists of all characters up to and including the final such character; +otherwise the file area is null. If the remaining file name contains +`\..', the file extension consists of all such characters from the first +remaining `\..' to the end, otherwise the file extension is null. +@^system dependencies@> + +We can scan such file names easily by using two global variables that keep +track of the occurrences of area and extension delimiters: + +@<Glob...@>= +@!area_delimiter:pool_pointer; {the most recent `\./', if any} +@!ext_delimiter:pool_pointer; {the most recent `\..', if any} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.769] MF area directories +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d MF_area=="MFinputs:" +@.MFinputs@> +@y +Under Berkeley {\mc UNIX}, the default paths are specified in a seprate +file, `\.{mfpaths.h}'. The file opening procedures do path searching +based either on those default paths, or on paths given by the user +in ``environment'' variables. +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.771] more_name +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +begin if c=" " then more_name:=false +else begin if (c=">")or(c=":") then +@y +begin if (c=" ")or(c=tab) then more_name:=false +else begin if (c="/") then +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.775] default base +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d base_default_length=18 {length of the |MF_base_default| string} +@d base_area_length=8 {length of its area part} +@d base_ext_length=5 {length of its `\.{.base}' part} +@y +Under Berkeley {\mc UNIX} we don't give the area part, instead depending +on the path searching that will happen during file opening. + +@d base_default_length=10 {length of the |MF_base_default| string} +@d base_area_length=0 {length of its area part} +@d base_ext_length=5 {length of its `\.{.base}' part} +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.776] plain base location +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +MF_base_default:='MFbases:plain.base'; +@y +MF_base_default:='plain.base'; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.779] w_open_in of base file needs to be called only once +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x + pack_buffered_name(0,loc,j-1); {try first without the system file area} + if w_open_in(base_file) then goto found; + pack_buffered_name(base_area_length,loc,j-1); + {now try the system base file area} + if w_open_in(base_file) then goto found; +@y + pack_buffered_name(0,loc,j-1); + if w_open_in(base_file) then goto found; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.780] make_name_string +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +which simply makes a \MF\ string from the value of |name_of_file|, should +ideally be changed to deduce the full name of file~|f|, which is the file +most recently opened, if it is possible to do this in a \PASCAL\ program. +@^system dependencies@> + +This routine might be called after string memory has overflowed, hence +we dare not use `|str_room|'. + +@p function make_name_string:str_number; +var @!k:1..file_name_size; {index into |name_of_file|} +begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then + make_name_string:="?" +else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]); + make_name_string:=make_string; + end; +end; +@y +which simply makes a \MF\ string from the value of |name_of_file|, should +ideally be changed to deduce the full name of file~|f|, which is the file +most recently opened, if it is possible to do this in a \PASCAL\ program. +With the Berkeley {\mc UNIX} version, we know that |real_name_of_file| +contains |name_of_file| prepended with the directory name that was found +by path searching. +If |real_name_of_file| starts with |'./'|, we don't use that part of the +name, since {\mc UNIX} users understand that. +@^system dependencies@> + +This routine might be called after string memory has overflowed, hence +we dare not use `|str_room|'. + +@p function make_name_string:str_number; +var @!k,@!kstart:1..file_name_size; {index into |name_of_file|} +begin +k:=1; +while (k<file_name_size) and (xord[real_name_of_file[k]]<>" ") do + incr(k); +name_length:=k-1; {the real |name_length|} +if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then + make_name_string:="?" +else begin + if (xord[real_name_of_file[1]]=".") and (xord[real_name_of_file[2]]="/") then + kstart:=3 + else + kstart:=1; + for k:=kstart to name_length do append_char(xord[real_name_of_file[k]]); + make_name_string:=make_string; + end; +end; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.781] scan_file_name ignore leading tabs as well as spaces +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@p procedure scan_file_name; +label done; +begin begin_name; +while buffer[loc]=" " do incr(loc); +@y +@p procedure scan_file_name; +label done; +begin begin_name; +while (buffer[loc]=" ")or(buffer[loc]=tab) do incr(loc); +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.787] <Scan_file_name...> needs similar leading tab treatment +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ @<Scan file name in the buffer@>= +begin begin_name; k:=first; +while (buffer[k]=" ")and(k<last) do incr(k); +@y +@ @<Scan file name in the buffer@>= +begin begin_name; k:=first; +while ((buffer[k]=" ")or(buffer[k]=tab))and(k<last) do incr(k); +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.793] a_open_in of input file needs path selector +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x + if a_open_in(cur_file) then goto done; + if cur_area="" then + begin pack_file_name(cur_name,MF_area,cur_ext); + if a_open_in(cur_file) then goto done; + end; +@y + if a_open_in(cur_file,input_file_path) then goto done; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [38.793] get rid of return of name to string pool +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +if name=str_ptr-1 then {we can conserve string pool space now} + begin flush_string(name); name:=cur_name; + end; +@y +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [45.1133] writing the tfm file +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@d tfm_out(#)==write(tfm_file,#) {output one byte to |tfm_file|} +@y +@d tfm_out(#) ==write(tfm_file,((#+128) mod 256)-128) +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [47.1154] write_gf +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@<Declare generic font output procedures@>= +procedure write_gf(@!a,@!b:gf_index); +var k:gf_index; +begin for k:=a to b do write(gf_file,gf_buf[k]); +end; +@y +For Berkeley {\mc UNIX}, this is going to be handled by an external procedure, +|writegf|, which will do the output using |fwrite|. +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [49.1204] Delete ready_already; also add call to set_paths; +% also add call to exit() depending upon value of `history' +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@ Now this is really it: \MF\ starts and ends here. + +The initial test involving |ready_already| should be deleted if the +\PASCAL\ runtime system is smart enough to detect such a ``mistake.'' +@y +@ Now this is really it: \MF\ starts and ends here. + +Instead of testing |ready_already|, we give up the idea of a preloaded +core image in favor of silently loading a format file based on the +name by which this program has been invoked. For example, if the +program is being called \.{mf}, we will load the \.{plain} base; +if \.{cmmf}, we will load \.{cmmf.base}. On my machine the +loading of a format isn't too slow. (I use the new string capabilities +of Sun Pascal here; |my_name| will be declared {\bf varying} [100] +{\bf of\/} |char|.) + +At the end of the job, we look at |history| to decide the correct +exit code. We use 1 if |history <= warning_issued| and 0 otherwise. + +@d UNIXexit==e@&x@&i@&t +@z + +@x +t_open_out; {open the terminal for output} +if ready_already=314159 then goto start_of_MF; +@y +t_open_out; {open the terminal for output} +set_paths; +@z +@x +start_of_MF: @<Initialize the output routines@>; +@y +start_of_MF: argv(0,my_name); +if (my_name<>'inimf')and(my_name<>'trapmf') then + begin if my_name = 'mf' then name_of_file:='plain.base' + else name_of_file:=my_name+'.base'; + if w_open_in(base_file) then + if not load_base_file then + begin w_close(base_file); goto final_end; + end + else w_close(base_file); + end; +@<Initialize the output routines@>; +@z + +@x +final_end: ready_already:=0; +@y +final_end: ready_already:=0; +if (history <= warning_issued) then + UNIXexit(0) +else + UNIXexit(1); +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [49.1204] print new line before termination; switch to editor if nec. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x + slow_print(log_name); print_char("."); + end; + end; +@y + slow_print(log_name); print_char("."); + end; + end; +print_ln; +if (ed_name_start<>0) and (interaction>batch_mode) then + calledit(str_pool[ed_name_start],ed_name_length,edit_line); +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% [51.1214] add editor-switch variable to globals +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x +@* \[51] System-dependent changes. +This section should be replaced, if necessary, by any special +modifications of the program +that are necessary to make \MF\ work at a particular installation. +It is usually best to design your change file so that all changes to +previous sections preserve the section numbering; then everybody's version +will be consistent with the published program. More extensive changes, +which introduce new sections, can be inserted here; then only the index +itself will get a new section number. +@^system dependencies@> +@y +@* \[51] System-dependent changes. +Here are the variables used to hold ``switch-to-editor'' information. +And the omphaloskeptic variable too. +@^system dependencies@> + +@<Global...@>= +@!ed_name_start: pool_pointer; +@!ed_name_length,@!edit_line: integer; +@!my_name:varying [100] of char; + +@ The |ed_name_start| will be set to point into |str_pool| somewhere after +its beginning if \MF\ is supposed to switch to an editor on exit. + +@<Set init...@>= +ed_name_start:=0; +@z + diff --git a/systems/knuth/local/mf-sparc/mf.pool b/systems/knuth/local/mf-sparc/mf.pool new file mode 100644 index 0000000000..4f1478cac2 --- /dev/null +++ b/systems/knuth/local/mf-sparc/mf.pool @@ -0,0 +1,824 @@ +11buffer size +09pool size +17number of strings +03??? +28End of file on the terminal! +02! +42(That makes 100 errors; please try again.) +02? +60Type <return> to proceed, S to scroll future error messages, +44R to run without stopping, Q to run quietly, +23I to insert something, +20E to edit your file, +561 or ... or 9 to ignore the next 1 to 9 tokens of input, +22H for help, X to quit. +13OK, entering +09batchmode +11nonstopmode +10scrollmode +03... +07insert> +44I have just deleted some text, as you asked. +48You can now delete more, or insert, or whatever. +50Sorry, I don't know how to help in this situation. +36Maybe you should try asking a human? +42Sorry, I already gave what help I could... +59An error might have occurred before I noticed any problems. +45``If all else fails, read the instructions.'' +00 +14Emergency stop +35METAFONT capacity exceeded, sorry [ +44If you really absolutely need more capacity, +35you can ask a wizard to enlarge me. +19This can't happen ( +59I'm broken. Please show this to someone who can fix can fix +35I can't go on meeting you like this +55One of your faux pas seems to have wounded me deeply... +59in fact, I'm barely conscious. Please fix it and try again. +12Interruption +09You rang? +57Try to insert some instructions for me (e.g.,`I show x'), +43unless you just want to quit by typing `X'. +09Missing ` +19' has been inserted +19Arithmetic overflow +59Uh, oh. A little while ago one of the quantities that I was +59computing got too large, so I'm afraid your answers will be +55somewhat askew. You'll probably have to adopt different +54tactics next time. But I shall try to carry on anyway. +15Square root of +23 has been replaced by 0 +52Since I don't take square roots of negative numbers, +52I'm zeroing this one. Proceed, with fingers crossed. +24Pythagorean subtraction +03+-+ +13Logarithm of +48Since I don't take logs of non-positive numbers, +27angle(0,0) is taken as zero +54The `angle' between two identical points is undefined. +16main memory size +24AVAIL list clobbered at +31Double-AVAIL list clobbered at +24Doubly free location at +12Bad flag at +14New busy locs: +05LINK( +05INFO( +07vacuous +07boolean +15unknown boolean +06string +14unknown string +03pen +11unknown pen +10future pen +04path +12unknown path +07picture +15unknown picture +09transform +04pair +13known numeric +09dependent +15proto-dependent +07numeric +11independent +10token list +10structured +16unsuffixed macro +14suffixed macro +09undefined +04true +05false +11nullpicture +07nullpen +07jobname +10readstring +09pencircle +13normaldeviate +03odd +05known +07unknown +03not +07decimal +07reverse +08makepath +07makepen +11totalweight +03oct +03hex +05ASCII +04char +06length +13turningnumber +05xpart +05ypart +06xxpart +06xypart +06yxpart +06yypart +04sqrt +04mexp +04mlog +04sind +04cosd +05floor +14uniformdeviate +10charexists +05angle +05cycle +02++ +02or +03and +02<= +02>= +02<> +07rotated +07slanted +06scaled +07shifted +11transformed +07xscaled +07yscaled +07zscaled +17intersectiontimes +09substring +07subpath +13directiontime +05point +10precontrol +11postcontrol +09penoffset +02.. +13tracingtitles +16tracingequations +15tracingcapsules +14tracingchoices +12tracingspecs +11tracingpens +15tracingcommands +15tracingrestores +13tracingmacros +12tracingedges +13tracingoutput +12tracingstats +13tracingonline +04year +05month +03day +04time +08charcode +07charext +06charwd +06charht +06chardp +06charic +06chardx +06chardy +10designsize +04hppp +04vppp +07xoffset +07yoffset +07pausing +12showstopping +10fontmaking +08proofing +09smoothing +12autorounding +11granularity +06fillin +12turningcheck +12warningcheck +12boundarychar +09 at line +14a bad variable +02fi +08endgroup +06enddef +06endfor +13 INACCESSIBLE +09hash size +06EQUIV( +02:: +03||: +02:= +05addto +02at +07atleast +10begingroup +08controls +04cull +04curl +10delimiters +07display +08everyjob +06exitif +11expandafter +04from +08inwindow +07interim +03let +11newinternal +02of +10openwindow +10randomseed +04save +10scantokens +07shipout +06skipto +04step +03str +07tension +02to +05until +05token +05 ETC. +10 CLOBBERED +11 IMPOSSIBLE +12 NONEXISTENT +04 BAD +02[] +05(EXPR +07(SUFFIX +05(TEXT +02-> +03>-> +08<expr>-> +19<expr>of<primary>-> +10<suffix>-> +08<text>-> +07(SAVED) +03var +02xx +02xy +02yx +02yy +08%CAPSULE +05part +06struct +11{restoring +04Path +07{open?} +10..control? +03 .. +06{curl +10..tension +05 and +11..controls +02?? +16, before choices +15, after choices +23Some number got too big +46The path that I just computed is out of range. +53So it will probably look funny. Proceed, for a laugh. +09path size +14Edge structure +04row +02 | +31Scaled picture would be too big +50I can't yscale the picture as requested---it would +45make some coordinates too large or too small. +42Proceed, and I'll omit the transformation. +50I can't xscale the picture as requested---it would +15move table size +13Tracing edges +09 (weight +21(No new edges added.) +10Cycle spec +24 % beginning in octant ` +19% entering octant ` +08 & cycle +03ENE +03NNE +03NNW +03WNW +03WSW +03SSW +03SSE +03ESE +14 ..controls +11 % segment +02 ( +33, before subdivision into octants +19, after subdivision +43, after subdivision and double autorounding +36, after subdivision and autorounding +18Curve out of range +56At least one of the coordinates in the path I'm about to +56digitize was really huge (potentially bigger than 4095). +40So I've cut it back to the maximum size. +41The results will probably be pretty wild. +19rounding table size +11Pen polygon +09 .. cycle +04 .. +16 (newly created) +13Pen too large +59The cycle you specified has a coordinate of 4095.5 or more. +55So I've replaced it by the trivial path `(0,0)..cycle'. +24Pen cycle must be convex +59The cycle you specified either has consecutive equal points +54or turns right or turns through more than 360 degrees. +16pen polygon size +09@ Octant +07 offset +08), from +04 to +23@ retrograde line from +18@ transition line +07, from +03dep +02*4 +20Value is too large ( +53The equation I just processed has given some variable +54a value of 4096 or more. Continue and I'll try to cope +47with that big value; but it might be dangerous. +47(Set warningcheck:=0 to suppress this message.) +05#### +03## +15Bad PREVDEP at +16Out of order at +18Redundant equation +43I already knew that this equation was true. +50But perhaps no harm has been done; let's continue. +23[unknown command code!] +03<*> +08<insert> +12<scantokens> +02l. +10<forever> +11<argument> +16<recently read> +19<to be read again> +16<inserted text> +05<for( +03)> +16input stack size +17text input levels +08endinput +47Incomplete if; all text was ignored after line +51A forbidden `outer' token occurred in skipped text. +58This kind of error happens when you say `if...' and forget +57the matching `fi'. I've inserted a `fi'; this might work. +53The file ended while I was skipping conditional text. +10File ended +21Forbidden token found +16 while scanning +41I suspect you have forgotten an `enddef', +52causing me to read past where you wanted me to stop. +49I'll try to recover; but if the error is serious, +51you'd better type `E' or `X' now and fix your file. +27to the end of the statement +42A previous error seems to have propagated, +15a text argument +45It seems that a right delimiter was left out, +18the definition of +14the text of a +05 loop +41I suspect you have forgotten an `endfor', +08Runaway +05text? +11definition? +05loop? +39Text line contains an invalid character +53A funny symbol that I can't read has just been input. +48Continue, and I'll forget that it ever happened. +40Incomplete string token has been flushed +53Strings should finish on the same line as they began. +50I've deleted the partial string; you might want to +48insert another by typing, e.g., `I"new string"'. +32Enormous number has been reduced +52I can't handle numbers bigger than about 4095.99998; +53so I've changed your constant to that maximum amount. +36(Please type a command or say `end') +37*** (job aborted, no legal end found) +02=> +03def +06vardef +10primarydef +12secondarydef +11tertiarydef +03for +11forsuffixes +07forever +05quote +02#@ +02@# +31Missing symbolic token inserted +52Sorry: You can't redefine a number, string, or expr. +49I've inserted an inaccessible symbol so that your +60definition will be completed without mixing me up too badly. +51Sorry: You can't redefine my error-recovery tokens. +50The next thing in this `def' should have been `=', +54because I've already looked at the definition heading. +49But don't worry; I'll pretend that an equals sign +45was present. Everything from here to `enddef' +43will be the replacement text of this macro. +04expr +06suffix +04text +07primary +09secondary +08tertiary +41This variable already starts with a macro +44After `vardef a' you can't say `vardef a.b'. +40So I'll have to discard this definition. +46Missing parameter type; `expr' will be assumed +52You should've had `expr' or `suffix' or `text' here. +20parameter stack size +14Extra `endfor' +40I'm not currently working on a for loop, +40so I had better not try to end anything. +05input +09Lost loop +53I'm confused; after exiting from a loop, I still seem +53to want to repeat it. I'll try to forget the problem. +22No loop is in progress +51Why say `exitif' when there's nothing to exit from? +57After `exitif <boolean exp>' I expect to see a semicolon. +35I shall pretend that one was there. +20*** (loop confusion) +12Not a string +41I'm going to flush this expression, since +48scantokens should be followed by a known string. +03)<- +22Too many arguments to +11 Missing ` +52I'm going to assume that the comma I just read was a +57right delimiter, and then I'll begin expanding the macro. +55You might want to delete some tokens before continuing. +20Missing argument to +48That macro has more parameters than you thought. +54I'll continue by pretending that each missing argument +23is either zero or null. +54I've finished reading a macro argument and am about to +56read another; the arguments weren't delimited correctly. +51I've gotten to the end of the macro parameter list. +05 for +57I've got the first argument; will look now for the other. +02if +04else +06elseif +49There should've been a colon after the condition. +06{true} +07{false} +06Extra +43I'm ignoring this; it doesn't match any if. +09Improper +38When you say `for x=a step b until c', +43the initial value `a' and the step size `b' +55and the final value `c' must have known numeric values. +57The next thing in this loop should have been `=' or `:='. +47was present, and I'll look for the values next. +51The next thing in this loop should have been a `:'. +41So I'll pretend that a colon was present; +50everything from here to `endfor' will be iterated. +07 ENDFOR +12{loop value= +13initial value +09step size +47I assume you meant to say `until' after `step'. +48So I'll look for the final value and colon next. +11final value +05.base +15input file name +19I can't find file ` +23I can't write on file ` +02'. +03.mf +20Please type another +45*** (job aborted, file error in nonstop mode) +02: +05mfput +04.log +02** +20transcript file name +02 +20file name for output +37File names can't appear within macros +46Sorry...I've converted what follows to tokens, +37possibly garbaging the name you gave. +51Please delete the tokens and insert the name again. +03exp +26 (see the transcript file) +13 (future pen) +10linearform +03>> +07recycle +04### +03 = +09A primary +30 expression can't begin with ` +58I'm afraid I need some sort of value in order to continue, +49so I've tentatively inserted `0'. You may want to +43delete this zero and insert something else; +50see Chapter 27 of The METAFONTbook for an example. +39Nonnumeric ypart has been replaced by 0 +48I thought you were giving me a pair `(x,y)'; but +50after finding a nice xpart `x' I found a ypart `y' +54that isn't of numeric type. So I've changed y to zero. +59(The y that I didn't like appears above the error message.) +22A group begun on line +12 never ended +56I saw a `begingroup' back there that hasn't been matched +47by `endgroup'. So I've inserted `endgroup' now. +16Division by zero +43I'll pretend that you meant to divide by 1. +44Improper subscript has been replaced by zero +54A bracketed subscript must have a known numeric value; +59unfortunately, what I found was the value that appears just +55above this error message. So I'll try a zero subscript. +09Variable +21 has been obliterated +54It seems you did a nasty thing---probably by accident, +46but nevertheless you nearly hornswoggled me... +50While I was evaluating the right-hand side of this +51command, something happened, and the left-hand side +52is no longer a variable! So I won't change anything. +51While I was evaluating the suffix of this variable, +55something was redefined, and it's no longer a variable! +59In order to get back on my feet, I've inserted `0' instead. +04copy +47I've scanned an expression of the form `a[b,c', +41so a right bracket should have come next. +51I've seen a `[' and a subscript value, in a suffix, +11A secondary +10A tertiary +24Pen path must be a cycle +39I can't make a pen from the given path. +02An +49Undefined coordinates have been replaced by (0,0) +49I need x and y numbers for this part of the path. +42The value I found (see above) was no good; +48so I'll try to keep going by using zero instead. +45(Chapter 27 of The METAFONTbook explains that +36you might want to type `I ???' now.) +45Undefined x coordinate has been replaced by 0 +51I need a `known' x value for this part of the path. +45Undefined y coordinate has been replaced by 0 +51I need a `known' y value for this part of the path. +49I've scanned a direction spec for part of a path, +39so a right brace should have come next. +36Improper curl has been replaced by 1 +43A curl must be a known, nonnegative number. +46I've got the x coordinate of a path direction; +36will look for the y coordinate next. +45A path join command should end with two dots. +34Improper tension has been set to 1 +53The expression above should have been a number >=3/4. +46Paths don't touch; `&' will be changed to `..' +48When you join paths `p&q', the ending point of p +49must be exactly equal to the starting point of q. +53So I'm going to pretend that you said `p..q' instead. +46Undefined condition will be treated as `false' +53The expression shown above should have had a definite +48true-or-false value. I'm changing it to `false'. +40*** (cannot readstring in nonstop modes) +12unknown pair +15unknown numeric +17Not implemented: +59I'm afraid I don't know how to apply that operation to that +53particular type. Continue, and I'll simply return the +54argument (shown above) as the result of the operation. +02)} +30String contains illegal digits +55I zeroed out characters that weren't in the range 0..7. +48I zeroed out characters that weren't hex digits. +18Number too large ( +57I have trouble with numbers greater than 4095; watch out. +58combination of types. Continue, and I'll return the second +52argument (see above) as the result of the operation. +02{( +49The quantities shown above have not been equated. +60Oh dear. I can't decide if the expression above is positive, +59negative, or zero. So this comparison test won't be `true'. +41Unknown relation will be considered false +03)*( +58You're trying to divide the quantity shown above the error +55message by zero. I'm going to divide it by one instead. +32Improper transformation argument +46The expression shown above has the wrong type, +39so I can't transform anything using it. +37Transform components aren't all known +56I'm unable to apply a partially specified transformation +42except to a fully known pair or transform. +31That transformation is too hard +49I can apply complicated transformations to paths, +49but I can only do integer operations on pictures. +16Too far to shift +49I can't shift the picture as requested---it would +30A statement can't begin with ` +51I was looking for the beginning of a new statement. +58If you just proceed without changing anything, I'll ignore +56everything up to the next `;'. Please insert a semicolon +58now in front of anything that you don't want me to delete. +52(See Chapter 27 of The METAFONTbook for an example.) +28Extra tokens will be flushed +59I've just read as much of that statement as I could fathom, +59so a semicolon should have been next. It's very puzzling... +53but I'll try to get myself back together, by ignoring +19Isolated expression +40I couldn't find an `=' or `:=' after the +50expression that is shown above this error message, +44so I guess I'll just ignore it and carry on. +36Improper `:=' will be changed to `=' +54I didn't find a variable name at the left of the `:=', +50so I'm going to pretend that you said `=' instead. +03)=( +19Internal quantity ` +28' must receive a known value +56I can't set an internal quantity to anything but a known +54numeric value, so I'll have to ignore this assignment. +30Equation cannot be performed ( +58I'm sorry, but I don't know how to make such things equal. +55(See the two expressions just above the error message.) +34Redundant or inconsistent equation +56An equation between already-known quantities can't help. +50But don't worry; continue and I'll just ignore it. +21Inconsistent equation +58The equation I just read contradicts what was said before. +09 (off by +48Declared variable conflicts with previous vardef +56You can't use, e.g., `numeric foo[]' after `vardef foo'. +51Proceed, and I'll ignore the illegal redeclaration. +51Illegal suffix of declared variable will be flushed +50Variables in declarations must consist entirely of +46names and collective subscripts, e.g., `x[]a'. +57Are you trying to use a reserved word in a variable name? +43I'm going to discard the junk I found here, +51up to the next comma or the end of the declaration. +49Explicit subscripts like `x15a' aren't permitted. +16Extra `endgroup' +44I'm not currently working on a `begingroup', +03end +04dump +46Always say `randomseed:=<numeric expression>'. +29Unknown value will be ignored +48Your expression was too random for me to handle, +43so I won't change the random seed just now. +13{randomseed:= +13errorstopmode +05inner +05outer +55I found no right delimiter to match a left one. So I've +56put one in, behind the scenes; this may fix the problem. +11The token ` +32' is no longer a right delimiter +48Strange: This token has lost its former meaning! +44I'll read it as a right delimiter this time; +43but watch out, I'll probably miss it later. +10(%CAPSULE) +28' isn't an internal quantity +55Something like `tracingonline' should follow `interim'. +46You should have said `let symbol = something'. +55was present. The next token I read will be `something'. +19number of internals +09showtoken +09showstats +04show +12showvariable +16showdependencies +02> +08(outer) +03lef +04righ +25t delimiter that matches +03tag +08variable +06macro: +09'd macro: +17[repeat the loop] +13Memory usage +17 still untouched) +13String usage +07=macro: +02OK +56This isn't an error message; I'm just showing something. +07contour +10doublepath +04also +07withpen +10withweight +08dropping +07keeping +13Improper type +54Next time say `withweight <known numeric expression>'; +55I'll ignore the bad `with' clause and look for another. +47Next time say `withpen <known pen expression>'; +40Weight must be -3, -2, -1, +1, +2, or +3 +20 is the wrong type ( +45I was looking for a "known" picture variable. +37So I'll not change anything just now. +23Not a suitable variable +61At this point I needed to see the name of a picture variable. +58(Or perhaps you have indeed presented me with one; I might +59have missed it, if it wasn't followed by the proper token.) +16Improper `addto' +54This expression should have specified a known picture. +46This expression should have been a known path. +11Not a cycle +58That contour should have ended with `..cycle' or `&cycle'. +37Strange path (turning number is zero) +43Backwards path (turning number is negative) +53The path doesn't have a counterclockwise orientation, +41so I'll probably have trouble drawing it. +51(See Chapter 27 of The METAFONTbook for more help.) +17Bad window number +42It should be the number of an open window. +21Improper `openwindow' +52Say `openwindow k from (r0,c0) to (r1,c1) at (x,y)', +57where all quantities are known and k is between 0 and 15. +19Bad culling amounts +44Always cull by known amounts that exclude 0. +07message +10errmessage +07errhelp +46A message should be a known string expression. +32(That was another `errmessage'.) +51This error message was generated by an `errmessage' +43command, so I can't give any explicit help. +51Pretend that you're Miss Marple: Examine all clues, +41and deduce the truth by inspired guesses. +09Enormous +17 has been reduced +48Font metric dimensions must be less than 2048pt. +08charlist +08ligtable +10extensible +10headerbyte +09fontdimen +35Invalid code has been replaced by 0 +54I was looking for a number between 0 and 255, or for a +55string of length 1. Didn't find it; will use 0 instead. +10Character +02|| +05code +12 is already +13in a ligtable +13in a charlist +51It's not legal to label a character more than once. +17Improper location +43I was looking for a known, positive number. +50For safety's sake I'll ignore the present command. +56A colon should follow a headerbyte or fontinfo location. +21Illegal ligtable step +38I was looking for `=:' or `kern' here. +13ligtable size +02=: +03=:| +04=:|> +03|=: +04|=:> +04|=:| +05|=:|> +06|=:|>> +04kern +15Too far to skip +57At most 127 lig/kern steps can separate skipto1 from 1::. +13Improper kern +51The amount of kern should be a known numeric value. +39I'm processing `extensible c: t,m,b,r'. +23Improper font parameter +06(some +41 values had to be adjusted by as much as +03pt) +47(illegal design size has been changed to 128pt) +04.tfm +26file name for font metrics +24Font metrics written on +13(local label +15:: was missing) +24(a font metric dimension +23 font metric dimensions +21 had to be decreased) +17 METAFONT output +03.gf +02gf +19 (just shipped out) +51(There's unbounded black in character shipped out!) +07special +10numspecial +21Unsuitable expression +59The expression shown above has the wrong type to be output. +06title +18Output written on +10 character +02, +08 bytes). +08 (INIMF) +25 strings of total length +43 memory locations dumped; current usage is +16 symbolic tokens +17 (preloaded base= +14base file name +26Beginning to dump on file +22Transcript written on +02 ) +19(end occurred when +09 on line +16 was incomplete) +52(see the transcript file for additional information) +33(dump is performed only by INIMF) +21debug # (-1 to exit): +*415546872 diff --git a/systems/knuth/local/mf-sparc/mf_arith.c b/systems/knuth/local/mf-sparc/mf_arith.c new file mode 100644 index 0000000000..5347107e81 --- /dev/null +++ b/systems/knuth/local/mf-sparc/mf_arith.c @@ -0,0 +1,142 @@ +/* + * mf_arith.c -- optimized arithmetic routines for UNIX METAFONT 84 + * + * 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. + * + * As yet I don't have code for SPARC, so I'm just using a C version + * by richards, in hopes that cc does better than pc on the brute-force + * algorithm found in mf.web. + * + * 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. } + * + */ + +#include "h00vars.h" + +extern bool aritherror; /* to be set on overflow */ + +#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 */ + +int makefraction(p, q) + register int p, q; +{ + int negative; + register int be_careful; + register int 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)); + +} + +int takefraction(q, f) + register int q; + register int 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)); +} + + diff --git a/systems/knuth/local/mf-sparc/mf_sunwin.c b/systems/knuth/local/mf-sparc/mf_sunwin.c new file mode 100644 index 0000000000..f1e9fa9b39 --- /dev/null +++ b/systems/knuth/local/mf-sparc/mf_sunwin.c @@ -0,0 +1,90 @@ +/* + * XView interface to MetaFont + * (written hastily and without much understanding...) + */ +#define SCREENWIDTH 1024 /* must match the constant in inimf.ch */ +#define SCREENDEPTH 800 /* must match the constant in inimf.ch */ + +#include <stdio.h> +#include <xview/xview.h> +#include <xview/canvas.h> +#include <X11/Xlib.h> + +static Frame frame; /* container */ +static Canvas canvas; /* the viewing and imaging area */ +static Xv_Window canvas_paintwin; /* image component of |canvas| */ +static Display *display; /* handle to X server */ +static Visual *screen; /* where the X server paints */ +static Window xcanvas; /* the X11 ``drawable'' component of our canvas */ +static GC gc; /* X graphic context */ +static XGCValues GCvalues; /* changes to a graphic context */ + +/* + * updatescreen; -- make sure screen display is current + */ + +updatescreen() +{ + notify_dispatch(); + XFlush(display); +} + +/* + * init_screen: boolean; return true if window operations legal + */ + +initscreen() +{ + if (xv_init(NULL)==NULL) return 0; + frame=(Frame)xv_create(NULL,FRAME,XV_WIDTH,700,XV_HEIGHT,600, + FRAME_SHOW_HEADER,FALSE, + XV_SHOW,TRUE,NULL); + canvas=(Canvas)xv_create(frame,CANVAS,CANVAS_REPAINT_PROC,updatescreen, + CANVAS_X_PAINT_WINDOW,TRUE, + XV_HEIGHT,SCREENDEPTH,XV_WIDTH,SCREENWIDTH, + CANVAS_AUTO_EXPAND,FALSE,CANVAS_AUTO_SHRINK,FALSE, + NULL); + canvas_paintwin=(Xv_window)xv_get(canvas,CANVAS_NTH_PAINT_WINDOW,0); + xcanvas=(Window)xv_get(canvas_paintwin,XV_XID); + display=(Display*)xv_get(frame,XV_DISPLAY); + screen=(Visual*)xv_get(frame,XV_VISUAL); + gc=XCreateGC(display,DefaultRootWindow(display),0,GCvalues); + notify_do_dispatch(); /* this should allow terminal input */ + return 1; +} + +/* + * blankrectangle: reset rectangle bounded by ([left,right],[top,bottom]) + * to background color + */ + +blankrectangle(left, right, top, bottom) + short left, right; + short top, bottom; +{ + XSetFunction(display,gc,GXclear); + XFillRectangle(display,xcanvas,gc,left,top,right-left,bottom-top); +} + +/* + * paintrow -- paint row r starting with color b, up to next + * transition specified by vector a, switch colors, + * and continue for n transitions. + */ + +paintrow(r, b, a, n) + short r; + short b; + short a[]; + short n; +{ + register short *p,*q=&a[n]; + XSetFunction(display,gc,b?GXset:GXclear); + for (p=a;p<q;p+=2) + XFillRectangle(display,xcanvas,gc,*p,r,*(p+1)-*p,1); + XSetFunction(display,gc,b?GXclear:GXset); + for (p=a+1;p<q;p+=2) + XFillRectangle(display,xcanvas,gc,*p,r,*(p+1)-*p,1); + notify_dispatch(); /* without this, the Notifier queue overflows */ +} + diff --git a/systems/knuth/local/mf-sparc/mf_window.h b/systems/knuth/local/mf-sparc/mf_window.h new file mode 100644 index 0000000000..761cf006c9 --- /dev/null +++ b/systems/knuth/local/mf-sparc/mf_window.h @@ -0,0 +1,15 @@ +{ $Header: mf_window.h,v 0.999999 86/01/13 00:43:56 richards Released $ } + +{ External procedures for UNIX MetaFont VIRMF for display graphics } + +function initscreen: boolean; + external; + +procedure updatescreen; + external; + +procedure blankrectangle(leftcol, rightcol: screencol; toprow, botrow: screenrow); + external; + +procedure paintrow(r: screenrow; b: pixelcolor; var a: transspec; n: screencol); + external; diff --git a/systems/knuth/local/mf-sparc/plain.base b/systems/knuth/local/mf-sparc/plain.base Binary files differnew file mode 100644 index 0000000000..8aff956dc2 --- /dev/null +++ b/systems/knuth/local/mf-sparc/plain.base diff --git a/systems/knuth/local/mf-sparc/plain.log b/systems/knuth/local/mf-sparc/plain.log new file mode 100644 index 0000000000..41d972df4f --- /dev/null +++ b/systems/knuth/local/mf-sparc/plain.log @@ -0,0 +1,16 @@ +This is METAFONT, Version 2.7182 for SunOS (INIMF) 8 AUG 1998 21:30 +**plain \input local \dump +(/home/tex/dist/lib/plain.mf +Preloading the plain base, version 2.71: preliminaries, + basic constants and mathematical macros, + macros for converting from device-independent units to pixels, + macros and tables for various modes of operation, + macros for drawing and filling, + macros for proof labels and rules, + macros for character and font administration, +and a few last-minute items.) (/home/tex/local/lib/local.mf) +Beginning to dump on file plain.base + (preloaded base=plain 98.8.8) +1407 strings of total length 23104 +5273 memory locations dumped; current usage is 1450&3664 +525 symbolic tokens diff --git a/systems/knuth/local/mf-sparc/trap1.in b/systems/knuth/local/mf-sparc/trap1.in new file mode 100644 index 0000000000..1e7b96cab3 --- /dev/null +++ b/systems/knuth/local/mf-sparc/trap1.in @@ -0,0 +1,3 @@ + +\input trap + diff --git a/systems/knuth/local/mf-sparc/trap2.in b/systems/knuth/local/mf-sparc/trap2.in new file mode 100644 index 0000000000..d3dba8ac65 --- /dev/null +++ b/systems/knuth/local/mf-sparc/trap2.in @@ -0,0 +1 @@ + &trap trap |