home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / Applications / Em_Editor / em1.c < prev    next >
Encoding:
Text File  |  1998-10-12  |  22.5 KB  |  1,608 lines

  1. #
  2.  
  3. /*
  4.  * Unix 6
  5.  * Editor
  6.  * with QMC mods Feb. 76, by  George Coulouris
  7.  * mods are:
  8.     prompts (suppress with '-p' flag)
  9.     ",%,&, to display a screen full of context
  10.     'x' - as 's' but interactive
  11.     'n' flag when appended to 's' or 'x' commands prints number of replacements
  12.  
  13.  * also mods by jrh 26 Feb 76
  14.     % == current file name in ! commands
  15.     !! == repeat the last ! command you executed
  16.     -e flag == "elfic" mode :-
  17.         no "w", "r\n" commands, auto w before q
  18.  
  19.     More mods by George March 76:
  20.  
  21.     'o' command for text input with local editing via control keys
  22.     'b' to set a threshold for automatic line breaks in 'o' mode.
  23.     'h' displays a screen full of help with editor commands
  24.         (the help is in /usr/lib/emhelp)
  25. bugs:
  26.     should not use printf in substitute()
  27.     (for space reasons).
  28.  */
  29.  
  30. /* this file contains all of the code except that used in the 'o' command.
  31.     that is in a second segment called em2.c */
  32.  
  33. /* screen dimensions */
  34. #define LINES    18
  35. #define LENGTH    80
  36. #define SPLIT    '-'
  37. #define PROMPT    '>'
  38. #define CONFIRM    '.'
  39. #define SCORE    "^"
  40. #define FORM    014
  41. #define    SIGHUP    1
  42. #define    SIGINTR    2
  43. #define    SIGQUIT    3
  44. #define    FNSIZE    64
  45. #define    LBSIZE    512
  46. #define    ESIZE    128
  47. #define    GBSIZE    256
  48. #define    NBRA    5
  49. #define    EOF    -1
  50.  
  51. #define    CBRA    1
  52. #define    CCHR    2
  53. #define    CDOT    4
  54. #define    CCL    6
  55. #define    NCCL    8
  56. #define    CDOL    10
  57. #define    CEOF    11
  58. #define    CKET    12
  59.  
  60. #define    STAR    01
  61.  
  62. #define    error    goto errlab
  63. #define    READ    0
  64. #define    WRITE    1
  65.  
  66.  
  67. #define UNIXBUFL 100
  68.  
  69. extern int margin;    /* used to set threshold in 'open' */
  70.  
  71. int    elfic    0;    /* true if "elfic" (-e) flag */
  72. int firstime    1;    /* ugh - used to frigg initial "read" */
  73. int    peekc;
  74. int    lastc;
  75. char    unixbuffer [UNIXBUFL];
  76. char    savedfile[FNSIZE];
  77. char    file[FNSIZE];
  78. char    linebuf[LBSIZE];
  79. char    rhsbuf[LBSIZE/2];
  80. char    expbuf[ESIZE+4];
  81. int    circfl;
  82. int    *zero;
  83. int    *dot;
  84. int    *dol;
  85. int    *endcore;
  86. int    *fendcore;
  87. int    *addr1;
  88. int    *addr2;
  89. char    genbuf[LBSIZE];
  90. int    count[2];
  91. char    *nextip;
  92. char    *linebp;
  93. int    ninbuf;
  94. int    io;
  95. int    pflag;
  96. int    onhup;
  97. int    onquit;
  98. int    vflag    0;
  99. int    xflag    0;    /*used in 'xchange' command */
  100. int    listf;
  101. int    col;
  102. char    *globp;
  103. int    tfile    -1;
  104. int    tline;
  105. char    *tfname;
  106. char    *loc1;
  107. char    *loc2;
  108. char    *locs;
  109. char    ibuff[512];
  110. int    iblock    -1;
  111. char    obuff[512];
  112. int    oblock    -1;
  113. int    ichanged;
  114. int    nleft;
  115. int    errfunc();
  116. int    *errlab    errfunc;
  117. char    TMPERR[] "TMP";
  118. int    names[26];
  119. char    *braslist[NBRA];
  120. char    *braelist[NBRA];
  121.  
  122. main(argc, argv)
  123. char **argv;
  124. {
  125.     register char *p1, *p2;
  126.     extern int onintr();
  127.  
  128.     onquit = signal(SIGQUIT, 1);
  129.     onhup = signal(SIGHUP, 1);
  130.     if(*(*argv+1) == 'm') vflag = 1;
  131.     argv++;
  132.     if (argc > 1 && **argv=='-') {
  133.         p1 = *argv+1;
  134.         while (*p1) {
  135.             switch (*p1++) {
  136.         case 'q':
  137.                 signal(SIGQUIT, 0);
  138.                 break;
  139.         case 'e':
  140.                 elfic = 1;
  141.                 break;
  142.         case 'p':
  143.                 vflag = 0;
  144.                 break;
  145.         case 's':
  146.                 vflag = -1;
  147.                 break;
  148.             }
  149.         }
  150.         if (!(*argv)[1])
  151.             vflag = -1;
  152.         argv++;
  153.         argc--;
  154.     }
  155.     if (argc>1) {
  156.         p1 = *argv;
  157.         p2 = savedfile;
  158.         while (*p2++ = *p1++);
  159.         breaks(p1-3);
  160.         globp = "r";
  161.     }
  162.     fendcore = sbrk(0);
  163.     if (vflag>0) puts("Editor");
  164.     init();
  165.     if ((signal(SIGINTR, 1) & 01) == 0)
  166.         signal(SIGINTR, onintr);
  167.     setexit();
  168.     commands(vflag);
  169.     unlink(tfname);
  170. }
  171.  
  172. commands(prompt)
  173. {
  174.     int getfile(), gettty();
  175.     register *a1, c;
  176.     register char *p;
  177.     char *p1,*p2;
  178.     int fd, r, n;
  179.  
  180.     for (;;) {
  181.     if (pflag) {
  182.         pflag = 0;
  183.         addr1 = addr2 = dot;
  184.         goto print;
  185.     }
  186.     if (prompt>0 && globp == 0) putch(PROMPT);
  187.     addr1 = 0;
  188.     addr2 = 0;
  189.     xflag = 0;
  190.     do {
  191.         addr1 = addr2;
  192.         if ((a1 = address())==0) {
  193.             c = getchar();
  194.             break;
  195.         }
  196.         addr2 = a1;
  197.         if ((c=getchar()) == ';') {
  198.             c = ',';
  199.             dot = a1;
  200.         }
  201.     } while (c==',');
  202.     if (addr1==0)
  203.         addr1 = addr2;
  204.     if (c>= 'A' && c<= 'Z')
  205.         c =| 040;
  206.     switch(c) {
  207.  
  208.     case 'a':
  209.         setdot();
  210.         newline();
  211.         append(gettty, addr2);
  212.         continue;
  213.  
  214.     case 'b':
  215.             if((c=peekc=getchar())== '+' || c =='-')
  216.                 peekc = 0;
  217.                 else if(c != '\n') error;
  218.             margin = c == '-' ? LBSIZE - 40 : LENGTH - 20;
  219.             newline();
  220.             continue;
  221.  
  222.     case 'c':
  223.         setdot();
  224.         newline();
  225.         delete();
  226.         append(gettty, addr1-1);
  227.         continue;
  228.  
  229.     case 'd':
  230.         setdot();
  231.         newline();
  232.         delete();
  233.         continue;
  234.  
  235.     case 'e':
  236.         if (elfic)
  237.             error;
  238.         setnoaddr();
  239.         if ((peekc = getchar()) != ' ')
  240.             error;
  241.         savedfile[0] = 0;
  242.         init();
  243.         addr2 = zero;
  244.         goto caseread;
  245.  
  246.     case 'f':
  247.         if (elfic)
  248.             error;
  249.         setnoaddr();
  250.         if ((c = getchar()) != '\n') {
  251.             peekc = c;
  252.             savedfile[0] = 0;
  253.             filename();
  254.         }
  255.         puts(savedfile);
  256.         continue;
  257.  
  258.     case 'g':
  259.         global(1);
  260.         continue;
  261.  
  262.     case 'h':
  263.         newline();
  264.         if((fd = open("/usr/lib/emhelp",0))<0) {
  265.             puts("/usr/lib/emhelp not found");
  266.             continue;
  267.         }
  268.             while (n = read( fd, linebuf, 512))
  269.                 write(1, linebuf, n);
  270.             close( fd);
  271.             continue;
  272.  
  273.     case 'i':
  274.         setdot();
  275.         nonzero();
  276.         newline();
  277.         append(gettty, addr2-1);
  278.         continue;
  279.  
  280.     case 'k':
  281.         if ((c = getchar()) < 'a' || c > 'z')
  282.             error;
  283.         newline();
  284.         setdot();
  285.         nonzero();
  286.         names[c-'a'] = *addr2 | 01;
  287.         continue;
  288.  
  289.     case 'm':
  290.         move(0);
  291.         continue;
  292.  
  293.     case '\n':
  294.         if (addr2==0)
  295.             addr2 = dot+1;
  296.         addr1 = addr2;
  297.         goto print;
  298.  
  299.     case 'l':
  300.         listf++;
  301.     case 'p':
  302.         newline();
  303.     print:
  304.         setdot();
  305.         nonzero();
  306.         a1 = addr1;
  307.         do
  308.             puts(getline(*a1++));
  309.         while (a1 <= addr2);
  310.         dot = addr2;
  311.         listf = 0;
  312.         continue;
  313.  
  314.     case 'o':
  315.         setdot();
  316.         op(globp);
  317.         continue;
  318.  
  319.     case 'q':
  320.         setnoaddr();
  321.         newline();
  322.         if (elfic) {
  323.             firstime = 1;
  324.             goto writeout;
  325.         }
  326.     quitit:
  327.         unlink(tfname);
  328.         exit();
  329.  
  330.     case 'r':
  331.     caseread:
  332.         filename();
  333.         if ((io = open(file, 0)) < 0) {
  334.             lastc = '\n';
  335.             error;
  336.         }
  337.         setall();
  338.         ninbuf = 0;
  339.         append(getfile, addr2);
  340.         exfile();
  341.         continue;
  342.  
  343.     case 'x':
  344.         xflag = 1;
  345.     case 's':
  346.         setdot();
  347.         nonzero();
  348.         substitute(globp);
  349.         xflag = 0;
  350.         continue;
  351.  
  352.     case 't':
  353.         move(1);
  354.         continue;
  355.  
  356.     case 'v':
  357.         global(0);
  358.         continue;
  359.  
  360.     case 'w':
  361.         if (elfic)
  362.             error;
  363.     writeout:
  364.         setall();
  365.         nonzero();
  366.         if (elfic) {
  367.             p1 = savedfile;
  368.             if (*p1==0)
  369.                 error;
  370.             p2 = file;
  371.             while (*p2++ = *p1++);
  372.         }
  373.         else
  374.             filename ();
  375.         if ((io = creat(file, 0666)) < 0)
  376.             error;
  377.         putfile();
  378.         exfile();
  379.         if (elfic)
  380.             goto quitit;
  381.         continue;
  382.  
  383.     case '"':
  384.         setdot();
  385.         newline();
  386.         nonzero();
  387.         dot = addr1;
  388.         if (dot == dol) error;
  389.         addr1 = dot+1;
  390.         addr2 = dot +LINES-1;
  391.         addr2 = addr2>dol? dol: addr2;
  392.     outlines:
  393.         putchar(FORM);
  394.         a1 = addr1-1;
  395.         while (++a1 <= addr2) puts(getline(*a1));
  396.         dot = addr2;
  397.         continue;
  398.  
  399.     case '&':
  400.         setdot();
  401.         newline();
  402.         nonzero();
  403.         dot = addr1;
  404.         addr1 = dot - (LINES-2);
  405.         addr2 = dot;
  406.         addr1 = addr1>zero? addr1: zero+1;
  407.         goto outlines;
  408.  
  409.     case '%':
  410.         newline();
  411.         setdot();
  412.         nonzero();
  413.         dot = addr1;
  414.         addr1 = dot - (LINES/2 - 2);
  415.         addr2 = dot + (LINES/2 - 2);
  416.         addr1 = addr1>zero? addr1 : zero+1;
  417.         addr2 = addr2>dol? dol : addr2;
  418.         a1 = addr1 - 1;
  419.         putchar(FORM);
  420.         while(++a1 <= addr2) {
  421.             if (a1 == dot) screensplit();
  422.             puts(getline(*a1));
  423.             if (a1 == dot) screensplit();
  424.         }
  425.         continue;
  426.  
  427.     case '>':
  428.         vflag = vflag>0? 0: vflag;
  429.         reset();
  430.  
  431.     case '<':
  432.         vflag = 1;
  433.         reset();
  434.  
  435.     case '=':
  436.         setall();
  437.         newline();
  438.         count[1] = (addr2-zero)&077777;
  439.         putd();
  440.         putchar('\n');
  441.         continue;
  442.  
  443.     case '!':
  444.         unix();
  445.         continue;
  446.  
  447.     case EOF:
  448.         if(prompt == -2 || ttyn(0) == 'x') return;
  449.         continue;
  450.  
  451.     }
  452.     error;
  453.     }
  454. }
  455.  
  456. address()
  457. {
  458.     register *a1, minus, c;
  459.     int n, relerr;
  460.  
  461.     minus = 0;
  462.     a1 = 0;
  463.     for (;;) {
  464.         c = getchar();
  465.         if ('0'<=c && c<='9') {
  466.             n = 0;
  467.             do {
  468.                 n =* 10;
  469.                 n =+ c - '0';
  470.             } while ((c = getchar())>='0' && c<='9');
  471.             peekc = c;
  472.             if (a1==0)
  473.                 a1 = zero;
  474.             if (minus<0)
  475.                 n = -n;
  476.             a1 =+ n;
  477.             minus = 0;
  478.             continue;
  479.         }
  480.         relerr = 0;
  481.         if (a1 || minus)
  482.             relerr++;
  483.         switch(c) {
  484.         case ' ':
  485.         case '\t':
  486.             continue;
  487.     
  488.         case '+':
  489.             minus++;
  490.             if (a1==0)
  491.                 a1 = dot;
  492.             continue;
  493.  
  494.         case '-':
  495.         case '^':
  496.             minus--;
  497.             if (a1==0)
  498.                 a1 = dot;
  499.             continue;
  500.     
  501.         case '?':
  502.         case '/':
  503.             compile(c);
  504.             a1 = dot;
  505.             for (;;) {
  506.                 if (c=='/') {
  507.                     a1++;
  508.                     if (a1 > dol)
  509.                         a1 = zero;
  510.                 } else {
  511.                     a1--;
  512.                     if (a1 < zero)
  513.                         a1 = dol;
  514.                 }
  515.                 if (execute(0, a1))
  516.                     break;
  517.                 if (a1==dot)
  518.                     {putchar('?'); error;}
  519.                         /* two '?'s for failed search */
  520.             }
  521.             break;
  522.     
  523.         case '$':
  524.             a1 = dol;
  525.             break;
  526.     
  527.         case '.':
  528.             a1 = dot;
  529.             break;
  530.  
  531.         case '\'':
  532.             if ((c = getchar()) < 'a' || c > 'z')
  533.                 error;
  534.             for (a1=zero; a1<=dol; a1++)
  535.                 if (names[c-'a'] == (*a1|01))
  536.                     break;
  537.             break;
  538.     
  539.         default:
  540.             peekc = c;
  541.             if (a1==0)
  542.                 return(0);
  543.             a1 =+ minus;
  544.             if (a1<zero || a1>dol)
  545.                 error;
  546.             return(a1);
  547.         }
  548.         if (relerr)
  549.             error;
  550.     }
  551. }
  552.  
  553. setdot()
  554. {
  555.     if (addr2 == 0)
  556.         addr1 = addr2 = dot;
  557.     if (addr1 > addr2)
  558.         error;
  559. }
  560.  
  561. setall()
  562. {
  563.     if (addr2==0) {
  564.         addr1 = zero+1;
  565.         addr2 = dol;
  566.         if (dol==zero)
  567.             addr1 = zero;
  568.     }
  569.     setdot();
  570. }
  571.  
  572. setnoaddr()
  573. {
  574.     if (addr2)
  575.         error;
  576. }
  577.  
  578. nonzero()
  579. {
  580.     if (addr1<=zero || addr2>dol)
  581.         error;
  582. }
  583.  
  584. newline()
  585. {
  586.     register c;
  587.  
  588.     if ((c = getchar()) == '\n')
  589.         return;
  590.     c = c >= 'A' && c <= 'Z' ? c + 32 : c;
  591.     if (c=='p' || c=='l') {
  592.         pflag++;
  593.         if (c=='l')
  594.             listf++;
  595.         if (getchar() == '\n')
  596.             return;
  597.     }
  598.     error;
  599. }
  600.  
  601. filename()
  602. {
  603.     register char *p1, *p2;
  604.     register c;
  605.  
  606.     count[1] = 0;
  607.     c = getchar();
  608.     if (c=='\n' || c==EOF) {
  609.         if (elfic && !firstime)
  610.             error;
  611.         else
  612.             firstime = 0;
  613.         p1 = savedfile;
  614.         if (*p1==0)
  615.             error;
  616.         p2 = file;
  617.         while (*p2++ = *p1++);
  618.         return;
  619.     }
  620.     if (c!=' ')
  621.         error;
  622.     while ((c = getchar()) == ' ');
  623.     if (c=='\n')
  624.         error;
  625.     p1 = file;
  626.     do {
  627.         *p1++ = c;
  628.     } while ((c = getchar()) != '\n');
  629.     *p1++ = 0;
  630.     if (savedfile[0]==0) {
  631.         p1 = savedfile;
  632.         p2 = file;
  633.         while (*p1++ = *p2++);
  634.         breaks(p1 - 3);
  635.     }
  636. }
  637.  
  638. breaks(p) char *p;
  639.  
  640. {
  641.     if(*p++ == '.')
  642.         if(*p == 'r' || *p == 'n') margin = LENGTH -20;
  643. }
  644.  
  645. exfile()
  646. {
  647.     close(io);
  648.     io = -1;
  649.     if (vflag>=0) {
  650.         putd();
  651.         putchar('\n');
  652.     }
  653. }
  654.  
  655. onintr()
  656. {
  657.     signal(SIGINTR, onintr);
  658.     putchar('\n');
  659.     lastc = '\n';
  660.     error;
  661. }
  662.  
  663. errfunc()
  664. {
  665.     register c;
  666.  
  667.     listf = 0;
  668.     puts("?");
  669.     count[0] = 0;
  670.     seek(0, 0, 2);
  671.     pflag = 0;
  672.     if (globp)
  673.         lastc = '\n';
  674.     globp = 0;
  675.     peekc = lastc;
  676.     while ((c = getchar()) != '\n' && c != EOF);
  677.     if (io > 0) {
  678.         close(io);
  679.         io = -1;
  680.     }
  681.     reset();
  682. }
  683.  
  684. getchar()
  685. {
  686.     if (lastc=peekc) {
  687.         peekc = 0;
  688.         return(lastc);
  689.     }
  690.     if (globp) {
  691.         if ((lastc = *globp++) != 0)
  692.             return(lastc);
  693.         globp = 0;
  694.         return(EOF);
  695.     }
  696.     if (read(0, &lastc, 1) <= 0)
  697.         return(lastc = EOF);
  698.     lastc =& 0177;
  699.     return(lastc);
  700. }
  701.  
  702. gettty()
  703. {
  704.     register c, gf;
  705.     register char *p;
  706.  
  707.     p = linebuf;
  708.     gf = globp;
  709.     while ((c = getchar()) != '\n') {
  710.         if (c==EOF) {
  711.             if (gf)
  712.                 peekc = c;
  713.             return(c);
  714.         }
  715.         if ((c =& 0177) == 0)
  716.             continue;
  717.         *p++ = c;
  718.         if (p >= &linebuf[LBSIZE-2])
  719.             error;
  720.     }
  721.     *p++ = 0;
  722.     if (linebuf[0]=='.' && linebuf[1]==0)
  723.         return(EOF);
  724.     return(0);
  725. }
  726.  
  727. getfile()
  728. {
  729.     register c;
  730.     register char *lp, *fp;
  731.  
  732.     lp = linebuf;
  733.     fp = nextip;
  734.     do {
  735.         if (--ninbuf < 0) {
  736.             if ((ninbuf = read(io, genbuf, LBSIZE)-1) < 0)
  737.                 return(EOF);
  738.             fp = genbuf;
  739.         }
  740.         if (lp >= &linebuf[LBSIZE])
  741.             error;
  742.         if ((*lp++ = c = *fp++ & 0177) == 0) {
  743.             lp--;
  744.             continue;
  745.         }
  746.         if (++count[1] == 0)
  747.             ++count[0];
  748.     } while (c != '\n');
  749.     *--lp = 0;
  750.     nextip = fp;
  751.     return(0);
  752. }
  753.  
  754. putfile()
  755. {
  756.     int *a1;
  757.     register char *fp, *lp;
  758.     register nib;
  759.  
  760.     nib = 512;
  761.     fp = genbuf;
  762.     a1 = addr1;
  763.     do {
  764.         lp = getline(*a1++);
  765.         for (;;) {
  766.             if (--nib < 0) {
  767.                 write(io, genbuf, fp-genbuf);
  768.                 nib = 511;
  769.                 fp = genbuf;
  770.             }
  771.             if (++count[1] == 0)
  772.                 ++count[0];
  773.             if ((*fp++ = *lp++) == 0) {
  774.                 fp[-1] = '\n';
  775.                 break;
  776.             }
  777.         }
  778.     } while (a1 <= addr2);
  779.     write(io, genbuf, fp-genbuf);
  780. }
  781.  
  782. append(f, a)
  783. int (*f)();
  784. {
  785.     register *a1, *a2, *rdot;
  786.     int nline, tl;
  787.     struct { int integer; };
  788.  
  789.     nline = 0;
  790.     dot = a;
  791.     while ((*f)() == 0) {
  792.         if (dol >= endcore) {
  793.             if (sbrk(1024) == -1)
  794.                 error;
  795.             endcore.integer =+ 1024;
  796.         }
  797.         tl = putline();
  798.         nline++;
  799.         a1 = ++dol;
  800.         a2 = a1+1;
  801.         rdot = ++dot;
  802.         while (a1 > rdot)
  803.             *--a2 = *--a1;
  804.         *rdot = tl;
  805.     }
  806.     return(nline);
  807. }
  808.  
  809. unix()
  810. {
  811.     register savint, pid, rpid;
  812.     int retcode;
  813.     char c,*lp,*fp;
  814.     pid = 0;
  815.     if ((c=getchar ()) != '!') {
  816.         lp = unixbuffer;
  817.         do {
  818.             if (c != '%')
  819.                 *lp++ = c;
  820.             else {
  821.             pid = 1;
  822.                 fp = savedfile;
  823.                 while ((*lp++ = *fp++));
  824.                 lp--;
  825.             }
  826.             c = getchar();
  827.         } while (c != '\n');
  828.         *lp = '\0';
  829.     }
  830.     else { pid = 1;
  831.         while (getchar () != '\n');}
  832.     if(pid) {
  833.         putchar('!');
  834.         puts(unixbuffer);
  835.     }
  836.     setnoaddr();
  837.     if ((pid = fork()) == 0) {
  838.         signal(SIGHUP, onhup);
  839.         signal(SIGQUIT, onquit);
  840.         execl ("/bin/sh", "sh", "-c", unixbuffer, 0);
  841.         exit();
  842.     }
  843.     savint = signal(SIGINTR, 1);
  844.     while ((rpid = wait(&retcode)) != pid && rpid != -1);
  845.     signal(SIGINTR, savint);
  846.     puts("!");
  847. }
  848.  
  849. delete()
  850. {
  851.     register *a1, *a2, *a3;
  852.  
  853.     nonzero();
  854.     a1 = addr1;
  855.     a2 = addr2+1;
  856.     a3 = dol;
  857.     dol =- a2 - a1;
  858.     do
  859.         *a1++ = *a2++;
  860.     while (a2 <= a3);
  861.     a1 = addr1;
  862.     if (a1 > dol)
  863.         a1 = dol;
  864.     dot = a1;
  865. }
  866.  
  867. getline(tl)
  868. {
  869.     register char *bp, *lp;
  870.     register nl;
  871.  
  872.     lp = linebuf;
  873.     bp = getblock(tl, READ);
  874.     nl = nleft;
  875.     tl =& ~0377;
  876.     while (*lp++ = *bp++)
  877.         if (--nl == 0) {
  878.             bp = getblock(tl=+0400, READ);
  879.             nl = nleft;
  880.         }
  881.     return(linebuf);
  882. }
  883.  
  884. putline()
  885. {
  886.     register char *bp, *lp;
  887.     register nl;
  888.     int tl;
  889.  
  890.     lp = linebuf;
  891.     tl = tline;
  892.     bp = getblock(tl, WRITE);
  893.     nl = nleft;
  894.     tl =& ~0377;
  895.     while (*bp = *lp++) {
  896.         if (*bp++ == '\n') {
  897.             *--bp = 0;
  898.             linebp = lp;
  899.             break;
  900.         }
  901.         if (--nl == 0) {
  902.             bp = getblock(tl=+0400, WRITE);
  903.             nl = nleft;
  904.         }
  905.     }
  906.     nl = tline;
  907.     tline =+ (((lp-linebuf)+03)>>1)&077776;
  908.     return(nl);
  909. }
  910.  
  911. getblock(atl, iof)
  912. {
  913.     extern read(), write();
  914.     register bno, off;
  915.     
  916.     bno = (atl>>8)&0377;
  917.     off = (atl<<1)&0774;
  918.     if (bno >= 255) {
  919.         puts(TMPERR);
  920.         error;
  921.     }
  922.     nleft = 512 - off;
  923.     if (bno==iblock) {
  924.         ichanged =| iof;
  925.         return(ibuff+off);
  926.     }
  927.     if (bno==oblock)
  928.         return(obuff+off);
  929.     if (iof==READ) {
  930.         if (ichanged)
  931.             blkio(iblock, ibuff, write);
  932.         ichanged = 0;
  933.         iblock = bno;
  934.         blkio(bno, ibuff, read);
  935.         return(ibuff+off);
  936.     }
  937.     if (oblock>=0)
  938.         blkio(oblock, obuff, write);
  939.     oblock = bno;
  940.     return(obuff+off);
  941. }
  942.  
  943. blkio(b, buf, iofcn)
  944. int (*iofcn)();
  945. {
  946.     seek(tfile, b, 3);
  947.     if ((*iofcn)(tfile, buf, 512) != 512) {
  948.         puts(TMPERR);
  949.         error;
  950.     }
  951. }
  952.  
  953. init()
  954. {
  955.     register char *p;
  956.     register pid;
  957.  
  958.     close(tfile);
  959.     tline = 0;
  960.     iblock = -1;
  961.     oblock = -1;
  962.     tfname = "/tmp/exxxxx";
  963.     ichanged = 0;
  964.     pid = getpid();
  965.     for (p = &tfname[11]; p > &tfname[6];) {
  966.         *--p = (pid&07) + '0';
  967.         pid =>> 3;
  968.     }
  969.     close(creat(tfname, 0600));
  970.     tfile = open(tfname, 2);
  971.     brk(fendcore);
  972.     dot = zero = dol = fendcore;
  973.     endcore = fendcore - 2;
  974. }
  975.  
  976. global(k)
  977. {
  978.     register char *gp;
  979.     register c;
  980.     register int *a1;
  981.     char globuf[GBSIZE];
  982.  
  983.     if (globp)
  984.         error;
  985.     setall();
  986.     nonzero();
  987.     if ((c=getchar())=='\n')
  988.         error;
  989.     compile(c);
  990.     gp = globuf;
  991.     while ((c = getchar()) != '\n') {
  992.         if (c==EOF)
  993.             error;
  994.         if (c=='\\') {
  995.             c = getchar();
  996.             if (c!='\n')
  997.                 *gp++ = '\\';
  998.         }
  999.         *gp++ = c;
  1000.         if (gp >= &globuf[GBSIZE-2])
  1001.             error;
  1002.     }
  1003.     *gp++ = '\n';
  1004.     *gp++ = 0;
  1005.     for (a1=zero; a1<=dol; a1++) {
  1006.         *a1 =& ~01;
  1007.         if (a1>=addr1 && a1<=addr2 && execute(0, a1)==k)
  1008.             *a1 =| 01;
  1009.     }
  1010.     for (a1=zero; a1<=dol; a1++) {
  1011.         if (*a1 & 01) {
  1012.             *a1 =& ~01;
  1013.             dot = a1;
  1014.             globp = globuf;
  1015.             commands(-2);
  1016.             a1 = zero;
  1017.         }
  1018.     }
  1019. }
  1020.  
  1021. substitute(inglob)
  1022. {
  1023.     register gsubf, *a1, nl;
  1024.     int nflag, nn, getsub();
  1025.  
  1026.     gsubf = compsub();
  1027.     nflag = gsubf > 1 ? 1 : 0;
  1028.     nn = 0;
  1029.     gsubf =& 01;
  1030.     gsubf =| xflag;
  1031.     for (a1 = addr1; a1 <= addr2; a1++) {
  1032.         if (execute(0, a1)==0)
  1033.             continue;
  1034.         inglob =| 01;
  1035.         if (confirmed()) { dosub(); nn++; }
  1036.         else donothing();
  1037.         if (gsubf) {
  1038.             while (*loc2) {
  1039.                 if (execute(1)==0)
  1040.                     break;
  1041.         if(confirmed()) {  dosub(); nn++; }
  1042.         else donothing();
  1043.         }
  1044.     }
  1045.         *a1 = putline();
  1046.         nl = append(getsub, a1);
  1047.         a1 =+ nl;
  1048.         addr2 =+ nl;
  1049.     }
  1050.     if (inglob==0)
  1051.         {putchar('?'); error; }
  1052.             /* two queries distinguish failed match */
  1053.     /* should use putd() and count here */
  1054.     if (nflag) printf( " %d \n", nn);
  1055. }
  1056.  
  1057. donothing() {
  1058.     char t1,t2;
  1059.             t1 = rhsbuf[0];
  1060.             t2 = rhsbuf[1];
  1061.             rhsbuf[0] = '&';
  1062.             rhsbuf[1] = 0;
  1063.             dosub();
  1064.             rhsbuf[0] = t1;
  1065.             rhsbuf[1] = t2;
  1066. }
  1067.  
  1068. confirmed()
  1069. {
  1070. int ch;
  1071.     if(xflag) {
  1072.         puts(linebuf);
  1073.         underline(linebuf, loc1, loc2, SCORE);
  1074.         ch = getchar();
  1075.         if ( ch != '\n') { while (getchar() != '\n');
  1076.                 if ( ch != CONFIRM ) puts("? '.' to confirm");
  1077.         }
  1078.         return (ch == CONFIRM ? 1: 0);
  1079.         }
  1080.     return 1;
  1081. }
  1082.  
  1083.  
  1084. underline (line, l1, l2, score)
  1085. char *line, *l1, *l2, *score;
  1086. {
  1087.     char *ch, *ll; int i;
  1088.     register char *p;
  1089.  
  1090.     p = line;
  1091.     ch = " ";
  1092.     ll = l1;
  1093.     i = 2;
  1094.     while (i--) {
  1095.         while (*p && p < ll) {
  1096.             write (1, (*p == '\t' ? p : ch),1);
  1097.             p++;
  1098.         }
  1099.         ch = score;
  1100.         ll = l2;
  1101.     }
  1102. }
  1103.  
  1104. screensplit()
  1105. {
  1106.     register a;
  1107.  
  1108.         a = LENGTH;
  1109.         while(a--) putchar(SPLIT);
  1110.         putchar('\n');
  1111. }
  1112.  
  1113. compsub()
  1114. {
  1115.     register seof, c;
  1116.     register char *p;
  1117.     int gsubf;
  1118.  
  1119.     gsubf = 0;
  1120.     if ((seof = getchar()) == '\n')
  1121.         error;
  1122.     compile(seof);
  1123.     p = rhsbuf;
  1124.     for (;;) {
  1125.         c = getchar();
  1126.         if (c=='\\')
  1127.             c = getchar() | 0200;
  1128.         if (c=='\n')
  1129.             error;
  1130.         if (c==seof)
  1131.             break;
  1132.         *p++ = c;
  1133.         if (p >= &rhsbuf[LBSIZE/2])
  1134.             error;
  1135.     }
  1136.     *p++ = 0;
  1137.     if(((peekc = getchar())| 040) == 'g') {
  1138.         peekc = 0;
  1139.         gsubf =| 1;
  1140.     }
  1141.     if (((peekc = getchar())| 040)  == 'n') {
  1142.         peekc = 0;
  1143.         gsubf =| 2;
  1144.     }
  1145.     newline();
  1146.     return(gsubf);
  1147. }
  1148.  
  1149. getsub()
  1150. {
  1151.     register char *p1, *p2;
  1152.  
  1153.     p1 = linebuf;
  1154.     if ((p2 = linebp) == 0)
  1155.         return(EOF);
  1156.     while (*p1++ = *p2++);
  1157.     linebp = 0;
  1158.     return(0);
  1159. }
  1160.  
  1161. dosub()
  1162. {
  1163.     register char *lp, *sp, *rp;
  1164.     int c;
  1165.  
  1166.     lp = linebuf;
  1167.     sp = genbuf;
  1168.     rp = rhsbuf;
  1169.     while (lp < loc1)
  1170.         *sp++ = *lp++;
  1171.     while (c = *rp++) {
  1172.         if (c=='&') {
  1173.             sp = place(sp, loc1, loc2);
  1174.             continue;
  1175.         } else if (c<0 && (c =& 0177) >='1' && c < NBRA+'1') {
  1176.             sp = place(sp, braslist[c-'1'], braelist[c-'1']);
  1177.             continue;
  1178.         }
  1179.         *sp++ = c&0177;
  1180.         if (sp >= &genbuf[LBSIZE])
  1181.             error;
  1182.     }
  1183.     lp = loc2;
  1184.     loc2 = sp + linebuf - genbuf;
  1185.     while (*sp++ = *lp++)
  1186.         if (sp >= &genbuf[LBSIZE])
  1187.             error;
  1188.     lp = linebuf;
  1189.     sp = genbuf;
  1190.     while (*lp++ = *sp++);
  1191. }
  1192.  
  1193. place(asp, al1, al2)
  1194. {
  1195.     register char *sp, *l1, *l2;
  1196.  
  1197.     sp = asp;
  1198.     l1 = al1;
  1199.     l2 = al2;
  1200.     while (l1 < l2) {
  1201.         *sp++ = *l1++;
  1202.         if (sp >= &genbuf[LBSIZE])
  1203.             error;
  1204.     }
  1205.     return(sp);
  1206. }
  1207.  
  1208. move(cflag)
  1209. {
  1210.     register int *adt, *ad1, *ad2;
  1211.     int getcopy();
  1212.  
  1213.     setdot();
  1214.     nonzero();
  1215.     if ((adt = address())==0)
  1216.         error;
  1217.     newline();
  1218.     ad1 = addr1;
  1219.     ad2 = addr2;
  1220.     if (cflag) {
  1221.         ad1 = dol;
  1222.         append(getcopy, ad1++);
  1223.         ad2 = dol;
  1224.     }
  1225.     ad2++;
  1226.     if (adt<ad1) {
  1227.         dot = adt + (ad2-ad1);
  1228.         if ((++adt)==ad1)
  1229.             return;
  1230.         reverse(adt, ad1);
  1231.         reverse(ad1, ad2);
  1232.         reverse(adt, ad2);
  1233.     } else if (adt >= ad2) {
  1234.         dot = adt++;
  1235.         reverse(ad1, ad2);
  1236.         reverse(ad2, adt);
  1237.         reverse(ad1, adt);
  1238.     } else
  1239.         error;
  1240. }
  1241.  
  1242. reverse(aa1, aa2)
  1243. {
  1244.     register int *a1, *a2, t;
  1245.  
  1246.     a1 = aa1;
  1247.     a2 = aa2;
  1248.     for (;;) {
  1249.         t = *--a2;
  1250.         if (a2 <= a1)
  1251.             return;
  1252.         *a2 = *a1;
  1253.         *a1++ = t;
  1254.     }
  1255. }
  1256.  
  1257. getcopy()
  1258. {
  1259.     if (addr1 > addr2)
  1260.         return(EOF);
  1261.     getline(*addr1++);
  1262.     return(0);
  1263. }
  1264.  
  1265. compile(aeof)
  1266. {
  1267.     register eof, c;
  1268.     register char *ep;
  1269.     char *lastep;
  1270.     char bracket[NBRA], *bracketp;
  1271.     int nbra;
  1272.     int cclcnt;
  1273.  
  1274.     ep = expbuf;
  1275.     eof = aeof;
  1276.     bracketp = bracket;
  1277.     nbra = 0;
  1278.     if ((c = getchar()) == eof) {
  1279.         if (*ep==0)
  1280.             error;
  1281.         return;
  1282.     }
  1283.     circfl = 0;
  1284.     if (c=='^') {
  1285.         c = getchar();
  1286.         circfl++;
  1287.     }
  1288.     if (c=='*')
  1289.         goto cerror;
  1290.     peekc = c;
  1291.     for (;;) {
  1292.         if (ep >= &expbuf[ESIZE])
  1293.             goto cerror;
  1294.         c = getchar();
  1295.         if (c==eof) {
  1296.             *ep++ = CEOF;
  1297.             return;
  1298.         }
  1299.         if (c!='*')
  1300.             lastep = ep;
  1301.         switch (c) {
  1302.  
  1303.         case '\\':
  1304.             if ((c = getchar())=='(') {
  1305.                 if (nbra >= NBRA)
  1306.                     goto cerror;
  1307.                 *bracketp++ = nbra;
  1308.                 *ep++ = CBRA;
  1309.                 *ep++ = nbra++;
  1310.                 continue;
  1311.             }
  1312.             if (c == ')') {
  1313.                 if (bracketp <= bracket)
  1314.                     goto cerror;
  1315.                 *ep++ = CKET;
  1316.                 *ep++ = *--bracketp;
  1317.                 continue;
  1318.             }
  1319.             *ep++ = CCHR;
  1320.             if (c=='\n')
  1321.                 goto cerror;
  1322.             *ep++ = c;
  1323.             continue;
  1324.  
  1325.         case '.':
  1326.             *ep++ = CDOT;
  1327.             continue;
  1328.  
  1329.         case '\n':
  1330.             goto cerror;
  1331.  
  1332.         case '*':
  1333.             if (*lastep==CBRA || *lastep==CKET)
  1334.                 error;
  1335.             *lastep =| STAR;
  1336.             continue;
  1337.  
  1338.         case '$':
  1339.             if ((peekc=getchar()) != eof)
  1340.                 goto defchar;
  1341.             *ep++ = CDOL;
  1342.             continue;
  1343.  
  1344.         case '[':
  1345.             *ep++ = CCL;
  1346.             *ep++ = 0;
  1347.             cclcnt = 1;
  1348.             if ((c=getchar()) == '^') {
  1349.                 c = getchar();
  1350.                 ep[-2] = NCCL;
  1351.             }
  1352.             do {
  1353.                 if (c=='\n')
  1354.                     goto cerror;
  1355.                 *ep++ = c;
  1356.                 cclcnt++;
  1357.                 if (ep >= &expbuf[ESIZE])
  1358.                     goto cerror;
  1359.             } while ((c = getchar()) != ']');
  1360.             lastep[1] = cclcnt;
  1361.             continue;
  1362.  
  1363.         defchar:
  1364.         default:
  1365.             *ep++ = CCHR;
  1366.             *ep++ = c;
  1367.         }
  1368.     }
  1369.    cerror:
  1370.     expbuf[0] = 0;
  1371.     error;
  1372. }
  1373.  
  1374. execute(gf, addr)
  1375. int *addr;
  1376. {
  1377.     register char *p1, *p2, c;
  1378.  
  1379.     if (gf) {
  1380.         if (circfl)
  1381.             return(0);
  1382.         p1 = linebuf;
  1383.         p2 = genbuf;
  1384.         while (*p1++ = *p2++);
  1385.         locs = p1 = loc2;
  1386.     } else {
  1387.         if (addr==zero)
  1388.             return(0);
  1389.         p1 = getline(*addr);
  1390.         locs = 0;
  1391.     }
  1392.     p2 = expbuf;
  1393.     if (circfl) {
  1394.         loc1 = p1;
  1395.         return(advance(p1, p2));
  1396.     }
  1397.     /* fast check for first character */
  1398.     if (*p2==CCHR) {
  1399.         c = p2[1];
  1400.         do {
  1401.             if (*p1!=c)
  1402.                 continue;
  1403.             if (advance(p1, p2)) {
  1404.                 loc1 = p1;
  1405.                 return(1);
  1406.             }
  1407.         } while (*p1++);
  1408.         return(0);
  1409.     }
  1410.     /* regular algorithm */
  1411.     do {
  1412.         if (advance(p1, p2)) {
  1413.             loc1 = p1;
  1414.             return(1);
  1415.         }
  1416.     } while (*p1++);
  1417.     return(0);
  1418. }
  1419.  
  1420. advance(alp, aep)
  1421. {
  1422.     register char *lp, *ep, *curlp;
  1423.     char *nextep;
  1424.  
  1425.     lp = alp;
  1426.     ep = aep;
  1427.     for (;;) switch (*ep++) {
  1428.  
  1429.     case CCHR:
  1430.         if (*ep++ == *lp++)
  1431.             continue;
  1432.         return(0);
  1433.  
  1434.     case CDOT:
  1435.         if (*lp++)
  1436.             continue;
  1437.         return(0);
  1438.  
  1439.     case CDOL:
  1440.         if (*lp==0)
  1441.             continue;
  1442.         return(0);
  1443.  
  1444.     case CEOF:
  1445.         loc2 = lp;
  1446.         return(1);
  1447.  
  1448.     case CCL:
  1449.         if (cclass(ep, *lp++, 1)) {
  1450.             ep =+ *ep;
  1451.             continue;
  1452.         }
  1453.         return(0);
  1454.  
  1455.     case NCCL:
  1456.         if (cclass(ep, *lp++, 0)) {
  1457.             ep =+ *ep;
  1458.             continue;
  1459.         }
  1460.         return(0);
  1461.  
  1462.     case CBRA:
  1463.         braslist[*ep++] = lp;
  1464.         continue;
  1465.  
  1466.     case CKET:
  1467.         braelist[*ep++] = lp;
  1468.         continue;
  1469.  
  1470.     case CDOT|STAR:
  1471.         curlp = lp;
  1472.         while (*lp++);
  1473.         goto star;
  1474.  
  1475.     case CCHR|STAR:
  1476.         curlp = lp;
  1477.         while (*lp++ == *ep);
  1478.         ep++;
  1479.         goto star;
  1480.  
  1481.     case CCL|STAR:
  1482.     case NCCL|STAR:
  1483.         curlp = lp;
  1484.         while (cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
  1485.         ep =+ *ep;
  1486.         goto star;
  1487.  
  1488.     star:
  1489.         do {
  1490.             lp--;
  1491.             if (lp==locs)
  1492.                 break;
  1493.             if (advance(lp, ep))
  1494.                 return(1);
  1495.         } while (lp > curlp);
  1496.         return(0);
  1497.  
  1498.     default:
  1499.         error;
  1500.     }
  1501. }
  1502.  
  1503. cclass(aset, ac, af)
  1504. {
  1505.     register char *set, c;
  1506.     register n;
  1507.  
  1508.     set = aset;
  1509.     if ((c = ac) == 0)
  1510.         return(0);
  1511.     n = *set++;
  1512.     while (--n)
  1513.         if (*set++ == c)
  1514.             return(af);
  1515.     return(!af);
  1516. }
  1517.  
  1518. putd()
  1519. {
  1520.     register r;
  1521.     extern ldivr;
  1522.  
  1523.     count[1] = ldiv(count[0], count[1], 10);
  1524.     count[0] = 0;
  1525.     r = ldivr;
  1526.     if (count[1])
  1527.         putd();
  1528.     putchar(r + '0');
  1529. }
  1530.  
  1531. puts(as)
  1532. char *as;
  1533. {
  1534.     register char *sp;
  1535.  
  1536.     sp = as;
  1537.     col = 0;
  1538.     while (*sp)
  1539.         putchar(*sp++);
  1540.     putchar('\n');
  1541. }
  1542.  
  1543. char    line[70];
  1544. char    *linp    line;
  1545.  
  1546. putchar(ac)
  1547. {
  1548.     register char *lp;
  1549.     register c;
  1550.  
  1551.     lp = linp;
  1552.     c = ac;
  1553.     if (listf) {
  1554.         col++;
  1555.         if (col >= 72) {
  1556.             col = 0;
  1557.             *lp++ = '\\';
  1558.             *lp++ = '\n';
  1559.         }
  1560.         if (c=='\t') {
  1561.             c = '>';
  1562.             goto esc;
  1563.         }
  1564.         if (c=='\b') {
  1565.             c = '<';
  1566.         esc:
  1567.             *lp++ = '-';
  1568.             *lp++ = '\b';
  1569.             *lp++ = c;
  1570.             goto out;
  1571.         }
  1572.         if (c<' ' && c!= '\n') {
  1573.             *lp++ = '\\';
  1574.             *lp++ = (c>>3)+'0';
  1575.             *lp++ = (c&07)+'0';
  1576.             col =+ 2;
  1577.             goto out;
  1578.         }
  1579.     }
  1580.     *lp++ = c;
  1581. out:
  1582.     if(c == '\n' || lp >= &line[64]) {
  1583.         linp = line;
  1584.         write(1, line, lp-line);
  1585.         return;
  1586.     }
  1587.     linp = lp;
  1588. }
  1589.  
  1590. /*
  1591.  * Get process ID routine if system call is unavailable.
  1592. getpid()
  1593. {
  1594.     register f;
  1595.     int b[1];
  1596.  
  1597.     f = open("/dev/kmem", 0);
  1598.     if(f < 0)
  1599.         return(-1);
  1600.     seek(f, 0140074, 0);
  1601.     read(f, b, 2);
  1602.     seek(f, b[0]+8, 0);
  1603.     read(f, b, 2);
  1604.     close(f);
  1605.     return(b[0]);
  1606. }
  1607.  */
  1608.