home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / oneliner.c < prev    next >
C/C++ Source or Header  |  1998-04-28  |  13KB  |  590 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.  *    Copyright (c) 1990, 1995 by Paul Fox, except for delins(), which is
  5.  *    Copyright (c) 1986 by University of Toronto, as noted below.
  6.  *
  7.  * $Header: /usr/build/vile/vile/RCS/oneliner.c,v 1.89 1998/04/28 10:17:39 tom Exp $
  8.  */
  9.  
  10. #include    "estruct.h"
  11. #include    "edef.h"
  12.  
  13. #define PLIST    0x01
  14. #define PNUMS    0x02
  15.  
  16. static    int    delins(regexp *exp, char *sourc);
  17. static    int    substline(regexp *exp, int nth_occur, int printit, int globally, int *confirmp);
  18. static    int    substreg1(int needpats, int use_opts);
  19.  
  20. static    int    lines_changed,
  21.         total_changes;
  22.  
  23. /*
  24.  * put lines in a popup window
  25.  */
  26. static int
  27. pregion(UINT flag)
  28. {
  29.     register WINDOW *wp;
  30.     register BUFFER *bp;
  31.     register int    status;
  32.     REGION        region;
  33.     register LINEPTR linep;
  34.     BUFFER *oldbp = curbp;
  35.  
  36.     if ((status = get_fl_region(®ion)) != TRUE) {
  37.         return (status);
  38.     }
  39.  
  40.     linep = region.r_orig.l;         /* Current line.     */
  41.  
  42.     /* first check if we are already here */
  43.     bp = bfind(P_LINES_BufName, 0);
  44.     if (bp == NULL) {
  45.         return FALSE;
  46.     }
  47.  
  48.     if (bp == curbp) {
  49.         mlforce("[Can't do that from this buffer.]");
  50.         return FALSE;
  51.     }
  52.  
  53.     if (!calledbefore) {        /* fresh start */
  54.         /* bring p-lines up */
  55.         if (popupbuff(bp) != TRUE
  56.          || bclear(bp) != TRUE) {
  57.             return FALSE;
  58.         }
  59.  
  60.         calledbefore = TRUE;
  61.     }
  62.  
  63.     do {
  64.         if (!addline(bp, linep->l_text, llength(linep)))
  65.             break;    /* out of memory */
  66.         if (flag & PNUMS) {
  67.             BUFFER *savebp = curbp;
  68.             WINDOW *savewp = curwp;
  69.             curbp = bp;
  70.             curwp = bp2any_wp(bp);
  71.             DOT.l = lback(buf_head(bp));
  72.             DOT.o = 0;
  73.             bprintf("%s:%d:", oldbp->b_bname, line_no(oldbp, linep));
  74.             DOT.o = 0;
  75.             curbp = savebp;
  76.             curwp = savewp;
  77.         }
  78.         linep = lforw(linep);
  79.     } while (linep != region.r_end.l);
  80.  
  81.     set_bname(bp, P_LINES_BufName);
  82.     set_rdonly(bp, non_filename(), MDVIEW);
  83.     set_b_val(bp,VAL_TAB,tabstop_val(curbp));
  84.  
  85.     for_each_visible_window(wp) {
  86.         if (wp->w_bufp == bp) {
  87.             make_local_w_val(wp,WMDLIST);
  88.             set_w_val(wp, WMDLIST, ((flag & PLIST) != 0) );
  89.             wp->w_flag |= WFMODE|WFFORCE;
  90.         }
  91.     }
  92.     return TRUE;
  93. }
  94.  
  95. int
  96. llineregion(void)
  97. {
  98.     return pregion(PLIST);
  99. }
  100.  
  101. int
  102. pplineregion(void)
  103. {
  104.     return pregion(PNUMS);
  105. }
  106.  
  107. int
  108. plineregion(void)
  109. {
  110.     return pregion(0);
  111. }
  112.  
  113. static regexp *substexp;
  114.  
  115. int
  116. substregion(void)
  117. {
  118.     return substreg1(TRUE,TRUE);
  119. }
  120.  
  121. int
  122. subst_again_region(void)
  123. {
  124.     return substreg1(FALSE,TRUE);
  125. }
  126.  
  127. /* traditional vi & command */
  128. /* ARGSUSED */
  129. int
  130. subst_again(int f GCC_UNUSED, int n GCC_UNUSED)
  131. {
  132.     int s;
  133.     MARK curpos;
  134.  
  135.     curpos = DOT;
  136.  
  137.     /* the region spans just the line */
  138.     MK.l = DOT.l;
  139.     DOT.o = 0;
  140.     MK.o = llength(MK.l);
  141.     s = substreg1(FALSE,FALSE);
  142.     if (s != TRUE) {
  143.         mlforce("[No match.]");
  144.         DOT = curpos;
  145.         return s;
  146.     }
  147.     swapmark();
  148.     return TRUE;
  149. }
  150.  
  151. static int
  152. substreg1(int needpats, int use_opts)
  153. {
  154.     int c, status;
  155.     static int printit, globally, nth_occur, confirm;
  156.     REGION region;
  157.     LINEPTR oline;
  158.     int    getopts = FALSE;
  159.     char    tpat[NPAT];
  160.  
  161.     if ((status = get_fl_region(®ion)) != TRUE) {
  162.         return (status);
  163.     }
  164.  
  165.     if (calledbefore == FALSE && needpats) {
  166.         c = kbd_delimiter();
  167.         if ((status = readpattern("substitute pattern: ", &pat[0],
  168.                     &gregexp, c, FALSE)) != TRUE) {
  169.             if (status != ABORT)
  170.                 mlforce("[No pattern.]");
  171.             return FALSE;
  172.         }
  173.  
  174.         if (gregexp) {
  175.             FreeIfNeeded(substexp);
  176.             substexp = castalloc(regexp,(ALLOC_T)(gregexp->size));
  177.             (void)memcpy((char *)substexp, (char *)gregexp,
  178.                             (SIZE_T)gregexp->size);
  179.         }
  180.  
  181.         tpat[0] = 0;
  182.         status = readpattern("replacement string: ",
  183.                      &tpat[0], (regexp **)0, c, FALSE);
  184.  
  185.         (void)strcpy(rpat, tpat);
  186.         if (status == ABORT)
  187.             /* if false, the pattern is null, which is okay... */
  188.             return FALSE;
  189.  
  190.         nth_occur = -1;
  191.         confirm = printit = globally = FALSE;
  192.         getopts = (lastkey == c); /* the user may have
  193.                         something to add */
  194.  
  195.     } else {
  196.         if (!use_opts) {
  197.             nth_occur = -1;
  198.             printit = globally = FALSE;
  199.         } else {
  200.             if (more_named_cmd()) {
  201.                 unkeystroke(lastkey);
  202.                 nth_occur = -1;
  203.                 printit = globally = FALSE;
  204.                 getopts = TRUE;
  205.             }
  206.         }
  207.     }
  208.  
  209.     if (getopts) {
  210.         char buf[4];
  211.         char *bp = buf;
  212.  
  213.         buf[0] = EOS;
  214.         status = mlreply(
  215. "(g)lobally, ([1-9])th occurrence on line, (c)onfirm, and/or (p)rint result: ",
  216.             buf, sizeof buf);
  217.         if (status == ABORT) {
  218.             return FALSE;
  219.         }
  220.         nth_occur = 0;
  221.         while (*bp) {
  222.             if (*bp == 'p' && !printit) {
  223.                 printit = TRUE;
  224.             } else if (*bp == 'g' &&
  225.                     !globally && !nth_occur) {
  226.                 globally = TRUE;
  227.             } else if (isDigit(*bp) &&
  228.                     !nth_occur && !globally) {
  229.                 nth_occur = *bp - '0';
  230.                 globally = TRUE;
  231.             } else if (*bp == 'c' && !confirm) {
  232.                 confirm = TRUE;
  233.             } else if (!isSpace(*bp)) {
  234.                 mlforce("[Unknown action %s]",buf);
  235.                 return FALSE;
  236.             }
  237.             bp++;
  238.         }
  239.         if (!nth_occur)
  240.             nth_occur = -1;
  241.     }
  242.  
  243.     lines_changed =
  244.     total_changes = 0;
  245.     DOT.l = region.r_orig.l;        /* Current line.        */
  246.     do {
  247.         oline = DOT.l;
  248.         if ((status = substline(substexp, nth_occur, printit,
  249.                         globally, &confirm)) != TRUE) {
  250.             return status;
  251.         }
  252.         DOT.l = lforw(oline);
  253.     } while (!sameline(DOT, region.r_end));
  254.     calledbefore = TRUE;
  255.  
  256.     if (do_report(total_changes)) {
  257.         mlforce("[%d change%s on %d line%s]",
  258.             total_changes, PLURAL(total_changes),
  259.             lines_changed, PLURAL(lines_changed));
  260.     }
  261.     return TRUE;
  262. }
  263.  
  264. /* show the pattern we've matched (at least one space, even for empty-string) */
  265. static void
  266. showpat(regexp *rp, int on)
  267. {
  268.     register LINEPTR    lp;
  269.     int    row;
  270.  
  271.     for (lp = curwp->w_line.l, row = curwp->w_toprow;
  272.         lp != DOT.l;
  273.             lp = lforw(lp))
  274.         row += line_height(curwp,lp);
  275.  
  276.     hilite(row,
  277.         offs2col(curwp, lp, DOT.o),
  278.         offs2col(curwp, lp, (C_NUM)(DOT.o + rp->mlen)) + (rp->mlen == 0),
  279.         on);
  280. }
  281.  
  282. static int
  283. substline(regexp *exp, int nth_occur, int printit, int globally, int *confirmp)
  284. {
  285.     int foundit;
  286.     int again = 0;
  287.     register int s;
  288.     register int which_occur = 0;
  289.     int matched_at_eol = FALSE;
  290.     int yes, c, skipped;
  291.  
  292.     /* if the "magic number" hasn't been set yet... */
  293.     if (!exp || UCHAR_AT(exp->program) != REGEXP_MAGIC) {
  294.         mlforce("[No pattern set yet]");
  295.         return FALSE;
  296.     }
  297.  
  298.     ignorecase = window_b_val(curwp, MDIGNCASE);
  299.  
  300.     foundit = FALSE;
  301.     scanboundpos.l = DOT.l;
  302.     scanbound_is_header = FALSE;
  303.     DOT.o = 0;
  304.     do {
  305.         scanboundpos.o = llength(DOT.l);
  306.         s = scanner(exp, FORWARD, FALSE, (int *)0);
  307.         if (s != TRUE)
  308.             break;
  309.  
  310.         /* found the pattern */
  311.         foundit = TRUE;
  312.         which_occur++;
  313.         if (nth_occur == -1 || which_occur == nth_occur) {
  314.             (void)setmark();
  315.             /* only allow one match at the end of line, to
  316.                 prevent loop with s/$/x/g  */
  317.             if (MK.o == llength(DOT.l)) {
  318.                 if (matched_at_eol)
  319.                     break;
  320.                 matched_at_eol = TRUE;
  321.             }
  322.  
  323.             /* if we need confirmation, get it */
  324.             skipped = FALSE;
  325.             if (*confirmp) {
  326.  
  327.                 /* force the pattern onto the screen */
  328.                 (void)gomark(FALSE, 0);
  329.                 if (update(TRUE) == TRUE)
  330.                     showpat(exp, TRUE);
  331.                 s = mlquickask("Make change [y/n/q/a]?",
  332.                     "ynqa\r",&c);
  333.  
  334.                 showpat(exp, FALSE);
  335.  
  336.                 if (s != TRUE)
  337.                     c = 'q';
  338.  
  339.                 switch(c) {
  340.                 case 'y' :
  341.                     yes = TRUE;
  342.                     break;
  343.                 default:
  344.                 case 'n' :
  345.                     yes = FALSE;
  346.                     (void)update(TRUE);
  347.                     skipped = TRUE;
  348.                     /* so we don't match this again */
  349.                     DOT.o += exp->mlen;
  350.                     break;
  351.                 case 'q' :
  352.                     mlerase();
  353.                     return(FALSE);
  354.                 case 'a' :
  355.                     yes = TRUE;
  356.                     *confirmp = FALSE;
  357.                     mlerase();
  358.                     break;
  359.                 }
  360.             } else {
  361.                 yes = TRUE;
  362.             }
  363.             if (yes) {
  364.                 s = delins(exp, &rpat[0]);
  365.                 if (s != TRUE)
  366.                     return s;
  367.                 if (!again++)
  368.                     lines_changed++;
  369.                 total_changes++;
  370.             }
  371.             if (*confirmp && !skipped) /* force a screen update */
  372.                 (void)update(TRUE);
  373.  
  374.             if (exp->mlen == 0 && forwchar(TRUE,1) == FALSE)
  375.                 break;
  376.             if (nth_occur > 0)
  377.                 break;
  378.         } else { /* non-overlapping matches */
  379.             s = forwchar(TRUE, (int)(exp->mlen));
  380.             if (s != TRUE)
  381.                 return s;
  382.         }
  383.     } while (globally && sameline(scanboundpos,DOT));
  384.     if (foundit && printit) {
  385.         register WINDOW *wp = curwp;
  386.         (void)setmark();
  387.         s = plineregion();
  388.         if (s != TRUE) return s;
  389.         /* back to our buffer */
  390.         swbuffer(wp->w_bufp);
  391.     }
  392.     if (*confirmp)
  393.         mlerase();
  394.     return TRUE;
  395. }
  396.  
  397. /*
  398.  * delins, modified by pgf from regsub
  399.  *
  400.  *    Copyright (c) 1986 by University of Toronto.
  401.  *    Written by Henry Spencer.  Not derived from licensed software.
  402.  *
  403.  *    Permission is granted to anyone to use this software for any
  404.  *    purpose on any computer system, and to redistribute it freely,
  405.  *    subject to the following restrictions:
  406.  *
  407.  *    1. The author is not responsible for the consequences of use of
  408.  *        this software, no matter how awful, even if they arise
  409.  *        from defects in it.
  410.  *
  411.  *    2. The origin of this software must not be misrepresented, either
  412.  *        by explicit claim or by omission.
  413.  *
  414.  *    3. Altered versions must be plainly marked as such, and must not
  415.  *        be misrepresented as being the original software.
  416.  */
  417.  
  418. static    char    *buf_delins;
  419. static    UINT    len_delins;
  420.  
  421. /*
  422.  - delins - perform substitutions after a regexp match
  423.  */
  424. static int
  425. delins(regexp *exp, char *sourc)
  426. {
  427.     register char *src;
  428.     register ALLOC_T dlength;
  429.     register char c;
  430.     register int no;
  431.     int s;
  432. #define NO_CASE    0
  433. #define UPPER_CASE 1
  434. #define LOWER_CASE 2
  435.     int case_next, case_all;
  436.  
  437.     if (exp == NULL || sourc == NULL) {
  438.         mlforce("BUG: NULL parm to delins");
  439.         return FALSE;
  440.     }
  441.     if (UCHAR_AT(exp->program) != REGEXP_MAGIC) {
  442.         regerror("damaged regexp fed to delins");
  443.         return FALSE;
  444.     }
  445.  
  446.     dlength = exp->mlen;
  447.  
  448.     if (buf_delins == NULL || dlength + 1 > len_delins) {
  449.         if (buf_delins)
  450.             free(buf_delins);
  451.         if ((buf_delins = castalloc(char,dlength+1)) == NULL) {
  452.             mlforce("[Out of memory in delins]");
  453.             return FALSE;
  454.         }
  455.         len_delins = dlength + 1;
  456.     }
  457.  
  458.     (void)memcpy(buf_delins, exp->startp[0], (SIZE_T)dlength);
  459.     buf_delins[dlength] = EOS;
  460.  
  461.     if (ldelete((long) dlength, FALSE) != TRUE) {
  462.         mlforce("[Error while deleting]");
  463.         return FALSE;
  464.     }
  465.     src = sourc;
  466.     case_next = case_all = NO_CASE;
  467.     while ((c = *src++) != EOS) {
  468.         no = 0;
  469.         s = TRUE;
  470.         switch(c) {
  471.         case '\\':
  472.             c = *src++;
  473.             if (c == EOS)
  474.             return TRUE;
  475.             if (!isDigit(c)) {
  476.                 /* here's where the \U \E \u \l \t etc.
  477.                 special escapes should be implemented */
  478.                 switch (c) {
  479.                 case 'U':
  480.                     case_all = UPPER_CASE;
  481.                     break;
  482.                 case 'L':
  483.                     case_all = LOWER_CASE;
  484.                     break;
  485.                 case 'u':
  486.                     case_next = UPPER_CASE;
  487.                     break;
  488.                 case 'l':
  489.                     case_next = LOWER_CASE;
  490.                     break;
  491.                 case 'E':
  492.                 case 'e':
  493.                     case_all = NO_CASE;
  494.                     break;
  495.                 case 'b':
  496.                     s = linsert(1,'\b');
  497.                     break;
  498.                 case 'f':
  499.                     s = linsert(1,'\f');
  500.                     break;
  501.                 case 'r':
  502.                     s = linsert(1,'\r');
  503.                     break;
  504.                 case 't':
  505.                     s = linsert(1,'\t');
  506.                     break;
  507.                 case 'n':
  508.                     s = lnewline();
  509.                     break;
  510.                 default:
  511.                     s = linsert(1,c);
  512.                     break;
  513.                 }
  514.                 break;
  515.             }
  516.             /* else it's a digit --
  517.                 get pattern number, and fall through */
  518.             no = c - '0';
  519.             /* FALLTHROUGH */
  520.         case '&':
  521.             if (exp->startp[no] != NULL && exp->endp[no] != NULL) {
  522.                 char *cp = buf_delins;
  523.                 long len = exp->endp[no] - exp->startp[no];
  524.                 long adj = exp->startp[no] - exp->startp[0];
  525.                 cp += (size_t)adj;
  526.                 while ((s == TRUE) && len--) {
  527.                     c = *cp++;
  528.                     if (c == EOS) {
  529.                         mlforce( "BUG: mangled replace");
  530.                         return FALSE;
  531.                     }
  532.                     if (c == '\n')
  533.                         s = lnewline();
  534.                     else if (case_next == NO_CASE && case_all == NO_CASE)
  535.                         s = linsert(1,c);
  536.                     else {
  537.                         int direction = case_next != NO_CASE ? case_next : case_all;
  538.                         case_next = NO_CASE;
  539.                         /* Somewhat convoluted to handle
  540.                            \u\L correctly (upper case first
  541.                            char, lower case remainder).
  542.                            This is the perl model, not the vi model. */
  543.                         if (isUpper(c) && (direction == LOWER_CASE))
  544.                             c = toLower(c);
  545.                         if (isLower(c) && (direction == UPPER_CASE))
  546.                             c = toUpper(c);
  547.                         s = linsert(1,c);
  548.                     }
  549.                 }
  550.             }
  551.             break;
  552.  
  553.         case '\n':
  554.         case '\r':
  555.             s = lnewline();
  556.             break;
  557.  
  558.         default:
  559.             if (case_next || case_all) {
  560.                 int direction = case_next != NO_CASE ? case_next : case_all;
  561.                 case_next = NO_CASE;
  562.                 /* Somewhat convoluted to handle
  563.                    \u\L correctly (upper case first
  564.                    char, lower case remainder).
  565.                    This is the perl model, not the vi model. */
  566.                 if (isUpper(c) && (direction == LOWER_CASE))
  567.                     c = toLower(c);
  568.                 if (isLower(c) && (direction == UPPER_CASE))
  569.                     c = toUpper(c);
  570.             }
  571.             s = linsert(1,c);
  572.             break;
  573.         }
  574.         if (s != TRUE) {
  575.             mlforce("[Out of memory while inserting]");
  576.             return FALSE;
  577.         }
  578.     }
  579.     return TRUE;
  580. }
  581.  
  582. #if NO_LEAKS
  583. void
  584. onel_leaks(void)
  585. {
  586.     FreeIfNeeded(substexp);
  587.     FreeIfNeeded(buf_delins);
  588. }
  589. #endif
  590.