emasedit2a.c

    /*

                                  EDIT

    Copyright (C)   A.Gibbons   University of Edinburgh   MCMXC

    */

    #define msdos 1
    #define castle 2
    #define metsun 4
    #define hp9000 8
    #define cssun 16
    #define DRS 32
    #define PTX 64
    #define LINUX 128
    #define TARGET LINUX

    #if (TARGET == msdos)

    #include <graph.h>
    #include <stdlib.h>
    #include <process.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <io.h>
    #include <malloc.h>
    #include <time.h>

    #else

    #if (TARGET == hp9000)

    #include <fcntl.h>
    #include <termio.h>
    struct termio termio0, *tio0;

    #else
    #if (TARGET == DRS)
    #include <fcntl.h>
    #endif

    #include <sgtty.h>
    struct sgttyb sgttyb0;

    #endif

    #include <sys/ioctl.h>
    #include <signal.h>
    #include <pwd.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #if (TARGET!=PTX)
    #include <sys/file.h>
    #include <sys/time.h>
    #else
    #include <fcntl.h>
    #endif
    #include <sys/param.h>

    #endif

    extern int errno;
    extern int sys_nerr;
    extern char *sys_errlist[];

    /* --------------------edit variables-------------------- */
    char indent[64];
    int wordm1, emode, use_sif, caseind, topa, bota, seta, curp, begp, endp, txtp,
       actions, cadnew, tmpnew, asl, wsp0, wsp, wse, level, comp, wseen,
       haltered, altered, hcurp, hset, back, changed, nlc, linecomplete,
       lcomp, slinest, sparast, slinel, eterminate, fileusedcount, newf_exists,
       linel, sym, firstpos, /* this line for LAYOUT */
       presif_altered;

    #define MAXPDICT 16384
    #define PRIVDICTNAME "~/.edit-dict"
    #define MAXSDICT 131072

    #ifndef SYSDICTNAME
    /* May be given on CC command line, eg  -DSYSDICTNAME=\"./edit-dict\" */
    #define SYSDICTNAME "/usr/local/lib/edit-dict"
    #endif

    int privdict_changed;
    int sysdicta, sysdictb, privdicta, privdictb, tempdicta, tempdictb;

    #define MAXHASH 10
    int hash[MAXHASH+1];

    static char spellch[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0,
    0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0};

    char cline[160], nls[2], sps[132];
    static char *tempfile = "temp";
    char *byteinteger, *ccase;
    int *integer;

    #define MAXCOUNT 15
    int count[MAXCOUNT+1];

    #define MAXFILE 8
    char fileused[MAXFILE][MAXPATHLEN+1];
    int start_address[MAXFILE], end_address[MAXFILE];

    char oldf[MAXPATHLEN+1], newf[MAXPATHLEN+1], word[33];
    char in[MAXPATHLEN+1], out[MAXPATHLEN+1], prstring[8];
    static char *eha = "~/eha";
    static char *explanation = "well\nnow";

    struct cell {int ll, lp, rp, rl;};

    #define TOPIDENTIFIER 512
    #define TOPSTRING 64
    char identifier[TOPIDENTIFIER], ident[31];
    struct cell string[TOPSTRING];

    struct cell lastrec [16];  /* twice as many as there are commands to allow */
                               /* two strings to be saved */

    struct cell *top, *bot, *set, *cur, *beg, *edit_end, *txt, *new,
       *htop, *hbot, *hcur, *scur,
       *ptop, *pbot;  /* for LAYOUT */

    struct cform {
       char lett, flags, level, swno, errno, loop;
       int count, par;};
    struct cform clist [100];
    struct cform *currcomp, *curcom, *lastcom;

    static unsigned char onecase[]=    {0,
       1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
      17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
      33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
      49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
      97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,
     113,114,115,116,117,118,119,120,121,122, 91, 92, 93, 94, 95, 96,
      97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,
     113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
     129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,
     145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,
     161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,
     177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
     193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,
     209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,
     225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,
     241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};

    static unsigned char twocase[]=    {0,
       1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
      17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
      33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
      49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
      65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
      81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
      97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112,
     113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
     129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,
     145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,
     161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,
     177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
     193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,
     209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,
     225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,
     241,242,243,244,245,246,247,248,249,250,251,252,253,254,255};

    #define BACKWARDS 1
    #define NUMPAR 2
    #define TEXTPAR 4
    #define FILEPAR 8
    #define ERROR 128
    #define NOTINLOOK 128
    #define SPECIAL 64
    #define ALLPAR 14
    #define NEEDSS 32
    #define STOPSPELL 16
    #define MAXI 20000000
    #define SHRIEK 11
    #define NONNULL 9
    #define TEXTCHAR 2
    #define LOOPSTART 7
    #define LOOPEND 8
    #define NUMCHAR 3
    #define FILECHAR 4
    #define FILEEND 5
    #define MINUS 6
    #define COMMAND 1
    #define YES 1
    #define NO 0
    #define SYNTAXERROR 7
    #define INVALIDLOOP 1
    #define CHINLOOK 2
    #define NL 10
    #define SP 32
    #define QUOTE 39
    #define DOUBLEQUOTE 34
    #define PSEUDX "/tmp/edit-XXXXXX"
    char PSEUD[32];
    struct sdf {long len, adr;};  /* so called 'string descriptor' */

    static char chartype1 [] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NL, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, NL, 0, 0, 0, 0, 0, 0,
    SP, SHRIEK, NONNULL, NONNULL, NONNULL, COMMAND, NONNULL, TEXTCHAR,
    LOOPSTART, LOOPEND, NUMCHAR, NUMCHAR, NONNULL, MINUS, TEXTCHAR, TEXTCHAR,
    NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR,
    NUMCHAR, NUMCHAR, NONNULL, NONNULL, FILECHAR, NONNULL, FILEEND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, NONNULL, COMMAND,
    COMMAND, COMMAND, COMMAND, NONNULL, NONNULL, NONNULL, NONNULL, NONNULL,
    NONNULL, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, NONNULL, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, NONNULL, COMMAND,
    COMMAND, COMMAND, COMMAND, NONNULL, NONNULL, NONNULL, NONNULL, 0};

    static char chartype2 [] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NL, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, NL, 0, 0, 0, 0, 0, 0,
    SP, SHRIEK, TEXTCHAR, TEXTCHAR, NONNULL, TEXTCHAR, NONNULL, TEXTCHAR,
    LOOPSTART, LOOPEND, NUMCHAR, NUMCHAR, NONNULL, MINUS, TEXTCHAR, TEXTCHAR,
    NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR, NUMCHAR,
    NUMCHAR, NUMCHAR, NONNULL, NONNULL, FILECHAR, NONNULL, FILEEND, TEXTCHAR,
    NONNULL, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, NONNULL, COMMAND,
    COMMAND, COMMAND, COMMAND, NONNULL, NONNULL, NONNULL, NONNULL, NONNULL,
    NONNULL, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, NONNULL, COMMAND, COMMAND, COMMAND,
    COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, COMMAND, NONNULL, COMMAND,
    COMMAND, COMMAND, COMMAND, NONNULL, NONNULL, NONNULL, NONNULL, 0};

    #define FIRSTCOM 62
    #define LASTCOM 90
       /* ie from > (which is pseudo) to Z */
    static int comdef[] = {
    /*%*/ (36<<16) | TEXTPAR | SPECIAL,
    /*?*/ (35<<24) | NUMPAR,
    /*@*/ (34<<24) | NUMPAR,
    /*A*/ (8<<24) | (7<<16) | ALLPAR | BACKWARDS | STOPSPELL,
    /*B*/ (2<<24) | STOPSPELL,
    /*C*/ (33<<24) | (32<<16) | (7<<12) | ALLPAR | BACKWARDS | NOTINLOOK | NEEDSS | STOPSPELL,
    /*D*/ (12<<24) | (11<<16) | (1<<12) | ALLPAR | BACKWARDS | NOTINLOOK | STOPSPELL,
    /*E*/ (3<<24) | SPECIAL,
    /*F*/ (24<<16) | FILEPAR,
    /*G*/ (23<<24) | NUMPAR | NOTINLOOK | STOPSPELL,
    /*H*/ (18<<24) | SPECIAL | STOPSPELL,
    /*I*/ (4<<16) | (2<<12) | BACKWARDS | FILEPAR | TEXTPAR |NOTINLOOK | STOPSPELL,
    /*J*/ (28<<24) | NUMPAR | NOTINLOOK | STOPSPELL,
    /*K*/ (17<<24) | NEEDSS | STOPSPELL,
    /*L*/ (27<<24) | NUMPAR | NOTINLOOK | STOPSPELL,
    /*M*/ (6<<24) | (5<<16) | (3<<12) |ALLPAR | BACKWARDS | STOPSPELL,
    /*N*/ (31<<24),
    /*O*/ (21<<24) | NEEDSS | STOPSPELL,
    /*P*/ (10<<24) | (9<<16) | (4<<12) | ALLPAR | BACKWARDS,
    /*Q*/ (15<<24),
    /*R*/ (14<<24) | (13<<16) | (5<<12) |ALLPAR | BACKWARDS | NOTINLOOK | STOPSPELL,
    /*S*/ (16<<24),
    /*T*/ (1<<24) | STOPSPELL,
    /*U*/ (20<<24) | (19<<16) | (6<<12) | ALLPAR | BACKWARDS | NOTINLOOK | NEEDSS | STOPSPELL,
    /*V*/ -1,
    /*W*/ (25<<24) | NOTINLOOK | STOPSPELL,
    /*X*/ (29<<24),
    /*Y*/ (30<<24),
    /*Z*/ (26<<24)};

    /*----------------------------------------------------------------------*/

    static int input_pointer;
    static char inputline[256];
    static char prompt_string[80];
    static char default_prompt[64];

    struct ff {
       int start;
       int end;
       int descr;
       int size;
       int timestamp;
       char file[MAXPATHLEN+1];
    };

    struct tracef {char w[256];};
    struct tracef traceb[20];
    int tracep;

    /*----------------------------------------------------------------------*/

    wrs(s) char *s; {
       printf("%s\n", s);
    } /* wrs */

    /*----------------------------------------------------------------------*/

    textof(flag, text) int flag; char *text; {
       if (flag < sys_nerr) strcpy(text, sys_errlist[flag]);
       else sprintf(text, "UNIX error %d", flag);
    } /* textof */

    /*----------------------------------------------------------------------*/

    emasconnect(f) struct ff *f; {
    struct stat buf;
    char s[127];

    /* open(2) #include <sys/file.h>
       stat(2) #include <sys/types.h>
               #include <sys/stat.h>
    */
       if ((f->descr = open(f->file, O_RDONLY, 0)) >= 0) {
          if (stat(f->file, &buf) >= 0) {
             f->size = buf.st_size;
             f->timestamp = buf.st_mtime;
             f->start = calloc(1, f->size+32);
             if (f->start >= 0) {
                f->start = (f->start + 31) & (-32);
                if(read(f->descr, f->start, f->size) >= 0) {
                   f->end = f->start + f->size;
                   close(f->descr); return(0);
                }
             }
          }
       }
       textof(errno, s);
       printf("%s\n", s);
       return(errno);
    } /* emasconnect */

    /*----------------------------------------------------------------------*/

    readline() {
    int p, ch;
       printf("%s", prompt_string);
       for (p=0;;) {
          if ((ch = getchar()) == NL) break;
          inputline[p++] = ch;
       }
       inputline[p] = 0;
       trace(inputline);
       inputline[p++] = NL; inputline[p] = 0;
       input_pointer = 0;
    } /* readline */

    /*----------------------------------------------------------------------*/

    skipsymbol() {
       if (inputline[input_pointer++] == 0) {
          readline();
          input_pointer = 1;
       }
    } /* skipsymbol */

    /*----------------------------------------------------------------------*/

    nextsymbol() {
       if (inputline[input_pointer] == 0) readline();
       return(inputline[input_pointer]);
    } /* nextsymbol */

    /*----------------------------------------------------------------------*/

    readsymbol() {
       if (inputline[input_pointer] == 0) readline();
       return(inputline[input_pointer++]);
    } /* readsymbol */

    /*----------------------------------------------------------------------*/

    substr(s1, s2, p, q) char *s1, *s2; int p, q; {
    int j;
       for (j=0;;) {
          s1[j++] = s2[p++];
          if (p > q) break;
       }
       s1[j] = 0;
    } /* substr */

    /*----------------------------------------------------------------------*/

    kday(d, m, y, dayno, date, ttime) int *d, *m, *y, *dayno; char *date, *ttime; {
    int id, im, iy,tvsecs;
    char dd[3], mm[5], yy[3];
    int secs_per_day, k, w;
    char *udt;

    /* gettimeofday(2) #include <sys/time.h>
       ctime(3c)
    */
    #if (TARGET != PTX)
    struct timeval tv;
    struct timezone tz;
       gettimeofday(&tv, &tz);
       udt = ctime(&tv.tv_sec);
         tvsecs=tv.tv_sec;
    #else
       tvsecs=time(0);
       udt=ctime(&tvsecs);
    #endif
       substr(ttime, udt, 11, 18);
       secs_per_day = 60 * 60 * 24;
       k = tvsecs / secs_per_day;
       k = k + 25567;
       *dayno = k;
       k = k + 693902;
       w = (4*k) - 1;
       iy = w / 146097;
       k = w - (146097*iy);
       id = k / 4;
       k = (4*id + 3) / 1461;
       id = 4*id + 3 - 1461*k;
       id = (id + 4) / 4;
       im = (5*id - 3) / 153;
       id = 5*id - 3 - 153*im;
       id = (id + 5) / 5;
       iy = k;
       if (im < 10) im = im + 3; else {
          im = im - 9;
          if (iy == 99) iy = 0; else iy++;
       }
       sprintf(dd, "%02d", id);
       sprintf(mm, "%02d", im);
       sprintf(yy, "%d", iy);
    strcpy(date, dd);
       strcat(date, "/"); strcat(date, mm);
       strcat(date, "/"); strcat(date, yy);
       *d = id; *m = im; *y = iy;
    } /* kday */

    /*----------------------------------------------------------------------*/

    datefields(monday, nth, july, y1988, date, time) char *monday, *nth, *july, *y1988, *date, *time; {

    static char *day[] = {"Mon", "Tues", "Wednes", "Thurs", "Fri", "Sat", "Sun"};
    static char *mon[] = {"", "January", "February", "March", "April", "May",
          "June", "July", "August", "September", "October", "November", "December"};
    static char *ord[] = {"", "st",  "nd", "rd"};

    int d, m, y, q, r, dayno;
    char th[3], dd[3], yy[3];

       kday(&d, &m, &y, &dayno, date, time);
       dayno = dayno - 7*(dayno/7);
       strcpy(monday, day[dayno]); strcat(monday, "day");
       q = d/10; r = d - (10*q);
       if ((q != 1) && (1 <= r) && (r <= 3)) strcpy(th, ord[r]); else strcpy(th, "th");
       sprintf(nth, "%d%s", d, th);
       strcpy(july, mon[m]);
       sprintf(y1988, "19%d", y);
    } /* datefields */

    /*----------------------------------------------------------------------*/

    vstring(n, s) int n; char *s; {
    char monday[15], nth[7], july[15], y1988[7];
    char date[16], time[16];

       datefields(monday, nth, july, y1988, date, time);
       switch(n) {
    case 1:
          sprintf(s, "%s %s %s %s", monday, nth, july, y1988);
          return;
    case 2:
          strcpy(s, time); return;
    default:
          sprintf(s, "%d", n);
       }
    } /* vstring */

    /*----------------------------------------------------------------------*/

    trace(w) char *w; {
    char ww[256];
       strcpy(ww, w);
       ww[80] = 0;
       strcpy(traceb[tracep++].w, ww);
       if (tracep == 19) tracep = 0;
    } /* trace */

    /*----------------------------------------------------------------------*/

    help(screen) int screen; {

    int q, p0;
    char w[80];

    if (screen <= 1) {
       wrs("         HELP Information for edit");
    drawline();
    wrs("a  After                               n  igNore                       ");
    wrs("b  Bottom                              o  Over                         ");
    wrs("c  Copy                                p  Print                        ");
    wrs("d  Delete                              q  Quit                         ");
    wrs("e  Exit                                r  Remove                       ");
    wrs("f  File                                s  Separate                     ");
    wrs("g  Goto                                t  Top                          ");
    wrs("h  Hold                                u  Uproot                       ");
    wrs("i  Insert                              v  XXXX                         ");
    wrs("j  Justify                             w  Write                        ");
    wrs("k  Kill                                x  Spell                        ");
    wrs("l  Layout                              y  Yes                          ");
    wrs("m  Move                                z  Case                         ");
    wrs("?2 for ALERT");

    drawline();
    }

    if (screen == 2) {
       wrs("        edit ALERT");
    drawline();
    wrs("? gives help information");
    wrs("");
    wrs("A value can be assigned to a variable and then used wherever a text");
    wrs("string is appropriate. For example,");
    wrs("     Edit: %me=/Tony Gibbons/");
    wrs("     Edit: (r.xxx.i%me)*");
    wrs("Assignments can also be made with f<%name>. %date and %time give the");
    wrs("current date and time. %z gives the value of the string last entered.");
    wrs("%name includes the value of the variable in the command string.");
    wrs("");
    wrs("#, or #1, gives the repetition number within a loop (0, 1, 2...)");
    wrs("#2, #3 etc for inner loops");
    wrs("");
    wrs("i-/text/ inserts text and leaves cursor before it");
    wrs("");
    wrs("c is similar to u but copies the text rather than moving it");
    wrs("");
    wrs("i' refers to the last specific text, i\" to the one before");
    wrs("similarly for a, d, m, p, r, u and v");

    drawline();
    }

    if (screen == 3) {
       wrs("edit trace");
       drawline();
       q = p0 = tracep;
       for (;;) {
          wrs(traceb[q++].w);
          if (q == 19) q = 0;
          if (q == p0) break;
       }
    }
    } /* help */

    /*----------------------------------------------------------------------*/

    drawline() {
    int n, width;
    char w[255];
       width = 80;
       for (n=0; n<width; n++) w[n] = '-';
       w[width] = 0;
       wrs(w);
    } /* drawline */

    /*----------------------------------------------------------------------*/

    move(length, from, to) int length; char *from, *to; {
    int j;
       for (j=0;j<length;j++) to[j] = from[j];
    } /* move */

    /*----------------------------------------------------------------------*/

    strres(s1,s2,s3,s4)  /* performs s1 -> s2 . (s3) . s4  */
                     /* return(0) for success          */
       char *s1;
       char *s2;
       char *s3;
       char *s4;
    {
       int len1, len3, i, j, p;
       len1 = strlen(s1);
       len3 = strlen(s3);
       if (len3 == 0) return(1);
       if (len3 > len1) return(2);

       for(i=0;;++i){
          if (i > (len1-len3)) return(3);
          for(j=0;;++j) {
             if (s3[j] == 0) {   /* success */
                if (i>0) strncpy(s2,s1,i);
                s2[i]=0;
                p=0;
                while ((s4[p]=s1[i+j+p]) != 0) ++p;
                return(0);
             }
             if (s3[j] != s1[i+j]) break;
          }
       }
    } /* strres */

    /*----------------------------------------------------------------------*/

    dump(adr, len) int adr, len; {
    int *p, j, k, t, u, lines;
    char *ch, y[36];

       lines = (len+15) >> 4;
       for (;;) {
          if (lines-- <= 0) break;
          p = (int *)adr;
          ch = (char *)adr;
          adr = adr + 16;
    /*      for (j=0; j<16; j++) {
             if ((ch[j]<32)||(ch[j]>126)) y[j]=32; else y[j] = ch[j];
          }
          y[16] = 0;
    */
    j = p[1]; k = p[2]; y[0] = 0;
    if (k > (j+32)) k = j + 32;
    if ((0 < j) && (j <= k)) {
       for (t=0; j<=k; j++) {
          u = byteinteger[j];
          if (u == NL) u = '<';
          y[t++] = u;
       }
       y[t] = 0;
    }
          printf("%c %x  %x %x %x %x  %s\n", fn1(adr-16), adr-16, p[0], p[1], p[2], p[3], y);
       }
    } /* dump */

    /*----------------------------------------------------------------------*/

    fn1(n) int n; {
       if (n == 0) return(42);
       return(((n-wsp0)>>4)+65);
    } /* fn1 */

    /*----------------------------*/

    diagnostic(n) int n; {
    int j, k, p, q, s;
    char w[80];
    struct cform *c;
       printf("Diagnostic output:\n");

    if ((n & 8) > 0) {
       printf("Strings:\n");
       p = 0;
       for (s=0;;s++) {
          for (q=0;;) {
             if ((ident[q++] = identifier[p++]) == 0) break;
          }
          if (q == 1) break;
          printf("%%%s is ", ident);
          switch(string[s].ll) {
    case 0:
             if (string[s].lp == 0) {printf("unassigned"); break;}
    case 1:
             if (string[s].lp != 0) {
                for (j=string[s].lp; j<=string[s].rp; j++) printf("%c", byteinteger[j]);
                break;
             }
    case 2:
             vstring(s, &w[0]);
             printf("%s", w);
             break;
          }
          printf("\n");
       }
    }

    if ((n & 4) > 0) {
       printf("Clist:\n");
       printf("currcomp=%x, curcom=%x, lastcom=%x, comp=%d, lcomp=%d\n",
          &currcomp->lett, &curcom->lett, &lastcom->lett, comp, lcomp);
    /*   dump(&clist[0].lett, 64); */
    for (j=0; j<comp; j++) {
       c = (struct cform *)(int)&clist[j].lett;
       printf("lett=%c, flags=x%02x, level=%d, swno=%2d, errno=%d, loop=%d,\
     count=%d, par=x%x\n", c->lett, c->flags, c->level, c->swno,
     c->errno, c->loop, c->count, c->par);
    }
    }

    if ((n & 1) > 0) {
       printf("Cell area:\n");
       printf("begp=%x, endp=%x, curp=%x, asl=%c\n", begp, endp, curp, fn1(asl));
       printf("topa=%c, seta=%c, bota=%c\n", fn1(topa), fn1(seta), fn1(bota));
       printf("top=%c,  bot=%c,  cur=%c,  beg=%c\n",
          fn1(&top->ll), fn1(&bot->ll), fn1(&cur->ll), fn1(&beg->ll));
       printf("set=%c,  end=%c,  txt=%c,  new=%c\n",
          fn1(&set->ll), fn1(&edit_end->ll), fn1(&txt->ll), fn1(&new->ll));
       printf("htop=%c, hbot=%c, hcur=%c, scur=%c\n",
          fn1(&htop->ll), fn1(&hbot->ll), fn1(&hcur->ll), fn1(&scur->ll));
    }
    if ((n & 2) > 0) {
       dump(wsp0, 256);
    }
    } /* diagnostic */

    /*-------------------------------------------------------*/

    expand_filename(s) char *s; {
    int j, pwad;
    char w[MAXPATHLEN];
    struct passwd *passwd;

       pwad = 0;
       if (s[0] == '~') {
          j = strres(s, w, "~", s);
          j = strres(s, w, "/", s);
          if (j == 0) {
             if (w[0] == 0) pwad = (int)getpwuid(getuid()); else pwad = (int)getpwnam(w);
             if (pwad != 0) {
                passwd = (struct passwd*)pwad;
                strcpy(w, passwd->pw_dir);
                strcat(w, "/"); strcat(w, s);
                strcpy(s, w);
             }
          }
       }
    } /* expand_filename

    /*----------------------------------------------------------------------*/

    exist(file) char *file; {
    int descr;
    char s[MAXPATHLEN+1];
    struct stat buf;
       strcpy(s, file);
       expand_filename(s);
       if (stat(s, &buf) == 0)
          return(1); /* exists */
       else return(0);
    } /* exist */

    /*----------------------------------------------------------------------*/

    newcell() {   /* 757 */
    int i, j, k;
    struct cell *w;
       i = asl;
       if (i == 0) {
          i = (wsp+3) & (-4);
          j = i + 4096;
          if (j > wse) extendwork("newcell");
          wsp = j; k = 0;
          while (j > i) {
             j = j - 16;
             integer[j>>2] = k;
             k = j;
          }
       }
       asl = integer[i>>2];
       w = (struct cell *) i;
       w->ll = w->lp = w->rp = w->rl = 0;
    /* printf("newcell: %c\n", fn1(i)); */
       return(i);
    } /* newcell */

    /*----------------------------------------------------------------------*/

    returnlist(one, two) int one, two; {   /* 790 */
    struct cell *work;
    int i;
    /* printf("returnlist: one=%c, two=%c\n", fn1(one), fn1(two)); */
       work = (struct cell *)one;
       while ((int)&work->ll != two) {
          i = work->rl;
          work = (struct cell *)returncell(&work->ll);
       }
    } /* returnlist */

    /*----------------------------------------------------------------------*/

    returncell(i) int i; {   /* 804 */
    struct cell *work;
    /* printf("returncell: %c\n", fn1(i)); */
       work = (struct cell *)i;
       work->ll = asl;
       asl = i;
       return(work->rl);
    } /* returncell */

    /*----------------------------------------------------------------------*/

    lookup(insert) int insert; {
    int n, p, q;
    /* printf("lookup %s, insert=%d\n", ident, insert); */
       n = p = q = 0;
       for (;;) {
          if (identifier[p] == ident[q++]) {
             if (identifier[p] == 0) {
                /* printf("return %d\n", n); */
                return(n);
             }
             p++;
          } else {
             n++;
    if (n >= TOPSTRING) {printf("Too many variables!!!\n"); return(-1);}
             while (identifier[p++] != 0) ;
             if (identifier[p] == 0) {
                if (insert == 0) {/* printf("not found\n"); */ return(-1);}
    if ((p+strlen(ident))>= TOPIDENTIFIER) {printf("Too many variable names!!!\n"); return(-1);}
                strcpy(&identifier[p], ident);
    /* printf("newname, return %d\n", n); */
                return(n);
             }
             q = 0;
          }
       }
    } /* lookup */

    /*----------------------*/

    readtext() {   /* 810 */
    int marker, ch, skippedch, cch, n, p, q;
    char w[128];
       cch = 0x3600; /* tab nl cr ff */
       while(nextsymbol() <= SP) skipsymbol();

       if (nextsymbol() == '%') {  /* use a string */
          skipsymbol();
          for (p=0;;) {
             ch = onecase[nextsymbol()];
             if ((('a' <= ch) && (ch <= 'z')) ||
               ((p > 0) && ('0' <= ch) && (ch <= '9'))) {
                ident[p++] = ch; skipsymbol();
             } else break;
          }
          if (p == 0) return(SYNTAXERROR);
          ident[p] = 0;
          q = lookup(0);
          if (q < 0) return(8);  /* not known */
          switch(string[q].ll) {
    case 0:   /* ordinary */
             if (string[q].lp == 0) return(8); /* string has name but */
                                         /* no value, ie %z initially */
             break;
    case 1:  /* fixed fn */
             if (string[q].lp != 0) break;
    case 2:  /* variable fn */
             vstring(q, &w[0]);
             n = strlen(w);
             if ((wsp+n) >= wse) extendwork("eval fn");
             string[q].lp = wsp;
             move(n, &w[0], wsp); wsp = wsp + n;
             string[q].rp = wsp - 1;
             break;
          }
          txt = (struct cell *)newcell();
          move(8, &string[q].lp, &txt->lp);
          return(0);
       }

       if (nextsymbol() == '#') {  /* loop counter */
          skipsymbol();
          ch = nextsymbol();
          if ((ch < '0') || (ch > '9')) n = 1;
          else {if (readi(&n) == 0) return(SYNTAXERROR);}
          if ((n < 1) || (n > level)) return(9);
          if (wsp+2 >= wse) extendwork("counter");
          txt = (struct cell *)newcell();
          txt->lp = wsp;
          byteinteger[wsp++] = 1;
          txt->rp = wsp;
          byteinteger[wsp++] = n;
          return(0);
       }

       if (nextsymbol() == '<') {marker = '>'; ch = 0;}
       else {
          marker = readsymbol();
          if ((marker != '.') && (marker != '/') && (marker != '?')) return(SYNTAXERROR);
          ch = nextsymbol();
          if (ch == marker) {
             skippedch = readsymbol();
             if (nextsymbol() != marker) return(SYNTAXERROR);
          }
       }
       w[0] = marker; w[1] = ':'; w[2] = 0;
       strcpy(prompt_string, w);
       txt = (struct cell *)newcell();
       txt->lp = wsp;
       for(;;) {
          skippedch = readsymbol();
          for (;;) {
             if (wsp == wse) extendwork("readtext");
             if ((marker == '?') || ((marker == '>') && (ch == 0)) ||
                  (ch >= 32) || (((1<<ch) & cch) != 0)) byteinteger[wsp++] = ch;
             for (;;) {
                ch = readsymbol();
                if ((marker != '>') || ((ch != NL) && (ch != ' '))) break;
             }
             if (ch == marker) break;
          }
          ch = nextsymbol();
          if (ch != marker) break;
       }
       txt->rp = wsp - 1;
       if (level == 0) strcpy(prompt_string, prstring);
       else strcpy(prompt_string, "):");
       if (marker != '>') move(8, &txt->lp, &string[0].lp);
       return(0);
    } /* readtext */

    /*----------------------------------------------------------------------*/

    readi(n) int *n; {   /* 847 */
    int i, j, k, pm;
       for (;;) {
          i = readsymbol();
          if (i > SP) break;
       }
       pm = 1;
       if (i == '-') pm = -1;
       if ((i == '-') || (i == '+')) i = readsymbol();
       if (i == '*') {j = 1; k = MAXI;
       } else {
          j = k = 0;
          for (;;) {
             if ((i < '0') || (i > '9')) break;
             k = 10 * k + i - '0';
             if (k > MAXI) return(0);
             if (j != 0) skipsymbol();
             else j = 1;
             i = nextsymbol();
             while (i == ' ') {
                skipsymbol();
                i = nextsymbol();
             }
          }
       }
       *n = k * pm;
       return(j);
    } /* readi */

    /*----------------------------------------------------------------------*/

    maptxt(adr) int adr; {   /* 873 */
    int d, q;
    char s[MAXPATHLEN+1];
    struct ff f;
       if (adr < 0) adr = -adr;
       txt = (struct cell *)adr;
       d = txt->lp;
       q = byteinteger[d];

       if (q == 1) {  /* # = loop counter */
          sprintf(s, "%d", count[byteinteger[d+1]]);
          q = strlen(s);
          if ((wsp + q) >= wse) extendwork("eval counter");
          txt = (struct cell *)newcell();
          txt->lp = wsp;
          txt->rp = wsp + q - 1;
          strncpy(wsp, s, q);
          wsp = wsp + q;
          return(1);
       }

       if (q == 0) {  /* a filename */
          q = txt->rp - d; /* length of name */
          strncpy(s, d+1, q);
          s[q] = 0;
          expand_filename(s);
          if (strcmp(s, newf) == 0) {
             printf("Inconsistent file use\n");
             return(0);
          }

          for (q=0; q<=fileusedcount; q++) {
             if (strcmp(s, fileused[q]) == 0) {
    /* printf("file %s already known\n", s); */
                txt->lp = start_address[q];
                txt->rp = end_address[q];
                return(1);
             }
          }
             /* not already known */
          strcpy(f.file, s);
          q = emasconnect(&f);
          if (q != 0) return(0);
          txt->lp = f.start;
          txt->rp = f.end - 1;

          if ((fileusedcount+1) < MAXFILE) { /* put in table */
    /* printf("file %s added to table\n", s); */
             strcpy(fileused[++fileusedcount], s);
             start_address[fileusedcount] = txt->lp;
             end_address[fileusedcount] = txt->rp;
          }
          return(1);
       }

       if (txt->rp < d) return(0);
       return(1);
    } /* maptxt */

    /*----------------------------------------------------------------------*/

    separate() {   /* 926 */
       new = (struct cell *)newcell();
       integer[(cur->ll + 12)>>2] = (int)&new->ll;
       new->ll = cur->ll;
       new->lp = cur->lp;
       new->rp = curp - 1;
       cur->lp = curp;
       cur->ll = (int)&new->ll;
       new->rl = (int)&cur->ll;
       altered++;
    } /* separate */

    /*----------------------------------------------------------------------*/

    hsave() {   /* 944 */
    int i;
    struct cell *work, *last, *acopy;
       if (haltered < altered) {
          returnlist(htop->rl, &hbot->ll);
          i = top->rl; last = (struct cell *)&htop->ll;
          for(;;) {
             acopy = (struct cell *)i;
             if (&acopy->ll == &bot->ll) break;
             work = (struct cell *)newcell();
             last->rl = (int)&work->ll;
             work->ll = (int)&last->ll;
             work->lp = acopy->lp;
             work->rp = acopy->rp;
             i = acopy->rl;
             if (&acopy->ll == &cur->ll) {
                hcur = (struct cell *)&work->ll;
                scur = (struct cell *)&cur->ll;
                hcurp = curp;
             }
             last = (struct cell *)&work->ll;
          }
          if (&cur->ll == &bot->ll) {
             hcur = (struct cell *)&hbot->ll;
             scur = (struct cell *)&cur->ll;
             hcurp = curp;
          }
          hbot->ll = (int)&last->ll;
          last->rl = (int)&hbot->ll;
          haltered = altered;
          return;
       }

       if (&scur->ll != &cur->ll) {
          acopy = (struct cell *)&top->ll;
          work = (struct cell *)&htop->ll;
          for (;;) {
             if (&acopy->ll == &cur->ll) break;
             acopy = (struct cell *)acopy->rl;
             work = (struct cell *)work->rl;
          }
          hcur = (struct cell *)&work->ll;
          scur = (struct cell *)&cur->ll;
       }
       hcurp = curp;
    } /* hsave */

    /*----------------------------------------------------------------------*/

    hrestore() {   /* 995 */
    int i, j;
    struct cell *work, *last, *copy;
       seta = 0;
       returnlist(top->rl, &bot->ll);
       last = (struct cell *)&top->ll;
       i = htop->rl;
       for (;;) {
          copy = (struct cell *)i;
          if (i == (int)&hbot->ll) break;
          j = newcell();
          last->rl = j;
          work = (struct cell *)j;
          work->ll = (int)&last->ll;
          work->lp = copy->lp;
          work->rp = copy->rp;
          i = copy->rl;
          if ((work->lp == 0) && (work->rp == 0)) {
             set = (struct cell *)&work->ll;
             seta = j;
          }
          if ((int)&copy->ll == (int)&hcur->ll) {
             cur = (struct cell *)&work->ll;
             scur = (struct cell *)&work->ll;
             curp = hcurp;
          }
          last = (struct cell *)&work->ll;
       }
       if ((int)&hcur->ll == (int)&hbot->ll) {
          cur = (struct cell *)&bot->ll;
          scur = (struct cell *)&bot->ll;
          curp = hcurp;
       }
       last->rl = bota;
       bot->ll = (int)&last->ll;
       altered = haltered;
    } /* hrestore */

    /*----------------------------------------------------------------------*/

    insert() {   /* 1025 */
    int new, prev, ac;
       if ((txt->lp != 0) || (txt->rp != 0)) changed = 1;
       altered++;
       if (curp != cur->lp) separate();
       ac = (int)&cur->ll;
       prev = integer[ac>>2];
       new = (int)&txt->ll;
       integer[ac>>2] = new;
       integer[(prev+12)>>2] = new;
       integer[new>>2] = prev;
       integer[(new+12)>>2] = ac;
    } /* insert */

    /*----------------------------------------------------------------------*/

    find() {   /* 1045 */
    int i;
       beg = (struct cell *) (int) &cur->ll;
       begp = curp;
       i = ccase[byteinteger[txt->lp]];
    thestart: if (begp == 0) return(0);
    again: if (ccase[byteinteger[begp]] == i) goto imp1;
       begp++;
       if (begp <= beg->rp) goto again;
       beg = (struct cell *)beg->rl;
       begp = beg->lp;
       goto thestart;
    imp1: edit_end = (struct cell *) (int) &beg->ll;
       endp = begp;
       txtp = txt->lp;
       for(;;) {
          if (caseind == 0) {
             if (byteinteger[endp] != byteinteger[txtp]) break;
          } else {
             if (ccase[byteinteger[endp]] != ccase[byteinteger[txtp]]) break;
          }
          endp++;
          if (endp > edit_end->rp) {
             edit_end = (struct cell *) edit_end->rl;
             endp = edit_end->lp;
          }
          if (txtp == txt->rp) return(1);
          txtp++;
          if (endp == 0) {
             beg = (struct cell *) (int) &edit_end->ll;
             begp = 0;
             return(0);
          }
       }
       begp++;
       if (begp > beg->rp) {
          beg = (struct cell *)beg->rl;
          begp = beg->lp;
          goto thestart;
       }
       goto again;
    } /* find */

    /*----------------------------------------------------------------------*/

    findb() {   /* 1104 */
    int last;
       edit_end = (struct cell *) (int) &cur->ll;
       endp = curp;
       last = ccase[byteinteger[txt->rp]];
       for (;;) {
          for (;;) {
             if (endp == edit_end->lp) {
                if (integer[(edit_end->ll+8)>>2] == 0) {
                   beg = (struct cell *) (int) &edit_end->ll;
                   begp = endp;
                   return(0);
                }
                edit_end = (struct cell *) edit_end->ll;
                endp = edit_end->rp;
             } else endp--;
             if (ccase[byteinteger[endp]] == last) break;
          }
          beg = (struct cell *) (int) &edit_end->ll;
          begp = endp;
          txtp = txt->rp;
          for (;;) {
             if (txtp <= txt->lp) {
                endp++;
                if (endp > edit_end->rp) {
                   edit_end = (struct cell *) edit_end->rl;
                   endp = edit_end->lp;
                }
                return(1);
             }
             begp--;
             if (begp <beg->lp) {
                if (integer[(beg->ll+8)>>2] == 0) {
                   begp = beg->lp;
                   return(0);
                }
                beg = (struct cell *) beg->ll;
                begp = beg->rp;
             }
             txtp--;
             if (ccase[byteinteger[txtp]] != ccase[byteinteger[begp]]) break;
          }
       }
    } /* findb */

    /*----------------------------------------------------------------------*/

    delete() {   /* 1156 */
    int i;
       changed = 1;
       altered++;
       if ((int)&beg->ll == (int)&edit_end->ll) {
          if (begp == endp) return;
          if (begp == beg->lp) {
             beg->lp = endp;
          } else {
             edit_end = (struct cell *)newcell();
             edit_end->rl = beg->rl;
             integer[(edit_end->rl)>>2] = (int)&edit_end->ll;
             edit_end->rp = beg->rp;
             edit_end->lp = endp;
             edit_end->ll = (int)&beg->ll;
             beg->rl = (int)&edit_end->ll;
             beg->rp = begp - 1;
          }
       } else {
          i = beg->rl;
          while (i != (int)&edit_end->ll) i = returncell(i);
          beg->rl = i;
          edit_end->ll = (int)&beg->ll;
          edit_end->lp = endp;
          if (begp == beg->lp) {
             edit_end->ll = beg->ll;
             if (edit_end->ll != 0) integer[(edit_end->ll + 12)>>2] = i;
             i = returncell(&beg->ll);
          } else {
             beg->rp = begp - 1;
          }
       }
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
    } /* delete */

    /*----------------------------------------------------------------------*/

    printtext() {   /* 1201 */
    int i, j, x;
    char w[3];
       j = 0; w[1] = 0;
       if (begp == beg->lp) {
          if (beg->ll == topa) printf("*T*\n");
          if (beg->ll == seta) printf("*S*\n");
       }
       for(;;) {
          if ((begp == curp) && (&beg->ll == &cur->ll)) printf("^");
          if ((begp == endp) && (&beg->ll == &edit_end->ll)) {
             if (begp == 0) {
                x = (int)&beg->ll;
                if (x == seta) printf("*S*\n");
                if (x == bota) printf("*B*\n");
             }
             return;
          }
          w[0] = byteinteger[begp];
          printf("%s", w);
          if (w[0] == NL) nlc++;
          begp++;
          if (begp > beg->rp) {
             beg = (struct cell *) beg->rl;
             begp = beg->lp;
          }
       }
    } /* printtext */

    /*----------------------------------------------------------------------*/

    charson(n) int n; {   /* 1236 */
    int len;
       edit_end = (struct cell *) &cur->ll;
       endp = curp;
       while (endp != 0) {
          len = edit_end->rp - endp;
          if (n <= len) {endp = endp + n; return(1);}  /* found OK */
          n = n - (len+1);
          edit_end = (struct cell *) edit_end->rl;
          endp = edit_end->lp;
          if (n == 0) return(1);  /* hit *S* or *B* exactly (it says) */
       }
       return(0);  /* hit *S* or *B* */
    } /* charson */

    /*----------------------------------------------------------------------*/

    lineson(n) int n; {   /* 1253 */
    int i;                      /* moves end,endp forward from cur,curp */
       if (n == MAXI) return(charson(n));
       edit_end = (struct cell *) &cur->ll;
       endp = curp;
       i = 0;
       for(;;) {
          if (i == n) return(1);
          if (endp == 0) return(0);
          if (byteinteger[endp] == NL) i++;
          endp++;
          if (endp > edit_end->rp) {
             edit_end = (struct cell *) edit_end->rl;
             endp = edit_end->lp;
          }
       }
    } /* lineson */

    /*----------------------------------------------------------------------*/

    charsback(n) int n; {   /* 1274 */
    int len;
       beg = (struct cell *) &cur->ll;
       begp = curp;
       for(;;){
          len = begp - beg->lp;
          if (len >= n) {
             begp = begp - n;
             return(1);
          }
          begp = beg->lp;
          n = n - (len+1);
          if (integer[(beg->ll+8)>>2] == 0) return(0);
          beg = (struct cell *) beg->ll;
          begp = beg->rp;
       }
    } /* charsback */

    /*----------------------------------------------------------------------*/

    linesback(n) int n; {   /* 1292 */
    int i, j;
       if (n == MAXI) return(charsback(n));
       j = (int)&cur->ll;
       beg = (struct cell *)j;
       begp = curp;
       i = -1;
       for (;;) {
          if (begp == beg->lp) {
             if (integer[(beg->ll+8)>>2] == 0) {
                if (i = (n-1)) return(1); else return(0);
             }
             beg = (struct cell *)beg->ll;
             begp = beg->rp;
          } else begp--;
          if (byteinteger[begp] == NL) i++;
          if (i == n) break;
       }
       begp++;
       if (begp > beg->rp) {
          beg = (struct cell *) beg->rl;
          begp = beg->lp;
       }
       return(1);
    } /* linesback */

    /*----------------------------------------------------------------------*/

    position(n) int n; {   /* 1316 */
    int i;
       n--;
       if (n < 0) n = 0;
       if (n > 132) n = 132;
       i = linesback(0);
       i = 0;
       for (;;) {
          if (i == n) {
             cur = (struct cell *)&beg->ll;
             curp = begp;
             return;
          }
          if ((begp == 0) || (byteinteger[begp] == NL)) {
             if (begp != 0) {
                edit_end = (struct cell *)&beg->ll;
                endp = begp + 1;
                if (endp > edit_end->rp) {
                   edit_end = (struct cell *)edit_end->rl;
                   endp = edit_end->lp;
                }
             }
             cur = (struct cell *)&beg->ll;
             curp = begp;
             txt = (struct cell *)newcell();
             txt->ll = 0;
             txt->lp = (int)&sps[0];
             txt->rp = txt->lp + n - i - 1;
             txt->rl = 0;
             insert();
             return;
          }
          begp++;
          i++;
          if (begp > beg->rp) {
             beg = (struct cell *)beg->rl;
             begp = beg->lp;
          }
       }
    } /* position */

    /*----------------------------------------------------------------------*/

    killpart() {   /* 1356 */
    int j;
    /* printf("-> killpart "); diagnostic(3); */
       altered++;
       integer[(set->ll + 12)>>2] = set->rl;
       integer[set->rl>>2] = set->ll;
       if ((int)&cur->ll == seta) {
          cur = (struct cell *)cur->rl;
          curp = cur->lp;
       }
       j = returncell(seta);
       seta = 0;
    } /* killpart */

    /*----------------------------------------------------------------------*/

    extract(adr) int adr; {   /* 1369 */
    int n, j, k, mod, desc, flag, wp;
    char file[MAXPATHLEN+1], com[256], dev[32], junk[2], tab[2], doubleq[2];
    struct cell *w;
    char errtxt[128];
       if (curp == 0) return;
       txt = (struct cell *)adr;
       j = txt->rp - txt->lp;
       if (j == 0) {
          printf("No destination specified\n");
          return;
       }
       strncpy(file, txt->lp+1, j); file[j] = 0;

       if (file[0] == '%') {
          k = 0;
          for (j=1;;) {
             if ((ident[k++] = onecase[file[j++]]) == 0) break;
          }
          j = lookup(YES);
          if (j < 0) return;
          string[j].ll = 0; /* ordinary string */
          string[j].lp = wsp;
          n = 0; w = (struct cell *)&cur->ll; wp = curp;
          while (wp != 0) {
             k = w->rp - wp + 1;
             w = (struct cell *)w->rl;
             if ((n == 0) && (w->lp == 0)) { /* only one cell */
                string[j].lp = wp;
                string[j].rp = wp + k - 1;
                return;
             }
             if ((wsp+k) >= wse) extendwork("extract");
             move(k, wp, wsp); wsp = wsp + k;
             wp = w->lp;
             n++;
          }
          string[j].rp = wsp - 1;
          return;
       }

       mod = O_TRUNC; com[0] = 0;
       if (file[0] == '.') {
          strres(file, junk, ".", dev);
          if (strcmp(dev, "lp") == 0) strcpy(com, "lpr ");
          else {
             strcpy(com, "lpr -P");
             tab[0] = 9; tab[1] = 0; doubleq[0] = 34; doubleq[1] = 0;
             sprintf(file, "printers | grep -s %s^%s%s\\\\*%s",
                        doubleq, dev, tab, doubleq);
             if (system(file) == 0) strcpy(com, "edlpr -P");
          }
          strcpy(file, PSEUDX); mktemp(file);
          sprintf(com, "%s%s %s", com, dev, file);
    printf("com=%s\n", com);
       } else {
          if (j > 4) {
             if ((onecase[file[j-1]] == 'D') &&
                 (onecase[file[j-2]] == 'O') &&
                 (onecase[file[j-3]] == 'M') &&
                 (file[j-4] == '-')) {file[j-4] = 0; mod = O_APPEND;}
          }
          expand_filename(file);
    /*  this bit not required
          for (j=0; j<=fileusedcount; j++) {
             if (strcmp(file, fileused[j]) == 0) {
                printf("File currently in use\n");
                return;
             }
          }
    */

       }
       desc = open(file, O_WRONLY | O_CREAT | mod, 0664);
       if (desc < 0) {
          textof(errno, errtxt);
          printf("edit failed to open %s: %s\n", file, errtxt);
          return;
       }
       w = (struct cell *)&cur->ll; wp = curp;
       while (wp != 0) {
          flag = write(desc, wp, w->rp - wp + 1);
          if (flag < 0) {
             textof(errno, txt);
             printf("edit failed to write to %s: %s\n", file, txt);
             return;
          }
          w = (struct cell *)w->rl; wp = w->lp;
       }
       close(desc);

       if (com[0] != 0) system(com);
    } /* extract */

    /*----------------------------------------------------------------------*/

    replace () {   /* 1419 */
       if (begp != beg->lp) {
          cur = (struct cell *)&beg->ll;
          curp = begp;
          separate();
       }
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       if (endp == edit_end->lp) {
          new = (struct cell *)cur->ll;
       } else {
          separate();
          if ((int)&beg->ll == (int)&edit_end->ll) beg = (struct cell *)&new->ll;
       }
       if (((int)&beg->ll != (int)&bot->ll) && ((int)&new->ll != (int)&top->ll)) {
          changed = 1;
          altered++;
          cur->ll = beg->ll;
          integer[(beg->ll+12)>>2] = new->rl;
          beg->ll = set->ll;
          integer[(set->ll+12)>>2] = (int)&beg->ll;
          new->rl = seta;
          set->ll = (int)&new->ll;
       }
    } /* replace */

    /*----------------------------------------------------------------------*/

    insertats() {
          /* inserts txt before separator */
       txt->ll = set->ll;
       txt->rl = seta;
       integer[(set->ll+12)>>2] = (int)&txt->ll;
       set->ll = (int)&txt->ll;
    } /* insertats */

    /*-------------------------*/

    copychain() {
    int lp, rl;
    /* printf("-> copychain "); diagnostic(3); */
       changed = 1; altered++;
       if (((int)&beg->ll == (int)&edit_end->ll)  /* only one cell in chain */
          && (begp == endp)) return; /* nothing to copy */
       lp = begp;
       for (;;) {
          txt = (struct cell *)newcell();
          txt->lp = lp;
          if ((int)&beg->ll == (int)&edit_end->ll) {
             txt->rp = endp - 1;
             lp = -1;
          } else txt->rp = beg->rp;
          rl = beg->rl;
          insertats();
          if (lp < 0) break;
          beg = (struct cell *)rl;
          lp = beg->lp;
          if (lp == 0) break;  /* reached *S* or *B*  */
       }
    } /* copychain */

    /*-----------------------------------*/

    copy(i) int i; {   /* 1443 */
       txt =  (struct cell *)newcell();
       move(16, i, &txt->ll);
    } /* copy */

    /*----------------------------------------------------------------------*/

    insertsp(after, last) int after, *last; {   /* 1677 */
    int k;
       k = *last;
       k = k + 2;
       for (; k >= after+1; k--) cline[k] = cline[k-1];
       (*last)++;
    } /* insertsp */

    /*----------------------------------------------------------------------*/

    just(line, first, last, desired, ss) int line, first, last, desired, ss; {   /* 1627 */
    int gaps, needed, i, flip, sgaps, sym;
       needed = desired - last;
       gaps = 0;
       sgaps = 0;
       if (needed <= 0) return(last+1);
       for (i=first+1; i <= last; i++) {
          if (cline[i] == SP) {
             sym = cline[i-1];
             if (sym != SP) gaps++;
             if ((sym == '.') || (sym == ',') || (sym == ';') || (sym == '!')
                  || (sym == '?')) sgaps++;
          }
       }
       if (gaps == 0) return(last+1);

       if ((ss == 0) && (sgaps > 0)) {
          i = first + 1;
          for (;;) {
             if (cline[i] == SP) {
                sym = cline[i-1];
                if ((sym == '.') || (sym == ',') || (sym == ';')
                     || (sym == '?') || (sym == '!')) {
                   insertsp(i, &last);
                   sgaps--;
                   needed--;
                   if ((needed > 0) && (needed > sgaps)) {
                      insertsp(i, &last);
                      needed--;
                   }
                   if (needed <= 0) return(last+1);
                }
             }
             i++;
             if ((i >= last) || (sgaps <= 0)) break;
          }
       }
       if ((line & 1) != 0) {
          flip = -1;
          i = last;
       } else {
          flip = 1;
          i = first + 1;
       }
       for (;;) {
          if ((cline[i] == SP) && (cline[i-1] != SP)) {
             insertsp(i, &last);
             i = i + flip;
             needed--;
             if (needed <= 0) return(last+1);
          }
          i = i + flip;
          if ((i <= first) || (i >= last)) break;
       }
       return(just(line, first, last, desired, 1));
    } /* just */

    /*----------------------------------------------------------------------*/

    adjustline(last) int last; {   /* 1567 */
    int i, j, xcurp;
    struct cell *xcur;
       if ((int)&cur->ll == (int)&pbot->ll) return(last);
       if ((sym == NL) && (linel <= last) && (last <= (linel+1))) return(last);
       if (last >= linel) {
          i = last + 1;
          while (i > firstpos) {
             if (cline[i] == ' ') break;
             i--;
          }
          if (i == firstpos) {
             cline[last+1] = NL;
             return(last+1);
          }
          j = charsback(last-i+1);
          cline[i] = NL;
          cur = (struct cell *)&beg->ll;
          curp = begp;
          return(i);
       }

       xcur = (struct cell *)&cur->ll;
       xcurp = curp;
       j = byteinteger[curp];
       while ((j == ' ') || (j == NL)) {
          if (curp < cur->rp) {
             curp++;
          } else {
             cur = (struct cell *)cur->rl;
             curp = cur->lp;
             if ((int)&cur->ll == (int)&pbot->ll) goto miss;
          }
          j = byteinteger[curp];
       }
       i = last + 1;
       for (;;) {
          j = byteinteger[curp];
          if ((j == ' ') || (j == NL)) break;
          cline[i] = j;
          if (i > linel) goto miss;
          i++;
          if (curp < cur->rp) {
             curp++;
          } else {
             cur = (struct cell *)cur->rl;
             curp = cur->lp;
            if ((int)&cur->ll == (int)&pbot->ll) {
                cline[last] = SP;
                return(i-1);
             }
          }
       }
       cline[last] = SP;
       cline[i] = NL;
       sym = NL;
       return(adjustline(i));
    miss:
       cur = (struct cell *)&xcur->ll;
       curp = xcurp;
       return(last);
    } /* adjustline */

    /*----------------------------------------------------------------------*/

    layout(param, justify) int param, justify; {   /* 1448 */
    /*
       NB some variables made global:

       linel, sym, firstpos, ptop, pbot, cline
    */

    int linest, parast, i, j, ptopp, line, n, scurp;
    struct cell *scur;
       linest = param / 100000;
       parast = (param - (100000*linest)) / 1000;
       linel = param - (100000*linest) - (1000*parast);
       if (linel == 0) linel = slinel;
       if (linest == 0) linest = slinest;
       if (parast == 0) parast = sparast;
       slinel = linel; slinest = linest; sparast = parast;
    /* printf("linel=%d, linest=%d, parast=%d\n", linel, linest, parast); */
       txt = (struct cell *)newcell();
       txt->lp = (int)&nls[0]; /* double NL */
       txt->rp = (int)&nls[1];

       i = find();
       cur = (struct cell *)&beg->ll;
       curp = begp;

       edit_end = (struct cell *)&cur->ll;
       endp = curp;
       for (;;) {
          if (charsback(1) == 0) break;
          if (byteinteger[begp] != SP) break;
          delete();
       }
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       txt->ll = txt->lp = txt->rp = txt->rl = 0; insert();
       pbot = (struct cell *)&txt->ll;
       cur = (struct cell *)&pbot->ll;
       curp = cur->rp;
       txt = (struct cell *)newcell();
       txt->lp = (int)&nls[0];
       txt->rp = (int)&nls[1];
       i = findb();
       ptop = (struct cell *)&edit_end->ll;
       ptopp = endp;
       cur = (struct cell *)&ptop->ll;
       curp = ptopp;
       i = returncell(&txt->ll);

       line = 0;
       for (;;) {
          line++;
          if (line == 1) i = parast; else i = linest;
          j = i - 1;
          while (j >= 1) {
             cline[j] = SP;
             j--;
          }
          firstpos = i;
          if ((int)&cur->ll == (int)&pbot->ll) break;
          scur = (struct cell *)&cur->ll;
          scurp = curp;

          for (;;) {
             i = byteinteger[curp];
             if ((i != SP) && (i != NL)) break;
             if (curp < cur->rp) {
                curp++;
             } else {
                cur = (struct cell *)cur->rl;
                curp = cur->lp;
                if ((int)&cur->ll == (int)&pbot->ll) goto wayout;
             }
          }

          n = firstpos;
          for (;;) {
             sym = byteinteger[curp];
             if ((justify == 0) || (n <= firstpos) || (cline[n-1] != SP)
                    || (sym != SP)) cline[n++] = sym;
             if (curp < cur->rp) {
                curp++;
             } else {
                cur = (struct cell *)cur->rl;
                curp = cur->lp;
             }
             while ((sym == NL) && (n > (firstpos+1)) && (cline[n-2] == SP)) {
                n--;
                cline[n-1] = NL;
             }
             if ((sym == NL) || (n > linel+1) || ((int)&cur->ll == (int)&pbot->ll)) break;
          }
          j = adjustline(n-1);
          i = firstpos;
          if (i < linest) i = linest;
          if ((justify != 0) && ((int)&cur->ll != (int)&pbot->ll)) j = just(line, i, j-1, linel, 0);

          beg = (struct cell *)&scur->ll;
          begp = scurp;
          edit_end = (struct cell *)&cur->ll;
          endp = curp;
          delete();
          if (j < firstpos) break;
          txt = (struct cell *)newcell();
          txt->lp = wsp;
          for (i=1; i <= j; i++) {
             byteinteger[wsp++] = cline[i];
          }
          txt->rp = wsp - 1;
          insert();
       }
    wayout:
       scur = (struct cell *)pbot->ll;
       scur->rl = pbot->rl;
       cur = (struct cell *)pbot->rl;
       cur->ll = pbot->ll;
       curp = cur->lp;
       i = returncell(&pbot->ll);
       i = charson(2);
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       return(i);
    } /* layout */

    /*----------------------------------------------------------------------*/

    initdict() {   /* 1687 */
    int j;
    struct ff f;
       strcpy(f.file, SYSDICTNAME);
       if (exist(f.file) == 0) {
          printf("sysdict %s does not exist\n", f.file);
          sysdicta = -1;
       } else {
          expand_filename(f.file);
          j = emasconnect(&f);
          if (j == 0) {
             sysdicta = f.start;
             sysdictb = f.size * 8;
    /*         printf("%s emasconnected, size=%d\n", f.file, f.size); */
          } else printf("could not emasconnect sysdict %s\n", f.file);
       }

       if (exist(PRIVDICTNAME) == 0) {
          privdicta = calloc(1, MAXPDICT);
          privdictb = MAXPDICT * 8;
       } else {
          strcpy(f.file, PRIVDICTNAME);
          expand_filename(f.file);
          j = emasconnect(&f);
          if (j == 0) {
             privdicta = f.start;
             privdictb = f.size * 8;
    /* printf("%s emasconnected, size=%d\n", f.file, f.size); */
          }
       }

       wsp = (wsp + 3) & (-4);
       tempdicta = wsp;
       tempdictb = 4096 * 8;
       if (wsp + 4096 > wse) extendwork("init dict");
       for (j=0; j<1024; j++) {integer[wsp>>2] = 0; wsp = wsp + 4;}
    /* printf("dictionaries initialised\n"); */
       return(0);
    } /* initdict */

    /*----------------------------------------------------------------------*/

    nextword() {   /* 1734 */
    int ch, len;
       if (curp == 0) return(0);
       ch = byteinteger[curp] & 127;
       while (spellch[ch] > 0) {
          if (charsback(1) == 0) break;
          cur = (struct cell *)&beg->ll;
          curp = begp;
          ch = byteinteger[curp] & 127;
       }
       for (;;) {
          ch = byteinteger[curp] & 127;
          if ((65 <= spellch[ch]) && (spellch[ch] <= 90)) break;
          if (curp < cur->rp) {
             curp++;
          } else {
             cur = (struct cell *)cur->rl;
             curp = cur->lp;
             if (curp == 0) return(0);
          }
       }
       len = 0;
       for (;;) {
          ch = byteinteger[curp] & 127;
          if (spellch[ch] == 0) break;
          word[len++] = spellch[ch];
          if (len > 31) break;
          if (curp < cur->rp) {
             curp++;
          } else {
             cur = (struct cell *)cur->rl;
             curp = cur->lp;
             if (curp == 0) break;
          }
       }
       if (len == 1) return(nextword());
       word[len] = 0;
       wordm1 = len;
       return(1);
    } /* nextword */

    /*----------------------------------------------------------------------*/

    sethashes() {   /* 1777 */
    int i, j;
    static int hconsts[] = {0, 1,
       997, 47, 2897, 19, 937, 2203,
       311, 1019, 23, 3041, 823, 227,
       2239, 211, 3181, 197, 3889,
       191, 2447, 179, 2153, 167, 163,
       3121, 2213, 149, 139, 2551, 131,
       3947, 113, 2707, 107, 103, 3109, 97,
       2647, 83, 79, 3797, 71, 2333,
       61, 3517, 53, 43, 3821, 37,
       31, 29, 17, 13, 11,
       7, 5};

       for (i=1; i<=MAXHASH; i++) {
          hash[i] = 0;
          for (j=0; word[j]!=0; j++) {
             hash[i] = hash[i] + word[j] * hconsts[(j+2*i)];
          }
       }
    } /* sethashes */

    /*----------------------------------------------------------------------*/

    dictlookup() {   /* 1799 */
    int i, j, found;
       if (sysdicta > 0) {
          found = 1;
          for (i=1; i<=MAXHASH; i++) {
             j = hash[i];
             j = j - (j / sysdictb) * sysdictb;
             if ((byteinteger[sysdicta+(j>>3)] & (128>>(j&7))) == 0) {
                found = 0;
                break;
             }
          }
          if (found != 0) return(found);
       }

       if (privdicta > 0) {
          found = 2;
          for (i=1; i<=MAXHASH; i++) {
             j = hash[i];
             j = j - (j / privdictb) * privdictb;
             if ((byteinteger[privdicta+(j>>3)] & (128>>(j&7))) == 0) {
                found = 0;
                break;
             }
          }
          if (found != 0) return(found);
       }

       found = 3;
       for (i=1; i<=MAXHASH; i++) {
          j = hash[i];
          j = j - (j / tempdictb) * tempdictb;
          if ((byteinteger[tempdicta+(j>>3)] & (128>>(j&7))) == 0) {
             found = 0;
             break;
          }
       }
       return(found);
    } /* dictlookup */

    /*----------------------------------------------------------------------*/

    enter() {   /* 1828 */
    int i, j;
       if (privdicta > 0) {
          for (i=1; i<=MAXHASH; i++) {
             j = hash[i];
             j = j - (j / privdictb) * privdictb;
             byteinteger[privdicta+(j>>3)] = (byteinteger[privdicta+(j>>3)] | (128>>(j&7)));
          }
          privdict_changed = YES;
       }
    } /* enter */

    /*----------------------------------------------------------------------*/

    entertemp() {   /* 1840 */
    int i, j;
       for (i=1; i<=MAXHASH; i++) {
          j = hash[i];
          j = j - (j / tempdictb) * tempdictb;
          byteinteger[tempdicta+(j>>3)] = (byteinteger[tempdicta+(j>>3)] | (128>>(j&7)));
       }
    } /* entertemp */

    /*----------------------------------------------------------------------*/

    extendwork(s) char *s; {   /* 1853 */
       printf("\nWorkspace Full, called from %s\nEdit:e    invoked\n", s);
       diagnostic(3); help(3);
       editexit(0);
       exit(0);
    } /* extendwork */

    /*----------------------------------------------------------------------*/

    readcstring() {   /* 1868 */
    int i, sym, j, k, err, n, def, cflags, parval, lrptr, ch, len, lp;
    char loopback[41], line[80];
       lcomp = comp;
       comp = level = hset = nlc = linecomplete = 0;
       goto normal;
    re_enter:
       strcpy(prompt_string, "):");
       level++;
       loopback[level] = comp;
    normal:
       while (linecomplete == 0) {
          for (;;) {
             sym = nextsymbol();
             if (('a' <= sym) && (sym <= 'z')) sym = sym - 32;
             j = chartype1[sym&127];
             if ((j != 0) && (j != SP)) break;
             skipsymbol();
          }
          err = SYNTAXERROR;
    /* printf("stype(%d)\n", j); */
          switch(j) {   /* FIRSTSWITCH */
    case TEXTCHAR:
    case FILECHAR:
    case FILEEND:
    case MINUS:
    case NONNULL:
       skipsymbol();
       break;
    case NUMCHAR:
       if ((comp == 0) && (lcomp > 1) && (readi(&i) > 0) && (nextsymbol() == NL)) {
          currcomp = (struct cform *) &clist[lcomp-2].lett;
          if (currcomp->lett == ']')
             comp = lcomp -1;
          else {
             currcomp = (struct cform *) &clist[lcomp-1].lett;
             comp = lcomp;
          }
          currcomp->flags = 0;
          currcomp->level = 0;
          currcomp->swno = 0;
          currcomp->errno = 0;
          currcomp->loop = 0;
          currcomp->count = 0;
          currcomp->lett = ']';
          currcomp->par = i;
          err = 0;
       }
       break;
    case SHRIEK:
       if (input_pointer > 0) {skipsymbol(); break;}
       n = 0;
       for (;;) {
          skipsymbol();
          j = nextsymbol();
          if (j == NL) break;
          line[n++] = j;
       }
       line[n] = 0;
       skipsymbol();
       system(line);
       err = 0;
       break;
    case NL:
       skipsymbol();
       err = 0;
       if ((level > 0) || (comp == 0)) break;
       goodcommand('P', NUMPAR, 1);
       linecomplete = 1;
       break;
    case LOOPEND:
       skipsymbol();
       if (level == 0) break;
       if (loopback[level] >= comp) break;
       if (readi(&i) > 0) {
          goodcommand(sym, 0, i);
          currcomp->loop = loopback[level--];
          goto backup;
       }
       err = INVALIDLOOP;
       break;
    case LOOPSTART:
       skipsymbol();
       goto re_enter;
    backup:
       if (level == 0) strcpy(prompt_string, prstring);
       if (i < 0) return(i);
       err = 0;
       break;
    case COMMAND:
       skipsymbol();

       if (sym == '%') {
          sym = FIRSTCOM;
          for (j=0;;) {
             ch = onecase[nextsymbol()];
             if ((('a' <= ch) && (ch <= 'z')) ||
               ((j>0) && ('0' <= ch) && (ch <= '9'))) {
                ident[j++] = ch;
                skipsymbol();
             } else break;
          }
          if (j == 0) break;
          ident[j] = 0;
          if ((ch = lookup(1)) < 0) break;
          while (nextsymbol() == SP) skipsymbol();

          if (nextsymbol() != '=') {  /* %name */
             if ((lp = string[ch].lp) == 0) {err=8; break;} /* unassigned */
             len = string[ch].rp - lp + 1;
             k = strlen(inputline);
             n = k - input_pointer;
    /* printf("was: %s", inputline); */
             for (j=0; j<=n; j++) inputline[k+len-j] = inputline[k-j];
             for (j=0; j<len; j++) inputline[input_pointer+j] = byteinteger[lp+j];
    /* printf(" is: %s", inputline); */
             err = 0; break;
          } else skipsymbol();
       }

       def = comdef[sym - FIRSTCOM];
       lrptr = (def >> 12) & 15;
       cflags = def & (STOPSPELL | NEEDSS);
       parval = 0;
       if ((emode != 0) && ((def & NOTINLOOK) != 0)) {
          err = CHINLOOK;
          break;
       }
       if ((def & ALLPAR) == 0) goto noparam;
       for(;;) {  /* a parameter required */
          k = nextsymbol();
          if ((k == NL) || (k > SP)) break;
          skipsymbol();
       }
       j = chartype2[k & 127];
       if (j == MINUS) {
          if ((def & BACKWARDS) == 0) break;
          cflags = cflags | BACKWARDS;
          for(;;) {
             skipsymbol(); k = nextsymbol();
             if ((k == NL) || (k > SP)) break;
          }
          j = chartype2[k & 127];
       }
    /* printf("sub(%d)\n", j); */
       switch(j) {   /* SECONDSWITCH */
    case NL:
    case LOOPSTART:
    case LOOPEND:
    case MINUS:
    case SHRIEK:
    case NONNULL:
    case FILEEND:
    case COMMAND:
       if (sym != '?')
    /*   if ((def & NOTINLOOK) != 0) */ break;  /* 'dangerous' commands */
    case NUMCHAR:
       if ((def & NUMPAR) == 0) break;
       parval = 1; /* default */
       if (j == NUMCHAR) readi(&parval);
       if (((sym == 'L') || (sym == 'J')) && (parval != 0)) {
          i = parval / 100000;
          j = (parval - (100000*i)) / 1000;
          k = parval - (100000*i) - (1000*j);
          if (i == 0) i = slinest;
          if (j == 0) j = sparast;
          if (k == 0) k = slinel;
          if (!((0<i)&&(i<k)&&(0<j)&&(j<k)&&(k<133)&&(j<51))) break;
       }
       cflags = cflags | NUMPAR;
       goto noparam;
    case TEXTCHAR:
       if ((def & TEXTPAR) == 0) break;

       if (sym == FIRSTCOM) {
          if ((err = readtext()) != 0) break;
       } else {
          if (k == QUOTE) {
             skipsymbol();
             if (lastrec[lrptr].lp == 0) break;
             copy(&lastrec[lrptr].ll);
          } else {
             if (k == DOUBLEQUOTE) {
                skipsymbol();
                if (lastrec[lrptr+8].lp == 0) break;
                copy(&lastrec[lrptr+8].ll);
             } else {
                if ((err = readtext()) != 0) break;
                move(16, &lastrec[lrptr].ll, &lastrec[lrptr+8].ll);
                move(16, &txt->ll, &lastrec[lrptr].ll);
             }
          }
       }
       parval = (int)&txt->ll;
       cflags = cflags | TEXTPAR;
       goto noparam;
    case FILECHAR:
       if ((def & FILEPAR) == 0) break;
       if ((err = readtext()) != 0) break;
       cflags = cflags | FILEPAR;
       parval = (int)&txt->ll;
    noparam:
       if ((def & SPECIAL) != 0) {
          if (sym == 'H') hset = 1;
          if ((sym == 'E') && (nextsymbol() != NL)) break;
          if (sym == FIRSTCOM) {  /* string assignment */
             cflags = cflags | SPECIAL;
             sym = ch;
          }
       }
       goodcommand(sym, cflags, parval);
       err = 0;
       break;
          }   /* END OF SECONDSWITCH */
          break;
          }   /* END OF FIRSTSWITCH */
          if (err > 0) {
             goodcommand(sym, ERROR, err);
             goodcommand('P', NUMPAR, 1);
             linecomplete = -1;
          }
       }
       return(linecomplete);
    } /* readcstring */

    /*----------------------------------------------------------------------*/

    goodcommand(sym, flags, param) int sym, flags, param; {   /* 2049 */
    int swno, i, lett;
       if (comp > 99) {
          printf("TOO MANY COMMANDS\n");
          editexit(0);
          exit(0);
       }
       if ((comp == 0) && (lcomp > 0)) {
          i = 0;
          for (;;) {
             curcom = (struct cform *) &clist[i].lett;
    /* printf("curcom->flags=%d\n", curcom->flags); */
             if ((curcom->flags & (TEXTPAR | FILEPAR)) != 0) returncell(curcom->par);
             i++;
             if (i == lcomp) break;
          }
          lcomp = 0;
       }

       lett = sym;
       if ((flags & SPECIAL) != 0) sym = FIRSTCOM;
       if ((FIRSTCOM <= sym) && (sym <= LASTCOM)) swno = comdef[sym-FIRSTCOM] >> 16; else swno = 0;
       if ((flags & (TEXTPAR|FILEPAR)) == 0) swno = swno >> 8;
       currcomp = (struct cform *) &clist[comp++].lett;
       currcomp->errno = currcomp->loop = currcomp->count = currcomp->par = 0;
       currcomp->lett = lett;
       currcomp->flags = flags;
       if ((flags & ERROR) == 0) currcomp->par = param;
          else currcomp->errno = param;
       currcomp->level = level;
       currcomp->swno = swno;
    } /* goodcommand */

    /*----------------------------------------------------------------------*/

    ermess(n, lett) int n, lett; {   /* 2093 */
    char w[7], a[60], b[60], c[60];
    static char *etext[] = {
       "",
       "Invalid loop repetition count",
       "## not allowed when looking",
       "Separator S not set for ##",
       "Cannot create private lexicon",
       "No word set up for Y command",
       "No word set up for N command",
       "Syntax error in command string",
       "",
       "Loop counter out of context"
     };

       if (n == 8) {
          sprintf(a, "Variable %%%s not assigned", ident);
       } else {
          strcpy(a, etext[n]);
          if (strres(a, b, "##", c) == 0) {
             w[0] = lett; w[1] = 0;
             sprintf(a, "%s%s%s", b, w, c);
          }
       }
       printf("%s\n", a);
    } /* ermess */

    /*----------------------------------------------------------------------*/

    initialise() {   /* 2126 */
    int flag;
    struct ff f;
       strcpy(prompt_string, prstring);
       eterminate = 0;
       while (fileusedcount >= 0) free(start_address[fileusedcount--]);
       flag = checkff(&f);
       if (flag == 0) {
          bot = (struct cell *)newcell();
          top = (struct cell *)newcell();
          htop = (struct cell *)newcell();
          hbot = (struct cell *)newcell();
          htop->rl = (int)&hbot->ll;
          hbot->ll = (int)&htop->ll;
          bota = (int)&bot->ll;
          top->rl = bota;
          topa = (int)&top->ll;
          bot->ll = topa;
          cur = (struct cell *) &bot->ll;
          curp = 0; altered = 0; presif_altered = 0; seta = 0;
          if (f.end > f.start) {
             txt = (struct cell *)newcell();
             txt->lp = f.start;
             txt->rp = f.end - 1;
             insert();
             cur = (struct cell *)top->rl;
             curp = cur->lp;
          }
          changed = 0;
          haltered = -1;
          hsave();
    /* dump(wsp0, 128);
    dump(f.start, f.size); */
       }
    /* printf("Initialise, flag=%d\n", flag); */
       return(flag);
    } /* initialise */

    /*----------------------------------------------------------------------*/

    editexit(why) int why; {   /* 2187 */
    int filelength, adr, desc, flag, p, len, err;
    char file[MAXPATHLEN+1], txt[MAXPATHLEN+1];
    struct cell *loccur;

       if (privdict_changed == YES) {
          err = 1;
          printf("privdict %s changed\n", PRIVDICTNAME);
          strcpy(txt, PRIVDICTNAME); expand_filename(txt);
          desc = creat(txt, 0664); /* read+write by owner */
          if (desc > 0) {
             flag = write(desc, privdicta, privdictb>>3);
             if (flag >= 0) {
                err = 0; close(desc);
                privdict_changed = NO;
                printf("privdict %s successfully written\n", PRIVDICTNAME);
             } else printf("failed to write privdict %s\n", PRIVDICTNAME);
          } else printf("failed to create privdict %s\n", PRIVDICTNAME);
          if (err > 0) {textof(errno, txt); printf("%s\n", txt);}
       }

       if ((strcmp(newf, ".NULL") == 0) || ((changed == 0) &&
             (strcmp(newf, oldf) == 0))) {
          if (wseen > 0) eterminate = 1; /* completed */
          else eterminate = 3; /* no changes */
          return;
       }

       eterminate = 4; /* ***NOT*** completed */
       if (seta != 0) killpart();
       filelength = 0;
       loccur = (struct cell *)top->rl;
       while (loccur->lp != 0) {
          filelength = filelength + loccur->rp - loccur->lp + 1;
          loccur = (struct cell *)loccur->rl;
       }
    /* printf("filelength=%d\n", filelength); */
       adr = calloc(1, filelength);
       if (adr > 0) {
          p = adr;
          loccur = (struct cell *)top->rl;
          while (loccur->lp != 0) {
             len = loccur->rp - loccur->lp + 1;
             move(len, loccur->lp, p);
             p = p + len;
             loccur = (struct cell *)returncell(&loccur->ll);
          }
          desc = creat(newf, 0664); /* read+write by owner */
          if (desc > 0) {
             flag = write(desc, adr, filelength);
             if ((flag > 0) || (filelength == 0)) eterminate = 1;
             else printf("edit failed to write to");
          } else printf("edit failed to create");
          if (eterminate == 4) {
             textof(errno, txt);
             printf(" %s: %s\n", newf, txt);
             strcpy(file, PSEUDX); mktemp(file); /* so try and write temp file */
             desc = creat(file, 0664);
             if (desc > 0) {
                flag = write(desc, adr, filelength);
                if (flag > 0) {
                   eterminate = 1;
                   printf("HOWEVER, your editing has been saved in %s\n", file);
                } else printf("edit failed to write to");
             } else printf("edit failed to create");
             if (eterminate == 4) {textof(errno, txt); printf(" %s: %s\n", file, txt);}
             else {close(desc); free(adr);}
          }
       } else printf("edit failed to get VM");
    } /* editexit */

    /*----------------------------------------------------------------------*/

    checkff(f) struct ff *f; {   /* 2316 */
    int j, k;
       f->start = f->end = 0;

       k = 1; /* oldf = newf */
       if (strcmp(oldf, newf) != 0) {
          if (strcmp(newf, ".NULL") == 0) k = 0; else k = 2;
       }
       newf_exists = exist(newf);

       if ((k != 1) || (newf_exists != 0)) {
          strcpy(f->file, oldf);
          j = emasconnect(f);
          if (j != 0) return(j);
          strcpy(fileused[++fileusedcount], oldf);
          start_address[fileusedcount] = f->start;
          end_address[fileusedcount] = f->end - 1;
       }

       if (newf_exists == 0) {
          if (k > 0) printf("%s is a new file\n", newf);
       } else {
          if (k == 2) printf("%s already exists\n", newf);
       }

       if (k == 2) strcpy(fileused[++fileusedcount], newf);
       return(0);
    } /* checkff */

    /*----------------------------------------------------------------------*/

    ed() {   /* 315 */
    static char *prt[] = {"Edit:", "Look:"};
    int i, j, k;
       strcpy(prstring, prt[emode]);
       caseind = 1;
       ccase = (char *)&onecase[0];
       for (j=0; j<=MAXCOUNT; j++) count[j] = 0;
       for (j=0; j<16;) lastrec[j++].lp = 0;

       for (j=0; j<26;) string[j++].lp = 0;
       strcpy(identifier, "z0date0time0");
       identifier[1] = identifier[6] = identifier[11] = 0;
       string[1].ll = 1;  /* date is a const fn */
       string[2].ll = 2;  /* time is a variable fn */
       if (emode == 0) { /* edit rather than look */
          if (exist(eha) > 0) {
             printf("%s\n", explanation);
             return(2);
          }
       }

       sysdicta = privdict_changed = privdicta = 0;
       wordm1 = 0;

       j = calloc(1, 512<<10);
       if (j < 0) return(errno);
       wsp0 = wsp = j; wse = j + (512<<10);
       comp = 0;
       slinest = 1; sparast = 6; slinel = 72;
       wseen = 0; asl = 0;
       strcpy(oldf, in);
       strcpy(newf, out);
       fileusedcount = -1;
       j = initialise();
       if (j != 0) goto err;
       lastcom = (struct cform *) (int) &clist[0].lett;

       for(;;) {              /* ********* primary loop ********* */
          linecomplete = readcstring();
          if (linecomplete < 0) {
             strcpy(prompt_string, prstring);
             while (nextsymbol() != NL) skipsymbol();
          }
          if (hset == 0) hsave();
          i = 0;
          for(;;) {
    /* printf("ed, i=%d, comp=%d\n", i, comp); */
             if (i >= comp) break;
             if ((i != 0) && (curcom->swno != 0)) lastcom = (struct cform *)&curcom->lett;
             curcom = (struct cform *) &clist[i++].lett;
             j = curcom->flags;
             if (((j & NEEDSS) != 0) && (seta == 0)) {
                ermess(3, curcom->lett);
                i = comp -1;
                continue;
             }
             back = j & BACKWARDS;
             if ((j & STOPSPELL) != 0) wordm1 = 0;
             if ((j & ERROR) != 0) {
                ermess(curcom->errno, curcom->lett);
                i = comp -1;
                continue;
             }
    /* printf("ed(%d)  ", curcom->swno); */
             switch(curcom->swno) {
    case 0: /* loop test */
       if (++curcom->count >= curcom->par) curcom->count = 0;
       else i = curcom->loop;
       count[curcom->level] = curcom->count;
       break;
    case 1: /* T */
       cur = (struct cell *) top->rl;
       curp = cur->lp;
       break;
    case 2: /* B */
       cur = (struct cell *) &bot->ll;
       curp = 0;
       break;
    case 3: /* E */
       editexit(0);
       return(eterminate);
    case 4: /* I */
       if (maptxt(curcom->par) == 0) {i = comp; break;}
       copy(&txt->ll);
       insert();
       if (back != 0) {
          cur = (struct cell *)&txt->ll;
          curp = txt->lp;
       }
       break;
    case 5: /* M TEXT */
       if (maptxt(curcom->par) == 0) {i = comp; break;}
       if (back == 0) k = find(); else k = findb();
       cur = (struct cell *) (int) &beg->ll;
       curp = begp;
       if (k == 0) i = comp - 1;
       break;
    case 6: /* M NO */
       if ((back == 0) && (curcom->par > 0)) {
          k = lineson(curcom->par);
          cur = (struct cell *)(int)&edit_end->ll;
          curp = endp;
       } else {
          k = linesback(curcom->par);
          cur = (struct cell *)(int)&beg->ll;
          curp = begp;
       }
       if (k == 0) i = comp - 1;
       break;
    case 7:  /* A TEXT */
       if (maptxt(curcom->par) == 0) {i=comp; break;}
       if (back == 0) k = find(); else k = findb();
       if (k == 0) {
          cur = (struct cell *)&beg->ll;
          curp = begp;
          i = comp - 1;
          break;
       }
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       break;
    case 8:  /* A NO */
       if (back == 0) {
          k = charson(curcom->par);
          cur = (struct cell *)&edit_end->ll;
          curp = endp;
       } else {
          k = charsback(curcom->par);
          cur = (struct cell *)&beg->ll;
          curp = begp;
       }
       if (k == 0) i = comp - 1;
       break;
    case 9:  /* P TEXT */
       if (maptxt(curcom->par) == 0) {i = comp; break;}
       if (back == 0) {
          if (find() == 0) {
             edit_end = (struct cell *)&beg->ll;
             endp = begp;
          } else {
             beg = (struct cell *)&cur->ll;
             begp = curp;
             cur = (struct cell *)&edit_end->ll;
             curp = endp;
             k = lineson(1);
             cur = (struct cell *)&beg->ll;
             curp = begp;
          }
          j = linesback(0);
       } else {
          k = findb();
          edit_end = (struct cell *)&cur->ll;
          endp = curp;
          cur = (struct cell *)&beg->ll;
          curp = begp;
          k = linesback(0);
          cur = (struct cell *)&edit_end->ll;
          curp = endp;
          k = lineson(1);
       }
       printtext();
       break;
    case 10: /* Pn */
       if ((i == comp) && (lastcom->lett == 'P')) break;
       if ((back == 0) && (curcom->par > 0)) {
          j = linesback(0);
          k = lineson(curcom->par);
       } else {
          k = linesback(curcom->par);
          j = lineson(1);
       }
       printtext();
       if ((j == 0) || (k == 0)) i = comp-1;
       break;
    case 11:  /* D TEXT */
    case 19:  /* U TEXT */
    case 32: /* C TEXT */
       if (maptxt(curcom->par) == 0) {i = comp; break;}
       if (back == 0) {
          if (find() == 0) {
             cur = (struct cell *)&beg->ll;
             curp = begp;
             i = comp - 1;
             break;
          }
          beg = (struct cell *)&cur->ll;
          begp = curp;
       } else {
          if (findb() == 0) {
             cur = (struct cell *)&beg->ll;
             curp = begp;
             i = comp - 1;
             break;
          }
          edit_end = (struct cell *)&cur->ll;
          endp = curp;
       }

       switch(curcom->swno) {
    case 11: delete(); break;
    case 19: replace(); break;
    case 32: copychain(); break;
       }
       break;
    case 12:  /* D NO */
    case 20:  /* U NO */
    case 33:  /* C NO */
       j = linesback(0);
       if (curcom->par == 0) {   /* n = 0 is a noop */
          cur = (struct cell *)&beg->ll;
          curp = begp;
          break;
       }
       if (back == 0) {
          k = lineson(curcom->par);
       } else {
          edit_end = (struct cell *)&beg->ll;
          endp = begp;
          k = linesback(curcom->par);
       }

       switch(curcom->swno) {
    case 12: delete(); break;
    case 20: replace(); break;
    case 33: copychain(); break;
       }
       if (k == 0) i = comp - 1;
       break;
    case 13:  /* R TEXT */
       if (maptxt(curcom->par) == 0) {i = comp; break;}
       if (back == 0) k = find(); else k = findb();
       if (k == 0) {
          cur = (struct cell *)&beg->ll;
          curp = begp;
          i = comp -1;
          break;
       }
       delete();
       break;
    case 14:  /* R NO */
       if (back == 0) {
          beg = (struct cell *)&cur->ll;
          begp = curp;
          k = charson(curcom->par);
       } else {
          k = charsback(curcom->par);
          edit_end = (struct cell *)&cur->ll;
          endp = curp;
       }
       delete();
       if (k == 0) i = comp - 1;
       break;
    case 15:  /* Q */
       return(2);
    case 16:  /* S */
       if (seta != 0) killpart();
       seta = newcell();
       txt = (struct cell *)seta;
       insert();
       set = (struct cell *)seta;
       break;
    case 17:  /* K */
       cur = (struct cell *)&set->ll;
       killpart();
       break;
    case 18:  /* H */
       hrestore();
       break;
    case 21:  /* O */
       cur = (struct cell *)seta;
       curp = 0;
       break;
    case 23:  /* G NO */
       position(curcom->par);
       break;
    case 24:  /* F */
       extract(curcom->par);
       break;
    case 25:  /* W */
       if (strcmp(newf, ".NULL") == 0) break;
       wseen++;
       j = seta;
       if (seta != 0) killpart();
       k = curp - cur->rp - 1;
       while((int)&cur->ll != (int)&top->ll) {
          k = k + cur->rp - cur->lp + 1;
          cur = (struct cell *)cur->ll;
       }
       editexit(-1);
       if (eterminate == 99) break;
    /*   if (contains(newf, tempfile) == 0) {
          strcpy(newf, oldf);
       }
    */
       printf("All changes incorporated in %s\n", newf);
       if (j != 0) printf("NB Separator *S* has been killed\n");
       strcpy(oldf, newf);
       returnlist(htop, hbot);
       j = returncell(&hbot->ll);
       j = initialise();
       if (j != 0) goto err;
       j = charson(k);
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       break;
    case 26:  /* Z */
       if (caseind == 0) {
          ccase = (char *)&onecase[0];
       } else {
          ccase = (char *)&twocase[0];
       }
       caseind = 1 - caseind;
       break;
    case 27:  /* L */
       if (layout(curcom->par, 0) == 0) i = comp - 1;
       break;
    case 28:  /* J */
       if (layout(curcom->par, 1) == 0) i = comp - 1;
       break;
    case 29:  /* X */
       if (sysdicta == 0) {
          j = initdict();
          if (j != 0) {
             ermess(4, 0);
             i = comp - 1;
             break;
          }
       }
       for (;;) {
          j = nextword();
          if (j == 0) break;
          sethashes();
          j = dictlookup();
    /* printf("lookup %s, j=%d\n", word, j); */
          if (j == 0) {j = -1; break;}
       }
       if (j == 0) {i = comp - 1; break;}
       j = charsback(wordm1);
       cur = (struct cell *)&beg->ll;
       curp = begp;
       break;
    case 30:  /* Y */
       if (wordm1 == 0) {
          ermess(5, 0);
          i = comp - 1;
          break;
       }
       enter();
       j = charson(wordm1);
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       break;
    case 31:  /* N */
       if (wordm1 == 0) {
          ermess(6, 0);
          i = comp - 1;
          break;
       }
       entertemp();
       j = charson(wordm1);
       cur = (struct cell *)&edit_end->ll;
       curp = endp;
       break;
    case 34: /* @ */
       diagnostic(curcom->par);
       break;
    case 35:  /* ? */
       help(curcom->par);
       break;
    case 36:  /* % */
       if (maptxt(curcom->par) == 0) {i = comp; break;}
       move(16, &txt->ll, &string[curcom->lett].ll);
       break;
             } /* end of switch */
          }
       }
    err:
       return(0);
    } /* ed */

    /*----------------------------------------------------------------------*/

    main(argc, argv) int argc; char *argv[]; {
    int j;
    char hold[128];
    static char *com[] = {"edit", "look"};
    static char *msg[] = {"finished", "completed", "abandoned", "no changes", "***NOT*** completed"};

    extern int optind;
    extern char *optarg;

       indent[0] = 0;
       nls[0] = NL; nls[1] = NL;
       for (j=0; j<132;) sps[j++] = SP;
       byteinteger = (char *)0;
       integer = (int *)0;
       input_pointer = 0; inputline[0] = 0;
       emode = 0; use_sif = 0;
       while ((j = getopt(argc, argv, "ls")) != EOF) switch(j) {
    case 'l': emode = 1; break;
    case 's': use_sif = 1; break;
    case '?': return;
       }

       j = 0;
       for (; optind < argc; optind++) {
          if (j == 0) strcpy(in, argv[optind]);
          if (j == 1) strcpy(out, argv[optind]);
          if (j > (1-emode)) {printf("Too many parameters\n"); return;}
          j++;
       }
       if (j == 0) {printf("No file name given\n"); return;}
       if (j == 1) {strcpy(out, in); strcpy(hold, in);
       } else sprintf(hold, "%s %s", in, out);
       expand_filename(in); expand_filename(out);
       if (emode == 1) strcpy(out, ".NULL");
       j = ed();
       if (emode == 1) j = 0;
       if ((0 <= j) && (j <= 4)) printf("%s %s %s\n", com[emode], hold, msg[j]);
    }