home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume4 / se / part2 / edit.c next >
C/C++ Source or Header  |  1986-11-30  |  27KB  |  1,464 lines

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