home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / se / part02 / edit.c next >
Encoding:
C/C++ Source or Header  |  1987-01-25  |  25.7 KB  |  1,428 lines

  1. #ifndef lint
  2. static char RCSid[] = "$Header: edit.c,v 1.3 86/07/11 15:11:34 osadr Exp $";
  3. #endif
  4.  
  5. /*
  6.  * $Log:    edit.c,v $
  7.  * Revision 1.3  86/07/11  15:11:34  osadr
  8.  * Removed Georgia Tech specific code.
  9.  * 
  10.  * Revision 1.2  86/05/27  17:44:56  osadr
  11.  * Removed flexnames dependancy; PREVLINE[2] --> PREVLN[2].
  12.  * Improved the sysname() routine, particularly to use the nodename
  13.  * member of the utsname structure under System V.
  14.  * 
  15.  * Revision 1.1  86/05/06  13:37:16  osadr
  16.  * Initial revision
  17.  * 
  18.  * 
  19.  */
  20.  
  21. /*
  22. ** edit.c
  23. **
  24. ** editor main routine, plus other routines used a lot.
  25. */
  26.  
  27. #include "se.h"
  28. #include "extern.h"
  29.  
  30. static char Savknm = DEFAULTNAME;    /* saved mark name for < and > */
  31.  
  32. /* edit --- main routine for screen editor */
  33.  
  34. edit (argc, argv)
  35. int argc;
  36. char *argv[];
  37. {
  38.     int cursav, status, len, cursor;
  39.     int ckglob (), docmd (), doglob (), doread ();
  40.     int getlst (), nextln (), prevln ();
  41.     char lin[MAXLINE], term;
  42.  
  43.     watch ();       /* display time of day */
  44.  
  45. #ifdef LOG_USAGE
  46.     log ();        /* log who used the program */
  47. #endif
  48.  
  49.     serc ();    /* execute commands in ./.serc or $HOME/.serc */
  50.  
  51.     status = OK;
  52.  
  53.     while (status == OK && Argno < argc)
  54.     {
  55.         strcpy (lin, argv[Argno]);
  56.         loadstr (lin, Argno, POOPCOL, Ncols);
  57.         if (lin[0] == '-')
  58.         {
  59.             len = strlen (lin) + 1;
  60.             lin[len - 1] = '\n';
  61.             lin[len] = EOS;
  62.             len = 0;
  63.             status = doopt (lin, &len);
  64.         }
  65.         else
  66.         {
  67.             dfltsopt (lin);
  68.             status = doread (Lastln, lin, NO);
  69.         }
  70.         Argno++;
  71.     }
  72.  
  73.     if (status == ERR)
  74.     {
  75.         if (Errcode == EHANGUP)
  76.             hangup ();
  77.         printverboseerrormessage ();
  78.     }
  79.     else
  80.         Curln = min (1, Lastln);
  81.  
  82.     Buffer_changed = NO;
  83.     First_affected = 1;     /* maintained by updscreen & commands */
  84.     updscreen ();
  85.  
  86.     if (status != ERR)    /* leave offending file name or option */
  87.         lin[0] = EOS;
  88.     cursor = 0;
  89.  
  90.     /* main command loop */
  91.     do {
  92.         intrpt ();    /* discard pending breaks (interrupts) */
  93.         if (Lost_lines > GARB_THRESHOLD
  94.             && (Lastln + Limcnt) / Lost_lines <= GARB_FACTOR)
  95.             garbage_collect ();
  96.  
  97.         mswait ();    /* check for pending messages */
  98.         Cmdrow = Botrow + 1;    /* reset the command line location */
  99.         prompt ("cmd>");
  100.         getcmd (lin, 0, &cursor, &term);
  101.         remark ("");    /* clear out any error messages */
  102.  
  103.         while (term == CURSOR_UP || term == CURSOR_DOWN
  104.             || term == CURSOR_SAME)
  105.         {
  106.             switch (term) {
  107.             case CURSOR_UP:
  108.                 if (Curln > 1)
  109.                     Curln--;
  110.                 else
  111.                     Curln = Lastln;
  112.                 break;
  113.  
  114.             case CURSOR_DOWN:
  115.                 if (Curln < Lastln)
  116.                     Curln++;
  117.                 else
  118.                     Curln = min (1, Lastln);
  119.                 break;
  120.             }
  121.             adjust_window (Curln, Curln);
  122.             updscreen ();
  123.             getcmd (lin, 0, &cursor, &term);
  124.         }
  125.  
  126.         prompt ("");    /* remove prompt */
  127.  
  128.         cursav = Curln;        /* remember it in case of an error */
  129.         Errcode = EEGARB;    /* default error code for garbage at end */
  130.  
  131.         len = 0;
  132.         if (getlst (lin, &len, &status) == OK)
  133.         {
  134.             if (ckglob (lin, &len, &status) == OK)
  135.                 doglob (lin, &len, &cursav, &status);
  136.             else if (status != ERR)
  137.                 docmd (lin, len, NO, &status);
  138.         }
  139.         if (status == ERR)
  140.         {
  141.             if (Errcode == EHANGUP)
  142.                 hangup ();
  143.             printverboseerrormessage ();
  144.             Curln = min (cursav, Lastln);
  145.         }
  146.         else if (term != FUNNY)
  147.         {
  148.             cursor = 0;
  149.             lin[0] = EOS;
  150.         }
  151.  
  152.         adjust_window (Curln, Curln);
  153.         updscreen ();
  154.  
  155.     } while (status != EOF);
  156.  
  157.     clrscreen ();
  158.     clrbuf ();
  159.     tflush ();
  160.  
  161.     return;
  162. }
  163.  
  164.  
  165. /* getlst --- collect line numbers (if any) at lin[*i], increment i */
  166.  
  167. int getlst (lin, i, status)
  168. char lin[];
  169. int *i, *status;
  170. {
  171.     int num;
  172.     int getone ();
  173.  
  174.     Line2 = 0;
  175.     for (Nlines = 0; getone (lin, i, &num, status) == OK; )
  176.     {
  177.         Line1 = Line2;
  178.         Line2 = num;
  179.         Nlines++;
  180.         if (lin[*i] != ',' && lin[*i] != ';')
  181.             break;
  182.         if (lin[*i] == ';')
  183.             Curln = num;
  184.         (*i)++;
  185.     }
  186.  
  187.     if (Nlines > 2)
  188.         Nlines = 2;
  189.  
  190.     if (Nlines <= 1)
  191.         Line1 = Line2;
  192.  
  193.     if (Line1 > Line2)
  194.     {
  195.         *status = ERR;
  196.         Errcode = EBACKWARD;
  197.     }
  198.  
  199.     if (*status != ERR)
  200.         *status = OK;
  201.  
  202.     return (*status);
  203. }
  204.  
  205.  
  206. /* getnum --- convert one term to line number */
  207.  
  208. int getnum (lin, i, pnum, status)
  209. char lin[];
  210. register int *i, *pnum, *status;
  211. {
  212.     int j, ret;
  213.     int ctoi (), optpat (), ptscan (), knscan (), getkn ();
  214.     int k;
  215.  
  216.     ret = OK;
  217.     SKIPBL (lin, *i);
  218.     if (lin[*i] >= Rel_a && lin[*i] <= Rel_z && Absnos == NO)
  219.         *pnum = Topln - Toprow + lin[*i] - Rel_a;
  220.     else if (lin[*i] == CURLINE)
  221.         *pnum = Curln;
  222.     else if (lin[*i] == PREVLN || lin[*i] == PREVLN2)
  223.         *pnum = Curln - 1;
  224.     else if (lin[*i] == LASTLINE)
  225.         *pnum = Lastln;
  226.     else if (lin[*i] == SCAN || lin[*i] == BACKSCAN)
  227.     {
  228.         int missing_delim = YES;
  229.  
  230.         /* see if trailing delim supplied, since command can follow pattern */
  231.         for (k = *i + 1; lin[k] != EOS; k++)
  232.             if (lin[k] == ESCAPE)
  233.                 k++;    /* skip esc, loop will skip escaped char */
  234.             else if (lin[k] == lin[*i])
  235.             {
  236.                 missing_delim = NO;
  237.                 break;
  238.             }
  239.             /* else
  240.                 continue */
  241.         
  242.         if (missing_delim == YES)
  243.         {
  244.             for (; lin[k] != EOS; k++)
  245.                 ;
  246.             k--;        /* k now at newline */
  247.  
  248.             /* supply trailing delim */
  249.             lin[k] = lin[*i];
  250.             lin[++k] = '\n';
  251.             lin[++k] = EOS;
  252.             Peekc = SKIP_RIGHT;
  253.         }
  254.  
  255.         if (optpat (lin, i) == ERR)
  256.             ret = ERR;
  257.         else if (lin[*i] == SCAN)
  258.             ret = ptscan (FORWARD, pnum);
  259.         else 
  260.             ret = ptscan (BACKWARD, pnum);
  261.     }
  262.     else if (lin[*i] == SEARCH || lin[*i] == BACKSEARCH)
  263.     {
  264.         j = *i;
  265.         (*i)++;
  266.         if (getkn (lin, i, &Savknm, Savknm) == ERR)
  267.             ret = ERR;
  268.         else if (lin[j] == SEARCH)
  269.             ret = knscan (FORWARD, pnum);
  270.         else
  271.             ret = knscan (BACKWARD, pnum);
  272.         (*i)--;
  273.     }
  274.     else if (isdigit (lin[*i]))
  275.     {
  276.         *pnum = ctoi (lin, i);
  277.         (*i)--;
  278.     }
  279.     else if (lin[*i] == TOPLINE)
  280.         *pnum = Topln;
  281.     else
  282.         ret = EOF;
  283.  
  284.     if (ret == OK)
  285.         (*i)++;
  286.     *status = ret;
  287.     return (ret);
  288. }
  289.  
  290.  
  291. /* getone --- evaluate one line number expression */
  292.  
  293. int getone (lin, i, num, status)
  294. char lin[];
  295. register int *i, *num, *status;
  296. {
  297.     int pnum, ret;
  298.     int getnum ();
  299.     char porm;    /* "plus or minus" (sic) */
  300.  
  301.     ret = EOF;    /* assume we won't find anything for now */
  302.     *num = 0;
  303.  
  304.     if (getnum (lin, i, num, status) == OK)        /* first term */
  305.     {
  306.         ret = OK;    /* to indicate we've seen something */
  307.         do {            /* + or - terms */
  308.             porm = EOS;
  309.             SKIPBL (lin, *i);
  310.             if (lin[*i] == '-' || lin[*i] == '+')
  311.             {
  312.                 porm = lin[*i];
  313.                 (*i)++;
  314.             }
  315.             if (getnum (lin, i, &pnum, status) == OK)
  316.                 if (porm == '-')
  317.                     *num -= pnum;
  318.                 else
  319.                     *num += pnum;
  320.             if (*status == EOF && porm != EOS)    /* trailing + or - */
  321.                 *status = ERR;
  322.         } while (*status == OK);
  323.     }
  324.  
  325.     if (*num < 0 || *num > Lastln)    /* make sure number is in range */
  326.     {
  327.         *status = ERR;
  328.         Errcode = EORANGE;
  329.     }
  330.  
  331.     if (*status == ERR)
  332.         ret = ERR;
  333.     else
  334.         *status = ret;
  335.  
  336.     return (ret);
  337. }
  338.  
  339.  
  340. #ifndef OLD_SCRATCH
  341. #ifndef OLD_GLOB
  342. static int special_casing = NO;
  343. #endif
  344. #endif
  345.  
  346. /* ckglob --- if global prefix, mark lines to be affected */
  347.  
  348. int ckglob (lin, i, status)
  349. char lin[];
  350. int *i, *status;
  351. {
  352.     register int line, tmp;
  353.     int usepat, usemark;
  354.     int defalt (), match (), optpat (), getkn ();
  355.     register LINEDESC *k;
  356.     LINEDESC *gettxt (), *getind ();
  357.  
  358.     *status = OK;
  359.     usepat = EOF;
  360.     usemark = EOF;
  361.  
  362. #ifndef OLD_SCRATCH
  363. #ifndef OLD_GLOB
  364.     if (    /* g/^/m0  or g/$/m0 -- special case the pathological */
  365.         /* cases in order to save time */
  366.         (lin[*i] == GLOBAL || lin[*i] == UCGLOBAL)
  367.         && (lin[*i + 1] == lin[*i + 3])
  368.         && (lin[*i + 2] == '^' || lin[*i + 2] == '$')
  369.         && (lin[*i + 4] == MOVECOM || lin[*i + 4] == UCMOVECOM)
  370.         && (lin[*i + 5] == '0' && lin[*i + 6] == '\n')   )
  371.     {
  372.         special_casing = YES;
  373.         remark ("GLOB");
  374.         return (OK);
  375.     }
  376. #endif
  377. #endif
  378.     if (lin[*i] == GMARK || lin[*i] == XMARK)    /* global markname prefix? */
  379.     {
  380.         if (lin[*i] == GMARK)    /* tag lines with the specified markname */
  381.             usemark = YES;
  382.         else            /* tag lines without the specified markname */
  383.             usemark = NO;
  384.         (*i)++;
  385.         *status = getkn (lin, i, &Savknm, Savknm);
  386.     }
  387.  
  388.     if (*status == OK)    /* check for a pattern prefix too */
  389.     {
  390.         if (lin[*i] == GLOBAL || lin[*i] == UCGLOBAL)
  391.             usepat = YES;
  392.  
  393.         if (lin[*i] == EXCLUDE || lin[*i] == UCEXCLUDE)
  394.             usepat = NO;
  395.  
  396.         if (usepat != EOF)
  397.         {
  398.             (*i)++;
  399.             if (optpat (lin, i) == ERR)
  400.                 *status = ERR;
  401.             else
  402.                 (*i)++;
  403.         }
  404.     }
  405.  
  406.     if (*status == OK && usepat == EOF && usemark == EOF)
  407.         *status = EOF;
  408.     else if (*status == OK)
  409.         defalt (1, Lastln);
  410.  
  411.     if (*status == OK)    /* no errors so far, safe to proceed */
  412.     {
  413.         remark ("GLOB");
  414.  
  415.         k = Line0;      /* unmark all lines preceeding range */
  416.         for (line = 0; line < Line1; line++)
  417.         {
  418.             k -> Globmark = NO;
  419.             k = NEXTLINE(k);
  420.         }
  421.  
  422.         for (; line <= Line2; line++)    /* mark lines in range */
  423.         {
  424.             if (intrpt ())
  425.             {
  426.                 *status = ERR;
  427.                 return (*status);
  428.             }
  429.             tmp = NO;
  430.             if (usemark == EOF
  431.                 || usemark == YES && k -> Markname == Savknm
  432.                 || usemark == NO && k -> Markname != Savknm)
  433.             {
  434.                 if (usepat == EOF)    /* no global pattern to look for */
  435.                     tmp = YES;
  436.                 else    /* there is also a pattern to look for */
  437.                 {
  438.                     gtxt (k);
  439.                     if (match (Txt, Pat) == usepat)
  440.                         tmp = YES;
  441.                 }
  442.             }
  443.  
  444.             k -> Globmark = tmp;
  445.  
  446.             k = NEXTLINE(k);
  447.         }
  448.  
  449. #ifdef OLD_SCRATCH
  450.         /* mark remaining lines */
  451.         for (; k != Line0; k = k -> Nextline)
  452.             k -> Globmark = NO;
  453. #else
  454.         /* mark remaining lines */
  455.         for (; line <= Lastln; line++)
  456.         {
  457.             k -> Globmark = NO;
  458.             k = NEXTLINE (k);
  459.         }
  460. #endif
  461.  
  462.         remark ("");
  463.     }
  464.  
  465.     return (*status);
  466. }
  467.  
  468.  
  469. /* doglob --- do command at lin[i] on all marked lines */
  470.  
  471. int doglob (lin, i, cursav, status)
  472. char lin[];
  473. int *i, *cursav, *status;
  474. {
  475.     register int istart, line;
  476.     int docmd (), getlst (), nextln ();
  477.     register LINEDESC *k;
  478.     LINEDESC *getind ();
  479.  
  480. #ifndef OLD_SCRATCH
  481. #ifndef OLD_GLOB
  482.     if (special_casing)
  483.     {
  484.         /*
  485.         remark ("Warp 7, Captain!");
  486.         */
  487.         /* not on the screen too long anyway */
  488.         reverse (1, Lastln);
  489.         Curln = Lastln;
  490.         special_casing = NO;
  491.         Buffer_changed = YES;
  492.         First_affected = min (1, First_affected);
  493.         remark ("");
  494.         adjust_window (Curln, Curln);
  495.         updscreen ();
  496.         return (OK);
  497.     }
  498. #endif
  499. #endif
  500.     *status = OK;
  501.     istart = *i;
  502.     k = Line0;
  503.     line = 0;
  504.  
  505.     do {
  506.         line++;
  507.         k = NEXTLINE(k);
  508.         if (k -> Globmark == YES)    /* line is marked */
  509.         {
  510.             k -> Globmark = NO;    /* unmark the line */
  511.             Curln = line;
  512.             *cursav = Curln;    /* remember where we are */
  513.             *i = istart;
  514.             if (getlst (lin, i, status) == OK)
  515.                 docmd (lin, *i, YES, status);
  516.             line = 0;        /* lines may have been moved */
  517.             k = Line0;
  518.         }
  519.         if (intrpt ())
  520.             *status = ERR;
  521.     } while (line <= Lastln && *status == OK);
  522.  
  523.     return (*status);
  524. }
  525.  
  526.  
  527. /* ckchar --- look for ch or altch on lin at i, set flag if found */
  528.  
  529. int ckchar (ch, altch, lin, i, flag, status)
  530. char ch, altch, lin[];
  531. int *i, *flag, *status;
  532. {
  533.  
  534.     if (lin[*i] == ch || lin[*i] == altch)
  535.     {
  536.         (*i)++;
  537.         *flag = YES;
  538.     }
  539.     else
  540.         *flag = NO;
  541.  
  542.     *status = OK;
  543.     return (OK);
  544. }
  545.  
  546.  
  547. /* ckp --- check for "p" after command */
  548.  
  549. int ckp (lin, i, pflag, status)
  550. char lin[];
  551. int i, *pflag, *status;
  552. {
  553.  
  554.     if (lin[i] == PRINT || lin[i] == UCPRINT)
  555.     {
  556.         i++;
  557.         *pflag = YES;
  558.     }
  559.     else
  560.         *pflag = NO;
  561.  
  562.     if (lin[i] == '\n')
  563.         *status = OK;
  564.     else
  565.         *status = ERR;
  566.  
  567.     return (*status);
  568. }
  569.  
  570.  
  571. /* ckupd --- make sure it is ok to destroy the buffer */
  572.  
  573. int ckupd (lin, i, cmd, status)
  574. char lin[], cmd;
  575. int *i, *status;
  576. {
  577.     int flag;
  578.     int ckchar ();
  579.  
  580.     *status = ckchar (ANYWAY, ANYWAY, lin, i, &flag, status);
  581.     if (flag == NO && Buffer_changed == YES && Probation != cmd)
  582.     {
  583.         *status = ERR;
  584.         Errcode = ESTUPID;
  585.         Probation = cmd;        /* if same command is repeated, */
  586.     }                       /* we'll keep quiet */
  587.  
  588.     return (*status);
  589. }
  590.  
  591.  
  592. /* defalt --- set defaulted line numbers */
  593.  
  594. defalt (def1, def2)
  595. int def1, def2;
  596. {
  597.  
  598.     if (Nlines == 0)        /* no line numbers supplied, use defaults */
  599.     {
  600.         Line1 = def1;
  601.         Line2 = def2;
  602.     }
  603.  
  604.     return;
  605. }
  606.  
  607.  
  608. /* getfn --- get file name from lin[i]... */
  609.  
  610. int getfn (lin, i, file)
  611. char lin[], file[];
  612. int i;
  613. {
  614.     int j, k, ret;
  615.  
  616.     ret = ERR;
  617.     if (lin[i + 1] == ' ')
  618.     {
  619.         j = i + 2;      /* get new file name */
  620.         SKIPBL (lin, j);
  621.         for (k = 0; lin[j] != NEWLINE; k++, j++)
  622.             file[k] = lin[j];
  623.         file[k] = EOS;
  624.         if (k > 0)
  625.             ret = OK;
  626.     }
  627.     else if (lin[i + 1] == '\n' && Savfil[0] != EOS)
  628.     {
  629.         strcpy (file, Savfil);    /* or old name */
  630.         ret = OK;
  631.     }
  632.     else 
  633.         if (lin[i + 1] == '\n')
  634.             Errcode = ENOFN;
  635.         else
  636.             Errcode = EFILEN;
  637.  
  638.     if (ret == OK && Savfil[1] == EOS)
  639.     {
  640.         strcpy (Savfil, file);        /* save if no old one */
  641.         mesg (Savfil, FILE_MSG);
  642.     }
  643.  
  644.     return (ret);
  645. }
  646.  
  647.  
  648. /* getkn --- get mark name from lin[i], increment i */
  649.  
  650. int getkn (lin, i, kname, dfltnm)
  651. char lin[], *kname, dfltnm;
  652. int *i;
  653. {
  654.  
  655.     if (lin[*i] == '\n' || lin[*i] == EOS)
  656.     {
  657.         *kname = dfltnm;
  658.         return (EOF);
  659.     }
  660.  
  661.     *kname = lin[*i];
  662.     (*i)++;
  663.     return (OK);
  664. }
  665.  
  666.  
  667. /* getrange --- get 'from' range for tlit command */
  668.  
  669. int getrange (array, k, set, size, allbut)
  670. char array[], set[];
  671. int *k, size, *allbut;
  672. {
  673.     int i, j;
  674.     int addset ();
  675.  
  676.     Errcode = EBADLIST;    /* preset error code */
  677.  
  678.     i = *k + 1;
  679.     if (array[i] == NOTINCCL)    /* check for negated character class */
  680.     {
  681.         *allbut = YES;
  682.         i++;
  683.     }
  684.     else
  685.         *allbut = NO;
  686.  
  687.     j = 0;
  688.     filset (array[*k], array, &i, set, &j, size);
  689.     if (array[i] != array[*k])
  690.     {
  691.         set[0] = EOS;
  692.         return (ERR);
  693.     }
  694.     if (set[0] == EOS)
  695.     {
  696.         Errcode = ENOLIST;
  697.         return (ERR);
  698.     }
  699.     if (j > 0 && addset (EOS, set, &j, size) == NO)
  700.     {
  701.         set[0] = EOS;
  702.         return (ERR);
  703.     }
  704.  
  705.     *k = i;
  706.     Errcode = EEGARB;
  707.  
  708.     return (OK);
  709. }
  710.  
  711.  
  712. /* getrhs --- get substitution string for 's' command */
  713.  
  714. int getrhs (lin, i, sub, gflag)
  715. char lin[], sub[];
  716. int *i, *gflag;
  717. {
  718.     static char Subs[MAXPAT] = "";    /* saved replacement pattern */
  719.     int j, maksub ();
  720.     /* saved replacement pattern char */
  721.  
  722.  
  723.     Errcode = EBADSUB;
  724.  
  725.     if (lin[*i] == EOS)    /* missing the middle delimeter */
  726.         return (ERR);
  727.  
  728.     if (lin[*i + 1] == '%' && (lin[*i + 2] == lin[*i]
  729.                     || lin[*i + 2] == '\n'))
  730.     {
  731.     /*
  732.      * s//%/ --- should mean do the same thing as I did last time, even
  733.      * s//&/ --- if I deleted something. So we comment out these lines.
  734.      *
  735.         if (Subs[0] == EOS)
  736.         {
  737.             Errcode = ENOSUB;
  738.             return (ERR);
  739.         }
  740.      */
  741.         strcpy (sub, Subs);
  742.         *i += 2;
  743.         if (lin[*i] == '\n')
  744.         {
  745.             /* fix it up for pattern matching routines */
  746.             lin[*i] = lin[*i - 2];
  747.             lin[*i + 1] = '\n';
  748.             lin[*i + 2] = EOS;
  749.             Peekc = SKIP_RIGHT;
  750.         }
  751.     }
  752.     else        /* not using saved substitution pattern */
  753.     {
  754.         if (lin[*i + 1] == '\n')
  755.         {
  756.             /* missing the trailing delimiter */
  757.             /* pattern was empty */
  758.             lin[*i + 1] = lin[*i];    /* supply missing delimiter */
  759.             lin[*i + 2] = '\n';
  760.             lin[*i + 3] = EOS;
  761.             Peekc = SKIP_RIGHT;
  762.             /* return (ERR);    /* this is the original action */
  763.         }
  764.         else
  765.         {
  766.             /* stuff in pattern, check end of line */
  767.             for (j = *i; lin[j] != EOS; j++)
  768.                 ;
  769.             j -= 2;        /* j now points to char before '\n' */
  770.  
  771.             if (lin[j] == 'p' || lin[j] == 'P')
  772.             {
  773.                 --j;
  774.                 if (lin[j] == GLOBAL || lin[j] == UCGLOBAL)
  775.                 {
  776.                     if (j >= *i + 1 && lin[j-1] == lin[*i]
  777.                         && (lin[j-2] != ESCAPE
  778.                             || lin[j-3] == ESCAPE))
  779.                         ;     /* leave alone */
  780.                     else
  781.                     {
  782.                         /* \<delim>gp\n is pattern */
  783.                         /* supply trailing delim */
  784.                         j +=  2;    /* j at \n */
  785.                         lin[j] = lin[*i];
  786.                         lin[++j] = '\n';
  787.                         lin[++j] = EOS;
  788.                         Peekc = SKIP_RIGHT;
  789.                     }
  790.                 }
  791.                 else if (j >= *i + 1 && lin[j] == lin[*i] &&
  792.                         (lin[j-1] != ESCAPE
  793.                          || lin[j-2] == ESCAPE))
  794.                     ;    /* leave alone */
  795.                 else
  796.                 {
  797.                     /* \<delim>p\n is pattern */
  798.                     /* supply trailing delim */
  799.                     j += 2;
  800.                     lin[j] = lin[*i];
  801.                     lin[++j] = '\n';
  802.                     lin[++j] = EOS;
  803.                     Peekc = SKIP_RIGHT;
  804.                 }
  805.             }
  806.             else if (lin[j] == GLOBAL || lin[j] == UCGLOBAL)
  807.             {
  808.                 --j;
  809.                 if (j >= *i + 1 && lin[j] == lin[*i] &&
  810.                     (lin[j-1] != ESCAPE
  811.                      || lin[j-2] == ESCAPE))
  812.                     ;     /* leave alone */
  813.                 else
  814.                 {
  815.                     /* \<delim>g\n is pattern */
  816.                     /* supply trailing delim */
  817.                     j +=  2;    /* j at \n */
  818.                     lin[j] = lin[*i];
  819.                     lin[++j] = '\n';
  820.                     lin[++j] = EOS;
  821.                     Peekc = SKIP_RIGHT;
  822.                 }
  823.             }
  824.             else if ((lin[j] != lin[*i]) ||
  825.                 (lin[j] == lin[*i] &&
  826.                 lin[j-1] == ESCAPE && lin[j-2] != ESCAPE))
  827.             {
  828.                 /* simply missing trailing delimeter */
  829.                 /* supply it */
  830.                 j++;        /* j at \n */
  831.                 lin[j] = lin[*i];
  832.                 lin[++j] = '\n';
  833.                 lin[++j] = EOS;
  834.                 Peekc = SKIP_RIGHT;
  835.             }
  836.             /* else
  837.                 unescaped delim is there,
  838.                 leave well enough alone */
  839.         }
  840.  
  841.         if ((*i = maksub (lin, *i + 1, lin[*i], sub)) == ERR)
  842.             return (ERR);
  843.  
  844.         strcpy (Subs, sub);    /* save pattern for later */
  845.     }
  846.  
  847.     if (lin[*i + 1] == GLOBAL || lin[*i + 1] == UCGLOBAL)
  848.     {
  849.         (*i)++;
  850.         *gflag = YES;
  851.     }
  852.     else
  853.         *gflag = NO;
  854.  
  855.     Errcode = EEGARB;    /* the default */
  856.  
  857.     return (OK);
  858.  
  859. }
  860.  
  861.  
  862. /* getstr --- get string from lin at i, copy to dst, bump i */
  863.  
  864. /*
  865. ** NOTE: this routine only called for doing the join command.
  866. ** therefore, don't do anything else with it.
  867. */
  868.  
  869. int getstr (lin, i, dst, maxdst)
  870. char lin[], dst[];
  871. int *i, maxdst;
  872. {
  873.     char delim;
  874.     char esc ();
  875.     int j, k, d;
  876.  
  877.     j = *i;
  878.     Errcode = EBADSTR;
  879.  
  880.     delim = lin[j];
  881.  
  882.     if (delim == '\n')
  883.     {
  884.         lin[j] = '/';
  885.         lin[++j] = ' ';        /* join with a single blank */
  886.         lin[++j] = '/';
  887.         lin[++j] = '\n';
  888.         lin[++j] = EOS;
  889.         j = *i;
  890.         delim = lin[j];
  891.         Peekc = SKIP_RIGHT;
  892.         /* now fall thru */
  893.  
  894.         /* return (ERR);    /* old way */
  895.     }
  896.     else if ((delim == 'p' || delim == 'P') && lin[j + 1] == '\n')    /* jp */
  897.     {
  898.         lin[j] = '/';
  899.         lin[++j] = ' ';        /* join with a single blank */
  900.         lin[++j] = '/';
  901.         lin[++j] = delim;    /* 'p' or 'P' */
  902.         lin[++j] = '\n';
  903.         lin[++j] = EOS;
  904.         j = *i;
  905.         delim = lin[j];
  906.         Peekc = SKIP_RIGHT;
  907.         /* now fall thru */
  908.     }
  909.  
  910.     if (lin[j + 1] == '\n')        /* command was 'j/' */
  911.     {
  912.         dst[0] = EOS;
  913.         Errcode = ENOERR;
  914.         return (OK);
  915.         /* return (ERR);    /* old way */
  916.     }
  917.  
  918.     /*
  919.      * otherwise, stuff there in the string, try to allow for
  920.      * a missing final delimiter.
  921.      */
  922.  
  923.     for (k = j + 1; lin[k] != '\n'; k++)
  924.         ;    /* find end */
  925.     
  926.     k--;    /* now points to char before newline */
  927.  
  928.     if (lin[k] == 'p' || lin[k] == 'P')
  929.     {
  930.         k--;
  931.         if (lin[k] == delim &&
  932.             (lin[k-1] != ESCAPE || lin[k-2] == ESCAPE))
  933.             ;    /* it's fine, leave it alone */
  934.         else
  935.         {
  936.             /* ESCAPE delim p NEWLINE is the join string */
  937.             /* supply trailing delimiter. */
  938.             k += 2;
  939.             lin[k] = delim;
  940.             lin[++k] = '\n';
  941.             lin[++k] = EOS;
  942.             Peekc = SKIP_RIGHT;
  943.         }
  944.     }
  945.     else if (lin[k] != delim || (lin[k-1] == ESCAPE && lin[k-2] != ESCAPE))
  946.     {
  947.         /* no delim and no p, or last char is escaped delim */
  948.         k++;
  949.         lin[k] = delim;
  950.         lin[++k] = '\n';
  951.         lin[++k] = EOS;
  952.         Peekc = SKIP_RIGHT;
  953.     }
  954.     /* else
  955.         delim is there
  956.         leave well enough alone */
  957.  
  958.     /* code to actually do the join */
  959.  
  960.     for (k = j + 1; lin[k] != delim; k++)    /* find end */
  961.     {
  962.         if (lin[k] == '\n' || lin[k] == EOS)
  963.             if (delim == ' ')
  964.                 break;
  965.             else
  966.                 return (ERR);
  967.         esc (lin, &k);
  968.     }
  969.     if (k - j > maxdst)
  970.         return (ERR);
  971.  
  972.     for (d = 0, j++; j < k; d++, j++)
  973.         dst[d] = esc (lin, &j);
  974.     dst[d] = EOS;
  975.  
  976.     *i = j;
  977.     Errcode = EEGARB;    /* the default */
  978.  
  979.     return (OK);
  980. }
  981.  
  982.  
  983. /* getwrd --- get next word from line at i; increment i */
  984.  
  985. int getwrd (line, i, word, size)
  986. char line[], word[];
  987. int *i, size;
  988. {
  989.     int j;
  990.  
  991.     SKIPBL (line, *i);
  992.     j = 0;
  993.     while (line[*i] != ' ' && line[*i] != '\n' && line[*i] != EOS)
  994.     {
  995.         if (j < size - 1)
  996.         {
  997.             word[j] = line[*i];
  998.             j++;
  999.         }
  1000.         (*i)++;
  1001.     }
  1002.     word[j] = EOS;
  1003.  
  1004.     return (j);
  1005. }
  1006.  
  1007.  
  1008. /* knscan --- scan for a line with a given mark name */
  1009.  
  1010. int knscan (way, num)
  1011. int way, *num;
  1012. {
  1013.     int nextln ();
  1014.     LINEDESC *k;
  1015.     LINEDESC *getind ();
  1016.  
  1017.     *num = Curln;
  1018.     k = getind (*num);
  1019.     do {
  1020.         bump (num, &k, way);
  1021.         if (k -> Markname == Savknm)
  1022.             return (OK);
  1023.     } while (*num != Curln && ! intrpt ());
  1024.  
  1025.     if (Errcode = EEGARB)
  1026.         Errcode = EKNOTFND;
  1027.     return (ERR);
  1028.  
  1029. }
  1030.  
  1031.  
  1032. /* makset --- make set from array[k] in set */
  1033.  
  1034. int makset (array, k, set, size)
  1035. char array[], set[];
  1036. int *k, size;
  1037. {
  1038.     static char Tset[MAXPAT] = "";    /* saved translit dest range */
  1039.     int i, j;
  1040.     int l;
  1041.     int addset ();
  1042.  
  1043.     Errcode = EBADLIST;
  1044.  
  1045.     /*
  1046.      * try to allow missing delimiter for translit command.
  1047.      */
  1048.     
  1049.     if (array[*k] == EOS)
  1050.         return (ERR);
  1051.  
  1052.     if (array[*k + 1] == '%' && (array[*k + 2] == array[*k]
  1053.                        || array[*k + 2] == '\n'))
  1054.     {
  1055.         strcpy (set, Tset);
  1056.         *k += 2;
  1057.         if (array[*k] == '\n')
  1058.         {
  1059.             /* fix it up for rest of the routines */
  1060.             array[*k] = array[*k - 2];
  1061.             array[*k+ 1] = '\n';
  1062.             array[*k+ 2] = EOS;
  1063.         }
  1064.         Peekc = SKIP_RIGHT;
  1065.     }
  1066.     else
  1067.     {
  1068.     
  1069.         for (l = *k; array[l] != EOS; l++)
  1070.             ;
  1071.         l -= 2;        /* l now points to char before '\n' */
  1072.     
  1073.         if (l == *k)    /* "y/.../\n" */
  1074.         {
  1075.             array[*k + 1] = array[*k];    /* add delimiter */
  1076.             array[*k + 2] = '\n';
  1077.             array[*k + 3] = EOS;
  1078.             Peekc = SKIP_RIGHT;
  1079.         }
  1080.         else if (array[l] == 'p' || array[l] == 'P')
  1081.         {
  1082.             --l;
  1083.             if (l >= *k + 1 && array[l] == array[*k] &&
  1084.                 (array[l-1] != ESCAPE || array[l-2] == ESCAPE))
  1085.                 ;    /* leave alone */
  1086.             else
  1087.             {
  1088.                 /* \<delim>p\n is set */
  1089.                 /* supply trailing delim */
  1090.                 l += 2;
  1091.                 array[l] = array[*k];
  1092.                 array[++l] = '\n';
  1093.                 array[++l] = EOS;
  1094.                 Peekc = SKIP_RIGHT;
  1095.             }
  1096.         }
  1097.         else if (array[l] != array[*k]    /* no delim, and no p */
  1098.             || (array[l-1] == ESCAPE    /* or last char is escaped delim */
  1099.             && array[l-2] != ESCAPE))
  1100.         {
  1101.             /* simply missing trailing delimeter */
  1102.             /* supply it */
  1103.             l++;        /* l now at \n */
  1104.             array[l] = array[*k];
  1105.             array[++l] = '\n';
  1106.             array[++l] = EOS;
  1107.             Peekc = SKIP_RIGHT;
  1108.         }
  1109.         /* else
  1110.             delim is there,
  1111.             leave well enough alone */
  1112.  
  1113.         j = 0;
  1114.         i = *k + 1;
  1115.         filset (array[*k], array, &i, set, &j, size);
  1116.  
  1117.         if (array[i] != array[*k])
  1118.             return (ERR);
  1119.  
  1120.         if (addset (EOS, set, &j, size) == NO)
  1121.             return (ERR);
  1122.  
  1123.         strcpy (Tset, set);    /* save for later */
  1124.         *k = i;
  1125.  
  1126.     }
  1127.  
  1128.     Errcode = EEGARB;
  1129.  
  1130.     return (OK);
  1131. }
  1132.  
  1133.  
  1134. /* optpat --- make pattern specified at lin[i] */
  1135.  
  1136. int optpat (lin, i)
  1137. char lin[];
  1138. int *i;
  1139. {
  1140.     int makpat ();
  1141.  
  1142.     if (lin[*i] == EOS)
  1143.         *i = ERR;
  1144.     else if (lin[*i + 1] == EOS)
  1145.         *i = ERR;
  1146.     else if (lin[*i + 1] == lin[*i])    /* repeated delimiter */
  1147.         (*i)++;        /* leave existing pattern alone */
  1148.     else
  1149.         *i = makpat (lin, *i + 1, lin[*i], Pat);
  1150.  
  1151.     if (Pat [0] == EOS)
  1152.     {
  1153.         Errcode = ENOPAT;
  1154.         return (ERR);
  1155.     }
  1156.     if (*i == ERR)
  1157.     {
  1158.         Pat[0] = EOS;
  1159.         Errcode = EBADPAT;
  1160.         return (ERR);
  1161.     }
  1162.     return (OK);
  1163. }
  1164.  
  1165.  
  1166. /* ptscan --- scan for next occurrence of pattern */
  1167.  
  1168. int ptscan (way, num)
  1169. int way, *num;
  1170. {
  1171.     LINEDESC *getind ();
  1172.     LINEDESC *k;
  1173.     int match ();
  1174.  
  1175.     *num = Curln;
  1176.     k = getind (*num);
  1177.     do {
  1178.         bump (num, &k, way);
  1179.         gtxt (k);
  1180.         if (match (Txt, Pat) == YES)
  1181.             return (OK);
  1182.     } while (*num != Curln && ! intrpt ());
  1183.  
  1184.     if (Errcode == EEGARB)
  1185.         Errcode = EPNOTFND;
  1186.  
  1187.     return (ERR);
  1188. }
  1189.  
  1190.  
  1191. /* settab --- set tab stops */
  1192.  
  1193. int settab (str)
  1194. char str[];
  1195. {
  1196.     int i, j, n, maxstop, last, inc, ret;
  1197.     int ctoi ();
  1198.  
  1199.     for (i = 0; i < MAXLINE; i++)   /* clear all tab stops */
  1200.         Tabstops[i] = NO;
  1201.  
  1202.     ret = OK;
  1203.     maxstop = 0;
  1204.     last = 1;
  1205.  
  1206.     i = 0;
  1207.     SKIPBL (str, i);
  1208.     while (str[i] != EOS && str[i] != '\n')
  1209.     {
  1210.         if (str[i] == '+')      /* increment */
  1211.         {
  1212.             i++;
  1213.             inc = YES;
  1214.         }
  1215.         else
  1216.             inc = NO;
  1217.  
  1218.         n = ctoi (str, &i);
  1219.  
  1220.         if (n <= 0 || n >= MAXLINE)
  1221.         {
  1222.             ret = ERR;
  1223.             Errcode = ENONSENSE;
  1224.             break;
  1225.         }
  1226.  
  1227.         if (str[i] != ' ' && str[i] != '+' &&
  1228.             str[i] != '\n' && str[i] != EOS)
  1229.         {
  1230.             ret = ERR;
  1231.             Errcode = EBADTABS;
  1232.             break;
  1233.         }
  1234.  
  1235.         if (inc == YES)
  1236.         {
  1237.             for (j = last + n; j < MAXLINE; j += n)
  1238.             {
  1239.                 Tabstops[j - 1] = YES;
  1240.                 maxstop = max (j, maxstop);
  1241.             }
  1242.         }
  1243.         else
  1244.         {
  1245.             Tabstops[n - 1] = YES;
  1246.             last = n;
  1247.             maxstop = max (n, maxstop);
  1248.         }
  1249.         SKIPBL (str, i);
  1250.     }       /* while ... */
  1251.  
  1252.     if (ret == ERR)
  1253.         maxstop = 0;
  1254.  
  1255.     if (maxstop == 0)       /* no tab stops specified, use defaults */
  1256.     {
  1257.         for (i = 4; i < MAXLINE - 1; i += 4)
  1258.             Tabstops[i] = YES;
  1259.         maxstop = i - 4 + 1;
  1260.     }
  1261.  
  1262.     Tabstops[0] = YES;      /* always set to YES */
  1263.  
  1264.     for (i = maxstop; i < MAXLINE; i++)
  1265.         Tabstops[i] = YES;
  1266.  
  1267.     return (ret);
  1268. }
  1269.  
  1270. /* serc --- read in ./.serc or $HOME/.serc and execute the commands in it. */
  1271.  
  1272. /*
  1273.  * note that se's special control characters are NOT processed,
  1274.  * and therefore should NOT be used in one's .serc file.
  1275.  */
  1276.  
  1277. static serc ()
  1278. {
  1279.     char file[MAXLINE];
  1280.     char lin[MAXLINE];
  1281.     char *expand_env ();
  1282.     FILE *fp;
  1283.     int status = ENOERR;
  1284.     int len, cursav;
  1285.  
  1286.     strcpy (file, expand_env ("$HOME/.serc"));
  1287.  
  1288.     if ((fp = fopen ("./.serc", "r")) == NULL ||
  1289.             (fp = fopen (file, "r")) == NULL)
  1290.         return;
  1291.     
  1292.     while (fgets (lin, sizeof lin, fp) != NULL && status != EOF /*??*/)
  1293.     {
  1294.         if (lin[0] == '#' || lin[0] == '\n')
  1295.             continue;    /* comment in .serc file */
  1296.  
  1297.         /* most of this code stolen from edit() */
  1298.         len = 0;
  1299.         cursav = Curln;
  1300.         if (getlst (lin, &len, &status) == OK)
  1301.         {
  1302.             if (ckglob (lin, &len, &status) == OK)
  1303.                 doglob (lin, &len, &cursav, &status);
  1304.             else if (status != ERR)
  1305.                 docmd (lin, len, NO, &status);
  1306.         }
  1307.         if (status == ERR)
  1308.         {
  1309.             if (Errcode == EHANGUP)
  1310.                 hangup ();
  1311.             Curln = min (cursav, Lastln);
  1312.         }
  1313.     }
  1314.     fclose (fp);
  1315. }
  1316.  
  1317. #ifdef LOG_USAGE
  1318.  
  1319. /* log -- log se usage */
  1320.  
  1321.  
  1322. static log ()
  1323. {
  1324.     static char logfile[] = "/usr/tmp/se.log";    /* a public file */
  1325.     char logname[MAXLINE], tod[26];        /* tod => time of day */
  1326.     long clock;
  1327.     FILE *fp;
  1328.     char *ctime ();
  1329.     long time ();
  1330.     int old_umask;
  1331. #ifdef BSD
  1332.     char *getlogin ();
  1333. #else
  1334.     char *cuserid ();
  1335. #endif
  1336.  
  1337.     /* get the login name */
  1338. #ifdef BSD
  1339.     strcpy (logname, getlogin ());
  1340. #else
  1341.     cuserid (logname);
  1342. #endif
  1343.  
  1344.     time (&clock);
  1345.     strcpy (tod, ctime (&clock));    /* see the manual on ctime(3C)  */
  1346.     tod[24] = EOS;            /* delete the '\n' at the end */
  1347.  
  1348.     old_umask = umask (0);        /* allow writes for everyone */
  1349.                     /* when first call creates the file */
  1350.  
  1351.     if ((fp = fopen (logfile, "a")) != NULL)
  1352.     {
  1353.         /* all ok, write out statistics */
  1354.         fprintf (fp, "%s used se on %s.\n", logname, tod);
  1355.         fclose (fp);
  1356.     }
  1357.     /* else
  1358.         don't do anything */
  1359.  
  1360.     umask (old_umask);
  1361.  
  1362. }
  1363. #endif
  1364.  
  1365. /* sysname --- return a string telling us who we are */
  1366.  
  1367. #ifdef USG
  1368. #include <sys/utsname.h>    /* stuff to find out who we are */
  1369. #endif
  1370.  
  1371. char *sysname ()
  1372. {
  1373.     int i, j, k;
  1374.     char c;
  1375.     static char buf[MAXLINE] = "";
  1376.     FILE *fp;
  1377.     static char unknown[] = "unknown";
  1378.  
  1379. #ifdef USG    /* System V */
  1380.     static struct utsname whoarewe;
  1381.  
  1382.     uname (& whoarewe);
  1383.     return (whoarewe.nodename);
  1384. #else
  1385. #ifdef BSD4_2    /* Berkeley 4.2 */
  1386.     if (buf[0] != EOS)
  1387.         return (buf);
  1388.  
  1389.     j = sizeof (buf);
  1390.     k = gethostname (buf, & j);
  1391.     if (k != 0)
  1392.         return (unknown);
  1393.     else
  1394.         return (buf);
  1395. #else        /* Berkeley 4.1 */
  1396.     if (buf[0] != EOS)
  1397.         return (buf);
  1398.  
  1399.     if ((fp = fopen ("/usr/include/whoami.h", "r")) == NULL)
  1400.         return (unknown);
  1401.     else
  1402.     {
  1403.         auto char *cp;
  1404.         /*
  1405.          * file should contain a single line:
  1406.          * #define sysname "......"
  1407.          */
  1408.         while ((c = getc (fp)) != '"' && c != EOF)
  1409.             ;
  1410.         if (c == EOF)
  1411.             cp = unknown;
  1412.         else
  1413.         {
  1414.             for (i = 0; (c = getc (fp)) != '"' && c != EOF; i++)
  1415.                 buf[i] = c;
  1416.             buf[i] = EOS;
  1417.             if (c == EOF && i == 0)
  1418.                 cp = unknown;
  1419.             else
  1420.                 cp = buf;
  1421.         }
  1422.         fclose (fp);
  1423.         return (cp);
  1424.     }
  1425. #endif
  1426. #endif
  1427. }
  1428.