home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / ed.zip / ed.c next >
C/C++ Source or Header  |  1994-08-26  |  36KB  |  1,561 lines

  1. /*
  2.  *  ed - standard editor
  3.  *  ~~
  4.  *  Authors: Brian Beattie, Kees Bot, and others
  5.  *
  6.  * Copyright 1987 Brian Beattie Rights Reserved.
  7.  * Permission to copy or distribute granted under the following conditions:
  8.  * 1). No charge may be made other than reasonable charges for reproduction.
  9.  * 2). This notice must remain intact.
  10.  * 3). No further restrictions may be added.
  11.  * 4). Except meaningless ones.
  12.  *
  13.  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  14.  *  TurboC mods and cleanup 8/17/88 RAMontante.
  15.  *  Further information (posting headers, etc.) at end of file.
  16.  *  RE stuff replaced with Spencerian version, sundry other bugfix+speedups
  17.  *  Ian Phillipps. Version incremented to "5".
  18.  * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  19.  */
  20.  
  21. int version = 5;    /* used only in the "set" function, for i.d. */
  22.  
  23. #include <stdio.h>
  24. /* Regexp is Henry Spencer's package. WARNING: regsub is modified to return
  25.  * a pointer to the \0 after the destination string, and this program refers
  26.  * to the "private" reganch field in the struct regexp.
  27.  */
  28. #include "regexp.h"
  29.  
  30. #ifdef __TURBOC__
  31. #include <stdlib.h>
  32. #include <signal.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <io.h>
  36.  
  37. #define _cleanup()  ;
  38.  
  39. #endif  /* ifdef __TURBOC__  */
  40.  
  41.  
  42. /*
  43.  *  #defines for non-printing ASCII characters
  44.  */
  45. #define NUL 0x00    /* ^@ */
  46. #define EOS 0x00    /* end of string */
  47. #define SOH 0x01    /* ^A */
  48. #define STX 0x02    /* ^B */
  49. #define ETX 0x03    /* ^C */
  50. #define EOT 0x04    /* ^D */
  51. #define ENQ 0x05    /* ^E */
  52. #define ACK 0x06    /* ^F */
  53. #define BEL 0x07    /* ^G */
  54. #define BS  0x08    /* ^H */
  55. #define HT  0x09    /* ^I */
  56. #define LF  0x0a    /* ^J */
  57. #define NL  '\n'
  58. #define VT  0x0b    /* ^K */
  59. #define FF  0x0c    /* ^L */
  60. #define CR  0x0d    /* ^M */
  61. #define SO  0x0e    /* ^N */
  62. #define SI  0x0f    /* ^O */
  63. #define DLE 0x10    /* ^P */
  64. #define DC1 0x11    /* ^Q */
  65. #define DC2 0x12    /* ^R */
  66. #define DC3 0x13    /* ^S */
  67. #define DC4 0x14    /* ^T */
  68. #define NAK 0x15    /* ^U */
  69. #define SYN 0x16    /* ^V */
  70. #define ETB 0x17    /* ^W */
  71. #define CAN 0x18    /* ^X */
  72. #define EM  0x19    /* ^Y */
  73. #define SUB 0x1a    /* ^Z */
  74. #define ESC 0x1b    /* ^[ */
  75. #define FS  0x1c    /* ^\ */
  76. #define GS  0x1d    /* ^] */
  77. #define RS  0x1e    /* ^^ */
  78. #define US  0x1f    /* ^_ */
  79. #define SP  0x20    /* space */
  80. #define DEL 0x7f    /* DEL*/
  81. #define ESCAPE  '\\'
  82.  
  83.  
  84. #define TRUE    1
  85. #define FALSE   0
  86. #define ERR     -2
  87. #define FATAL       (ERR-1)
  88. #define CHANGED     (ERR-2)
  89. #define SET_FAIL    (ERR-3)
  90. #define SUB_FAIL    (ERR-4)
  91. #define MEM_FAIL    (ERR-5)
  92.  
  93.  
  94. #define BUFFER_SIZE 2048    /* stream-buffer size:  == 1 hd cluster */
  95.  
  96. #define LINFREE 1   /* entry not in use */
  97. #define LGLOB   2       /* line marked global */
  98.  
  99. #define MAXLINE 512 /* max number of chars per line */
  100. #define MAXPAT  256 /* max number of chars per replacement pattern */
  101. #define MAXFNAME 256    /* max file name size */
  102.  
  103.  
  104. /**  Global variables  **/
  105.  
  106. struct  line {
  107.     int     l_stat;     /* empty, mark */
  108.     struct line *l_prev;
  109.     struct line *l_next;
  110.     char        l_buff[1];
  111. };
  112. typedef struct line LINE;
  113.  
  114.  
  115. int diag = 1;       /* diagnostic-output? flag */
  116. int truncflg = 1;   /* truncate long line flag */
  117. int eightbit = 1;   /* save eighth bit */
  118. int nonascii;   /* count of non-ascii chars read */
  119. int nullchar;   /* count of null chars read */
  120. int truncated;  /* count of lines truncated */
  121. char    fname[MAXFNAME];
  122. int fchanged;   /* file-changed? flag */
  123. int nofname;
  124. int mark['z'-'a'+1];
  125. regexp  *oldpat;
  126.  
  127. LINE    Line0;
  128. int CurLn = 0;
  129. LINE    *CurPtr = &Line0;   /* CurLn and CurPtr must be kept in step */
  130. int LastLn = 0;
  131. char    inlin[MAXLINE];
  132. int pflag;
  133. int Line1, Line2, nlines;
  134. int nflg;       /* print line number flag */
  135. int lflg;       /* print line in verbose mode */
  136. int pflg;       /* print current line after each command */
  137. char    *inptr;     /* tty input buffer */
  138.  
  139. struct tbl {
  140.     char    *t_str;
  141.     int *t_ptr;
  142.     int t_val;
  143. } *t, tbl[] = {
  144.     "number",   &nflg,      TRUE,
  145.     "nonumber", &nflg,      FALSE,
  146.     "list",     &lflg,      TRUE,
  147.     "nolist",   &lflg,      FALSE,
  148.     "eightbit", &eightbit,  TRUE,
  149.     "noeightbit",   &eightbit,  FALSE,
  150.     0
  151. };
  152.  
  153.  
  154. /*-------------------------------------------------------------------------*/
  155.  
  156. #ifdef __TURBOC__       /*  prototypes (unneeded?)  */
  157.  
  158. void    prntln(char *, int, int);
  159. void    putcntl(char , FILE *);
  160. int doprnt(int, int);
  161. LINE    *getptr(int);
  162. int del(int, int);
  163. int ins(char *);
  164. int append(int, int);
  165. int deflt(int, int);
  166. regexp  *optpat(void);
  167. int egets( char*, int, FILE* );
  168. int ckglob( void );
  169. int doglob( void );
  170. int docmd( int );
  171. int dolst( int, int );
  172. int doread( int, char* );
  173. int dowrite( int, int, char*, int );
  174. int find( regexp*, int );
  175. char*   getfn( void );
  176. int getlst( void );
  177. int getnum( int );
  178. int getone( void );
  179. int getrhs( char* );
  180. int join( int, int );
  181. int move( int );
  182. int set( void );
  183. int subst( regexp*, char*, int, int );
  184. int transfer( int );
  185.  
  186. #else   /* !__TURBOC__ */
  187.  
  188. extern  char    *strcpy();
  189. extern  int *malloc();
  190. extern  LINE    *getptr();
  191. extern  char    *gettxt();
  192. extern  char    *gettxtl();
  193. extern  char    *catsub();
  194. regexp  *optpat();
  195.  
  196. #endif  /* __TURBOC__ */
  197.  
  198.  
  199. /*________  Macros  ________________________________________________________*/
  200.  
  201. #ifndef max
  202. #  define max(a,b)  ((a) > (b) ? (a) : (b))
  203. #endif
  204.  
  205. #ifndef min
  206. #  define min(a,b)  ((a) < (b) ? (a) : (b))
  207. #endif
  208.  
  209. #ifndef toupper
  210. #  define toupper(c)    ((c >= 'a' && c <= 'z') ? c-32 : c )
  211. #endif
  212.  
  213. #define nextln(l)   ((l)+1 > LastLn ? 0 : (l)+1)
  214. #define prevln(l)   ((l)-1 < 0 ? LastLn : (l)-1)
  215.  
  216. #define gettxtl(lin)    ((lin)->l_buff)
  217. #define gettxt(num) (gettxtl( getptr(num) ))
  218.  
  219. #define getnextptr(p)   ((p)->l_next)
  220. #define getprevptr(p)   ((p)->l_prev)
  221.  
  222. #define setCurLn( lin ) ( CurPtr = getptr( CurLn = (lin) ) )
  223. #define nextCurLn() ( CurLn = nextln(CurLn), CurPtr = getnextptr( CurPtr ) )
  224. #define prevCurLn() ( CurLn = prevln(CurLn), CurPtr = getprevptr( CurPtr ) )
  225.  
  226. #define clrbuf()    del(1, LastLn)
  227.  
  228. #define Skip_White_Space    {while (*inptr==SP || *inptr==HT) inptr++;}
  229.  
  230. #define relink(a, x, y, b) { (x)->l_prev = (a); (y)->l_next = (b); }
  231.  
  232.  
  233. /*________  functions  ______________________________________________________*/
  234.  
  235.  
  236. /*  append.c    */
  237.  
  238. append(line, glob)
  239. int line, glob;
  240. {
  241.     char    lin[MAXLINE];
  242.  
  243.     if(glob)
  244.         return(ERR);
  245.     setCurLn( line );
  246.     for (;;) {
  247.         char *p = lin;
  248.         if(nflg)
  249.             printf("%6d. ",CurLn+1);
  250.         while( p < &lin[ MAXLINE ] ) {
  251.             int ch = getchar();
  252.             if( ch == EOF )
  253.                 return EOF;
  254.             if( ch == '\n' ) {
  255.                 *p = EOS; break;
  256.             }
  257.             *p++ = ch;
  258.         }
  259.         if(lin[0] == '.' && lin[1] == '\0')
  260.             return(0);
  261.         if( ins(lin) < 0)
  262.             return( MEM_FAIL );
  263.     }
  264. }
  265.  
  266. /*  ckglob.c    */
  267.  
  268. ckglob()
  269. {
  270.     regexp  *glbpat;
  271.     char    c, delim, *lin;
  272.     int num;
  273.     LINE    *ptr;
  274.  
  275.     c = *inptr;
  276.  
  277.     if(c != 'g' && c != 'v')
  278.         return(0);
  279.     if (deflt(1, LastLn) < 0)
  280.         return(ERR);
  281.  
  282.     delim = *++inptr;
  283.     if(delim <= ' ')
  284.         return(ERR);
  285.  
  286.     glbpat = optpat();
  287.     if(*inptr == delim)
  288.         inptr++;
  289.     ptr = getptr(1);
  290.     for (num=1; num<=LastLn; num++) {
  291.         ptr->l_stat &= ~LGLOB;
  292.         if (Line1 <= num && num <= Line2) {
  293.             lin = gettxtl(ptr);
  294.             if(regexec(glbpat, lin )) {
  295.                 if (c=='g') ptr->l_stat |= LGLOB;
  296.             } else {
  297.                 if (c=='v') ptr->l_stat |= LGLOB;
  298.             }
  299.         ptr = getnextptr(ptr);
  300.         }
  301.     }
  302.     return(1);
  303. }
  304.  
  305.  
  306. /*  deflt.c
  307.  *  Set Line1 & Line2 (the command-range delimiters) if the file is
  308.  *  empty; Test whether they have valid values.
  309.  */
  310.  
  311. int deflt(def1, def2)
  312. int def1, def2;
  313. {
  314.     if(nlines == 0) {
  315.         Line1 = def1;
  316.         Line2 = def2;
  317.     }
  318.     return ( (Line1>Line2 || Line1<=0) ? ERR : 0 );
  319. }
  320.  
  321.  
  322. /*  del.c   */
  323.  
  324. /* One of the calls to this function tests its return value for an error
  325.  * condition.  But del doesn't return any error value, and it isn't obvious
  326.  * to me what errors might be detectable/reportable.  To silence a warning
  327.  * message, I've added a constant return statement. -- RAM
  328.  * ... It could check to<=LastLn ... igp
  329.  */
  330.  
  331. del(from, to)
  332. int from, to;
  333. {
  334.     LINE    *first, *last, *next, *tmp;
  335.  
  336.     if(from < 1)
  337.         from = 1;
  338.     first = getprevptr( getptr( from ) );
  339.     last = getnextptr( getptr( to ) );
  340.     next = first->l_next;
  341.     while(next != last && next != &Line0) {
  342.         tmp = next->l_next;
  343.         free(next);
  344.         next = tmp;
  345.     }
  346.     relink(first, last, first, last);
  347.     LastLn -= (to - from)+1;
  348.     setCurLn( prevln(from) );
  349.     return(0);
  350. }
  351.  
  352.  
  353. int dolst(line1, line2)
  354. int line1, line2;
  355. {
  356.     int oldlflg=lflg, p;
  357.  
  358.     lflg = 1;
  359.     p = doprnt(line1, line2);
  360.     lflg = oldlflg;
  361.     return p;
  362. }
  363.  
  364.  
  365. /*  esc.c
  366.  * Map escape sequences into their equivalent symbols.  Returns the
  367.  * correct ASCII character.  If no escape prefix is present then s
  368.  * is untouched and *s is returned, otherwise **s is advanced to point
  369.  * at the escaped character and the translated character is returned.
  370.  */
  371. esc(s)
  372. char    **s;
  373. {
  374.     register int    rval;
  375.  
  376.     if (**s != ESCAPE) {
  377.         rval = **s;
  378.     } else {
  379.         (*s)++;
  380.         switch(toupper(**s)) {
  381.         case '\000':
  382.             rval = ESCAPE;  break;
  383.         case 'S':
  384.             rval = ' '; break;
  385.         case 'N':
  386.             rval = '\n';    break;
  387.         case 'T':
  388.             rval = '\t';    break;
  389.         case 'B':
  390.             rval = '\b';    break;
  391.         case 'R':
  392.             rval = '\r';    break;
  393.         default:
  394.             rval = **s; break;
  395.         }
  396.     }
  397.     return (rval);
  398. }
  399.  
  400.  
  401. /*  doprnt.c    */
  402.  
  403. int doprnt(from, to)
  404. int from, to;
  405. {
  406.     from = (from < 1) ? 1 : from;
  407.     to = (to > LastLn) ? LastLn : to;
  408.  
  409.     if(to != 0) {
  410.         setCurLn( from );
  411.         while( CurLn <= to ) {
  412.             prntln( gettxtl( CurPtr ), lflg, (nflg ? CurLn : 0));
  413.             if( CurLn == to )
  414.                 break;
  415.             nextCurLn();
  416.         }
  417.     }
  418.     return(0);
  419. }
  420.  
  421.  
  422. void prntln(str, vflg, lin)
  423. char    *str;
  424. int vflg, lin;
  425. {
  426.     if(lin)
  427.         printf("%7d ",lin);
  428.     while(*str && *str != NL) {
  429.         if(*str < ' ' || *str >= 0x7f) {
  430.             switch(*str) {
  431.             case '\t':
  432.                 if(vflg)
  433.                     putcntl(*str, stdout);
  434.                 else
  435.                     putc(*str, stdout);
  436.                 break;
  437.  
  438.             case DEL:
  439.                 putc('^', stdout);
  440.                 putc('?', stdout);
  441.                 break;
  442.  
  443.             default:
  444.                 putcntl(*str, stdout);
  445.                 break;
  446.             }
  447.         } else
  448.             putc(*str, stdout);
  449.         str++;
  450.     }
  451.     if(vflg)
  452.         putchar('$');
  453.     putchar('\n');
  454. }
  455.  
  456.  
  457. void putcntl(c, stream)
  458. char    c;
  459. FILE    *stream;
  460. {
  461.     putc('^', stream);
  462.     putc((c&31)|'@', stream);
  463. }
  464.  
  465.  
  466. /*  egets.c */
  467.  
  468. egets(str,size,stream)
  469. char    *str;
  470. int size;
  471. FILE    *stream;
  472. {
  473.     int c, count;
  474.     char    *cp;
  475.  
  476.     for(count = 0, cp = str; size > count;) {
  477.         c = getc(stream);
  478.         if(c == EOF) {
  479.             *cp = EOS;
  480.             if(count)
  481.                 puts("[Incomplete last line]");
  482.             return(count);
  483.         }
  484.         else if(c == NL) {
  485.             *cp = EOS;
  486.             return(++count);
  487.         }
  488.         else if (c == 0)
  489.             nullchar++; /* count nulls */
  490.         else {
  491.             if(c > 127) {
  492.                 if(!eightbit)       /* if not saving eighth bit */
  493.                     c = c&127;  /* strip eigth bit */
  494.                 nonascii++;     /* count it */
  495.             }
  496.             *cp++ = c;  /* not null, keep it */
  497.             count++;
  498.         }
  499.     }
  500.     str[count-1] = EOS;
  501.     if(c != NL) {
  502.         puts("truncating line");
  503.         truncated++;
  504.         while((c = getc(stream)) != EOF)
  505.             if(c == NL)
  506.                 break;
  507.     }
  508.     return(count);
  509. }  /* egets */
  510.  
  511.  
  512. doread(lin, fname)
  513. int lin;
  514. char    *fname;
  515. {
  516.     FILE    *fp;
  517.     int err;
  518.     unsigned long   bytes;
  519.     unsigned int    lines;
  520.     static char str[MAXLINE];
  521.  
  522.     err = 0;
  523.     nonascii = nullchar = truncated = 0;
  524.  
  525.     if (diag) printf("\"%s\" ",fname);
  526.     if( (fp = fopen(fname, "r")) == NULL ) {
  527.         puts(" isn't readable.");
  528.         return( ERR );
  529.     }
  530.     setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
  531.     setCurLn( lin );
  532.     for(lines = 0, bytes = 0;(err = egets(str,MAXLINE,fp)) > 0;) {
  533.         bytes += err;
  534.         if(ins(str) < 0) {
  535.             err = MEM_FAIL;
  536.             break;
  537.         }
  538.         lines++;
  539.     }
  540.     fclose(fp);
  541.     if(err < 0)
  542.         return(err);
  543.     if (diag) {
  544.         printf("%u lines %u bytes",lines,bytes);
  545.         if(nonascii)
  546.             printf(" [%d non-ascii]",nonascii);
  547.         if(nullchar)
  548.             printf(" [%d nul]",nullchar);
  549.         if(truncated)
  550.             printf(" [%d lines truncated]",truncated);
  551.         putchar('\n');
  552.     }
  553.     return( err );
  554. }  /* doread */
  555.  
  556.  
  557. int dowrite(from, to, fname, apflg)
  558. int from, to;
  559. char    *fname;
  560. int apflg;
  561. {
  562.     FILE    *fp;
  563.     int lin, err;
  564.     unsigned int    lines;
  565.     unsigned long   bytes;
  566.     char    *str;
  567.     LINE    *lptr;
  568.  
  569.     err = 0;
  570.     lines = bytes = 0;
  571.  
  572.     printf("\"%s\" ",fname);
  573.     if((fp = fopen(fname,(apflg?"a":"w"))) == NULL) {
  574.         puts(" can't be opened for writing!");
  575.         return( ERR );
  576.     }
  577.  
  578.     setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
  579.     lptr = getptr(from);
  580.     for(lin = from; lin <= to; lin++) {
  581.         str = lptr->l_buff;
  582.         lines++;
  583.         bytes += strlen(str) + 1;   /* str + '\n' */
  584.         if(fputs(str, fp) == EOF) {
  585.             puts("file write error");
  586.             err++;
  587.             break;
  588.         }
  589.         fputc('\n', fp);
  590.         lptr = lptr->l_next;
  591.     }
  592.     printf("%u lines %lu bytes\n",lines,bytes);
  593.     fclose(fp);
  594.     return( err );
  595. }  /* dowrite */
  596.  
  597.  
  598. /*  find.c  */
  599.  
  600. find(pat, dir)
  601. regexp  *pat;
  602. int dir;
  603. {
  604.     int i, num;
  605.     LINE    *lin;
  606.  
  607.     num = CurLn;
  608.     lin = CurPtr;
  609.     for(i=0; i<LastLn; i++ ) {
  610.         if(regexec( pat, gettxtl( lin ) ))
  611.             return(num);
  612.         if( dir )
  613.             num = nextln(num), lin = getnextptr(lin);
  614.         else
  615.             num = prevln(num), lin = getprevptr(lin);
  616.     }
  617.     return ( ERR );
  618. }
  619.  
  620.  
  621. /*  getfn.c */
  622.  
  623. char *getfn()
  624. {
  625.     static char file[256];
  626.     char    *cp;
  627.  
  628.     if(*inptr == NL) {
  629.         nofname=TRUE;
  630.         strcpy(file, fname);
  631.     } else {
  632.         nofname=FALSE;
  633.         Skip_White_Space;
  634.  
  635.         cp = file;
  636.         while(*inptr && *inptr != NL && *inptr != SP && *inptr != HT)
  637.             *cp++ = *inptr++;
  638.         *cp = '\0';
  639.  
  640.         if(strlen(file) == 0) {
  641.             puts("bad file name");
  642.             return( NULL );
  643.         }
  644.     }
  645.  
  646.     if(strlen(file) == 0) {
  647.         puts("no file name");
  648.         return(NULL);
  649.     }
  650.     return( file );
  651. }  /* getfn */
  652.  
  653.  
  654. int getnum(first)
  655. int first;
  656. {
  657.     regexp  *srchpat;
  658.     int num;
  659.     char    c;
  660.  
  661.     Skip_White_Space;
  662.  
  663.     if(*inptr >= '0' && *inptr <= '9') {    /* line number */
  664.         for(num = 0; *inptr >= '0' && *inptr <= '9'; ++inptr) {
  665.             num = (num * 10) + (*inptr - '0');
  666.         }
  667.         return num;
  668.     }
  669.  
  670.     switch(c = *inptr) {
  671.     case '.':
  672.         inptr++;
  673.         return (CurLn);
  674.  
  675.     case '$':
  676.         inptr++;
  677.         return (LastLn);
  678.  
  679.     case '/':
  680.     case '?':
  681.         srchpat = optpat();
  682.         if(*inptr == c)
  683.             *inptr++;
  684.         return(find(srchpat,c == '/'?1:0));
  685.  
  686.     case '-':
  687.     case '+':
  688.         return(first ? CurLn : 1);
  689.  
  690.     case '\'':
  691.         inptr++;
  692.         if (*inptr < 'a' || *inptr > 'z')
  693.             return(EOF);
  694.         return mark[ *inptr++ - 'a' ];
  695.  
  696.     default:
  697.         return ( first ? EOF : 1 ); /* unknown address */
  698.     }
  699. }  /* getnum */
  700.  
  701.  
  702. /*  getone.c
  703.  *  Parse a number (or arithmetic expression) off the command line.
  704.  */
  705. #define FIRST 1
  706. #define NOTFIRST 0
  707.  
  708. int getone()
  709. {
  710.     int c, i, num;
  711.  
  712.     if((num = getnum(FIRST)) >= 0) {
  713.         for (;;) {
  714.             Skip_White_Space;
  715.             if(*inptr != '+' && *inptr != '-')
  716.                 break;  /* exit infinite loop */
  717.  
  718.                         c = *inptr++;
  719.             if((i = getnum(NOTFIRST)) < 0)
  720.                 return ( i );
  721.             if(c == '+')
  722.                 num += i;
  723.             else
  724.                 num -= i;
  725.         }
  726.     }
  727.     return ( num>LastLn ? ERR : num );
  728. }  /* getone */
  729.  
  730.  
  731. getlst()
  732. {
  733.     int num;
  734.  
  735.     Line2 = 0;
  736.     for(nlines = 0; (num = getone()) >= 0;)
  737.     {
  738.         Line1 = Line2;
  739.         Line2 = num;
  740.         nlines++;
  741.         if(*inptr != ',' && *inptr != ';')
  742.             break;
  743.         if(*inptr == ';')
  744.             setCurLn( num );
  745.         inptr++;
  746.     }
  747.     nlines = min(nlines, 2);
  748.     if(nlines == 0)
  749.         Line2 = CurLn;
  750.     if(nlines <= 1)
  751.         Line1 = Line2;
  752.  
  753.     return ( (num == ERR) ? num : nlines );
  754. }  /* getlst */
  755.  
  756.  
  757. /*  getptr.c    */
  758.  
  759. LINE *getptr(num)
  760. int num;
  761. {
  762.     LINE    *ptr;
  763.     int j;
  764.  
  765.     if (2*num>LastLn && num<=LastLn) {  /* high line numbers */
  766.         ptr = Line0.l_prev;
  767.         for (j = LastLn; j>num; j--)
  768.             ptr = ptr->l_prev;
  769.     } else {                /* low line numbers */
  770.         ptr = &Line0;
  771.         for(j = 0; j < num; j++)
  772.             ptr = ptr->l_next;
  773.     }
  774.     return(ptr);
  775. }
  776.  
  777.  
  778. /*  getrhs.c    */
  779.  
  780. int getrhs(sub)
  781. char    *sub;
  782. {
  783.     char delim = *inptr++;
  784.     char *outmax = sub + MAXPAT;
  785.     if( delim == NL || *inptr == NL)    /* check for eol */
  786.         return( ERR );
  787.     while( *inptr != delim && *inptr != NL ) {
  788.         if ( sub > outmax )
  789.             return ERR;
  790.         if ( *inptr == ESCAPE ) {
  791.             switch ( *++inptr ) {
  792.             case 'r':
  793.                 *sub++ = '\r';
  794.                 inptr++;
  795.                 break;
  796.             case ESCAPE:
  797.                 *sub++ = ESCAPE;
  798.                 *sub++ = ESCAPE;
  799.                 inptr++;
  800.             case 'n':
  801.                 *sub++ = '\n';
  802.                 inptr++;
  803.                 break;
  804.             case 'b':
  805.                 *sub++ = '\b';
  806.                 inptr++;
  807.                 break;
  808.             case '0': {
  809.                 int i=3;
  810.                 *sub = 0;
  811.                 do {
  812.                     if (*++inptr<'0' || *inptr >'7')
  813.                         break;
  814.                     *sub = (*sub<<3) | (*inptr-'0');
  815.                 } while (--i!=0);
  816.                 sub++;
  817.                 } break;
  818.             default:
  819.                 if ( *inptr != delim )
  820.                     *sub++ = ESCAPE;
  821.                 *sub++ = *inptr;
  822.                 if ( *inptr != NL )
  823.                     inptr++;
  824.             }
  825.         }
  826.         else *sub++ = *inptr++;
  827.     }
  828.     *sub = '\0';
  829.  
  830.     inptr++;        /* skip over delimter */
  831.     Skip_White_Space;
  832.     if(*inptr == 'g') {
  833.         *inptr++;
  834.         return( 1 );
  835.     }
  836.     return( 0 );
  837. }
  838.  
  839. /*  ins.c   */
  840.  
  841. ins(str)
  842. char    *str;
  843. {
  844.     char    *cp;
  845.     LINE    *new, *nxt;
  846.     int len;
  847.  
  848.     do {
  849.         for ( cp = str; *cp && *cp != NL; cp++ )
  850.             ;
  851.         len = cp - str;
  852.         /* cp now points to end of first or only line */
  853.  
  854.         if((new = (LINE *)malloc(sizeof(LINE)+len)) == NULL)
  855.             return( MEM_FAIL );     /* no memory */
  856.  
  857.         new->l_stat=0;
  858.         strncpy(new->l_buff,str,len);   /* build new line */
  859.         new->l_buff[len] = EOS;
  860.         nxt = getnextptr(CurPtr);   /* get next line */
  861.         relink(CurPtr, new, new, nxt);  /* add to linked list */
  862.         relink(new, nxt, CurPtr, new);
  863.         LastLn++;
  864.         CurLn++;
  865.         CurPtr = new;
  866.         str = cp + 1;
  867.     }
  868.         while( *cp != EOS );
  869.     return 1;
  870. }
  871.  
  872.  
  873. /*  join.c  */
  874.  
  875. int join(first, last)
  876. int first, last;
  877. {
  878.     char buf[MAXLINE];
  879.     char *cp=buf, *str;
  880.     LINE *lin;
  881.     int num;
  882.  
  883.     if (first<=0 || first>last || last>LastLn)
  884.         return(ERR);
  885.     if (first==last) {
  886.         setCurLn( first );
  887.         return 0;
  888.     }
  889.     lin = getptr(first);
  890.     for (num=first; num<=last; num++) {
  891.         str=gettxtl(lin);
  892.         while ( *str ) {
  893.             if (cp >= buf + MAXLINE-1 ) {
  894.                 puts("line too long");
  895.                 return(ERR);
  896.             }
  897.             *cp++ = *str++;
  898.         }
  899.         lin = getnextptr(lin);
  900.     }
  901.     *cp = EOS;
  902.     del(first, last);
  903.     if( ins(buf) < 0 )
  904.         return MEM_FAIL;
  905.     fchanged = TRUE;
  906.     return 0;
  907. }
  908.  
  909.  
  910. /*  move.c
  911.  *  Unlink the block of lines from Line1 to Line2, and relink them
  912.  *  after line "num".
  913.  */
  914.  
  915. int move(num)
  916. int num;
  917. {
  918.     int range;
  919.     LINE    *before, *first, *last, *after;
  920.  
  921.     if( Line1 <= num && num <= Line2 )
  922.         return( ERR );
  923.     range = Line2 - Line1 + 1;
  924.     before = getptr(prevln(Line1));
  925.     first = getptr(Line1);
  926.     last = getptr(Line2);
  927.     after = getptr(nextln(Line2));
  928.  
  929.     relink(before, after, before, after);
  930.     LastLn -= range;    /* per AST's posted patch 2/2/88 */
  931.     if (num > Line1)
  932.         num -= range;
  933.  
  934.     before = getptr(num);
  935.     after = getptr(nextln(num));
  936.     relink(before, first, last, after);
  937.     relink(last, after, before, first);
  938.     LastLn += range;    /* per AST's posted patch 2/2/88 */
  939.     setCurLn( num + range );
  940.     return( 1 );
  941. }
  942.  
  943.  
  944. int transfer(num)
  945. int num;
  946. {
  947.     int mid, lin, ntrans;
  948.  
  949.     if (Line1<=0 || Line1>Line2)
  950.         return(ERR);
  951.  
  952.     mid= num<Line2 ? num : Line2;
  953.  
  954.     setCurLn( num );
  955.     ntrans=0;
  956.  
  957.     for (lin=Line1; lin<=mid; lin++) {
  958.         if( ins(gettxt(lin)) < 0 )
  959.             return MEM_FAIL;
  960.         ntrans++;
  961.     }
  962.     lin+=ntrans;
  963.     Line2+=ntrans;
  964.  
  965.     for ( ; lin <= Line2; lin += 2 ) {
  966.         if( ins(gettxt(lin)) < 0 )
  967.             return MEM_FAIL;
  968.         Line2++;
  969.     }
  970.     return(1);
  971. }
  972.  
  973.  
  974. /*  optpat.c    */
  975.  
  976. regexp *optpat(void)
  977. {
  978.     char    delim, str[MAXPAT], *cp;
  979.  
  980.     delim = *inptr++;
  981.     cp = str;
  982.     while(*inptr != delim && *inptr != NL) {
  983.         if(*inptr == ESCAPE && inptr[1] != NL)
  984.             *cp++ = *inptr++;
  985.         *cp++ = *inptr++;
  986.     }
  987.  
  988.     *cp = EOS;
  989.     if(*str == EOS)
  990.         return(oldpat);
  991.     if(oldpat)
  992.         free(oldpat);
  993.     return oldpat = regcomp(str);
  994. }
  995.  
  996. /* regerror.c */
  997. void regerror( char *s )
  998. {
  999.     fprintf( stderr, "ed: %s\n", s );
  1000. }
  1001.  
  1002.  
  1003. set()
  1004. {
  1005.     char    word[16];
  1006.     int i;
  1007.  
  1008.     if(*(++inptr) != 't') {
  1009.         if(*inptr != SP && *inptr != HT && *inptr != NL)
  1010.             return(ERR);
  1011.     } else
  1012.         inptr++;
  1013.  
  1014.     if ( (*inptr == NL)
  1015. #ifdef __TURBOC__
  1016.         || (*inptr == CR)
  1017. #endif
  1018.        )
  1019.     {
  1020.         printf("ed version %d.%d\n", version/100, version%100);
  1021.         printf( "number %s, list %s\n",
  1022.             nflg?"ON":"OFF",
  1023.             lflg?"ON":"OFF");
  1024.         return(0);
  1025.     }
  1026.  
  1027.     Skip_White_Space;
  1028.     for(i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
  1029.         word[i++] = *inptr++;
  1030.     word[i] = EOS;
  1031.     for(t = tbl; t->t_str; t++) {
  1032.         if(strcmp(word,t->t_str) == 0) {
  1033.             *t->t_ptr = t->t_val;
  1034.             return(0);
  1035.         }
  1036.     }
  1037.     return SET_FAIL;
  1038. }
  1039.  
  1040. #ifndef relink
  1041. void relink(a, x, y, b)
  1042. LINE    *a, *x, *y, *b;
  1043. {
  1044.     x->l_prev = a;
  1045.     y->l_next = b;
  1046. }
  1047. #endif
  1048.  
  1049.  
  1050. void set_ed_buf(void)
  1051. {
  1052.     relink(&Line0, &Line0, &Line0, &Line0);
  1053.     CurLn = LastLn = 0;
  1054.     CurPtr = &Line0;
  1055. }
  1056.  
  1057.  
  1058. /*  subst.c */
  1059.  
  1060. int subst(pat, sub, gflg, pflag)
  1061. regexp  *pat;
  1062. char    *sub;
  1063. int gflg, pflag;
  1064. {
  1065.     int nchngd = 0;
  1066.     char    *txtptr;
  1067.     char    *new, buf[MAXLINE];
  1068.     int still_running = 1;
  1069.     LINE    *lastline = getptr( Line2 );
  1070.  
  1071.     if(Line1 <= 0)
  1072.         return( SUB_FAIL );
  1073.     nchngd = 0;     /* reset count of lines changed */
  1074.  
  1075.     for( setCurLn( prevln( Line1 ) ); still_running; ) {
  1076.         nextCurLn();
  1077.         new = buf;
  1078.         if ( CurPtr == lastline )
  1079.             still_running = 0;
  1080.         if ( regexec( pat, txtptr = gettxtl( CurPtr ) ) ) {
  1081.             do
  1082.                 {
  1083.                 /* Copy leading text */
  1084.                 int diff = pat->startp[0] - txtptr;
  1085.                 strncpy( new, txtptr, diff );
  1086.                 new += diff;
  1087.                 /* Do substitution */
  1088.                 new = regsub( pat, sub, new );
  1089.                 txtptr = pat->endp[0];
  1090.                 }
  1091.             while( gflg && !pat->reganch && regexec( pat, txtptr ));
  1092.  
  1093.             /* Copy trailing chars */
  1094.             while( *txtptr ) *new++ = *txtptr++;
  1095.  
  1096.             if(new >= buf+MAXLINE)
  1097.                 return( SUB_FAIL );
  1098.             *new++ = EOS;
  1099.             del(CurLn,CurLn);
  1100.             if( ins(buf) < 0 )
  1101.                 return MEM_FAIL;
  1102.             nchngd++;
  1103.             if(pflag)
  1104.                 doprnt(CurLn, CurLn);
  1105.         }
  1106.         }
  1107.     return (( nchngd == 0 && !gflg ) ? SUB_FAIL : nchngd);
  1108. }
  1109.  
  1110.  
  1111. /*  system.c    */
  1112. #ifndef __TURBOC__
  1113.  
  1114. #define SHELL   "/bin/sh"
  1115.  
  1116. system(c)
  1117. char *c; {
  1118.     int pid, status;
  1119.  
  1120.     switch (pid = fork()) {
  1121.     case -1:
  1122.         return -1;
  1123.     case 0:
  1124.         execl(SHELL, "sh", "-c", c, (char *) 0);
  1125.         exit(-1);
  1126.     default:
  1127.         while (wait(&status) != pid)
  1128.             ;
  1129.     }
  1130.     return status;
  1131. }
  1132. #endif  /* ifndef __TURBOC__ */
  1133.  
  1134.  
  1135. /*  docmd.c
  1136.  *  Perform the command specified in the input buffer, as pointed to
  1137.  *  by inptr.  Actually, this finds the command letter first.
  1138.  */
  1139.  
  1140. int docmd(glob)
  1141. int glob;
  1142. {
  1143.     static char rhs[MAXPAT];
  1144.     regexp  *subpat;
  1145.     int c, err, line3;
  1146.     int apflg, pflag, gflag;
  1147.     int nchng;
  1148.     char    *fptr;
  1149.  
  1150.     pflag = FALSE;
  1151.     Skip_White_Space;
  1152.  
  1153.     c = *inptr++;
  1154.     switch(c) {
  1155.     case NL:
  1156.         if( nlines == 0 && (Line2 = nextln(CurLn)) == 0 )
  1157.             return(ERR);
  1158.         setCurLn( Line2 );
  1159.         return (1);
  1160.  
  1161.     case '=':
  1162.         printf("%d\n",Line2);
  1163.         break;
  1164.  
  1165.     case 'a':
  1166.         if(*inptr != NL || nlines > 1)
  1167.             return(ERR);
  1168.  
  1169.         if(append(Line1, glob) < 0)
  1170.             return(ERR);
  1171.         fchanged = TRUE;
  1172.         break;
  1173.  
  1174.     case 'c':
  1175.         if(*inptr != NL)
  1176.             return(ERR);
  1177.  
  1178.         if(deflt(CurLn, CurLn) < 0)
  1179.             return(ERR);
  1180.  
  1181.         if(del(Line1, Line2) < 0)
  1182.             return(ERR);
  1183.         if(append(CurLn, glob) < 0)
  1184.             return(ERR);
  1185.         fchanged = TRUE;
  1186.         break;
  1187.  
  1188.     case 'd':
  1189.         if(*inptr != NL)
  1190.             return(ERR);
  1191.  
  1192.         if(deflt(CurLn, CurLn) < 0)
  1193.             return(ERR);
  1194.  
  1195.         if(del(Line1, Line2) < 0)
  1196.             return(ERR);
  1197.         if(nextln(CurLn) != 0)
  1198.             nextCurLn();
  1199.         fchanged = TRUE;
  1200.         break;
  1201.  
  1202.     case 'e':
  1203.         if(nlines > 0)
  1204.             return(ERR);
  1205.         if(fchanged)
  1206.             return CHANGED;
  1207.         /*FALL THROUGH*/
  1208.     case 'E':
  1209.         if(nlines > 0)
  1210.             return(ERR);
  1211.  
  1212.         if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1213.             return(ERR);
  1214.  
  1215.         if((fptr = getfn()) == NULL)
  1216.             return(ERR);
  1217.  
  1218.         clrbuf();
  1219.         if((err = doread(0, fptr)) < 0)
  1220.             return(err);
  1221.  
  1222.         strcpy(fname, fptr);
  1223.         fchanged = FALSE;
  1224.         break;
  1225.  
  1226.     case 'f':
  1227.         if(nlines > 0)
  1228.             return(ERR);
  1229.  
  1230.         if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1231.             return(ERR);
  1232.  
  1233.         if((fptr = getfn()) == NULL)
  1234.             return(ERR);
  1235.  
  1236.         if (nofname)
  1237.             printf("%s\n", fname);
  1238.         else
  1239.             strcpy(fname, fptr);
  1240.         break;
  1241.  
  1242.     case 'i':
  1243.         if(*inptr != NL || nlines > 1)
  1244.             return(ERR);
  1245.  
  1246.         if(append(prevln(Line1), glob) < 0)
  1247.             return(ERR);
  1248.         fchanged = TRUE;
  1249.         break;
  1250.  
  1251.     case 'j':
  1252.         if (*inptr != NL || deflt(CurLn, CurLn+1)<0)
  1253.             return(ERR);
  1254.  
  1255.         if (join(Line1, Line2) < 0)
  1256.             return(ERR);
  1257.         break;
  1258.  
  1259.     case 'k':
  1260.         Skip_White_Space;
  1261.  
  1262.         if (*inptr < 'a' || *inptr > 'z')
  1263.             return ERR;
  1264.         c= *inptr++;
  1265.  
  1266.         if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1267.             return(ERR);
  1268.  
  1269.         mark[c-'a'] = Line1;
  1270.         break;
  1271.  
  1272.     case 'l':
  1273.         if(*inptr != NL)
  1274.             return(ERR);
  1275.         if(deflt(CurLn,CurLn) < 0)
  1276.             return(ERR);
  1277.         if (dolst(Line1,Line2) < 0)
  1278.             return(ERR);
  1279.         break;
  1280.  
  1281.     case 'm':
  1282.         if((line3 = getone()) < 0)
  1283.             return(ERR);
  1284.         if(deflt(CurLn,CurLn) < 0)
  1285.             return(ERR);
  1286.         if(move(line3) < 0)
  1287.             return(ERR);
  1288.         fchanged = TRUE;
  1289.         break;
  1290.  
  1291.     case 'P':
  1292.     case 'p':
  1293.         if(*inptr != NL)
  1294.             return(ERR);
  1295.         if(deflt(CurLn,CurLn) < 0)
  1296.             return(ERR);
  1297.         if(doprnt(Line1,Line2) < 0)
  1298.             return(ERR);
  1299.         break;
  1300.  
  1301.     case 'q':
  1302.         if(fchanged)
  1303.             return CHANGED;
  1304.         /*FALL THROUGH*/
  1305.     case 'Q':
  1306.         if(*inptr == NL && nlines == 0 && !glob)
  1307.             return(EOF);
  1308.         else
  1309.             return(ERR);
  1310.  
  1311.     case 'r':
  1312.         if(nlines > 1)
  1313.             return(ERR);
  1314.  
  1315.         if(nlines == 0)         /* The original code tested */
  1316.             Line2 = LastLn;     /*  if(nlines = 0)      */
  1317.                         /* which looks wrong.  RAM  */
  1318.  
  1319.         if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1320.             return(ERR);
  1321.  
  1322.         if((fptr = getfn()) == NULL)
  1323.             return(ERR);
  1324.  
  1325.         if((err = doread(Line2, fptr)) < 0)
  1326.             return(err);
  1327.         fchanged = TRUE;
  1328.         break;
  1329.  
  1330.     case 's':
  1331.         if(*inptr == 'e')
  1332.             return(set());
  1333.         Skip_White_Space;
  1334.         if((subpat = optpat()) == NULL)
  1335.             return(ERR);
  1336.         if((gflag = getrhs(rhs)) < 0)
  1337.             return(ERR);
  1338.         if(*inptr == 'p')
  1339.             pflag++;
  1340.         if(deflt(CurLn, CurLn) < 0)
  1341.             return(ERR);
  1342.         if((nchng = subst(subpat, rhs, gflag, pflag)) < 0)
  1343.             return(ERR);
  1344.         if(nchng)
  1345.             fchanged = TRUE;
  1346.         break;
  1347.  
  1348.     case 't':
  1349.         if((line3 = getone()) < 0)
  1350.             return(ERR);
  1351.         if(deflt(CurLn,CurLn) < 0)
  1352.             return(ERR);
  1353.         if(transfer(line3) < 0)
  1354.             return(ERR);
  1355.         fchanged = TRUE;
  1356.         break;
  1357.  
  1358.     case 'W':
  1359.     case 'w':
  1360.         apflg = (c=='W');
  1361.  
  1362.         if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1363.             return(ERR);
  1364.  
  1365.         if((fptr = getfn()) == NULL)
  1366.             return(ERR);
  1367.  
  1368.         if(deflt(1, LastLn) < 0)
  1369.             return(ERR);
  1370.         if(dowrite(Line1, Line2, fptr, apflg) < 0)
  1371.             return(ERR);
  1372.         fchanged = FALSE;
  1373.         break;
  1374.  
  1375.     case 'x':
  1376.         if(*inptr == NL && nlines == 0 && !glob) {
  1377.             if((fptr = getfn()) == NULL)
  1378.                 return(ERR);
  1379.             if(dowrite(1, LastLn, fptr, 0) >= 0)
  1380.                 return(EOF);
  1381.         }
  1382.         return(ERR);
  1383.  
  1384.     case 'z':
  1385.         if(deflt(CurLn,CurLn) < 0)
  1386.             return(ERR);
  1387.  
  1388.         switch(*inptr) {
  1389.         case '-':
  1390.             if(doprnt(Line1-21,Line1) < 0)
  1391.                 return(ERR);
  1392.             break;
  1393.  
  1394.         case '.':
  1395.             if(doprnt(Line1-11,Line1+10) < 0)
  1396.                 return(ERR);
  1397.             break;
  1398.  
  1399.         case '+':
  1400.         case '\n':
  1401.             if(doprnt(Line1,Line1+21) < 0)
  1402.                 return(ERR);
  1403.             break;
  1404.         }
  1405.         break;
  1406.  
  1407.     default:
  1408.         return(ERR);
  1409.     }
  1410.     return (0);
  1411. }  /* docmd */
  1412.  
  1413.  
  1414. /*  doglob.c    */
  1415. doglob()
  1416. {
  1417.     int lin, stat;
  1418.     char    *cmd;
  1419.     LINE    *ptr;
  1420.  
  1421.     cmd = inptr;
  1422.  
  1423.     for (;;) {
  1424.         ptr = getptr(1);
  1425.         for (lin=1; lin<=LastLn; lin++) {
  1426.             if (ptr->l_stat & LGLOB)
  1427.                 break;
  1428.             ptr = getnextptr(ptr);
  1429.         }
  1430.         if (lin > LastLn)
  1431.             break;
  1432.  
  1433.         ptr->l_stat &= ~LGLOB;
  1434.         CurLn = lin; CurPtr = ptr;
  1435.         inptr = cmd;
  1436.         if((stat = getlst()) < 0)
  1437.             return(stat);
  1438.         if((stat = docmd(1)) < 0)
  1439.             return(stat);
  1440.     }
  1441.     return(CurLn);
  1442. }  /* doglob */
  1443.  
  1444.  
  1445. /*
  1446.  *  Software signal 2 or SIGINT is caught and the result is to resume
  1447.  *  the main loop at a command prompt.
  1448.  */
  1449. #include <setjmp.h>
  1450. jmp_buf env;
  1451.  
  1452. #ifndef __TURBOC__
  1453. intr()
  1454. {
  1455.     puts("intr()?");
  1456.     longjmp(env, 1);
  1457. }
  1458.  
  1459. #else
  1460.  
  1461. void Catcher(void)
  1462. {
  1463.     longjmp(env, 1);
  1464. }
  1465. #endif  /* !__TURBOC__ */
  1466.  
  1467.  
  1468. /*--------  main  ---------------------------------------------------------*/
  1469. #ifndef _Cdecl
  1470. # define _Cdecl
  1471. #endif
  1472.  
  1473. void _Cdecl main(argc,argv)
  1474. int argc;
  1475. char    **argv;
  1476. {
  1477.     int stat, i, doflush;
  1478.  
  1479.     set_ed_buf();
  1480.     doflush=isatty(1);
  1481.  
  1482.     if (argc>1 && argv[1][0]=='-' && argv[1][1]==0) {
  1483.         diag = 0;
  1484.         argc--;
  1485.         argv++;
  1486.     }
  1487.     if(argc > 1) {
  1488.         for(i = 1; i < argc; i++) {
  1489.             if(doread(0,argv[i])==0) {
  1490.                 setCurLn( 1 );
  1491.                 strcpy(fname, argv[i]);
  1492.                 break;
  1493.             }
  1494.         }
  1495.     }
  1496.  
  1497.     for (;;) {
  1498.  
  1499.         setjmp(env);
  1500.         putchar(':');       /*  The command-line prompt  */
  1501.  
  1502. #ifndef __TURBOC__
  1503.         signal(2, intr);
  1504. #else   /* __TURBOC__ */
  1505.         signal(SIGINT, Catcher);
  1506. #endif  /* !__TURBOC__ */
  1507.  
  1508.         if (doflush)
  1509.             fflush(stdout);
  1510.         if (fgets(inlin, sizeof(inlin),stdin) == NULL) {
  1511.             puts("Null input.");
  1512.             break;
  1513.         }
  1514.         if(*inlin == '!') {
  1515.             for(inptr = inlin; *inptr != NL; inptr++)
  1516.                 ;
  1517.             *inptr = EOS;
  1518.             system(inlin+1);
  1519.             continue;
  1520.         }
  1521.         inptr = inlin;
  1522.         if(getlst() >= 0)
  1523.             if((stat = ckglob()) != 0) {
  1524.                 if(stat >= 0 && (stat = doglob()) >= 0) {
  1525.                     setCurLn( stat );
  1526.                     continue;
  1527.                 }
  1528.             } else {
  1529.                 if((stat = docmd(0)) >= 0) {
  1530.                     if(stat == 1)
  1531.                         doprnt(CurLn, CurLn);
  1532.                     continue;
  1533.                 }
  1534.             }
  1535.         switch (stat) {
  1536.         case EOF:
  1537.             _cleanup(); exit(0);
  1538.         case FATAL:
  1539.             fputs("FATAL ERROR\n",stderr);
  1540.             _cleanup(); exit(1);
  1541.         case CHANGED:
  1542.             puts("File has been changed.");
  1543.             break;
  1544.         case SET_FAIL:
  1545.             puts("`set' command failed.");
  1546.             break;
  1547.         case SUB_FAIL:
  1548.             puts("string substitution failed.");
  1549.             break;
  1550.         case MEM_FAIL:
  1551.             puts("Out of memory: text may have been lost." );
  1552.             break;
  1553.         default:
  1554.             puts("Oops?");
  1555.             /*  Unrecognized or failed command (this  */
  1556.             /*  is SOOOO much better than "?" :-)     */
  1557.         }
  1558.     }
  1559. }  /* main */
  1560. /*________  end of source code  ____________________________________________*/
  1561.