home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / oneliner.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  12KB  |  547 lines

  1. /*
  2.  *    A few functions that used to operate on single whole lines, mostly
  3.  *    here to support the globals() function.  They now work on regions.
  4.  *    Written (except for delins()) for vile by Paul Fox, (c)1990
  5.  *
  6.  * $Log: oneliner.c,v $
  7.  * Revision 1.33  1992/12/07  23:32:29  foxharp
  8.  * fix backslash processing in the replacement pattern in delins()
  9.  *
  10.  * Revision 1.32  1992/05/19  09:14:27  foxharp
  11.  * drop cntrl char in comment
  12.  *
  13.  * Revision 1.31  1992/05/19  08:55:44  foxharp
  14.  * more prototype and shadowed decl fixups
  15.  *
  16.  * Revision 1.30  1992/05/16  12:00:31  pgf
  17.  * prototypes/ansi/void-int stuff/microsoftC
  18.  *
  19.  * Revision 1.29  1992/05/05  17:47:10  pgf
  20.  * clear fulllineregions after using it, in substregion1, and pregion
  21.  *
  22.  * Revision 1.28  1992/03/13  08:12:11  pgf
  23.  * attempt to use args passed after :& command, as in ":&g"
  24.  *
  25.  * Revision 1.27  1992/03/03  08:42:59  pgf
  26.  * skip a char when doing /g if the pattern can or does match nothing
  27.  *
  28.  * Revision 1.26  1992/03/01  18:41:31  pgf
  29.  * /g finds non-overlapping matches, and in addition, must skip a character
  30.  * if a pattern can find nothing
  31.  *
  32.  * Revision 1.25  1992/02/26  21:56:36  pgf
  33.  * fixed inf. loop caused by s/$/string/g
  34.  *
  35.  * Revision 1.24  1992/01/22  16:58:20  pgf
  36.  * substline() now always returns true except on hard failure -- this makes
  37.  * substreg work properly, instead of quitting on the first line not containing
  38.  * a pattern
  39.  *
  40.  * Revision 1.23  1992/01/05  00:06:13  pgf
  41.  * split mlwrite into mlwrite/mlprompt/mlforce to make errors visible more
  42.  * often.  also normalized message appearance somewhat.
  43.  *
  44.  * Revision 1.22  1992/01/03  23:31:49  pgf
  45.  * use new ch_fname() to manipulate filenames, since b_fname is now
  46.  * a malloc'ed sting, to avoid length limits
  47.  *
  48.  * Revision 1.21  1991/12/22  12:03:09  pgf
  49.  * bug fix for global subst, and allow aborts at the "g, p, or n" prompt
  50.  *
  51.  * Revision 1.20  1991/11/16  18:37:27  pgf
  52.  * use memcpy instead of strncpy
  53.  *
  54.  * Revision 1.19  1991/11/04  14:29:22  pgf
  55.  * extra caution in delins
  56.  *
  57.  * Revision 1.18  1991/11/03  17:46:30  pgf
  58.  * removed f,n args from all region functions -- they don't use them,
  59.  * since they're no longer directly called by the user
  60.  *
  61.  * Revision 1.17  1991/11/01  14:38:00  pgf
  62.  * saber cleanup
  63.  *
  64.  * Revision 1.16  1991/11/01  14:10:35  pgf
  65.  * regexps are now relocatable, so the subst commands can keep a copy
  66.  * of their pattern around
  67.  *
  68.  * Revision 1.15  1991/10/31  02:37:02  pgf
  69.  * implement vi-like substagain
  70.  *
  71.  * Revision 1.14  1991/10/30  14:55:43  pgf
  72.  * fixed boundary position in substline, renamed thescanner to scanner
  73.  *
  74.  * Revision 1.13  1991/10/29  14:35:29  pgf
  75.  * implemented the & commands: substagain
  76.  *
  77.  * Revision 1.12  1991/10/27  01:50:16  pgf
  78.  * switched from regex to regexp, and
  79.  * used Spencer's regsub routine as the basis for a new delins()
  80.  * that allows for replacement metachars
  81.  *
  82.  * Revision 1.11  1991/10/24  13:05:52  pgf
  83.  * conversion to new regex package -- much faster
  84.  *
  85.  * Revision 1.10  1991/10/23  14:17:36  pgf
  86.  * initialize nth_occur in all cases
  87.  *
  88.  * Revision 1.9  1991/09/26  13:11:19  pgf
  89.  * LIST mode moved to the window
  90.  *
  91.  * Revision 1.8  1991/09/16  23:48:30  pgf
  92.  * added "nth occurrence" support to s/repl/pat
  93.  *
  94.  * Revision 1.7  1991/09/10  00:55:24  pgf
  95.  * don't re-popup the buffer everytime -- only on first call
  96.  *
  97.  * Revision 1.6  1991/08/07  12:35:07  pgf
  98.  * added RCS log messages
  99.  *
  100.  * revision 1.5
  101.  * date: 1991/08/06 15:24:19;
  102.  *  global/local values
  103.  * 
  104.  * revision 1.4
  105.  * date: 1991/06/27 18:33:47;
  106.  * made screen oriented substitutes always act globally across line
  107.  * 
  108.  * revision 1.3
  109.  * date: 1991/06/25 19:53:07;
  110.  * massive data structure restructure
  111.  * 
  112.  * revision 1.2
  113.  * date: 1991/05/31 11:14:50;
  114.  * turned these into region operators.
  115.  * they're not one-liners anymore
  116.  * 
  117.  * revision 1.1
  118.  * date: 1990/09/21 10:25:51;
  119.  * initial vile RCS revision
  120.  */
  121.  
  122. #include    "estruct.h"
  123. #include    "edef.h"
  124. #include    <stdio.h>
  125.  
  126. #define PLIST    0x01
  127.  
  128. /*
  129.  * put lines in a popup window
  130.  */
  131. int
  132. pregion(flag)
  133. int flag;
  134. {
  135.     register WINDOW *wp;
  136.     register BUFFER *bp;
  137.     register int    s;
  138.     REGION        region;
  139.     static char bname[] = "[p-lines]";
  140.     register LINE *linep;
  141.  
  142.     fulllineregions = TRUE;
  143.             
  144.     s = getregion(®ion);
  145.  
  146.     fulllineregions = FALSE;
  147.  
  148.     if (s != TRUE)
  149.         return (s);
  150.  
  151.     linep = region.r_orig.l;         /* Current line.     */
  152.             
  153.     /* first check if we are already here */
  154.     bp = bfind(bname, OK_CREAT, 0);
  155.     if (bp == NULL)
  156.         return FALSE;
  157.  
  158.     if (!calledbefore) {        /* fresh start */
  159.         /* bring p-lines up */
  160.         if (popupbuff(bp) != TRUE)
  161.             return FALSE;
  162.             
  163.         bclear(bp);
  164.         make_local_b_val(bp,WMDLIST);
  165.         set_b_val(bp, WMDLIST, ((flag & PLIST) != 0) );
  166.         calledbefore = TRUE;
  167.     }
  168.         
  169.     do {
  170.         addline(bp,linep->l_text,llength(linep));
  171.         linep = lforw(linep);
  172.     } while (linep != region.r_end.l);
  173.  
  174.     bp->b_flag &= ~BFCHG;
  175.         
  176.     strcpy(bp->b_bname,bname);
  177.     ch_fname(bp, "");
  178.  
  179.     make_local_b_val(bp,MDVIEW);
  180.     set_b_val(bp,MDVIEW,TRUE);
  181.  
  182.     make_local_b_val(bp,VAL_TAB);
  183.     set_b_val(bp,VAL_TAB,tabstop_val(curbp));
  184.  
  185.     bp->b_active = TRUE;
  186.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  187.         if (wp->w_bufp == bp) {
  188.             wp->w_flag |= WFMODE|WFFORCE;
  189.             wp->w_traits.w_vals = bp->b_wtraits.w_vals;
  190.         }
  191.     }
  192.     return TRUE;
  193. }
  194.  
  195. int
  196. llineregion()
  197. {
  198.     return pregion(PLIST);
  199. }
  200.  
  201. int
  202. plineregion()
  203. {
  204.     return pregion(0);
  205. }
  206.  
  207. static regexp *substexp;
  208.  
  209. int
  210. substregion()
  211. {
  212.     return substreg1(TRUE,TRUE);
  213. }
  214.  
  215. int
  216. subst_again_region()
  217. {
  218.     return substreg1(FALSE,TRUE);
  219. }
  220.  
  221. /* traditional vi & command */
  222. /* ARGSUSED */
  223. int
  224. subst_again(f,n)
  225. int f,n;
  226. {
  227.     int s;
  228.     MARK curpos;
  229.  
  230.     curpos = DOT;
  231.  
  232.     /* the region spans just the line */
  233.     MK.l = DOT.l;
  234.     DOT.o = 0;
  235.     MK.o = llength(MK.l);
  236.     s = substreg1(FALSE,FALSE);
  237.     if (s != TRUE) {
  238.         mlforce("[No match.]");
  239.         DOT = curpos;
  240.         return s;
  241.     }
  242.     swapmark();
  243.     return TRUE;
  244. }
  245.  
  246. int
  247. substreg1(needpats, use_opts)
  248. int needpats, use_opts;
  249. {
  250.     int c, s;
  251.     static int printit, globally, nth_occur;
  252.     REGION region;
  253.     LINE *oline;
  254.  
  255.     fulllineregions = TRUE;
  256.             
  257.     s = getregion(®ion);
  258.  
  259.     fulllineregions = FALSE;
  260.  
  261.     if (s != TRUE)
  262.         return (s);
  263.  
  264.     if (calledbefore == FALSE && needpats) {
  265.         c = '\n';
  266.         if (isnamedcmd) {
  267.             c = tpeekc();
  268.             if (c < 0) {
  269.                 c = '\n';
  270.             } else {
  271.                 if (ispunct(c)) {
  272.                     (void)kbd_key();
  273.                 }
  274.             }
  275.         } else {
  276.             /* if it's a screen region, assume they want .../g */
  277.             globally = TRUE;
  278.         }
  279.         if ((s = readpattern("substitute pattern: ", &pat[0],
  280.                     &gregexp, c, FALSE)) != TRUE) {
  281.             if (s != ABORT)
  282.                 mlforce("[No pattern.]");
  283.             return FALSE;
  284.         }
  285.  
  286.         if (gregexp) {
  287.             if (substexp)
  288.                 free((char *)substexp);
  289.             substexp = (regexp *)malloc(gregexp->size);
  290.             memcpy((char *)substexp, (char *)gregexp, gregexp->size);
  291.         }
  292.  
  293.         if ((s = readpattern("replacement string: ", &rpat[0], NULL, c,
  294.                 FALSE)) != TRUE) {
  295.             if (s == ABORT)
  296.                 return FALSE;
  297.             /* else the pattern is null, which is okay... */
  298.         }
  299.         nth_occur = -1;
  300.         printit = globally = FALSE;
  301.         if (lastkey == c) { /* the user may have something to add */
  302.             char buf[3];
  303.             char *bp;
  304.         getopts:
  305.             bp = buf;
  306.             buf[0] = 0;
  307.             s = mlreply(
  308.     "(g)lobally or ([1-9])th occurrence on line and/or (p)rint result: ",
  309.                 buf, sizeof buf);
  310.             if (s == ABORT)
  311.                 return FALSE;
  312.             nth_occur = 0;
  313.             while (*bp) {
  314.                 if (*bp == 'p' && !printit) {
  315.                     printit = TRUE;
  316.                 } else if (*bp == 'g' &&
  317.                         !globally && !nth_occur) {
  318.                     globally = TRUE;
  319.                 } else if (isdigit(*bp) &&
  320.                         !nth_occur && !globally) {
  321.                     nth_occur = *bp - '0';
  322.                     globally = TRUE;
  323.                 } else if (!isspace(*bp)) {
  324.                     mlforce("[Unknown action %s]",buf);
  325.                     return FALSE;
  326.                 }
  327.                 bp++;
  328.             }
  329.             if (!nth_occur)
  330.                 nth_occur = -1;
  331.         }
  332.     } else {
  333.         if (!use_opts) {
  334.             nth_occur = -1;
  335.             printit = globally = FALSE;
  336.         } else {
  337.             if (isnamedcmd && lastkey != '\r') {
  338.                 tungetc(lastkey);
  339.                 nth_occur = -1;
  340.                 printit = globally = FALSE;
  341.                 goto getopts;
  342.             }
  343.         }
  344.     }
  345.  
  346.     DOT.l = region.r_orig.l;        /* Current line.        */
  347.  
  348.     do {
  349.         oline = DOT.l;
  350.         if ((s = substline( substexp, nth_occur, printit, globally))
  351.                                 != TRUE)
  352.             return s;
  353.         DOT.l = lforw(oline);
  354.     } while (!sameline(DOT, region.r_end));
  355.     calledbefore = TRUE;
  356.     return TRUE;
  357. }
  358.  
  359. int
  360. substline(exp, nth_occur, printit, globally)
  361. regexp *exp;
  362. int nth_occur, printit, globally;
  363. {
  364.     MARK eol;
  365.     int foundit;
  366.     register int s;
  367.     register int which_occur = 0;
  368.     int matched_at_eol = FALSE;
  369.     extern MARK scanboundpos;
  370.  
  371.     /* if the "magic number" hasn't been set yet... */
  372.     if (!exp || UCHARAT(exp->program) != REGEXP_MAGIC) {
  373.         mlforce("[No pattern set yet]");
  374.         return FALSE;
  375.     }
  376.  
  377.     ignorecase = b_val(curwp->w_bufp, MDIGNCASE);
  378.  
  379.     foundit = FALSE;
  380.     eol.l = DOT.l;
  381.     eol.o = llength(DOT.l);
  382.     scanboundpos = eol;
  383.     DOT.o = 0;
  384.     do {
  385.         s = scanner(exp, FORWARD, FALSE);
  386.         if (s != TRUE)
  387.             break;
  388.                 
  389.         /* found the pattern */
  390.         foundit = TRUE;
  391.         which_occur++;
  392.         if (nth_occur == -1 || which_occur == nth_occur) {
  393.             setmark();
  394.             /* only allow one match at the end of line, to
  395.                 prevent loop with s/$/x/g  */
  396.             if (MK.o == llength(DOT.l)) {
  397.                 if (matched_at_eol)
  398.                     break;
  399.                 matched_at_eol = TRUE;
  400.             }
  401.             s = delins(exp, &rpat[0]);
  402.             if (s != TRUE)
  403.                 return s;
  404.             if ((exp->mlen == 0 || exp->regmlen == 0) &&
  405.                     forwchar(TRUE,1) == FALSE)
  406.                 break;
  407.             if (nth_occur > 0)
  408.                 break;
  409.         } else { /* non-overlapping matches */
  410.             s = forwchar(TRUE, exp->mlen);
  411.             if (s != TRUE)
  412.                 return s;
  413.         }
  414.     } while (globally && sameline(eol,DOT));
  415.     if (foundit && printit) {
  416.         register WINDOW *wp = curwp;
  417.         setmark();
  418.         s = plineregion();
  419.         if (s != TRUE) return s;
  420.         /* back to our buffer */
  421.         swbuffer(wp->w_bufp);
  422.     }
  423.     return TRUE;
  424. }
  425.  
  426. /*
  427.  * delins, modified by pgf from regsub
  428.  *
  429.  *    Copyright (c) 1986 by University of Toronto.
  430.  *    Written by Henry Spencer.  Not derived from licensed software.
  431.  *
  432.  *    Permission is granted to anyone to use this software for any
  433.  *    purpose on any computer system, and to redistribute it freely,
  434.  *    subject to the following restrictions:
  435.  *
  436.  *    1. The author is not responsible for the consequences of use of
  437.  *        this software, no matter how awful, even if they arise
  438.  *        from defects in it.
  439.  *
  440.  *    2. The origin of this software must not be misrepresented, either
  441.  *        by explicit claim or by omission.
  442.  *
  443.  *    3. Altered versions must be plainly marked as such, and must not
  444.  *        be misrepresented as being the original software.
  445.  */
  446.  
  447. /*
  448.  - delins - perform substitutions after a regexp match
  449.  */
  450. int
  451. delins(exp, sourc)
  452. regexp *exp;
  453. char *sourc;
  454. {
  455.     register char *src;
  456.     register int dlength;
  457.     register char c;
  458.     register int no;
  459.     static char *buf = NULL;
  460.     static buflen = -1;
  461.     int s;
  462.  
  463.     if (exp == NULL || sourc == NULL) {
  464.         mlforce("BUG: NULL parm to delins");
  465.         return FALSE;
  466.     }
  467.     if (UCHARAT(exp->program) != REGEXP_MAGIC) {
  468.         regerror("damaged regexp fed to delins");
  469.         return FALSE;
  470.     }
  471.  
  472.     dlength = exp->mlen;
  473.  
  474.     if (buf == NULL || dlength + 1 > buflen) {
  475.         if (buf)
  476.             free(buf);
  477.         if ((buf = (char *)malloc(dlength+1)) == NULL) {
  478.             mlforce("[Out of memory in delins]");
  479.             return FALSE;
  480.         }
  481.         buflen = dlength + 1;
  482.     }
  483.  
  484.     memcpy(buf, exp->startp[0], dlength);
  485.     buf[dlength] = '\0';
  486.  
  487.     if (ldelete((long) dlength, FALSE) != TRUE) {
  488.         mlforce("[Error while deleting]");
  489.         return FALSE;
  490.     }
  491.     src = sourc;
  492.     while ((c = *src++) != '\0') {
  493.         no = 0;
  494.         s = TRUE;
  495.         switch(c) {
  496.         case '\\':
  497.             c = *src++;
  498.             if (c == '\0')
  499.                 return TRUE;
  500.             if (!isdigit(c)) {
  501.                 /* here's where the \U \E \u \l \t etc.
  502.                 special escapes should be implemented */
  503.                 s = linsert(1,c);
  504.                 break;
  505.             }
  506.             /* else it's a digit --
  507.                 get pattern number, and fall through */
  508.             no = c - '0';
  509.         case '&':
  510.             if (exp->startp[no] != NULL && exp->endp[no] != NULL) {
  511.                 char *cp;
  512.                 int len;
  513.                 len = (exp->endp[no] - exp->startp[no]);
  514.                 cp = (exp->startp[no] - exp->startp[0]) + buf;
  515.                 while (len--) {
  516.                     if (!*cp) {
  517.                         mlforce( "BUG: mangled replace");
  518.                         return FALSE;
  519.                     }
  520.                     if (*cp == '\n')
  521.                         s = lnewline();
  522.                     else
  523.                         s = linsert(1,*cp);
  524.                     if (s != TRUE)
  525.                         goto nomem;
  526.                     cp++;
  527.                 }
  528.             }
  529.             break;
  530.  
  531.         case '\n':
  532.             s = lnewline();
  533.             break;
  534.  
  535.         default:
  536.             s = linsert(1,c);
  537.             break;
  538.         }
  539.         if (s != TRUE) {
  540.         nomem:
  541.             mlforce("[Out of memory while inserting]");
  542.             return FALSE;
  543.         }
  544.     }
  545.     return TRUE;
  546. }
  547.