ed.c

Go to the documentation of this file.
00001 /* Copyright 1987 Brian Beattie Rights Reserved.
00002  *
00003  * Permission to copy and/or distribute granted under the
00004  * following conditions:
00005  *
00006  * 1). No charge may be made other than resonable charges
00007  *      for reproduction.
00008  *
00009  * 2). This notice must remain intact.
00010  *
00011  * 3). No further restrictions may be added.
00012  *
00013  */
00014 
00015 /*      This program used to be in many little pieces, with this makefile:
00016 .SUFFIXES:      .c .s
00017 
00018 CFLAGS = -F
00019 
00020 OBJS =  append.s catsub.s ckglob.s deflt.s del.s docmd.s doglob.s\
00021   doprnt.s doread.s dowrite.s ed.s egets.s find.s getfn.s getlst.s\
00022   getnum.s getone.s getptr.s getrhs.s gettxt.s ins.s join.s maksub.s\
00023   move.s optpat.s set.s setbuf.s subst.s getpat.s matchs.s amatch.s\
00024   unmkpat.s omatch.s makepat.s bitmap.s dodash.s esc.s System.s
00025 
00026 ed:     $(OBJS)
00027   cc -T. -i -o ed $(OBJS)
00028 */
00029 
00030 #include <sys/types.h>
00031 #include <signal.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <unistd.h>
00035 #include <sys/wait.h>
00036 #include <stdio.h>
00037 
00038 /****************************/
00039 
00040 /*      tools.h */
00041 /*
00042  *      #defines for non-printing ASCII characters
00043  */
00044 
00045 #define NUL     0x00            /* ^@ */
00046 #define EOS     0x00            /* end of string */
00047 #define SOH     0x01            /* ^A */
00048 #define STX     0x02            /* ^B */
00049 #define ETX     0x03            /* ^C */
00050 #define EOT     0x04            /* ^D */
00051 #define ENQ     0x05            /* ^E */
00052 #define ACK     0x06            /* ^F */
00053 #define BEL     0x07            /* ^G */
00054 #define BS      0x08            /* ^H */
00055 #define HT      0x09            /* ^I */
00056 #define LF      0x0a            /* ^J */
00057 #define NL      '\n'
00058 #define VT      0x0b            /* ^K */
00059 #define FF      0x0c            /* ^L */
00060 #define CR      0x0d            /* ^M */
00061 #define SO      0x0e            /* ^N */
00062 #define SI      0x0f            /* ^O */
00063 #define DLE     0x10            /* ^P */
00064 #define DC1     0x11            /* ^Q */
00065 #define DC2     0x12            /* ^R */
00066 #define DC3     0x13            /* ^S */
00067 #define DC4     0x14            /* ^T */
00068 #define NAK     0x15            /* ^U */
00069 #define SYN     0x16            /* ^V */
00070 #define ETB     0x17            /* ^W */
00071 #define CAN     0x18            /* ^X */
00072 #define EM      0x19            /* ^Y */
00073 #define SUB     0x1a            /* ^Z */
00074 #define ESC     0x1b            /* ^[ */
00075 #define FS      0x1c            /* ^\ */
00076 #define GS      0x1d            /* ^] */
00077 #define RS      0x1e            /* ^^ */
00078 #define US      0x1f            /* ^_ */
00079 #define SP      0x20            /* space */
00080 #define DEL     0x7f            /* DEL */
00081 
00082 
00083 #define TRUE    1
00084 #define FALSE   0
00085 #define ERR     -2
00086 
00087 
00088 /*      Definitions of meta-characters used in pattern matching
00089  *      routines.  LITCHAR & NCCL are only used as token identifiers;
00090  *      all the others are also both token identifier and actual symbol
00091  *      used in the regular expression.
00092  */
00093 
00094 
00095 #define BOL     '^'
00096 #define EOL     '$'
00097 #define ANY     '.'
00098 #define LITCHAR 'L'
00099 #define ESCAPE  '\\'
00100 #define CCL     '['             /* Character class: [...] */
00101 #define CCLEND  ']'
00102 #define NEGATE  '^'
00103 #define NCCL    '!'             /* Negative character class [^...] */
00104 #define CLOSURE '*'
00105 #define OR_SYM  '|'
00106 #define DITTO   '&'
00107 #define OPEN    '('
00108 #define CLOSE   ')'
00109 
00110 /* Largest permitted size for an expanded character class.  (i.e. the class
00111  * [a-z] will expand into 26 symbols; [a-z0-9] will expand into 36.)
00112  */
00113 #define CLS_SIZE        128
00114 
00115 /*
00116  *      Tokens are used to hold pattern templates. (see makepat())
00117  */
00118 typedef char BITMAP;
00119 
00120 typedef struct token {
00121   char tok;
00122   char lchar;
00123   BITMAP *bitmap;
00124   struct token *next;
00125 } TOKEN;
00126 
00127 #define TOKSIZE sizeof (TOKEN)
00128 
00129 /*
00130  *      An absolute maximun for strings.
00131  */
00132 
00133 #define MAXSTR  132             /* Maximum numbers of characters in a line */
00134 
00135 
00136 /* Macros */
00137 #define max(a,b)        ((a>b)?a:b)
00138 #define min(a,b)        ((a<b)?a:b)
00139 #define toupper(c)      (c>='a'&&c<='z'?c-32:c)
00140 
00141 /*      ed.h    */
00142 #define FATAL   (ERR-1)
00143 struct line {
00144   int l_stat;                   /* empty, mark */
00145   struct line *l_prev;
00146   struct line *l_next;
00147   char l_buff[1];
00148 };
00149 
00150 typedef struct line LINE;
00151 
00152 #define LINFREE 1               /* entry not in use */
00153 #define LGLOB   2               /* line marked global */
00154 
00155                                 /* max number of chars per line */
00156 #define MAXLINE (sizeof(int) == 2 ? 256 : 8192)
00157 #define MAXPAT  256             /* max number of chars per replacement
00158                                  * pattern */
00159                                 /* max file name size */
00160 #define MAXFNAME (sizeof(int) == 2 ? 256 : 1024)
00161 
00162 extern LINE line0;
00163 extern int curln, lastln, line1, line2, nlines;
00164 extern int nflg;                /* print line number flag */
00165 extern int lflg;                /* print line in verbose mode */
00166 extern char *inptr;             /* tty input buffer */
00167 extern char linbuf[], *linptr;  /* current line */
00168 extern int truncflg;            /* truncate long line flag */
00169 extern int eightbit;            /* save eighth bit */
00170 extern int nonascii;            /* count of non-ascii chars read */
00171 extern int nullchar;            /* count of null chars read */
00172 extern int truncated;           /* count of lines truncated */
00173 extern int fchanged;            /* file changed */
00174 
00175 #define nextln(l)       ((l)+1 > lastln ? 0 : (l)+1)
00176 #define prevln(l)       ((l)-1 < 0 ? lastln : (l)-1)
00177 
00178 /*      amatch.c        */
00179 /* #include <stdio.h> */
00180 /* #include "tools.h" */
00181 
00182 _PROTOTYPE(int main, (int argc, char **argv));
00183 _PROTOTYPE(static char *match, (char *lin, TOKEN *pat, char *boln));
00184 _PROTOTYPE(char *amatch, (char *lin, TOKEN *pat, char *boln));
00185 _PROTOTYPE(int append, (int line, int glob));
00186 _PROTOTYPE(BITMAP *makebitmap, (unsigned size));
00187 _PROTOTYPE(int setbit, (unsigned c, char *map, unsigned val));
00188 _PROTOTYPE(int testbit, (unsigned c, char *map));
00189 _PROTOTYPE(char *catsub, (char *from, char *to, char *sub, char *new, char *newend));
00190 _PROTOTYPE(int ckglob, (void));
00191 _PROTOTYPE(int deflt, (int def1, int def2));
00192 _PROTOTYPE(int del, (int from, int to));
00193 _PROTOTYPE(int docmd, (int glob));
00194 _PROTOTYPE(int dolst, (int line1, int line2));
00195 _PROTOTYPE(char *dodash, (int delim, char *src, char *map));
00196 _PROTOTYPE(int doglob, (void));
00197 _PROTOTYPE(int doprnt, (int from, int to));
00198 _PROTOTYPE(void prntln, (char *str, int vflg, int lin));
00199 _PROTOTYPE(void putcntl, (int c, FILE *stream));
00200 _PROTOTYPE(int doread, (int lin, char *fname));
00201 _PROTOTYPE(int dowrite, (int from, int to, char *fname, int apflg));
00202 _PROTOTYPE(void intr, (int sig));
00203 _PROTOTYPE(int egets, (char *str, int size, FILE *stream));
00204 _PROTOTYPE(int esc, (char **s));
00205 _PROTOTYPE(int find, (TOKEN *pat, int dir));
00206 _PROTOTYPE(char *getfn, (void));
00207 _PROTOTYPE(int getlst, (void));
00208 _PROTOTYPE(int getnum, (int first));
00209 _PROTOTYPE(int getone, (void));
00210 _PROTOTYPE(TOKEN *getpat, (char *arg));
00211 _PROTOTYPE(LINE *getptr, (int num));
00212 _PROTOTYPE(int getrhs, (char *sub));
00213 _PROTOTYPE(char *gettxt, (int num));
00214 _PROTOTYPE(int ins, (char *str));
00215 _PROTOTYPE(int System, (char *c));
00216 _PROTOTYPE(int join, (int first, int last));
00217 _PROTOTYPE(TOKEN *makepat, (char *arg, int delim));
00218 _PROTOTYPE(char *maksub, (char *sub, int subsz));
00219 _PROTOTYPE(char *matchs, (char *line, TOKEN *pat, int ret_endp));
00220 _PROTOTYPE(int move, (int num));
00221 _PROTOTYPE(int transfer, (int num));
00222 _PROTOTYPE(int omatch, (char **linp, TOKEN *pat, char *boln));
00223 _PROTOTYPE(TOKEN *optpat, (void));
00224 _PROTOTYPE(int set, (void));
00225 _PROTOTYPE(int show, (void));
00226 _PROTOTYPE(void relink, (LINE *a, LINE *x, LINE *y, LINE *b));
00227 _PROTOTYPE(void clrbuf, (void));
00228 _PROTOTYPE(void set_buf, (void));
00229 _PROTOTYPE(int subst, (TOKEN *pat, char *sub, int gflg, int pflag));
00230 _PROTOTYPE(void unmakepat, (TOKEN *head));
00231 
00232 /*     Scans throught the pattern template looking for a match
00233  * with lin.  Each element of lin is compared with the template
00234  * until either a mis-match is found or the end of the template
00235  * is reached.  In the former case a 0 is returned; in the latter,
00236  * a pointer into lin (pointing to the character following the
00237  * matched pattern) is returned.
00238  *
00239  *      "lin"   is a pointer to the line being searched.
00240  *      "pat"   is a pointer to a template made by makepat().
00241  *      "boln"  is a pointer into "lin" which points at the
00242  *                      character at the beginning of the line.
00243  */
00244 
00245 char *paropen[9], *parclose[9];
00246 int between, parnum;
00247 
00248 char *amatch(lin, pat, boln)
00249 char *lin;
00250 TOKEN *pat;
00251 char *boln;
00252 {
00253   between = 0;
00254   parnum = 0;
00255 
00256   lin = match(lin, pat, boln);
00257 
00258   if (between) return 0;
00259 
00260   while (parnum < 9) {
00261         paropen[parnum] = parclose[parnum] = "";
00262         parnum++;
00263   }
00264   return lin;
00265 }
00266 
00267 static char *match(lin, pat, boln)
00268 char *lin;
00269 TOKEN *pat;
00270 char *boln;
00271 {
00272   register char *bocl, *rval, *strstart;
00273 
00274   if (pat == 0) return 0;
00275 
00276   strstart = lin;
00277 
00278   while (pat) {
00279         if (pat->tok == CLOSURE && pat->next) {
00280                 /* Process a closure: first skip over the closure
00281                  * token to the object to be repeated.  This object
00282                  * can be a character class. */
00283 
00284                 pat = pat->next;
00285 
00286                 /* Now match as many occurrences of the closure
00287                  * pattern as possible. */
00288                 bocl = lin;
00289 
00290                 while (*lin && omatch(&lin, pat, boln));
00291 
00292                 /* 'Lin' now points to the character that made made
00293                  * us fail.  Now go on to process the rest of the
00294                  * string.  A problem here is a character following
00295                  * the closure which could have been in the closure.
00296                  * For example, in the pattern "[a-z]*t" (which
00297                  * matches any lower-case word ending in a t), the
00298                  * final 't' will be sucked up in the while loop.
00299                  * So, if the match fails, we back up a notch and try
00300                  * to match the rest of the string again, repeating
00301                  * this process recursively until we get back to the
00302                  * beginning of the closure.  The recursion goes, at
00303                  * most two levels deep. */
00304 
00305                 if (pat = pat->next) {
00306                         int savbtwn = between;
00307                         int savprnm = parnum;
00308 
00309                         while (bocl <= lin) {
00310                                 if (rval = match(lin, pat, boln)) {
00311                                         /* Success */
00312                                         return(rval);
00313                                 } else {
00314                                         --lin;
00315                                         between = savbtwn;
00316                                         parnum = savprnm;
00317                                 }
00318                         }
00319                         return(0);      /* match failed */
00320                 }
00321         } else if (pat->tok == OPEN) {
00322                 if (between || parnum >= 9) return 0;
00323                 paropen[parnum] = lin;
00324                 between = 1;
00325                 pat = pat->next;
00326         } else if (pat->tok == CLOSE) {
00327                 if (!between) return 0;
00328                 parclose[parnum++] = lin;
00329                 between = 0;
00330                 pat = pat->next;
00331         } else if (omatch(&lin, pat, boln)) {
00332                 pat = pat->next;
00333         } else {
00334                 return(0);
00335         }
00336   }
00337 
00338   /* Note that omatch() advances lin to point at the next character to
00339    * be matched.  Consequently, when we reach the end of the template,
00340    * lin will be pointing at the character following the last character
00341    * matched.  The exceptions are templates containing only a BOLN or
00342    * EOLN token.  In these cases omatch doesn't advance.
00343    * 
00344    * A philosophical point should be mentioned here.  Is $ a position or a
00345    * character? (i.e. does $ mean the EOL character itself or does it
00346    * mean the character at the end of the line.)  I decided here to
00347    * make it mean the former, in order to make the behavior of match()
00348    * consistent.  If you give match the pattern ^$ (match all lines
00349    * consisting only of an end of line) then, since something has to be
00350    * returned, a pointer to the end of line character itself is
00351    * returned. */
00352 
00353   return((char *) max(strstart, lin));
00354 }
00355 
00356 /*      append.c        */
00357 /* #include <stdio.h> */
00358 /* #include "tools.h" */
00359 /* #include "ed.h" */
00360 
00361 int append(line, glob)
00362 int line, glob;
00363 {
00364   int stat;
00365   char lin[MAXLINE];
00366 
00367   if (glob) return(ERR);
00368   curln = line;
00369   while (1) {
00370         if (nflg) printf("%6d. ", curln + 1);
00371 
00372         if (fgets(lin, MAXLINE, stdin) == NULL) return(EOF);
00373         if (lin[0] == '.' && lin[1] == '\n') return (0);
00374         stat = ins(lin);
00375         if (stat < 0) return(ERR);
00376 
00377   }
00378 }
00379 
00380 /*      bitmap.c        */
00381 /*
00382  *      BITMAP.C -      makebitmap, setbit, testbit
00383  *                      bit-map manipulation routines.
00384  *
00385  *      Copyright (c) Allen I. Holub, all rights reserved.  This program may
00386  *              for copied for personal, non-profit use only.
00387  *
00388  */
00389 
00390 #ifdef DEBUG
00391 /* #include <stdio.h> */
00392 #endif
00393 
00394 /* #include "tools.h" */
00395 
00396 
00397 BITMAP *makebitmap(size)
00398 unsigned size;
00399 {
00400   /* Make a bit map with "size" bits.  The first entry in the map is an
00401    * "unsigned int" representing the maximum bit.  The map itself is
00402    * concatenated to this integer. Return a pointer to a map on
00403    * success, 0 if there's not enough memory. */
00404 
00405   unsigned *map, numbytes;
00406 
00407   numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0);
00408 
00409 #ifdef DEBUG
00410   printf("Making a %d bit map (%d bytes required)\n", size, numbytes);
00411 #endif
00412 
00413   if (map = (unsigned *) malloc(numbytes + sizeof(unsigned))) {
00414         *map = size;
00415         memset(map + 1, 0, numbytes);
00416   }
00417 
00418   return((BITMAP *) map);
00419 }
00420 
00421 int setbit(c, map, val)
00422 unsigned c, val;
00423 char *map;
00424 {
00425   /* Set bit c in the map to val. If c > map-size, 0 is returned, else
00426    * 1 is returned. */
00427 
00428   if (c >= *(unsigned *) map)   /* if c >= map size */
00429         return 0;
00430 
00431   map += sizeof(unsigned);      /* skip past size */
00432 
00433   if (val)
00434         map[c >> 3] |= 1 << (c & 0x07);
00435   else
00436         map[c >> 3] &= ~(1 << (c & 0x07));
00437 
00438   return 1;
00439 }
00440 
00441 int testbit(c, map)
00442 unsigned c;
00443 char *map;
00444 {
00445   /* Return 1 if the bit corresponding to c in map is set. 0 if it is not. */
00446 
00447   if (c >= *(unsigned *) map) return 0;
00448 
00449   map += sizeof(unsigned);
00450 
00451   return(map[c >> 3] & (1 << (c & 0x07)));
00452 }
00453 
00454 /*      catsub.c        */
00455 /* #include <stdio.h> */
00456 /* #include "tools.h" */
00457 /* #include "ed.h" */
00458 
00459 extern char *paropen[9], *parclose[9];
00460 
00461 char *catsub(from, to, sub, new, newend)
00462 char *from, *to, *sub, *new, *newend;
00463 {
00464   char *cp, *cp2;
00465 
00466   for (cp = new; *sub != EOS && cp < newend;) {
00467         if (*sub == DITTO) for (cp2 = from; cp2 < to;) {
00468                         *cp++ = *cp2++;
00469                         if (cp >= newend) break;
00470                 }
00471         else if (*sub == ESCAPE) {
00472                 sub++;
00473                 if ('1' <= *sub && *sub <= '9') {
00474                         char *parcl = parclose[*sub - '1'];
00475 
00476                         for (cp2 = paropen[*sub - '1']; cp2 < parcl;) {
00477                                 *cp++ = *cp2++;
00478                                 if (cp >= newend) break;
00479                         }
00480                 } else
00481                         *cp++ = *sub;
00482         } else
00483                 *cp++ = *sub;
00484 
00485         sub++;
00486   }
00487 
00488   return(cp);
00489 }
00490 
00491 /*      ckglob.c        */
00492 /* #include <stdio.h> */
00493 /* #include "tools.h" */
00494 /* #include "ed.h" */
00495 
00496 int ckglob()
00497 {
00498   TOKEN *glbpat;
00499   char c, delim;
00500   char lin[MAXLINE];
00501   int num;
00502   LINE *ptr;
00503 
00504   c = *inptr;
00505 
00506   if (c != 'g' && c != 'v') return(0);
00507 
00508   if (deflt(1, lastln) < 0) return(ERR);
00509 
00510   delim = *++inptr;
00511   if (delim <= ' ') return(ERR);
00512 
00513   glbpat = optpat();
00514 
00515   if (*inptr == delim) inptr++;
00516 
00517   ptr = getptr(1);
00518   for (num = 1; num <= lastln; num++) {
00519         ptr->l_stat &= ~LGLOB;
00520         if (line1 <= num && num <= line2) {
00521                 strcpy(lin, ptr->l_buff);
00522                 strcat(lin, "\n");
00523                 if (matchs(lin, glbpat, 0)) {
00524                         if (c == 'g') ptr->l_stat |= LGLOB;
00525                 } else {
00526                         if (c == 'v') ptr->l_stat |= LGLOB;
00527                 }
00528         }
00529         ptr = ptr->l_next;
00530   }
00531   return(1);
00532 }
00533 
00534 /*      deflt.c */
00535 /* #include <stdio.h> */
00536 /* #include "tools.h" */
00537 /* #include "ed.h" */
00538 
00539 int deflt(def1, def2)
00540 int def1, def2;
00541 {
00542   if (nlines == 0) {
00543         line1 = def1;
00544         line2 = def2;
00545   }
00546   if (line1 > line2 || line1 <= 0) return(ERR);
00547   return(0);
00548 }
00549 
00550 /*      del.c   */
00551 /* #include <stdio.h> */
00552 /* #include "tools.h" */
00553 /* #include "ed.h" */
00554 
00555 int del(from, to)
00556 int from, to;
00557 {
00558   LINE *first, *last, *next, *tmp;
00559 
00560   if (from < 1) from = 1;
00561   first = getptr(prevln(from));
00562   last = getptr(nextln(to));
00563   next = first->l_next;
00564   while (next != last && next != &line0) {
00565         tmp = next->l_next;
00566         free((char *) next);
00567         next = tmp;
00568   }
00569   relink(first, last, first, last);
00570   lastln -= (to - from) + 1;
00571   curln = prevln(from);
00572   return(0);
00573 }
00574 
00575 /*      docmd.c */
00576 /* #include <stdio.h> */
00577 /* #include "tools.h" */
00578 /* #include "ed.h" */
00579 
00580 char fname[MAXFNAME];
00581 int fchanged;
00582 extern int nofname;
00583 
00584 extern int mark[];
00585 
00586 int docmd(glob)
00587 int glob;
00588 {
00589   static char rhs[MAXPAT];
00590   TOKEN *subpat;
00591   int c, err, line3;
00592   int apflg, pflag, gflag;
00593   int nchng;
00594   char *fptr;
00595 
00596   pflag = FALSE;
00597   while (*inptr == SP && *inptr == HT) inptr++;
00598 
00599   c = *inptr++;
00600 
00601   switch (c) {
00602       case NL:
00603         if (nlines == 0) {
00604                 if ((line2 = nextln(curln)) == 0) return(ERR);
00605         }
00606         curln = line2;
00607         return(1);
00608         break;
00609 
00610       case '=': printf("%d\n", line2);  break;
00611 
00612       case 'a':
00613         if (*inptr != NL || nlines > 1) return(ERR);
00614 
00615         if (append(line1, glob) < 0) return(ERR);;
00616         fchanged = TRUE;
00617         break;
00618 
00619       case 'c':
00620         if (*inptr != NL) return(ERR);
00621 
00622         if (deflt(curln, curln) < 0) return(ERR);
00623 
00624         if (del(line1, line2) < 0) return(ERR);
00625         if (append(curln, glob) < 0) return (ERR);
00626         fchanged = TRUE;
00627         break;
00628 
00629       case 'd':
00630         if (*inptr != NL) return(ERR);
00631 
00632         if (deflt(curln, curln) < 0) return(ERR);
00633 
00634         if (del(line1, line2) < 0) return(ERR);
00635         if (nextln(curln) != 0) curln = nextln(curln);
00636         fchanged = TRUE;
00637         break;
00638 
00639       case 'e':
00640         if (nlines > 0) return(ERR);
00641         if (fchanged) {
00642                 fchanged = FALSE;
00643                 return(ERR);
00644         }
00645 
00646         /* FALL THROUGH */
00647       case 'E':
00648         if (nlines > 0) return(ERR);
00649 
00650         if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
00651 
00652         if ((fptr = getfn()) == NULL) return(ERR);
00653 
00654         clrbuf();
00655         if ((err = doread(0, fptr)) < 0) return(err);
00656 
00657         strcpy(fname, fptr);
00658         fchanged = FALSE;
00659         break;
00660 
00661       case 'f':
00662         if (nlines > 0) return(ERR);
00663 
00664         if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
00665 
00666         if ((fptr = getfn()) == NULL) return(ERR);
00667 
00668         if (nofname)
00669                 printf("%s\n", fname);
00670         else
00671                 strcpy(fname, fptr);
00672         break;
00673 
00674       case 'i':
00675         if (*inptr != NL || nlines > 1) return(ERR);
00676 
00677         if (append(prevln(line1), glob) < 0) return(ERR);
00678         fchanged = TRUE;
00679         break;
00680 
00681       case 'j':
00682         if (*inptr != NL || deflt(curln, curln + 1) < 0) return(ERR);
00683 
00684         if (join(line1, line2) < 0) return(ERR);
00685         break;
00686 
00687       case 'k':
00688         while (*inptr == ' ' || *inptr == HT) inptr++;
00689 
00690         if (*inptr < 'a' || *inptr > 'z') return ERR;
00691         c = *inptr++;
00692 
00693         if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
00694 
00695         mark[c - 'a'] = line1;
00696         break;
00697 
00698       case 'l':
00699         if (*inptr != NL) return(ERR);
00700         if (deflt(curln, curln) < 0) return (ERR);
00701         if (dolst(line1, line2) < 0) return (ERR);
00702         break;
00703 
00704       case 'm':
00705         if ((line3 = getone()) < 0) return(ERR);
00706         if (deflt(curln, curln) < 0) return (ERR);
00707         if (move(line3) < 0) return (ERR);
00708         fchanged = TRUE;
00709         break;
00710 
00711       case 'P':
00712       case 'p':
00713         if (*inptr != NL) return(ERR);
00714         if (deflt(curln, curln) < 0) return (ERR);
00715         if (doprnt(line1, line2) < 0) return (ERR);
00716         break;
00717 
00718       case 'q':
00719         if (fchanged) {
00720                 fchanged = FALSE;
00721                 return(ERR);
00722         }
00723 
00724         /* FALL THROUGH */
00725       case 'Q':
00726         if (*inptr == NL && nlines == 0 && !glob)
00727                 return(EOF);
00728         else
00729                 return(ERR);
00730 
00731       case 'r':
00732         if (nlines > 1) return(ERR);
00733 
00734         if (nlines == 0) line2 = lastln;
00735 
00736         if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
00737 
00738         if ((fptr = getfn()) == NULL) return(ERR);
00739 
00740         if ((err = doread(line2, fptr)) < 0) return(err);
00741         fchanged = TRUE;
00742         break;
00743 
00744       case 's':
00745         if (*inptr == 'e') return(set());
00746         while (*inptr == SP || *inptr == HT) inptr++;
00747         if ((subpat = optpat()) == NULL) return (ERR);
00748         if ((gflag = getrhs(rhs)) < 0) return (ERR);
00749         if (*inptr == 'p') pflag++;
00750         if (deflt(curln, curln) < 0) return (ERR);
00751         if ((nchng = subst(subpat, rhs, gflag, pflag)) < 0) return (ERR);
00752         if (nchng) fchanged = TRUE;
00753         break;
00754 
00755       case 't':
00756         if ((line3 = getone()) < 0) return(ERR);
00757         if (deflt(curln, curln) < 0) return (ERR);
00758         if (transfer(line3) < 0) return (ERR);
00759         fchanged = TRUE;
00760         break;
00761 
00762       case 'W':
00763       case 'w':
00764         apflg = (c == 'W');
00765 
00766         if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
00767 
00768         if ((fptr = getfn()) == NULL) return(ERR);
00769 
00770         if (deflt(1, lastln) < 0) return(ERR);
00771         if (dowrite(line1, line2, fptr, apflg) < 0) return (ERR);
00772         fchanged = FALSE;
00773         break;
00774 
00775       case 'x':
00776         if (*inptr == NL && nlines == 0 && !glob) {
00777                 if ((fptr = getfn()) == NULL) return(ERR);
00778                 if (dowrite(1, lastln, fptr, 0) >= 0) return (EOF);
00779         }
00780         return(ERR);
00781 
00782       case 'z':
00783         if (deflt(curln, curln) < 0) return(ERR);
00784 
00785         switch (*inptr) {
00786             case '-':
00787                 if (doprnt(line1 - 21, line1) < 0) return(ERR);
00788                 break;
00789 
00790             case '.':
00791                 if (doprnt(line1 - 11, line1 + 10) < 0) return(ERR);
00792                 break;
00793 
00794             case '+':
00795             case '\n':
00796                 if (doprnt(line1, line1 + 21) < 0) return(ERR);
00797                 break;
00798         }
00799         break;
00800 
00801       default:  return(ERR);
00802 }
00803   return(0);
00804 }
00805 
00806 int dolst(line1, line2)
00807 int line1, line2;
00808 {
00809   int oldlflg = lflg, p;
00810 
00811   lflg = 1;
00812   p = doprnt(line1, line2);
00813   lflg = oldlflg;
00814 
00815   return p;
00816 }
00817 
00818 /*      dodash.c        */
00819 /* #include <stdio.h> */
00820 /* #include "tools.h" */
00821 
00822 /*      Expand the set pointed to by *src into dest.
00823  *      Stop at delim.  Return 0 on error or size of
00824  *      character class on success.  Update *src to
00825  *      point at delim.  A set can have one element
00826  *      {x} or several elements ( {abcdefghijklmnopqrstuvwxyz}
00827  *      and {a-z} are equivalent ).  Note that the dash
00828  *      notation is expanded as sequential numbers.
00829  *      This means (since we are using the ASCII character
00830  *      set) that a-Z will contain the entire alphabet
00831  *      plus the symbols: [\]^_`.  The maximum number of
00832  *      characters in a character class is defined by maxccl.
00833  */
00834 char *dodash(delim, src, map)
00835 int delim;
00836 char *src, *map;
00837 {
00838 
00839   register int first, last;
00840   char *start;
00841 
00842   start = src;
00843 
00844   while (*src && *src != delim) {
00845         if (*src != '-') setbit(esc(&src), map, 1);
00846 
00847         else if (src == start || *(src + 1) == delim)
00848                 setbit('-', map, 1);
00849         else {
00850                 src++;
00851 
00852                 if (*src < *(src - 2)) {
00853                         first = *src;
00854                         last = *(src - 2);
00855                 } else {
00856                         first = *(src - 2);
00857                         last = *src;
00858                 }
00859 
00860                 while (++first <= last) setbit(first, map, 1);
00861 
00862         }
00863         src++;
00864   }
00865   return(src);
00866 }
00867 
00868 /*      doglob.c        */
00869 /* #include <stdio.h> */
00870 /* #include "tools.h" */
00871 /* #include "ed.h" */
00872 
00873 int doglob()
00874 {
00875   int lin, stat;
00876   char *cmd;
00877   LINE *ptr;
00878 
00879   cmd = inptr;
00880 
00881   while (1) {
00882         ptr = getptr(1);
00883         for (lin = 1; lin <= lastln; lin++) {
00884                 if (ptr->l_stat & LGLOB) break;
00885                 ptr = ptr->l_next;
00886         }
00887         if (lin > lastln) break;
00888 
00889         ptr->l_stat &= ~LGLOB;
00890         curln = lin;
00891         inptr = cmd;
00892         if ((stat = getlst()) < 0) return(stat);
00893         if ((stat = docmd(1)) < 0) return (stat);
00894   }
00895   return(curln);
00896 }
00897 
00898 /*      doprnt.c        */
00899 /* #include <stdio.h> */
00900 /* #include "tools.h" */
00901 /* #include "ed.h" */
00902 
00903 int doprnt(from, to)
00904 int from, to;
00905 {
00906   int i;
00907   LINE *lptr;
00908 
00909   from = from < 1 ? 1 : from;
00910   to = to > lastln ? lastln : to;
00911 
00912   if (to != 0) {
00913         lptr = getptr(from);
00914         for (i = from; i <= to; i++) {
00915                 prntln(lptr->l_buff, lflg, (nflg ? i : 0));
00916                 lptr = lptr->l_next;
00917         }
00918         curln = to;
00919   }
00920   return(0);
00921 }
00922 
00923 void prntln(str, vflg, lin)
00924 char *str;
00925 int vflg, lin;
00926 {
00927   if (lin) printf("%7d ", lin);
00928   while (*str && *str != NL) {
00929         if (*str < ' ' || *str >= 0x7f) {
00930                 switch (*str) {
00931                     case '\t':
00932                         if (vflg)
00933                                 putcntl(*str, stdout);
00934                         else
00935                                 putc(*str, stdout);
00936                         break;
00937 
00938                     case DEL:
00939                         putc('^', stdout);
00940                         putc('?', stdout);
00941                         break;
00942 
00943                     default:
00944                         putcntl(*str, stdout);
00945                         break;
00946                 }
00947         } else
00948                 putc(*str, stdout);
00949         str++;
00950   }
00951   if (vflg) putc('$', stdout);
00952   putc('\n', stdout);
00953 }
00954 
00955 void putcntl(c, stream)
00956 char c;
00957 FILE *stream;
00958 {
00959   putc('^', stream);
00960   putc((c & 31) | '@', stream);
00961 }
00962 
00963 /*      doread.c        */
00964 /* #include <stdio.h> */
00965 /* #include "tools.h" */
00966 /* #include "ed.h" */
00967 
00968 extern int diag;
00969 
00970 int doread(lin, fname)
00971 int lin;
00972 char *fname;
00973 {
00974   FILE *fp;
00975   int err;
00976   long bytes;
00977   int lines;
00978   static char str[MAXLINE];
00979 
00980   err = 0;
00981   nonascii = nullchar = truncated = 0;
00982 
00983   if (diag) printf("\"%s\" ", fname);
00984   if ((fp = fopen(fname, "r")) == NULL) {
00985         printf("file open err\n");
00986         return(ERR);
00987   }
00988   curln = lin;
00989   for (lines = 0, bytes = 0; (err = egets(str, MAXLINE, fp)) > 0;) {
00990         bytes += strlen(str);
00991         if (ins(str) < 0) {
00992                 printf("file insert error\n");
00993                 err++;
00994                 break;
00995         }
00996         lines++;
00997   }
00998   fclose(fp);
00999   if (err < 0) return(err);
01000   if (diag) {
01001         printf("%d lines %ld bytes", lines, bytes);
01002         if (nonascii) printf(" [%d non-ascii]", nonascii);
01003         if (nullchar) printf(" [%d nul]", nullchar);
01004         if (truncated) printf(" [%d lines truncated]", truncated);
01005         printf("\n");
01006   }
01007   return(err);
01008 }
01009 
01010 /*      dowrite.c       */
01011 /* #include <stdio.h> */
01012 /* #include "tools.h" */
01013 /* #include "ed.h" */
01014 
01015 int dowrite(from, to, fname, apflg)
01016 int from, to;
01017 char *fname;
01018 int apflg;
01019 {
01020   FILE *fp;
01021   int lin, err;
01022   int lines;
01023   long bytes;
01024   char *str;
01025   LINE *lptr;
01026 
01027   err = 0;
01028 
01029   lines = bytes = 0;
01030   if (diag) printf("\"%s\" ", fname);
01031   if ((fp = fopen(fname, (apflg ? "a" : "w"))) == NULL) {
01032         printf("file open error\n");
01033         return(ERR);
01034   }
01035   lptr = getptr(from);
01036   for (lin = from; lin <= to; lin++) {
01037         str = lptr->l_buff;
01038         lines++;
01039         bytes += strlen(str) + 1;
01040         if (fputs(str, fp) == EOF) {
01041                 printf("file write error\n");
01042                 err++;
01043                 break;
01044         }
01045         fputc('\n', fp);
01046         lptr = lptr->l_next;
01047   }
01048   if (diag) printf("%d lines %ld bytes\n", lines, bytes);
01049   fclose(fp);
01050   return(err);
01051 }
01052 
01053 /*      ed.c    */
01054 /* Copyright 1987 Brian Beattie Rights Reserved.
01055  *
01056  * Permission to copy and/or distribute granted under the
01057  * following conditions:
01058  *
01059  * 1). No charge may be made other than resonable charges
01060  *      for reproduction.
01061  *
01062  * 2). This notice must remain intact.
01063  *
01064  * 3). No further restrictions may be added.
01065  *
01066  */
01067 /* #include <stdio.h> */
01068 /* #include <signal.h> */
01069 /* #include "tools.h" */
01070 /* #include "ed.h" */
01071 #include <setjmp.h>
01072 jmp_buf env;
01073 
01074 LINE line0;
01075 int curln = 0;
01076 int lastln = 0;
01077 char *inptr;
01078 static char inlin[MAXLINE];
01079 int nflg, lflg;
01080 int line1, line2, nlines;
01081 extern char fname[];
01082 int version = 1;
01083 int diag = 1;
01084 
01085 void intr(sig)
01086 int sig;
01087 {
01088   printf("?\n");
01089   longjmp(env, 1);
01090 }
01091 
01092 int main(argc, argv)
01093 int argc;
01094 char **argv;
01095 {
01096   int stat, i, doflush;
01097 
01098   set_buf();
01099   doflush = isatty(1);
01100 
01101   if (argc > 1 && (strcmp(argv[1], "-") == 0 || strcmp(argv[1], "-s") == 0)) {
01102         diag = 0;
01103         argc--;
01104         argv++;
01105   }
01106   if (argc > 1) {
01107         for (i = 1; i < argc; i++) {
01108                 if (doread(0, argv[i]) == 0) {
01109                         curln = 1;
01110                         strcpy(fname, argv[i]);
01111                         break;
01112                 }
01113         }
01114   }
01115   while (1) {
01116         setjmp(env);
01117         if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, intr);
01118 
01119         if (doflush) fflush(stdout);
01120 
01121         if (fgets(inlin, sizeof(inlin), stdin) == NULL) {
01122                 break;
01123         }
01124         for (;;) {
01125                 inptr = strchr(inlin, EOS);
01126                 if (inptr >= inlin+2 && inptr[-2] == '\\' && inptr[-1] == NL) {
01127                         inptr[-1] = 'n';
01128                         if (fgets(inptr, sizeof(inlin) - (inptr - inlin),
01129                                                 stdin) == NULL) break;
01130                 } else {
01131                         break;
01132                 }
01133         }
01134         if (*inlin == '!') {
01135                 if ((inptr = strchr(inlin, NL)) != NULL) *inptr = EOS;
01136                 System(inlin + 1);
01137                 continue;
01138         }
01139         inptr = inlin;
01140         if (getlst() >= 0)
01141                 if ((stat = ckglob()) != 0) {
01142                         if (stat >= 0 && (stat = doglob()) >= 0) {
01143                                 curln = stat;
01144                                 continue;
01145                         }
01146                 } else {
01147                         if ((stat = docmd(0)) >= 0) {
01148                                 if (stat == 1) doprnt(curln, curln);
01149                                 continue;
01150                         }
01151                 }
01152         if (stat == EOF) {
01153                 exit(0);
01154         }
01155         if (stat == FATAL) {
01156                 fputs("FATAL ERROR\n", stderr);
01157                 exit(1);
01158         }
01159         printf("?\n");
01160   }
01161   return(0);
01162 }
01163 
01164 /*      egets.c */
01165 /* #include <stdio.h> */
01166 /* #include "tools.h" */
01167 /* #include "ed.h" */
01168 
01169 int eightbit = 1;               /* save eight bit */
01170 int nonascii, nullchar, truncated;
01171 int egets(str, size, stream)
01172 char *str;
01173 int size;
01174 FILE *stream;
01175 {
01176   int c, count;
01177   char *cp;
01178 
01179   for (count = 0, cp = str; size > count;) {
01180         c = getc(stream);
01181         if (c == EOF) {
01182                 *cp++ = '\n';
01183                 *cp = EOS;
01184                 if (count) {
01185                         printf("[Incomplete last line]\n");
01186                 }
01187                 return(count);
01188         }
01189         if (c == NL) {
01190                 *cp++ = c;
01191                 *cp = EOS;
01192                 return(++count);
01193         }
01194         if (c > 127) {
01195                 if (!eightbit)  /* if not saving eighth bit */
01196                         c = c & 127;    /* strip eigth bit */
01197                 nonascii++;     /* count it */
01198         }
01199         if (c) {
01200                 *cp++ = c;      /* not null, keep it */
01201                 count++;
01202         } else
01203                 nullchar++;     /* count nulls */
01204   }
01205   str[count - 1] = EOS;
01206   if (c != NL) {
01207         printf("truncating line\n");
01208         truncated++;
01209         while ((c = getc(stream)) != EOF)
01210                 if (c == NL) break;
01211   }
01212   return(count);
01213 }
01214 
01215 /*      esc.c   */
01216 /* #include <stdio.h> */
01217 /* #include "tools.h" */
01218 
01219 /* Map escape sequences into their equivalent symbols.  Returns the
01220  * correct ASCII character.  If no escape prefix is present then s
01221  * is untouched and *s is returned, otherwise **s is advanced to point
01222  * at the escaped character and the translated character is returned.
01223  */
01224 int esc(s)
01225 char **s;
01226 {
01227   register int rval;
01228 
01229 
01230   if (**s != ESCAPE) {
01231         rval = **s;
01232   } else {
01233         (*s)++;
01234 
01235         switch (toupper(**s)) {
01236             case '\000':        rval = ESCAPE;  break;
01237             case 'S':   rval = ' ';     break;
01238             case 'N':   rval = '\n';    break;
01239             case 'T':   rval = '\t';    break;
01240             case 'B':   rval = '\b';    break;
01241             case 'R':   rval = '\r';    break;
01242             default:    rval = **s;     break;
01243         }
01244   }
01245 
01246   return(rval);
01247 }
01248 
01249 /*      find.c  */
01250 /* #include <stdio.h> */
01251 /* #include "tools.h" */
01252 /* #include "ed.h" */
01253 
01254 int find(pat, dir)
01255 TOKEN *pat;
01256 int dir;
01257 {
01258   int i, num;
01259   char lin[MAXLINE];
01260   LINE *ptr;
01261 
01262   num = curln;
01263   ptr = getptr(curln);
01264   num = (dir ? nextln(num) : prevln(num));
01265   ptr = (dir ? ptr->l_next : ptr->l_prev);
01266   for (i = 0; i < lastln; i++) {
01267         if (num == 0) {
01268                 num = (dir ? nextln(num) : prevln(num));
01269                 ptr = (dir ? ptr->l_next : ptr->l_prev);
01270         }
01271         strcpy(lin, ptr->l_buff);
01272         strcat(lin, "\n");
01273         if (matchs(lin, pat, 0)) {
01274                 return(num);
01275         }
01276         num = (dir ? nextln(num) : prevln(num));
01277         ptr = (dir ? ptr->l_next : ptr->l_prev);
01278   }
01279   return(ERR);
01280 }
01281 
01282 /*      getfn.c */
01283 /* #include <stdio.h> */
01284 /* #include "tools.h" */
01285 /* #include "ed.h" */
01286 
01287 extern char fname[MAXFNAME];
01288 int nofname;
01289 
01290 char *getfn()
01291 {
01292   static char file[256];
01293   char *cp;
01294 
01295   if (*inptr == NL) {
01296         nofname = TRUE;
01297         strcpy(file, fname);
01298   } else {
01299         nofname = FALSE;
01300         while (*inptr == SP || *inptr == HT) inptr++;
01301 
01302         cp = file;
01303         while (*inptr && *inptr != NL && *inptr != SP && *inptr != HT) {
01304                 *cp++ = *inptr++;
01305         }
01306         *cp = '\0';
01307 
01308         if (strlen(file) == 0) {
01309                 printf("bad file name\n");
01310                 return(NULL);
01311         }
01312   }
01313 
01314   if (strlen(file) == 0) {
01315         printf("no file name\n");
01316         return(NULL);
01317   }
01318   return(file);
01319 }
01320 
01321 /*      getlst.c        */
01322 /* #include <stdio.h> */
01323 /* #include "tools.h" */
01324 /* #include "ed.h" */
01325 
01326 int getlst()
01327 {
01328   int num;
01329 
01330   line2 = 0;
01331   for (nlines = 0; (num = getone()) >= 0;) {
01332         line1 = line2;
01333         line2 = num;
01334         nlines++;
01335         if (*inptr != ',' && *inptr != ';') break;
01336         if (*inptr == ';') curln = num;
01337         inptr++;
01338   }
01339   nlines = min(nlines, 2);
01340   if (nlines == 0) line2 = curln;
01341   if (nlines <= 1) line1 = line2;
01342 
01343   if (num == ERR)
01344         return(num);
01345   else
01346         return(nlines);
01347 }
01348 
01349 /*      getnum.c        */
01350 /* #include <stdio.h> */
01351 /* #include "tools.h" */
01352 /* #include "ed.h" */
01353 
01354 int mark['z' - 'a' + 1];
01355 
01356 int getnum(first)
01357 int first;
01358 {
01359   TOKEN *srchpat;
01360   int num;
01361   char c;
01362 
01363   while (*inptr == SP || *inptr == HT) inptr++;
01364 
01365   if (*inptr >= '0' && *inptr <= '9') { /* line number */
01366         for (num = 0; *inptr >= '0' && *inptr <= '9';) {
01367                 num = (num * 10) + *inptr - '0';
01368                 inptr++;
01369         }
01370         return num;
01371   }
01372   switch (c = *inptr) {
01373       case '.':
01374         inptr++;
01375         return(curln);
01376 
01377       case '$':
01378         inptr++;
01379         return(lastln);
01380 
01381       case '/':
01382       case '?':
01383         srchpat = optpat();
01384         if (*inptr == c) inptr++;
01385         return(find(srchpat, c == '/' ? 1 : 0));
01386 
01387       case '-':
01388       case '+':
01389         return(first ? curln : 1);
01390 
01391       case '\'':
01392         inptr++;
01393         if (*inptr < 'a' || *inptr > 'z') return(EOF);
01394 
01395         return mark[*inptr++ - 'a'];
01396 
01397       default:
01398         return(first ? EOF : 1);/* unknown address */
01399   }
01400 }
01401 
01402 /*      getone.c        */
01403 /* #include <stdio.h> */
01404 /* #include "tools.h" */
01405 /* #include "ed.h" */
01406 
01407 #define FIRST 1
01408 #define NOTFIRST 0
01409 
01410 int getone()
01411 {
01412   int c, i, num;
01413 
01414   if ((num = getnum(FIRST)) >= 0) {
01415         while (1) {
01416                 while (*inptr == SP || *inptr == HT) inptr++;
01417 
01418                 if (*inptr != '+' && *inptr != '-') break;
01419                 c = *inptr++;
01420 
01421                 if ((i = getnum(NOTFIRST)) < 0) return(i);
01422 
01423                 if (c == '+') {
01424                         num += i;
01425                 } else {
01426                         num -= i;
01427                 }
01428         }
01429   }
01430   return(num > lastln ? ERR : num);
01431 }
01432 
01433 /*      getpat.c        */
01434 /* #include <stdio.h> */
01435 /* #include "tools.h" */
01436 
01437 /* Translate arg into a TOKEN string */
01438 TOKEN *
01439  getpat(arg)
01440 char *arg;
01441 {
01442 
01443   return(makepat(arg, '\000'));
01444 }
01445 
01446 /*      getptr.c        */
01447 /* #include <stdio.h> */
01448 /* #include "tools.h" */
01449 /* #include "ed.h" */
01450 
01451 LINE *
01452  getptr(num)
01453 int num;
01454 {
01455   LINE *ptr;
01456   int j;
01457 
01458   if (2 * num > lastln && num <= lastln) {      /* high line numbers */
01459         ptr = line0.l_prev;
01460         for (j = lastln; j > num; j--) ptr = ptr->l_prev;
01461   } else {                      /* low line numbers */
01462         ptr = &line0;
01463         for (j = 0; j < num; j++) ptr = ptr->l_next;
01464   }
01465   return(ptr);
01466 }
01467 
01468 /*      getrhs.c        */
01469 /* #include <stdio.h> */
01470 /* #include "tools.h" */
01471 /* #include "ed.h" */
01472 
01473 int getrhs(sub)
01474 char *sub;
01475 {
01476   if (inptr[0] == NL || inptr[1] == NL) /* check for eol */
01477         return(ERR);
01478 
01479   if (maksub(sub, MAXPAT) == NULL) return(ERR);
01480 
01481   inptr++;                      /* skip over delimter */
01482   while (*inptr == SP || *inptr == HT) inptr++;
01483   if (*inptr == 'g') {
01484         inptr++;
01485         return(1);
01486   }
01487   return(0);
01488 }
01489 
01490 /*      gettxt.c        */
01491 /* #include <stdio.h> */
01492 /* #include "tools.h" */
01493 /* #include "ed.h" */
01494 
01495 char *
01496  gettxt(num)
01497 int num;
01498 {
01499   LINE *lin;
01500   static char txtbuf[MAXLINE];
01501 
01502   lin = getptr(num);
01503   strcpy(txtbuf, lin->l_buff);
01504   strcat(txtbuf, "\n");
01505   return(txtbuf);
01506 }
01507 
01508 /*      ins.c   */
01509 /* #include <stdio.h> */
01510 /* #include "tools.h" */
01511 /* #include "ed.h" */
01512 
01513 int ins(str)
01514 char *str;
01515 {
01516   char buf[MAXLINE], *cp;
01517   LINE *new, *cur, *nxt;
01518 
01519   cp = buf;
01520   while (1) {
01521         if ((*cp = *str++) == NL) *cp = EOS;
01522         if (*cp) {
01523                 cp++;
01524                 continue;
01525         }
01526         if ((new = (LINE *) malloc(sizeof(LINE) + strlen(buf))) == NULL)
01527                 return(ERR);    /* no memory */
01528 
01529         new->l_stat = 0;
01530         strcpy(new->l_buff, buf);       /* build new line */
01531         cur = getptr(curln);    /* get current line */
01532         nxt = cur->l_next;      /* get next line */
01533         relink(cur, new, new, nxt);     /* add to linked list */
01534         relink(new, nxt, cur, new);
01535         lastln++;
01536         curln++;
01537 
01538         if (*str == EOS)        /* end of line ? */
01539                 return(1);
01540 
01541         cp = buf;
01542   }
01543 }
01544 
01545 /*      join.c  */
01546 /* #include <stdio.h> */
01547 /* #include "tools.h" */
01548 /* #include "ed.h" */
01549 
01550 extern int fchanged;
01551 
01552 int join(first, last)
01553 int first, last;
01554 {
01555   char buf[MAXLINE];
01556   char *cp = buf, *str;
01557   int num;
01558 
01559   if (first <= 0 || first > last || last > lastln) return(ERR);
01560   if (first == last) {
01561         curln = first;
01562         return 0;
01563   }
01564   for (num = first; num <= last; num++) {
01565         str = gettxt(num);
01566 
01567         while (*str != NL && cp < buf + MAXLINE - 1) *cp++ = *str++;
01568 
01569         if (cp == buf + MAXLINE - 1) {
01570                 printf("line too long\n");
01571                 return(ERR);
01572         }
01573   }
01574   *cp++ = NL;
01575   *cp = EOS;
01576   del(first, last);
01577   curln = first - 1;
01578   ins(buf);
01579   fchanged = TRUE;
01580   return 0;
01581 }
01582 
01583 /*      makepat.c       */
01584 /* #include <stdio.h> */
01585 /* #include "tools.h" */
01586 
01587 /* Make a pattern template from the strinng pointed to by arg.  Stop
01588  * when delim or '\000' or '\n' is found in arg.  Return a pointer to
01589  * the pattern template.
01590  *
01591  * The pattern template used here are somewhat different than those
01592  * used in the "Software Tools" book; each token is a structure of
01593  * the form TOKEN (see tools.h).  A token consists of an identifier,
01594  * a pointer to a string, a literal character and a pointer to another
01595  * token.  This last is 0 if there is no subsequent token.
01596  *
01597  * The one strangeness here is caused (again) by CLOSURE which has
01598  * to be put in front of the previous token.  To make this insertion a
01599  * little easier, the 'next' field of the last to point at the chain
01600  * (the one pointed to by 'tail) is made to point at the previous node.
01601  * When we are finished, tail->next is set to 0.
01602  */
01603 TOKEN *
01604  makepat(arg, delim)
01605 char *arg;
01606 int delim;
01607 {
01608   TOKEN *head, *tail, *ntok;
01609   int error;
01610 
01611   /* Check for characters that aren't legal at the beginning of a template. */
01612 
01613   if (*arg == '\0' || *arg == delim || *arg == '\n' || *arg == CLOSURE)
01614         return(0);
01615 
01616   error = 0;
01617   tail = head = NULL;
01618 
01619   while (*arg && *arg != delim && *arg != '\n' && !error) {
01620         ntok = (TOKEN *) malloc(TOKSIZE);
01621         ntok->lchar = '\000';
01622         ntok->next = 0;
01623 
01624         switch (*arg) {
01625             case ANY:   ntok->tok = ANY;        break;
01626 
01627             case BOL:
01628                 if (head == 0)  /* then this is the first symbol */
01629                         ntok->tok = BOL;
01630                 else
01631                         ntok->tok = LITCHAR;
01632                 ntok->lchar = BOL;
01633                 break;
01634 
01635             case EOL:
01636                 if (*(arg + 1) == delim || *(arg + 1) == '\000' ||
01637                     *(arg + 1) == '\n') {
01638                         ntok->tok = EOL;
01639                 } else {
01640                         ntok->tok = LITCHAR;
01641                         ntok->lchar = EOL;
01642                 }
01643                 break;
01644 
01645             case CLOSURE:
01646                 if (head != 0) {
01647                         switch (tail->tok) {
01648                             case BOL:
01649                             case EOL:
01650                             case CLOSURE:
01651                                 return(0);
01652 
01653                             default:
01654                                 ntok->tok = CLOSURE;
01655                         }
01656                 }
01657                 break;
01658 
01659             case CCL:
01660 
01661                 if (*(arg + 1) == NEGATE) {
01662                         ntok->tok = NCCL;
01663                         arg += 2;
01664                 } else {
01665                         ntok->tok = CCL;
01666                         arg++;
01667                 }
01668 
01669                 if (ntok->bitmap = makebitmap(CLS_SIZE))
01670                         arg = dodash(CCLEND, arg, ntok->bitmap);
01671                 else {
01672                         fprintf(stderr, "Not enough memory for pat\n");
01673                         error = 1;
01674                 }
01675                 break;
01676 
01677             default:
01678                 if (*arg == ESCAPE && *(arg + 1) == OPEN) {
01679                         ntok->tok = OPEN;
01680                         arg++;
01681                 } else if (*arg == ESCAPE && *(arg + 1) == CLOSE) {
01682                         ntok->tok = CLOSE;
01683                         arg++;
01684                 } else {
01685                         ntok->tok = LITCHAR;
01686                         ntok->lchar = esc(&arg);
01687                 }
01688         }
01689 
01690         if (error || ntok == 0) {
01691                 unmakepat(head);
01692                 return(0);
01693         } else if (head == 0) {
01694                 /* This is the first node in the chain. */
01695 
01696                 ntok->next = 0;
01697                 head = tail = ntok;
01698         } else if (ntok->tok != CLOSURE) {
01699                 /* Insert at end of list (after tail) */
01700 
01701                 tail->next = ntok;
01702                 ntok->next = tail;
01703                 tail = ntok;
01704         } else if (head != tail) {
01705                 /* More than one node in the chain.  Insert the
01706                  * CLOSURE node immediately in front of tail. */
01707 
01708                 (tail->next)->next = ntok;
01709                 ntok->next = tail;
01710         } else {
01711                 /* Only one node in the chain,  Insert the CLOSURE
01712                  * node at the head of the linked list. */
01713 
01714                 ntok->next = head;
01715                 tail->next = ntok;
01716                 head = ntok;
01717         }
01718         arg++;
01719   }
01720 
01721   tail->next = 0;
01722   return(head);
01723 }
01724 
01725 /*      maksub.c        */
01726 /* #include <stdio.h> */
01727 /* #include "tools.h" */
01728 /* #include "ed.h" */
01729 
01730 char *
01731  maksub(sub, subsz)
01732 char *sub;
01733 int subsz;
01734 {
01735   int size;
01736   char delim, *cp;
01737 
01738   size = 0;
01739   cp = sub;
01740 
01741   delim = *inptr++;
01742   for (size = 0; *inptr != delim && *inptr != NL && size < subsz; size++) {
01743         if (*inptr == '&') {
01744                 *cp++ = DITTO;
01745                 inptr++;
01746         } else if ((*cp++ = *inptr++) == ESCAPE) {
01747                 if (size >= subsz) return(NULL);
01748 
01749                 switch (toupper(*inptr)) {
01750                     case NL:    *cp++ = ESCAPE;         break;
01751                         break;
01752                     case 'S':
01753                         *cp++ = SP;
01754                         inptr++;
01755                         break;
01756                     case 'N':
01757                         *cp++ = NL;
01758                         inptr++;
01759                         break;
01760                     case 'T':
01761                         *cp++ = HT;
01762                         inptr++;
01763                         break;
01764                     case 'B':
01765                         *cp++ = BS;
01766                         inptr++;
01767                         break;
01768                     case 'R':
01769                         *cp++ = CR;
01770                         inptr++;
01771                         break;
01772                     case '0':{
01773                                 int i = 3;
01774                                 *cp = 0;
01775                                 do {
01776                                         if (*++inptr < '0' || *inptr > '7')
01777                                                 break;
01778 
01779                                         *cp = (*cp << 3) | (*inptr - '0');
01780                                 } while (--i != 0);
01781                                 cp++;
01782                         } break;
01783                     default:    *cp++ = *inptr++;       break;
01784                 }
01785         }
01786   }
01787   if (size >= subsz) return(NULL);
01788 
01789   *cp = EOS;
01790   return(sub);
01791 }
01792 
01793 /*      matchs.c        */
01794 /* #include <stdio.h> */
01795 /* #include "tools.h" */
01796 
01797 /* Compares line and pattern.  Line is a character string while pat
01798  * is a pattern template made by getpat().
01799  * Returns:
01800  *      1. A zero if no match was found.
01801  *
01802  *      2. A pointer to the last character satisfing the match
01803  *         if ret_endp is non-zero.
01804  *
01805  *      3. A pointer to the beginning of the matched string if
01806  *         ret_endp is zero.
01807  *
01808  * e.g.:
01809  *
01810  *      matchs ("1234567890", getpat("4[0-9]*7), 0);
01811  * will return a pointer to the '4', while:
01812  *
01813  *      matchs ("1234567890", getpat("4[0-9]*7), 1);
01814  * will return a pointer to the '7'.
01815  */
01816 char *
01817  matchs(line, pat, ret_endp)
01818 char *line;
01819 TOKEN *pat;
01820 int ret_endp;
01821 {
01822 
01823   char *rval, *bptr;
01824   char *line2;
01825   TOKEN *pat2;
01826   char c;
01827   short ok;
01828 
01829   bptr = line;
01830 
01831   while (*line) {
01832 
01833         if (pat && pat->tok == LITCHAR) {
01834                 while (*line) {
01835                         pat2 = pat;
01836                         line2 = line;
01837                         if (*line2 != pat2->lchar) {
01838                                 c = pat2->lchar;
01839                                 while (*line2 && *line2 != c) ++line2;
01840                                 line = line2;
01841                                 if (*line2 == '\0') break;
01842                         }
01843                         ok = 1;
01844                         ++line2;
01845                         pat2 = pat2->next;
01846                         while (pat2 && pat2->tok == LITCHAR) {
01847                                 if (*line2 != pat2->lchar) {
01848                                         ok = 0;
01849                                         break;
01850                                 }
01851                                 ++line2;
01852                                 pat2 = pat2->next;
01853                         }
01854                         if (!pat2) {
01855                                 if (ret_endp)
01856                                         return(--line2);
01857                                 else
01858                                         return(line);
01859                         } else if (ok)
01860                                 break;
01861                         ++line;
01862                 }
01863                 if (*line == '\0') return(0);
01864         } else {
01865                 line2 = line;
01866                 pat2 = pat;
01867         }
01868         if ((rval = amatch(line2, pat2, bptr)) == 0) {
01869                 if (pat && pat->tok == BOL) break;
01870                 line++;
01871         } else {
01872                 if (rval > bptr && rval > line)
01873                         rval--; /* point to last char matched */
01874                 rval = ret_endp ? rval : line;
01875                 break;
01876         }
01877   }
01878   return(rval);
01879 }
01880 
01881 /*      move.c  */
01882 /* #include <stdio.h> */
01883 /* #include "tools.h" */
01884 /* #include "ed.h" */
01885 
01886 int move(num)
01887 int num;
01888 {
01889   LINE *k0, *k1, *k2, *k3;
01890 
01891   if (line1 <= 0 || line2 < line1 || (line1 <= num && num <= line2))
01892         return(ERR);
01893   k0 = getptr(prevln(line1));
01894   k1 = getptr(line1);
01895   k2 = getptr(line2);
01896   k3 = getptr(nextln(line2));
01897 
01898   relink(k0, k3, k0, k3);
01899   lastln -= line2 - line1 + 1;
01900 
01901   if (num > line1) num -= line2 - line1 + 1;
01902 
01903   curln = num + (line2 - line1 + 1);
01904 
01905   k0 = getptr(num);
01906   k3 = getptr(nextln(num));
01907 
01908   relink(k0, k1, k2, k3);
01909   relink(k2, k3, k0, k1);
01910   lastln += line2 - line1 + 1;
01911 
01912   return(1);
01913 }
01914 
01915 int transfer(num)
01916 int num;
01917 {
01918   int mid, lin, ntrans;
01919 
01920   if (line1 <= 0 || line1 > line2) return(ERR);
01921 
01922   mid = num < line2 ? num : line2;
01923 
01924   curln = num;
01925   ntrans = 0;
01926 
01927   for (lin = line1; lin <= mid; lin++) {
01928         ins(gettxt(lin));
01929         ntrans++;
01930   }
01931   lin += ntrans;
01932   line2 += ntrans;
01933 
01934   for (; lin <= line2; lin += 2) {
01935         ins(gettxt(lin));
01936         line2++;
01937   }
01938   return(1);
01939 }
01940 
01941 /*      omatch.c        */
01942 /* #include <stdio.h> */
01943 /* #include "tools.h" */
01944 
01945 /* Match one pattern element, pointed at by pat, with the character at
01946  * **linp.  Return non-zero on match.  Otherwise, return 0.  *Linp is
01947  * advanced to skip over the matched character; it is not advanced on
01948  * failure.  The amount of advance is 0 for patterns that match null
01949  * strings, 1 otherwise.  "boln" should point at the position that will
01950  * match a BOL token.
01951  */
01952 int omatch(linp, pat, boln)
01953 char **linp;
01954 TOKEN *pat;
01955 char *boln;
01956 {
01957 
01958   register int advance;
01959 
01960   advance = -1;
01961 
01962   if (**linp) {
01963         switch (pat->tok) {
01964             case LITCHAR:
01965                 if (**linp == pat->lchar) advance = 1;
01966                 break;
01967 
01968             case BOL:
01969                 if (*linp == boln) advance = 0;
01970                 break;
01971 
01972             case ANY:
01973                 if (**linp != '\n') advance = 1;
01974                 break;
01975 
01976             case EOL:
01977                 if (**linp == '\n') advance = 0;
01978                 break;
01979 
01980             case CCL:
01981                 if (testbit(**linp, pat->bitmap)) advance = 1;
01982                 break;
01983 
01984             case NCCL:
01985                 if (!testbit(**linp, pat->bitmap)) advance = 1;
01986                 break;
01987         }
01988   }
01989   if (advance >= 0) *linp += advance;
01990 
01991   return(++advance);
01992 }
01993 
01994 /*      optpat.c        */
01995 /* #include <stdio.h> */
01996 /* #include "tools.h" */
01997 /* #include "ed.h" */
01998 
01999 TOKEN *oldpat;
02000 
02001 TOKEN *
02002  optpat()
02003 {
02004   char delim, str[MAXPAT], *cp;
02005 
02006   delim = *inptr++;
02007   cp = str;
02008   while (*inptr != delim && *inptr != NL) {
02009         if (*inptr == ESCAPE && inptr[1] != NL) *cp++ = *inptr++;
02010         *cp++ = *inptr++;
02011   }
02012 
02013   *cp = EOS;
02014   if (*str == EOS) return(oldpat);
02015   if (oldpat) unmakepat(oldpat);
02016   oldpat = getpat(str);
02017   return(oldpat);
02018 }
02019 
02020 /*      set.c   */
02021 /* #include <stdio.h> */
02022 /* #include "tools.h" */
02023 /* #include "ed.h" */
02024 
02025 struct tbl {
02026   char *t_str;
02027   int *t_ptr;
02028   int t_val;
02029 } *t, tbl[] = {
02030 
02031   "number", &nflg, TRUE,
02032   "nonumber", &nflg, FALSE,
02033   "list", &lflg, TRUE,
02034   "nolist", &lflg, FALSE,
02035   "eightbit", &eightbit, TRUE,
02036   "noeightbit", &eightbit, FALSE,
02037   0
02038 };
02039 
02040 int set()
02041 {
02042   char word[16];
02043   int i;
02044 
02045   inptr++;
02046   if (*inptr != 't') {
02047         if (*inptr != SP && *inptr != HT && *inptr != NL) return(ERR);
02048   } else
02049         inptr++;
02050 
02051   if (*inptr == NL) return(show());
02052   /* Skip white space */
02053   while (*inptr == SP || *inptr == HT) inptr++;
02054 
02055   for (i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
02056         word[i++] = *inptr++;
02057   word[i] = EOS;
02058   for (t = tbl; t->t_str; t++) {
02059         if (strcmp(word, t->t_str) == 0) {
02060                 *t->t_ptr = t->t_val;
02061                 return(0);
02062         }
02063   }
02064   return(0);
02065 }
02066 
02067 int show()
02068 {
02069   extern int version;
02070 
02071   printf("ed version %d.%d\n", version / 100, version % 100);
02072   printf("number %s, list %s\n", nflg ? "ON" : "OFF", lflg ? "ON" : "OFF");
02073   return(0);
02074 }
02075 
02076 /*      setbuf.c        */
02077 /* #include <stdio.h> */
02078 /* #include "tools.h" */
02079 /* #include "ed.h" */
02080 
02081 void relink(a, x, y, b)
02082 LINE *a, *x, *y, *b;
02083 {
02084   x->l_prev = a;
02085   y->l_next = b;
02086 }
02087 
02088 void clrbuf()
02089 {
02090   del(1, lastln);
02091 }
02092 
02093 void set_buf()
02094 {
02095   relink(&line0, &line0, &line0, &line0);
02096   curln = lastln = 0;
02097 }
02098 
02099 /*      subst.c */
02100 /* #include <stdio.h> */
02101 /* #include "tools.h" */
02102 /* #include "ed.h" */
02103 
02104 int subst(pat, sub, gflg, pflag)
02105 TOKEN *pat;
02106 char *sub;
02107 int gflg, pflag;
02108 {
02109   int lin, chngd, nchngd;
02110   char *txtptr, *txt;
02111   char *lastm, *m, *new, buf[MAXLINE];
02112 
02113   if (line1 <= 0) return(ERR);
02114   nchngd = 0;                   /* reset count of lines changed */
02115   for (lin = line1; lin <= line2; lin++) {
02116         txt = txtptr = gettxt(lin);
02117         new = buf;
02118         chngd = 0;
02119         lastm = NULL;
02120         while (*txtptr) {
02121                 if (gflg || !chngd)
02122                         m = amatch(txtptr, pat, txt);
02123                 else
02124                         m = NULL;
02125                 if (m != NULL && lastm != m) {
02126                         chngd++;
02127                         new = catsub(txtptr, m, sub, new,
02128                                      buf + MAXLINE);
02129                         lastm = m;
02130                 }
02131                 if (m == NULL || m == txtptr) {
02132                         *new++ = *txtptr++;
02133                 } else {
02134                         txtptr = m;
02135                 }
02136         }
02137         if (chngd) {
02138                 if (new >= buf + MAXLINE) return(ERR);
02139                 *new++ = EOS;
02140                 del(lin, lin);
02141                 ins(buf);
02142                 nchngd++;
02143                 if (pflag) doprnt(curln, curln);
02144         }
02145   }
02146   if (nchngd == 0 && !gflg) {
02147         return(ERR);
02148   }
02149   return(nchngd);
02150 }
02151 
02152 /*      System.c        */
02153 #define SHELL   "/bin/sh"
02154 #define SHELL2  "/usr/bin/sh"
02155 
02156 int System(c)
02157 char *c;
02158 {
02159   int pid, status;
02160 
02161   switch (pid = fork()) {
02162       case -1:
02163         return -1;
02164       case 0:
02165         execl(SHELL, "sh", "-c", c, (char *) 0);
02166         execl(SHELL2, "sh", "-c", c, (char *) 0);
02167         exit(-1);
02168       default:  while (wait(&status) != pid);
02169 }
02170   return status;
02171 }
02172 
02173 /*      unmkpat.c       */
02174 /* #include <stdio.h> */
02175 /* #include "tools.h" */
02176 
02177 /* Free up the memory usde for token string */
02178 void unmakepat(head)
02179 TOKEN *head;
02180 {
02181 
02182   register TOKEN *old_head;
02183 
02184   while (head) {
02185         switch (head->tok) {
02186             case CCL:
02187             case NCCL:
02188                 free(head->bitmap);
02189                 /* Fall through to default */
02190 
02191             default:
02192                 old_head = head;
02193                 head = head->next;
02194                 free((char *) old_head);
02195                 break;
02196         }
02197   }
02198 }

Generated on Fri Apr 14 22:57:06 2006 for minix by  doxygen 1.4.6