home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / jove / part06 / re1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-02-02  |  9.4 KB  |  475 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986 by Jonathan Payne.  JOVE is       *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "io.h"
  10. #include "re.h"
  11.  
  12. static
  13. substitute(query, l1, char1, l2, char2)
  14. Line    *l1,
  15.     *l2;
  16. {
  17.     Line    *lp;
  18.     int    numdone = 0,
  19.         offset = curchar,
  20.         stop = 0;
  21.     disk_line    UNDO_da = 0;
  22.     Line        *UNDO_lp = 0;
  23.  
  24.     lsave();
  25.     REdirection = FORWARD;
  26.  
  27.     lp = l1;
  28.     for (lp = l1; (lp != l2->l_next) && !stop; lp = lp->l_next) {
  29.         offset = (lp == l1) ? char1 : 0;
  30.         while (!stop && re_lindex(lp, offset, compbuf, alternates, 0)) {
  31.             if (lp == l2 && REeom > char2)    /* nope, leave this alone */
  32.                 break;
  33.             DotTo(lp, REeom);
  34.             offset = curchar;
  35.             if (query) {
  36.                 message("Replace (Type '?' for help)? ");
  37. reswitch:            redisplay();
  38.                 switch (Upper(getchar())) {
  39.                 case '.':
  40.                     stop++;
  41.                     /* Fall into ... */
  42.  
  43.                 case ' ':
  44.                 case 'Y':
  45.                     break;
  46.  
  47.                 case BS:
  48.                 case RUBOUT:
  49.                 case 'N':
  50.                     if (linebuf[offset++] == '\0')
  51.                         goto nxtline;
  52.                     continue;
  53.  
  54.                 case CTL(W):
  55.                     re_dosub(linebuf, YES);
  56.                     numdone++;
  57.                     offset = curchar = REbom;
  58.                     makedirty(curline);
  59.                     /* Fall into ... */
  60.  
  61.                 case CTL(R):
  62.                 case 'R':
  63.                     RErecur();
  64.                     offset = curchar;
  65.                     lp = curline;
  66.                     continue;
  67.  
  68.                 case CTL(U):
  69.                 case 'U':
  70.                     if (UNDO_lp == 0)
  71.                         continue;
  72.                     lp = UNDO_lp;
  73.                     lp->l_dline = UNDO_da | DIRTY;
  74.                     offset = 0;
  75.                     numdone--;
  76.                     continue;
  77.  
  78.                 case 'P':
  79.                 case '!':
  80.                     query = 0;
  81.                     break;
  82.  
  83.                 case CR:
  84.                 case LF:
  85.                 case 'Q':
  86.                     goto done;
  87.  
  88.                 case CTL(L):
  89.                     RedrawDisplay();
  90.                     goto reswitch;
  91.  
  92.                 default:
  93.                     rbell();
  94. message("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
  95.                     goto reswitch;
  96.                 }
  97.             }
  98.             re_dosub(linebuf, NO);
  99.             numdone++;
  100.             modify();
  101.             offset = curchar = REeom;
  102.             makedirty(curline);
  103.             if (query) {
  104.                 message(mesgbuf);    /* No blinking. */
  105.                 redisplay();        /* Show the change. */
  106.             }
  107.             UNDO_da = curline->l_dline;
  108.             UNDO_lp = curline;
  109.             if (linebuf[offset] == 0)
  110. nxtline:            break;
  111.         }
  112.     }
  113.     SetMark();
  114. done:    s_mess("%d substitution%n.", numdone, numdone);
  115. }
  116.  
  117. /* Prompt for search and replacement strings and do the substitution.  The
  118.    point is restored when we're done. */
  119.  
  120. static
  121. replace(query, inreg)
  122. {
  123.     Mark    *save = MakeMark(curline, curchar, FLOATER),
  124.         *m;
  125.     char    *rep_ptr;
  126.     Line    *l1 = curline,
  127.         *l2 = curbuf->b_last;
  128.     int    char1 = curchar,
  129.         char2 = length(curbuf->b_last);
  130.  
  131.     if (inreg) {
  132.         m = CurMark();
  133.         l2 = m->m_line;
  134.         char2 = m->m_char;
  135.         (void) fixorder(&l1, &char1, &l2, &char2);
  136.     }
  137.  
  138.     /* Get search string. */
  139.     strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *) 0, ProcFmt));
  140.     REcompile(rep_search, UseRE, compbuf, alternates);
  141.     /* Now the replacement string.  Do_ask() so the user can play with
  142.        the default (previous) replacement string by typing C-R in ask(),
  143.        OR, he can just hit Return to replace with nothing. */
  144.     rep_ptr = do_ask("\r\n", (int (*)()) 0, rep_str, ": %f %s with ", rep_search);
  145.     if (rep_ptr == 0)
  146.         rep_ptr = NullStr;
  147.     strcpy(rep_str, rep_ptr);
  148.  
  149.     substitute(query, l1, char1, l2, char2);
  150.     ToMark(save);
  151.     DelMark(save);
  152. }
  153.  
  154. RegReplace()
  155. {
  156.     replace(0, YES);
  157. }
  158.  
  159. QRepSearch()
  160. {
  161.     replace(1, NO);
  162. }
  163.  
  164. RepSearch()
  165. {
  166.     replace(0, NO);
  167. }
  168.  
  169. /* C tags package. */
  170.  
  171. static
  172. lookup(searchbuf, filebuf, tag, file)
  173. char    *searchbuf,
  174.     *filebuf,
  175.     *tag,
  176.     *file;
  177. {
  178.     register int    taglen = strlen(tag);
  179.     char    line[128],
  180.         pattern[100];
  181.     File    *fp;
  182.  
  183.     fp = open_file(file, iobuff, F_READ, !COMPLAIN, QUIET);
  184.     if (fp == NIL)
  185.         return 0;
  186.     sprintf(pattern, "^%s[^\t]*\t\\([^\t]*\\)\t[?/]\\(.*\\)[?/]$", tag);
  187.     while (f_gets(fp, line, sizeof line) != EOF) {
  188.         if (line[0] != *tag || strncmp(tag, line, taglen) != 0)
  189.             continue;
  190.         if (!LookingAt(pattern, line, 0)) {
  191.             complain("I thought I saw it!");
  192.             break;
  193.         } else {
  194.             putmatch(2, searchbuf, 100);
  195.             putmatch(1, filebuf, 100);
  196.             close_file(fp);
  197.             return 1;
  198.         }
  199.     }
  200.     f_close(fp);
  201.     s_mess("Can't find tag \"%s\".", tag);
  202.     return 0;
  203. }
  204.  
  205. char    TagFile[128] = "./tags";
  206.  
  207. find_tag(tag, localp)
  208. char    *tag;
  209. {
  210.     char    filebuf[FILESIZE],
  211.         sstr[100],
  212.         tfbuf[FILESIZE];
  213.     register Bufpos    *bp;
  214.     register Buffer    *b;
  215.     char    *tagfname;
  216.  
  217.     if (!localp) {
  218.         char    prompt[128];
  219.  
  220.         sprintf(prompt, "With tag file (%s default): ", TagFile);
  221.         tagfname = ask_file(prompt, TagFile, tfbuf);
  222.     } else
  223.         tagfname = TagFile;
  224.     if (lookup(sstr, filebuf, tag, tagfname) == 0)
  225.         return;
  226.     SetMark();
  227.     b = do_find(curwind, filebuf, 0);
  228.     if (curbuf != b)
  229.         SetABuf(curbuf);
  230.     SetBuf(b);
  231.     if ((bp = dosearch(sstr, BACKWARD, 0)) == 0 &&
  232.         (WrapScan || ((bp = dosearch(sstr, FORWARD, 0)) == 0)))
  233.         message("Well, I found the file, but the tag is missing.");
  234.     else
  235.         SetDot(bp);
  236. }
  237.  
  238. FindTag()
  239. {
  240.     int    localp = !exp_p;
  241.     char    tag[128];
  242.  
  243.     strcpy(tag, ask((char *) 0, ProcFmt));
  244.     find_tag(tag, localp);
  245. }
  246.  
  247. /* Find Tag at Dot. */
  248.  
  249. FDotTag()
  250. {
  251.     int    c1 = curchar,
  252.         c2 = c1;
  253.     char    tagname[50];
  254.  
  255.     if (!ismword(linebuf[curchar]))
  256.         complain("Not a tag!");
  257.     while (c1 > 0 && ismword(linebuf[c1 - 1]))
  258.         c1--;
  259.     while (ismword(linebuf[c2]))
  260.         c2++;
  261.  
  262.     null_ncpy(tagname, linebuf + c1, c2 - c1);
  263.     find_tag(tagname, !exp_p);
  264. }
  265.  
  266. /* I-search returns a code saying what to do:
  267.    STOP:    We found the match, so unwind the stack and leave
  268.         where it is.
  269.    DELETE:    Rubout the last command.
  270.    BACKUP:    Back up to where the isearch was last NOT failing.
  271.  
  272.    When a character is typed it is appended to the search string, and
  273.    then, isearch is called recursively.  When C-S or C-R is typed, isearch
  274.    is again called recursively. */
  275.  
  276. #define STOP    1
  277. #define DELETE    2
  278. #define BACKUP    3
  279. #define TOSTART    4
  280.  
  281. static char    ISbuf[128],
  282.         *incp = 0;
  283. int    SExitChar = CR;
  284.  
  285. #define cmp_char(a, b)    ((a) == (b) || (CaseIgnore && (Upper(a) == Upper(b))))
  286.  
  287. static Bufpos *
  288. doisearch(dir, c, failing)
  289. register int    c,
  290.         dir,
  291.         failing;
  292. {
  293.     static Bufpos    buf;
  294.     Bufpos    *bp;
  295.     extern int    okay_wrap;
  296.  
  297.     if (c == CTL(S) || c == CTL(R))
  298.         goto dosrch;
  299.  
  300.     if (failing)
  301.         return 0;
  302.     DOTsave(&buf);
  303.     if (dir == FORWARD) {
  304.         if (cmp_char(linebuf[curchar], c)) {
  305.             buf.p_char = curchar + 1;
  306.             return &buf;
  307.         }
  308.     } else {
  309.         if (look_at(ISbuf))
  310.             return &buf;
  311.     }
  312. dosrch:    okay_wrap = YES;
  313.     if ((bp = dosearch(ISbuf, dir, 0)) == 0)
  314.         rbell();    /* ring the first time there's no match */
  315.     okay_wrap = NO;
  316.     return bp;
  317. }
  318.  
  319. IncFSearch()
  320. {
  321.     IncSearch(FORWARD);
  322. }
  323.  
  324. IncRSearch()
  325. {
  326.     IncSearch(BACKWARD);
  327. }
  328.  
  329. static
  330. IncSearch(dir)
  331. {
  332.     Bufpos    save_env;
  333.  
  334.     DOTsave(&save_env);
  335.     ISbuf[0] = 0;
  336.     incp = ISbuf;
  337.     if (isearch(dir, &save_env) == TOSTART)
  338.         SetDot(&save_env);
  339.     else {
  340.         if (LineDist(curline, save_env.p_line) >= MarkThresh)
  341.             DoSetMark(save_env.p_line, save_env.p_char);
  342.     }
  343.     setsearch(ISbuf);
  344. }
  345.  
  346. /* Nicely recursive. */
  347.  
  348. static
  349. isearch(dir, bp)
  350. Bufpos    *bp;
  351. {
  352.     Bufpos    pushbp;
  353.     int    c,
  354.         ndir,
  355.         failing;
  356.     char    *orig_incp;
  357.  
  358.     if (bp != 0) {        /* Move to the new position. */
  359.         pushbp.p_line = bp->p_line;
  360.         pushbp.p_char = bp->p_char;
  361.         SetDot(bp);
  362.         failing = 0;
  363.     } else {
  364.         DOTsave(&pushbp);
  365.         failing = 1;
  366.     }
  367.     orig_incp = incp;
  368.     ndir = dir;        /* Same direction as when we got here, unless
  369.                    we change it with C-S or C-R. */
  370.     for (;;) {
  371.         SetDot(&pushbp);
  372.         message(NullStr);
  373.         if (failing)
  374.             add_mess("Failing ");
  375.         if (dir == BACKWARD)
  376.             add_mess("reverse-");
  377.         add_mess("I-search: %s", ISbuf);
  378.         DrawMesg(NO);
  379.         add_mess(NullStr);    /* tell me this is disgusting ... */
  380.         c = getch();
  381.         if (c == SExitChar)
  382.             return STOP;
  383.         switch (c) {
  384.         case RUBOUT:
  385.         case BS:
  386.             return DELETE;
  387.  
  388.         case CTL(G):
  389.             /* If we're failing, we backup until we're no longer
  390.                failing or we've reached the beginning; else, we
  391.                just about the search and go back to the start. */
  392.             if (failing)
  393.                 return BACKUP;
  394.             return TOSTART;
  395.  
  396.         case CTL(\\):
  397.             c = CTL(S);
  398.         case CTL(S):
  399.         case CTL(R):
  400.             /* If this is the first time through and we have a
  401.                search string left over from last time, use that
  402.                one now. */
  403.             if (incp == ISbuf) {
  404.                 strcpy(ISbuf, getsearch());
  405.                 incp = &ISbuf[strlen(ISbuf)];
  406.             }
  407.             ndir = (c == CTL(S)) ? FORWARD : BACKWARD;
  408.             /* If we're failing and we're not changing our
  409.                direction, don't recur since there's no way
  410.                the search can work. */
  411.             if (failing && ndir == dir) {
  412.                 rbell();
  413.                 continue;
  414.             }
  415.             break;
  416.  
  417.         case '\\':
  418.             if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
  419.                 rbell();
  420.                 continue;
  421.             }
  422.             *incp++ = '\\';
  423.             add_mess("\\");
  424.             /* Fall into ... */
  425.  
  426.         case CTL(Q):
  427.         case CTL(^):
  428.             add_mess("");
  429.             c = getch() | 0400;
  430.             /* Fall into ... */
  431.  
  432.         default:
  433.             if (c & 0400)
  434.                 c &= 0177;
  435.             else {
  436.                 if (c > RUBOUT || (c < ' ' && c != '\t')) {
  437.                     Ungetc(c);
  438.                     return STOP;
  439.                 }
  440.             }
  441.             if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
  442.                 rbell();
  443.                 continue;
  444.             }
  445.             *incp++ = c;
  446.             *incp = 0;
  447.             break;
  448.         }
  449.         add_mess("%s", orig_incp);
  450.         add_mess(" ...");    /* so we know what's going on */
  451.         DrawMesg(NO);        /* do it now */
  452.         switch (isearch(ndir, doisearch(ndir, c, failing))) {
  453.         case TOSTART:
  454.             return TOSTART;
  455.  
  456.         case STOP:
  457.             return STOP;
  458.  
  459.         case BACKUP:
  460.             /* If we're not failing, we just continue to to the
  461.                for loop; otherwise we keep returning to the 
  462.                previous levels until we find one that isn't
  463.                failing OR we reach the beginning. */
  464.             if (failing)
  465.                 return BACKUP;
  466.             /* Fall into ... */
  467.  
  468.         case DELETE:
  469.             incp = orig_incp;
  470.             *incp = 0;
  471.             continue;
  472.         }
  473.     }
  474. }
  475.