/*

                              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]);
}