On Friday, 23 April 2021 at 00:58:41 UTC+8, jacobnavia wrote:
> Recently, somebody started a thread about how C wasn't a simple
> language. The excuse was a text editor project for a beginner.
>
> Attached is the source code for the 10th edition of Unix of the "ed"
> text editor, published by Brian Kernighan for his CS classes at
> Princeton in 2001.
>
> Maybe C is not a simple language but one of its incredible strengths is
> its stability. This code is around 40 (yes FORTY) years old and you can
> compile it without any trouble today and it will work in any UNIX system.
>
> ----------------------------------------------------------------cut here
> /* This file contains the source for the 10th Edition Unix version of
> ed, which is
> 1700 lines long. It dates from about 1989, but is typical of Unix
> code from the
> mid 1970's: terse, tight, efficient, and largely uncommented
> This is a slightly modified version that compiles without any
> warnings under gcc in 2021
> See
https://www.cs.princeton.edu/courses/archive/spring01/cs333/ed.c
> Compile with gcc -O2 -o ed -Wall -Wno-parentheses ed.c
> */
> #include <signal.h>
> #include <stdlib.h>
> #include <setjmp.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <wait.h>
> #include <string.h>
> #define BLKSIZE 4096 /* make BLKSIZE and LBSIZE 512 for smaller machines */
> #define NBLK 2047
> #define FNSIZE 128
> #define LBSIZE 4096
> #define ESIZE 256
> #define GBSIZE 256
> #define NBRA 5
> #define KSIZE 9
> #define CBRA 1
> #define CCHR 2
> #define CDOT 4
> #define CCL 6
> #define NCCL 8
> #define CDOL 10
> #define CEOF 11
> #define CKET 12
> #define CBACK 14
> #define CCIRC 15
> #define STAR 01
> static unsigned char Q[] = "";
> static unsigned char T[] = "TMP";
> #define READ 0
> #define WRITE 1
> static int peekc;
> static int lastc;
> static unsigned char savedfile[FNSIZE];
> static unsigned char file[FNSIZE];
> static unsigned char linebuf[LBSIZE];
> static unsigned char rhsbuf[LBSIZE/2];
> static unsigned char expbuf[ESIZE+4];
> static int given;
> static unsigned int *addr1, *addr2;
> static unsigned int *dot, *dol, *zero;
> static unsigned char genbuf[LBSIZE];
> static long count;
> static unsigned char *nextip;
> static unsigned char *linebp;
> static int ninbuf;
> static int io;
> static int pflag;
> static int vflag = 1;
> static int oflag;
> static int listf;
> static int listn;
> static int col;
> static unsigned char *globp;
> static int tfile = -1;
> static int tline;
> static char tfname[50];
> static unsigned char *loc1;
> static unsigned char *loc2;
> static unsigned char ibuff[BLKSIZE];
> static int iblock = -1;
> static unsigned char obuff[BLKSIZE];
> static int oblock = -1;
> static int ichanged;
> static int nleft;
> static char WRERR[] = "WRITE ERROR";
> static int names[26];
> static int anymarks;
> static unsigned char *braslist[NBRA];
> static unsigned char *braelist[NBRA];
> static int nbra;
> static int subnewa;
> static int subolda;
> static int fchange;
> static int wrapp;
> static unsigned nlall = 128;
> static char tmpXXXXX[50] = "/tmp/eXXXXXX";
>
> static unsigned char *getblock(unsigned int atl, int iof);
> static unsigned char *GetLine(unsigned int tl);
> static unsigned char *place(unsigned char *sp,unsigned char *l1,unsigned
> char *l2);
> static void add(int i);
> static int advance(unsigned char *lp, unsigned char *ep);
> static int append(int (*f)(void), unsigned int *a);
> static int backref(int i,unsigned char *lp);
> static void blkio(int b, unsigned char *buf, int iof);
> static void callunix(void);
> static int cclass(unsigned char *set, int c, int af);
> static void commands(void);
> static void compile(int eof);
> static int compsub(void);
> static void dosub(void);
> static void error(unsigned char *s);
> static int execute(unsigned int *addr);
> static void exfile(void);
> static void filename(int comm);
> static void gdelete(void);
> static int getchr(void);
> static int getcopy(void);
> static int getfile(void);
> static int getnum(void);
> static int getsub(void);
> static int gettty(void);
> static int gety(void);
> static void global(int k);
> static void init(void);
> static unsigned int *address(void);
> static void join(void);
> static void move(int cflag);
> static void newline(void);
> static void nonzero(void);
> static void onhup(int n);
> static void onintr(int n);
> static void print(void);
> static void putchr(int ac);
> static void putd(void);
> static void putfile(void);
> static int putline(void);
> static void quit(int n);
> static void rdelete(unsigned int *ad1, unsigned int *ad2);
> static void reverse(unsigned int *a1, unsigned int *a2);
> static void setwide(void);
> static void setnoaddr(void);
> static void squeeze(int i);
> static void substitute(int inglob);
> static jmp_buf savej;
> typedef void (*SIG_TYP)(int);
> static SIG_TYP oldhup;
> static SIG_TYP oldquit;
> /* these two are not in ansi, but we need them */
> #define SIGHUP 1 /* hangup */
> #define SIGQUIT 3 /* quit (ASCII FS) */
>
> int main(int argc, char *argv[])
> {
> unsigned char *p1, *p2;
> SIG_TYP oldintr;
>
> oldquit = signal(SIGQUIT, SIG_IGN);
> oldhup = signal(SIGHUP, SIG_IGN);
> oldintr = signal(SIGINT, SIG_IGN);
> if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
> signal(SIGTERM, quit);
> argv++;
> while (argc > 1 && **argv=='-') {
> switch((*argv)[1]) {
>
> case '\0':
> vflag = 0;
> break;
>
> case 'q':
> signal(SIGQUIT, SIG_DFL);
> vflag = 1;
> break;
>
> case 'o':
> oflag = 1;
> break;
> }
> argv++;
> argc--;
> }
> if (oflag) {
> p1 = (unsigned char *)"/dev/stdout";
> p2 = savedfile;
> while (*p2++ = *p1++)
> ;
> }
> if (argc>1) {
> p1 = (unsigned char *)*argv;
> p2 = savedfile;
> while (*p2++ = *p1++)
> if (p2 >= &savedfile[sizeof(savedfile)])
> p2--;
> globp = (unsigned char *)"r";
> }
> zero = (unsigned *)malloc(nlall*sizeof(unsigned));
> strcpy(tfname,tmpXXXXX);
> mkstemp(tfname);
>
> init();
> if (oldintr!=SIG_IGN)
> signal(SIGINT, onintr);
> if (oldhup!=SIG_IGN)
> signal(SIGHUP, onhup);
> setjmp(savej);
> commands();
> quit(0);
> return 0;
> }
> static void commands(void)
> {
> unsigned int *a1;
> int c;
> int temp;
> unsigned char lastsep;
>
> for (;;) {
> if (pflag) {
> pflag = 0;
> addr1 = addr2 = dot;
> print();
> }
> c = '\n';
> for (addr1 = 0;;) {
> lastsep = c;
> a1 = address();
> c = getchr();
> if (c!=',' && c!=';')
> break;
> if (lastsep==',')
> error(Q);
> if (a1==0) {
> a1 = zero+1;
> if (a1>dol)
> a1--;
> }
> addr1 = a1;
> if (c==';')
> dot = a1;
> }
> if (lastsep!='\n' && a1==0)
> a1 = dol;
> if ((addr2=a1)==0) {
> given = 0;
> addr2 = dot;
> }
> else
> given = 1;
> if (addr1==0)
> addr1 = addr2;
> switch(c) {
> case 'a':
> add(0);
> continue;
> case 'c':
> nonzero();
> newline();
> rdelete(addr1, addr2);
> append(gettty, addr1-1);
> continue;
> case 'd':
> nonzero();
> newline();
> rdelete(addr1, addr2);
> continue;
> case 'E':
> fchange = 0;
> c = 'e';
> case 'e':
> setnoaddr();
> if (vflag && fchange) {
> fchange = 0;
> error(Q);
> }
> filename(c);
> init();
> addr2 = zero;
> goto caseread;
> case 'f':
> setnoaddr();
> filename(c);
> puts((const char *)savedfile);
> continue;
> case 'g':
> global(1);
> continue;
> case 'i':
> add(-1);
> continue;
> case 'j':
> if (!given)
> addr2++;
> newline();
> join();
> continue;
> case 'k':
> nonzero();
> if ((c = getchr()) < 'a' || c > 'z')
> error(Q);
> newline();
> names[c-'a'] = *addr2 & ~01;
> anymarks |= 01;
> continue;
> case 'm':
> move(0);
> continue;
> case 'n':
> listn++;
> newline();
> print();
> continue;
> case '\n':
> if (a1==0) {
> a1 = dot+1;
> addr2 = a1;
> addr1 = a1;
> }
> if (lastsep==';')
> addr1 = a1;
> print();
> continue;
> case 'l':
> listf++;
> case 'p':
> case 'P':
> newline();
> print();
> continue;
> case 'Q':
> fchange = 0;
> case 'q':
> setnoaddr();
> newline();
> quit(0);
> case 'r':
> filename(c);
> caseread:
> if ((io = open((const char *)file, 0)) < 0) {
> lastc = '\n';
> error(file);
> }
> setwide();
> squeeze(0);
> ninbuf = 0;
> c = zero != dol;
> append(getfile, addr2);
> exfile();
> fchange = c;
> continue;
> case 's':
> nonzero();
> substitute(globp!=0);
> continue;
> case 't':
> move(1);
> continue;
> case 'u':
> nonzero();
> newline();
> if ((*addr2&~01) != subnewa)
> error(Q);
> *addr2 = subolda;
> dot = addr2;
> continue;
> case 'v':
> global(0);
> continue;
> case 'W':
> wrapp++;
> case 'w':
> setwide();
> squeeze(dol>zero);
> if ((temp = getchr()) != 'q' && temp != 'Q') {
> peekc = temp;
> temp = 0;
> }
> filename(c);
> if(!wrapp ||
> ((io = open((const char *)file,1)) == -1) ||
> ((lseek(io, 0L, 2)) == -1))
> if ((io = creat((const char *)file, 0666)) < 0)
> error(file);
> wrapp = 0;
> if (dol > zero)
> putfile();
> exfile();
> if (addr1<=zero+1 && addr2==dol)
> fchange = 0;
> if (temp == 'Q')
> fchange = 0;
> if (temp)
> quit(0);
> continue;
> case '=':
> setwide();
> squeeze(0);
> newline();
> count = addr2 - zero;
> putd();
> putchr('\n');
> continue;
> case '!':
> callunix();
> continue;
> case EOF:
> return;
> }
> error(Q);
> }
> }
> static void print(void)
> {
> unsigned int *a1;
>
> nonzero();
> a1 = addr1;
> do {
> if (listn) {
> count = a1-zero;
> putd();
> putchr('\t');
> }
> puts((const char *)GetLine(*a1++));
> } while (a1 <= addr2);
> dot = addr2;
> listf = 0;
> listn = 0;
> pflag = 0;
> }
> static unsigned int * address(void)
> {
> int sign;
> unsigned int *a, *b;
> int opcnt, nextopand;
> int c;
>
> nextopand = -1;
> sign = 1;
> opcnt = 0;
> a = dot;
> do {
> do c = getchr(); while (c==' ' || c=='\t');
> if ('0'<=c && c<='9') {
> peekc = c;
> if (!opcnt) a = zero;
> a += sign*getnum();
> } else switch (c) {
> case '$':
> a = dol;
> /* fall through */
> case '.':
> if (opcnt) error(Q);
> break;
> case '\'':
> c = getchr();
> if (opcnt || c<'a' || 'z'<c) error(Q);
> a = zero;
> do a++; while (a<=dol && names[c-'a']!=(*a&~01));
> break;
> case '?':
> sign = -sign;
> /* fall through */
> case '/':
> compile(c);
> b = a;
> for (;;) {
> a += sign;
> if (a<=zero) a = dol;
> if (a>dol) a = zero;
> if (execute(a)) break;
> if (a==b) error(Q);
> }
> break;
> default:
> if (nextopand == opcnt) {
> a += sign;
> if (a<zero || dol<a)
> continue; /* error(Q); */
> }
> if (c!='+' && c!='-' && c!='^') {
> peekc = c;
> if (opcnt==0) a = 0;
> return (a);
> }
> sign = 1;
> if (c!='+') sign = -sign;
> nextopand = ++opcnt;
> continue;
> }
> sign = 1;
> opcnt++;
> } while (zero<=a && a<=dol);
> error(Q);
> /*NOTREACHED*/
> return 0;
> }
> static int getnum(void)
> {
> int r, c;
>
> r = 0;
> while ((c=getchr())>='0' && c<='9')
> r = r*10 + c - '0';
> peekc = c;
> return (r);
> }
> static void setwide(void)
> {
> if (!given) {
> addr1 = zero + (dol>zero);
> addr2 = dol;
> }
> }
> static void setnoaddr(void)
> {
> if (given) error(Q);
> }
> static void nonzero(void)
> {
> squeeze(1);
> }
> static void squeeze(int i)
> {
> if (addr1<zero+i || addr2>dol || addr1>addr2)
> error(Q);
> }
> static void newline(void)
> {
> int c;
>
> if ((c = getchr()) == '\n' || c == EOF) return;
> if (c=='p' || c=='l' || c=='n') {
> pflag++;
> if (c=='l') listf++;
> else if (c=='n') listn++;
> if ((c=getchr())=='\n') return;
> }
> error(Q);
> }
> static void filename(int comm)
> {
> unsigned char *p1, *p2;
> int c;
>
> count = 0;
> c = getchr();
> if (c=='\n' || c==EOF) {
> p1 = savedfile;
> if (*p1==0 && comm!='f') error(Q);
> p2 = file;
> while (*p2++ = *p1++)
> ;
> return;
> }
> if (c!=' ')
> error(Q);
> while ((c = getchr()) == ' ')
> ;
> if (c=='\n') error(Q);
> p1 = file;
> do {
> if (p1 >= &file[sizeof(file)-1] || c==' ' || c==EOF) error(Q);
> *p1++ = c;
> } while ((c = getchr()) != '\n');
> *p1++ = 0;
> if (savedfile[0]==0 || comm=='e' || comm=='f') {
> p1 = savedfile;
> p2 = file;
> while (*p1++ = *p2++)
> ;
> }
> }
> static void exfile(void)
> {
> close(io);
> io = -1;
> if (vflag) {
> putd();
> putchr('\n');
> }
> }
> static void onintr(int n)
> {
> signal(SIGINT, onintr);
> putchr('\n');
> lastc = '\n';
> error(Q);
> }
> static void onhup(int n)
> {
> signal(SIGINT, SIG_IGN);
> signal(SIGHUP, SIG_IGN);
> if (dol > zero) {
> addr1 = zero+1;
> addr2 = dol;
> io = creat("ed.hup", 0600);
> if (io > 0)
> putfile();
> }
> fchange = 0;
> quit(0);
> }
> static void error(unsigned char *s)
> {
> int c;
>
> wrapp = 0;
> listf = 0;
> listn = 0;
> putchr('?');
> puts((const char *)s);
> count = 0;
> lseek(0, (long)0, 2);
> pflag = 0;
> if (globp)
> lastc = '\n';
> globp = 0;
> peekc = lastc;
> if(lastc)
> while ((c = getchr()) != '\n' && c != EOF)
> ;
> if (io > 0) {
> close(io);
> io = -1;
> }
> longjmp(savej, 1);
> }
> static int getchr(void)
> {
> char c;
> if (lastc=peekc) {
> peekc = 0;
> return(lastc);
> }
> if (globp) {
> if ((lastc = *globp++) != 0)
> return(lastc);
> globp = 0;
> return(EOF);
> }
> if (read(0, &c, 1) <= 0)
> return(lastc = EOF);
> lastc = c&0177;
> return(lastc);
> }
> static int gettty(void)
> {
> int rc;
>
> if (rc = gety())
> return(rc);
> if (linebuf[0]=='.' && linebuf[1]==0)
> return(EOF);
> return(0);
> }
> static int gety(void)
> {
> int c;
> unsigned char *gf;
> unsigned char *p;
>
> p = linebuf;
> gf = globp;
> while ((c = getchr()) != '\n') {
> if (c==EOF) {
> if (gf)
> peekc = c;
> return(c);
> }
> if ((c &= 0177) == 0)
> continue;
> *p++ = c;
> if (p >= &linebuf[LBSIZE-2])
> error(Q);
> }
>
> *p++ = 0;
> return(0);
> }
> static int getfile(void)
> {
> int c;
> unsigned char *lp, *fp;
>
> lp = linebuf;
> fp = nextip;
> do {
> if (--ninbuf < 0) {
> if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
> if (lp>linebuf) {
> puts("'\\n' appended");
> *genbuf = '\n';
> }
> else return(EOF);
> fp = genbuf;
> while(fp < &genbuf[ninbuf]) {
> if (*fp++ & 0200)
> break;
> }
> fp = genbuf;
> }
> c = *fp++;
> if (c=='\0')
> continue;
> if (c&0200 || lp >= &linebuf[LBSIZE]) {
> lastc = '\n';
> error(Q);
> }
> *lp++ = c;
> count++;
> } while (c != '\n');
> *--lp = 0;
> nextip = fp;
> return(0);
> }
> static void putfile(void)
> {
> unsigned int *a1;
> int n;
> unsigned char *fp, *lp;
> int nib;
>
> nib = BLKSIZE;
> fp = genbuf;
> a1 = addr1;
> do {
> lp = GetLine(*a1++);
> for (;;) {
> if (--nib < 0) {
> n = fp-genbuf;
> if(write(io, genbuf, n) != n) {
> puts((const char *)WRERR);
> error(Q);
> }
> nib = BLKSIZE-1;
> fp = genbuf;
> }
> count++;
> if ((*fp++ = *lp++) == 0) {
> fp[-1] = '\n';
> break;
> }
> }
> } while (a1 <= addr2);
> n = fp-genbuf;
> if(write(io, genbuf, n) != n) {
> puts((const char *)WRERR);
> error(Q);
> }
> }
> static int append(int (*f)(void), unsigned int *a)
> {
> unsigned int *a1, *a2, *rdot;
> int nline, tl;
>
> nline = 0;
> dot = a;
> while ((*f)() == 0) {
> if ((dol-zero)+1 >= nlall) {
> unsigned *ozero = zero;
>
> nlall += 1024;
> if ((zero = (unsigned *)realloc((unsigned char *)zero,
> nlall*sizeof(unsigned)))==NULL) {
> error((unsigned char *)"MEM?");
> onhup(0);
> }
> dot += zero - ozero;
> dol += zero - ozero;
> }
> tl = putline();
> nline++;
> a1 = ++dol;
> a2 = a1+1;
> rdot = ++dot;
> while (a1 > rdot)
> *--a2 = *--a1;
> *rdot = tl;
> }
> return(nline);
> }
> static void add(int i)
> {
> if (i && (given || dol>zero)) {
> addr1--;
> addr2--;
> }
> squeeze(0);
> newline();
> append(gettty, addr2);
> }
> static void callunix(void)
> {
> SIG_TYP savint;
> int pid, rpid;
> int retcode;
>
> setnoaddr();
> if ((pid = fork()) == 0) {
> signal(SIGHUP, oldhup);
> signal(SIGQUIT, oldquit);
> execl("/bin/sh", "sh", "-t", NULL);
> exit(0100);
> }
> savint = signal(SIGINT, SIG_IGN);
> while ((rpid = wait(&retcode)) != pid && rpid != -1)
> ;
> signal(SIGINT, savint);
> if (vflag) {
> puts("!");
> }
> }
> static void quit(int n)
> {
> if (vflag && fchange && dol!=zero) {
> fchange = 0;
> error(Q);
> }
> unlink(tfname);
> exit(0);
> }
> static void rdelete(unsigned int *ad1, unsigned int *ad2)
> {
> unsigned int *a1, *a2, *a3;
>
> a1 = ad1;
> a2 = ad2+1;
> a3 = dol;
> dol -= a2 - a1;
> do {
> *a1++ = *a2++;
> } while (a2 <= a3);
> a1 = ad1;
> if (a1 > dol)
> a1 = dol;
> dot = a1;
> fchange = 1;
> }
> static void gdelete(void)
> {
> unsigned int *a1, *a2, *a3;
>
> a3 = dol;
> for (a1=zero; (*a1&01)==0; a1++)
> if (a1>=a3)
> return;
> for (a2=a1+1; a2<=a3;) {
> if (*a2&01) {
> a2++;
> dot = a1;
> } else
> *a1++ = *a2++;
> }
> dol = a1-1;
> if (dot>dol)
> dot = dol;
> fchange = 1;
> }
> static unsigned char *GetLine(unsigned int tl)
> {
> unsigned char *bp, *lp;
> int nl;
>
> lp = linebuf;
> bp = getblock(tl, READ);
> nl = nleft;
> tl &= ~((BLKSIZE/2)-1);
> while (*lp++ = *bp++)
> if (--nl == 0) {
> bp = getblock(tl+=(BLKSIZE/2), READ);
> nl = nleft;
> }
> return(linebuf);
> }
> static int putline(void)
> {
> unsigned char *bp, *lp;
> int nl;
> unsigned int tl;
>
> fchange = 1;
> lp = linebuf;
> tl = tline;
> bp = getblock(tl, WRITE);
> nl = nleft;
> tl &= ~((BLKSIZE/2)-1);
> while (*bp = *lp++) {
> if (*bp++ == '\n') {
> *--bp = 0;
> linebp = lp;
> break;
> }
> if (--nl == 0) {
> bp = getblock(tl+=(BLKSIZE/2), WRITE);
> nl = nleft;
> }
> }
> nl = tline;
> tline += (((lp-linebuf)+03)>>1)&077776;
> return(nl);
> }
> static unsigned char * getblock(unsigned int atl, int iof)
> {
> int bno, off;
>
> bno = (atl/(BLKSIZE/2));
> off = (atl<<1) & (BLKSIZE-1) & ~03;
> if (bno >= NBLK) {
> lastc = '\n';
> error(T);
> }
> nleft = BLKSIZE - off;
> if (bno==iblock) {
> ichanged |= iof;
> return(ibuff+off);
> }
> if (bno==oblock)
> return(obuff+off);
> if (iof==READ) {
> if (ichanged)
> blkio(iblock, ibuff, iof);
> ichanged = 0;
> iblock = bno;
> blkio(bno, ibuff, iof);
> return(ibuff+off);
> }
> if (oblock>=0)
> blkio(oblock, obuff, iof);
> oblock = bno;
> return(obuff+off);
> }
> static void blkio(int b, unsigned char *buf, int iof)
> {
> lseek(tfile, (long)b*BLKSIZE, 0);
> if (iof == READ) {
> if (read(tfile, buf, BLKSIZE) != BLKSIZE) {
> error(T);
> }
> }
> else {
> if (write(tfile, buf, BLKSIZE) != BLKSIZE) {
> error(T);
> }
> }
> }
> static void init(void)
> {
> int *markp;
>
> close(tfile);
> tline = 2;
> for (markp = names; markp < &names[26]; )
> *markp++ = 0;
> subnewa = 0;
> anymarks = 0;
> iblock = -1;
> oblock = -1;
> ichanged = 0;
> close(creat(tfname, 0600));
> tfile = open(tfname, 2);
> dot = dol = zero;
> }
> static void global(int k)
> {
> unsigned char *gp;
> int c;
> unsigned int *a1;
> unsigned char globuf[GBSIZE];
>
> if (globp)
> error(Q);
> setwide();
> squeeze(dol>zero);
> if ((c=getchr())=='\n')
> error(Q);
> compile(c);
> gp = globuf;
> while ((c = getchr()) != '\n') {
> if (c==EOF)
> error(Q);
> if (c=='\\') {
> c = getchr();
> if (c!='\n')
> *gp++ = '\\';
> }
> *gp++ = c;
> if (gp >= &globuf[GBSIZE-2])
> error(Q);
> }
> if (gp == globuf)
> *gp++ = 'p';
> *gp++ = '\n';
> *gp++ = 0;
> for (a1=zero; a1<=dol; a1++) {
> *a1 &= ~01;
> if (a1>=addr1 && a1<=addr2 && execute(a1)==k)
> *a1 |= 01;
> }
> /*
> * Special case: g/.../d (avoid n^2 algorithm)
> */
> if (globuf[0]=='d' && globuf[1]=='\n' && globuf[2]=='\0') {
> gdelete();
> return;
> }
> for (a1=zero; a1<=dol; a1++) {
> if (*a1 & 01) {
> *a1 &= ~01;
> dot = a1;
> globp = globuf;
> commands();
> a1 = zero;
> }
> }
> }
> static void join(void)
> {
> unsigned char *gp, *lp;
> unsigned int *a1;
>
> nonzero();
> gp = genbuf;
> for (a1=addr1; a1<=addr2; a1++) {
> lp = GetLine(*a1);
> while (*gp = *lp++)
> if (gp++ >= &genbuf[LBSIZE-2])
> error(Q);
> }
> lp = linebuf;
> gp = genbuf;
> while (*lp++ = *gp++)
> ;
> *addr1 = putline();
> if (addr1<addr2)
> rdelete(addr1+1, addr2);
> dot = addr1;
> }
> static void substitute(int inglob)
> {
> int *mp, nl;
> unsigned int *a1;
> int gsubf;
> int n;
>
> n = getnum(); /* OK even if n==0 */
> gsubf = compsub();
> for (a1 = addr1; a1 <= addr2; a1++) {
> if (execute(a1)){
> unsigned *ozero;
> int m = n;
> do {
> int span = loc2-loc1;
> if (--m <= 0) {
> dosub();
> if (!gsubf)
> break;
> if (span==0) { /* null RE match */
> if (*loc2=='\0')
> break;
> loc2++;
> }
> }
> } while (execute((unsigned *)0));
> if (m <= 0) {
> inglob |= 01;
> subnewa = putline();
> *a1 &= ~01;
> if (anymarks) {
> for (mp = names; mp < &names[26]; mp++)
> if (*mp == *a1)
> *mp = subnewa;
> }
> subolda = *a1;
> *a1 = subnewa;
> ozero = zero;
> nl = append(getsub, a1);
> nl += zero-ozero;
> a1 += nl;
> addr2 += nl;
> }
> }
> }
> if (inglob==0)
> error(Q);
> }
> static int compsub(void)
> {
> int seof, c;
> unsigned char *p;
>
> if ((seof = getchr()) == '\n' || seof == ' ')
> error(Q);
> compile(seof);
> p = rhsbuf;
> for (;;) {
> c = getchr();
> if (c=='\\')
> c = getchr() | 0200;
> if (c=='\n') {
> if (globp && globp[0]) /* last '\n' does not count */
> c |= 0200;
> else {
> peekc = c;
> pflag++;
> break;
> }
> }
> if (c==seof)
> break;
> *p++ = c;
> if (p >= &rhsbuf[LBSIZE/2])
> error(Q);
> }
> *p++ = 0;
> if ((peekc = getchr()) == 'g') {
> peekc = 0;
> newline();
> return(1);
> }
> newline();
> return(0);
> }
> static int getsub(void)
> {
> unsigned char *p1, *p2;
>
> p1 = linebuf;
> if ((p2 = linebp) == 0)
> return(EOF);
> while (*p1++ = *p2++)
> ;
> linebp = 0;
> return(0);
> }
> static void dosub(void)
> {
> unsigned char *lp, *sp, *rp;
> int c;
>
> lp = linebuf;
> sp = genbuf;
> rp = rhsbuf;
> while (lp < loc1)
> *sp++ = *lp++;
> while (c = *rp++&0377) {
> if (c=='&') {
> sp = place(sp, loc1, loc2);
> continue;
> } else if (c&0200 && (c &= 0177) >='1' && c < nbra+'1') {
> sp = place(sp, braslist[c-'1'], braelist[c-'1']);
> continue;
> }
> *sp++ = c&0177;
> if (sp >= &genbuf[LBSIZE])
> error(Q);
> }
> lp = loc2;
> loc2 = sp - genbuf + linebuf;
> while (*sp++ = *lp++)
> if (sp >= &genbuf[LBSIZE])
> error(Q);
> lp = linebuf;
> sp = genbuf;
> while (*lp++ = *sp++)
> ;
> }
> static unsigned char * place(unsigned char *sp, unsigned char
> *l1,unsigned char *l2)
> {
>
> while (l1 < l2) {
> *sp++ = *l1++;
> if (sp >= &genbuf[LBSIZE])
> error(Q);
> }
> return(sp);
> }
> static void move(int cflag)
> {
> unsigned int *adt, *ad1, *ad2;
>
> nonzero();
> if ((adt = address())==0) /* address() guarantees addr is in range */
> error(Q);
> newline();
> if (cflag) {
> unsigned int *ozero;
> int delta;
>
> ad1 = dol;
> ozero = zero;
> append(getcopy, ad1++);
> ad2 = dol;
> delta = zero - ozero;
> ad1 += delta;
> adt += delta;
> } else {
> ad2 = addr2;
> for (ad1 = addr1; ad1 <= ad2;)
> *ad1++ &= ~01;
> ad1 = addr1;
> }
> ad2++;
> if (adt<ad1) {
> dot = adt + (ad2-ad1);
> if ((++adt)==ad1)
> return;
> reverse(adt, ad1);
> reverse(ad1, ad2);
> reverse(adt, ad2);
> } else if (adt >= ad2) {
> dot = adt++;
> reverse(ad1, ad2);
> reverse(ad2, adt);
> reverse(ad1, adt);
> } else
> error(Q);
> fchange = 1;
> }
> static void reverse(unsigned int *a1, unsigned int *a2)
> {
> int t;
>
> for (;;) {
> t = *--a2;
> if (a2 <= a1)
> return;
> *a2 = *a1;
> *a1++ = t;
> }
> }
> static int getcopy(void)
> {
> if (addr1 > addr2)
> return(EOF);
> GetLine(*addr1++);
> return(0);
> }
> static void compile(int eof)
> {
> int c;
> unsigned char *ep;
> unsigned char *lastep;
> unsigned char bracket[NBRA], *bracketp;
> int cclcnt;
>
> ep = expbuf;
> bracketp = bracket;
> if ((c = getchr()) == '\n') {
> peekc = c;
> c = eof;
> }
> if (c == eof) {
> if (*ep==0)
> error(Q);
> return;
> }
> nbra = 0;
> if (c=='^') {
> c = getchr();
> *ep++ = CCIRC;
> }
> peekc = c;
> lastep = 0;
> for (;;) {
> if (ep >= &expbuf[ESIZE])
> goto cerror;
> c = getchr();
> if (c == '\n') {
> peekc = c;
> c = eof;
> }
> if (c==eof) {
> if (bracketp != bracket)
> goto cerror;
> *ep++ = CEOF;
> return;
> }
> if (c!='*')
> lastep = ep;
> switch (c) {
>
> case '\\':
> if ((c = getchr())=='(') {
> if (nbra >= NBRA)
> goto cerror;
> *bracketp++ = nbra;
> *ep++ = CBRA;
> *ep++ = nbra++;
> continue;
> }
> if (c == ')') {
> if (bracketp <= bracket)
> goto cerror;
> *ep++ = CKET;
> *ep++ = *--bracketp;
> continue;
> }
> if (c>='1' && c<'1'+NBRA) {
> *ep++ = CBACK;
> *ep++ = c-'1';
> continue;
> }
> *ep++ = CCHR;
> if (c=='\n')
> goto cerror;
> *ep++ = c;
> continue;
>
> case '.':
> *ep++ = CDOT;
> continue;
>
> case '\n':
> goto cerror;
>
> case '*':
> if (lastep==0 || *lastep==CBRA || *lastep==CKET)
> goto defchar;
> *lastep |= STAR;
> continue;
>
> case '$':
> if ((peekc=getchr()) != eof && peekc!='\n')
> goto defchar;
> *ep++ = CDOL;
> continue;
>
> case '[':
> *ep++ = CCL;
> *ep++ = 0;
> cclcnt = 1;
> if ((c=getchr()) == '^') {
> c = getchr();
> ep[-2] = NCCL;
> }
> do {
> if (c=='\n')
> goto cerror;
> if (c=='-' && ep[-1]!=0) {
> if ((c=getchr())==']') {
> *ep++ = '-';
> cclcnt++;
> break;
> }
> while (ep[-1]<c) {
> *ep = ep[-1]+1;
> ep++;
> cclcnt++;
> if (ep>=&expbuf[ESIZE])
> goto cerror;
> }
> }
> *ep++ = c;
> cclcnt++;
> if (ep >= &expbuf[ESIZE])
> goto cerror;
> } while ((c = getchr()) != ']');
> lastep[1] = cclcnt;
> continue;
>
> defchar:
> default:
> *ep++ = CCHR;
> *ep++ = c;
> }
> }
> cerror:
> expbuf[0] = 0;
> nbra = 0;
> error(Q);
> }
> static int execute(unsigned int *addr)
> {
> unsigned char *p1, *p2;
> int c;
>
> for (c=0; c<NBRA; c++) {
> braslist[c] = 0;
> braelist[c] = 0;
> }
> p2 = expbuf;
> if (addr == (unsigned *)0) {
> if (*p2==CCIRC)
> return(0);
> p1 = loc2;
> } else if (addr==zero)
> return(0);
> else
> p1 = GetLine(*addr);
> if (*p2==CCIRC) {
> loc1 = p1;
> return(advance(p1, p2+1));
> }
> /* fast check for first character */
> if (*p2==CCHR) {
> c = p2[1];
> do {
> if (*p1!=c)
> continue;
> if (advance(p1, p2)) {
> loc1 = p1;
> return(1);
> }
> } while (*p1++);
> return(0);
> }
> /* regular algorithm */
> do {
> if (advance(p1, p2)) {
> loc1 = p1;
> return(1);
> }
> } while (*p1++);
> return(0);
> }
> static int advance(unsigned char *lp,unsigned char *ep)
> {
> unsigned char *curlp;
> int i;
>
> for (;;) switch (*ep++) {
>
> case CCHR:
> if (*ep++ == *lp++)
> continue;
> return(0);
>
> case CDOT:
> if (*lp++)
> continue;
> return(0);
>
> case CDOL:
> if (*lp==0)
> continue;
> return(0);
>
> case CEOF:
> loc2 = lp;
> return(1);
>
> case CCL:
> if (cclass(ep, *lp++, 1)) {
> ep += *ep;
> continue;
> }
> return(0);
>
> case NCCL:
> if (cclass(ep, *lp++, 0)) {
> ep += *ep;
> continue;
> }
> return(0);
>
> case CBRA:
> braslist[*ep++] = lp;
> continue;
>
> case CKET:
> braelist[*ep++] = lp;
> continue;
>
> case CBACK:
> if (braelist[i = *ep++]==0)
> error(Q);
> if (backref(i, lp)) {
> lp += braelist[i] - braslist[i];
> continue;
> }
> return(0);
>
> case CBACK|STAR:
> if (braelist[i = *ep++] == 0)
> error(Q);
> curlp = lp;
> while (backref(i, lp))
> lp += braelist[i] - braslist[i];
> while (lp >= curlp) {
> if (advance(lp, ep))
> return(1);
> lp -= braelist[i] - braslist[i];
> }
> continue;
>
> case CDOT|STAR:
> curlp = lp;
> while (*lp++)
> ;
> goto star;
>
> case CCHR|STAR:
> curlp = lp;
> while (*lp++ == *ep)
> ;
> ep++;
> goto star;
>
> case CCL|STAR:
> case NCCL|STAR:
> curlp = lp;
> while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)))
> ;
> ep += *ep;
> goto star;
>
> star:
> do {
> lp--;
> if (advance(lp, ep))
> return(1);
> } while (lp > curlp);
> return(0);
>
> default:
> error(Q);
> }
> }
> static int backref(int i,unsigned char *lp)
> {
> unsigned char *bp;
>
> bp = braslist[i];
> while (*bp++ == *lp++)
> if (bp >= braelist[i])
> return(1);
> return(0);
> }
> static int cclass(unsigned char *set, int c, int af)
> {
> int n;
>
> if (c==0)
> return(0);
> n = *set++;
> while (--n)
> if (*set++ == c)
> return(af);
> return(!af);
> }
> static void putd(void)
> {
> int r;
>
> r = count%10;
> count /= 10;
> if (count)
> putd();
> putchr(r + '0');
> }
> static unsigned char line[70];
> static unsigned char *linp = line;
> static void putchr(int ac)
> {
> unsigned char *lp;
> int c;
>
> lp = linp;
> c = ac;
> if (listf) {
> if (c=='\n') {
> if (linp!=line && linp[-1]==' ') {
> *lp++ = '\\';
> *lp++ = 'n';
> }
> } else {
> if (col > (72-4-2)) {
> col = 8;
> *lp++ = '\\';
> *lp++ = '\n';
> *lp++ = '\t';
> }
> col++;
> if (c=='\b' || c=='\t' || c=='\\') {
> *lp++ = '\\';
> if (c=='\b')
> c = 'b';
> else if (c=='\t')
> c = 't';
> col++;
> } else if (c<' ' || c=='\177') {
> *lp++ = '\\';
> *lp++ = (c>>6) +'0';
> *lp++ = ((c>>3)&07)+'0';
> c = ( c &07)+'0';
> col += 3;
> }
> }
> }
> *lp++ = c;
> if(c == '\n' || lp >= &line[64]) {
> linp = line;
> write(oflag?2:1, line, lp-line);
> return;
> }
> linp = lp;
> }
I just looked into the code deeper, quite tricky and old fassion.
No good for beginners, except several recurrsive method.