home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / memacs400_src.lzh / MEMACS400 / SRC / replace.c < prev    next >
Text File  |  1996-04-25  |  12KB  |  524 lines

  1. /*
  2.  * replace.c
  3.  *
  4.  * Functions, formerly in search.c, which handle the search and replace
  5.  * functionality.
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include "estruct.h"
  10. #include "eproto.h"
  11. #include "edef.h"
  12. #include "elang.h"
  13.  
  14. static int    replen;        /* length of replacement string */
  15. static char    *oldpatmatch = NULL;    /* allocated memory for un-do.*/
  16.  
  17. /*
  18.  * sreplace -- Search and replace.
  19.  */
  20. int PASCAL NEAR sreplace(f, n)
  21. int f;                    /* default flag */
  22. int n;                    /* # of repetitions wanted */
  23. {
  24.     return(replaces(FALSE, f, n));
  25. }
  26.  
  27. /*
  28.  * qreplace -- search and replace with query.
  29.  */
  30. int PASCAL NEAR qreplace(f, n)
  31. int f;                    /* default flag */
  32. int n;                    /* # of repetitions wanted */
  33. {
  34.     return(replaces(TRUE, f, n));
  35. }
  36.  
  37. /*
  38.  * replaces -- Search for a string and replace it with another
  39.  *    string.  Query might be enabled (according to kind).
  40.  */
  41. int PASCAL NEAR    replaces(kind, f, n)
  42. int    kind;                /* Query enabled flag */
  43. int    f;                    /* default flag */
  44. int    n;                    /* # of repetitions wanted */
  45. {
  46.     register int status;    /* success flag on pattern inputs */
  47.     register int nummatch;    /* number of found matches */
  48.     long numsub;            /* number of substitutions */
  49.     int nlflag;            /* last char of search string a <NL>? */
  50.     int nlrepl;            /* was a replace done on the last line? */
  51.     char c;                /* input char for query */
  52.     LINE *origline;        /* original "." position */
  53.     int origoff;        /* and offset (for . query option) */
  54.     LINE *lastline;        /* position of last replace and */
  55.     int lastoff;        /* offset (for 'u' query option) */
  56.     int oldmatchlen;    /* Closure may alter the match length.*/
  57.  
  58.     /*
  59.      * Don't allow this command if we are
  60.      * in read only mode.
  61.      */
  62.     if (curbp->b_mode & MDVIEW)
  63.         return (rdonly());
  64.  
  65.     /* Check for negative repetitions.
  66.      */
  67.     if (f && n < 0)
  68.         return (FALSE);
  69.  
  70.     /* Ask the user for the text of a pattern.
  71.      */
  72.     if ((status = readpattern(kind ? TEXT85 : TEXT84, (char *) &pat[0], TRUE)) != TRUE)
  73. /*                "Replace" */
  74. /*                        "Query replace" */
  75.         return (status);
  76.  
  77.     /* Ask for the replacement string, and get its length.
  78.      */
  79.     if ((status = readpattern(TEXT86, (char *) &rpat[0], FALSE)) == ABORT)
  80. /*                "with" */
  81.         return (status);
  82.  
  83.     /* Set up flags so we can make sure not to do a recursive
  84.      * replace on the last line.
  85.      */
  86.     nlflag = (pat[strlen(pat) - 1] == '\r');
  87.     nlrepl = FALSE;
  88.  
  89.     /* Save original . position, reset the number of matches and
  90.      * substitutions, and scan through the file.
  91.      */
  92.     origline = curwp->w_dotp;
  93.     origoff = curwp->w_doto;
  94.     numsub = 0L;
  95.     nummatch = 0;
  96.     lastline = (LINE *) NULL;
  97.     mmove_flag = FALSE;    /* disable mouse move events          */
  98.  
  99.     while ((f == FALSE || n > nummatch) &&
  100.         (nlflag == FALSE || nlrepl == FALSE))
  101.     {
  102.         /* let the undo checkpoint out position each q-replacement */
  103.         if (kind)
  104.             undo_insert(OP_CMND, 1, obj);
  105.  
  106.         /* Search for the pattern.
  107.          * If we search with a regular expression,
  108.          * matchlen is reset to the true length of
  109.          * the matched string.
  110.          */
  111. #if    MAGIC
  112.         if (magical && (curwp->w_bufp->b_mode & MDMAGIC)) {
  113.             if (!mcscanner(&mcpat[0], FORWARD, PTBEG, 1))
  114.                 break;
  115.         }
  116.         else
  117.             if (!mcscanner(&mcdeltapat[0], FORWARD, PTBEG, 1))
  118.                 break;    /* all done */
  119. #else
  120.         if (!scanner(FORWARD, PTBEG, 1))
  121.             break;    /* all done */
  122. #endif
  123.  
  124.         ++nummatch;        /* Increment # of matches */
  125.  
  126.         /* Check if we are on the last line.
  127.          */
  128.         nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
  129.  
  130.         /* Check for query.
  131.          */
  132.         if (kind) {
  133.             /* Get the query.
  134.              */
  135. pprompt:    mlrquery();
  136. qprompt:
  137.             /* Show the proposed place to change, and
  138.              * update the position on the modeline if needed.
  139.              */
  140.             if (posflag)
  141.                 upmode();
  142.             update(TRUE);
  143.             c = tgetc();    /* and input */
  144.             mlerase();    /* and clear it */
  145.  
  146.             /* And respond appropriately.
  147.              */
  148.             switch (c) {
  149. #if    FRENCH
  150.                 case 'o':    /* oui, substitute */
  151.                 case 'O':
  152. #endif
  153.             case 'y':    /* yes, substitute */
  154.             case 'Y':
  155.             case 'l':    /* last substitute */
  156.             case 'L':
  157.             case ' ':
  158.                 break;
  159.  
  160.             case 'n':    /* no, onward */
  161.             case 'N':
  162.                 forwchar(FALSE, 1);
  163.                 continue;
  164.  
  165.             case '!':    /* yes/stop asking */
  166.                 kind = FALSE;
  167.                 break;
  168.  
  169.             case 'u':    /* undo last and re-prompt */
  170.             case 'U':
  171.                 /* Restore old position.
  172.                  */
  173.                 if (lastline == (LINE *) NULL) {
  174.                     /* There is nothing to undo.
  175.                      */
  176.                     TTbeep();
  177.                     goto pprompt;
  178.                 }
  179.                 curwp->w_dotp = lastline;
  180.                 curwp->w_doto = lastoff;
  181.                 lastline = NULL;
  182.                 lastoff = 0;
  183.  
  184.                 /* Delete the new string,
  185.                  * restore the old match.
  186.                  */
  187.                 backchar(FALSE, replen);
  188.                 status = delins(replen, oldpatmatch, FALSE);
  189.                 if (status != TRUE) {
  190.                     mmove_flag = TRUE;
  191.                     return (status);
  192.                 }
  193.  
  194.                 /* Record one less substitution,
  195.                  * backup, save our place, and
  196.                  * reprompt.
  197.                  */
  198.                 --numsub;
  199.                 backchar(FALSE, oldmatchlen);
  200.                 matchlen = oldmatchlen;
  201.                 matchline = curwp->w_dotp;
  202.                 matchoff = curwp->w_doto;
  203.                 continue;
  204.  
  205.             case '.':    /* abort! and return */
  206.                 /* restore old position */
  207.                 curwp->w_dotp = origline;
  208.                 curwp->w_doto = origoff;
  209.                 curwp->w_flag |= WFMOVE;
  210.  
  211.             case BELL:    /* abort! and stay */
  212.                 mlwrite(TEXT89);
  213. /*                        "Aborted!" */
  214.                 mmove_flag = TRUE;
  215.                 return (FALSE);
  216.  
  217.             default:    /* bitch and beep */
  218.                 TTbeep();
  219.  
  220.             case '?':    /* help me */
  221.                 mlwrite(TEXT90);
  222. /*"(Y)es, (N)o, (!)Do rest, (U)ndo last, (^G)Abort, (.)Abort back, (?)Help: "*/
  223.                 goto qprompt;
  224.  
  225.             }        /* end of switch */
  226.         }        /* end of "if kind" */
  227.  
  228.         /* if this is the point origin, flag so we a can reset it */
  229.         if (curwp->w_dotp == origline) {
  230.             origline = NULL;
  231.             lastline = lback(curwp->w_dotp);
  232.         }
  233.  
  234.         /* Delete the sucker, and insert its
  235.          * replacement.
  236.          */
  237. #if    MAGIC
  238.         status = delins(matchlen, (char *)&rpat[0], rmagical);
  239. #else
  240.         status = delins(matchlen, (char *)&rpat[0], FALSE);
  241. #endif
  242.         if (origline == NULL) {
  243.             origline = lforw(lastline);
  244.             origoff = 0;
  245.         }
  246.  
  247.         if (status != TRUE) {
  248.             mmove_flag = TRUE;
  249.             return (status);
  250.         }
  251.  
  252.         numsub++;        /* increment # of substitutions */
  253.  
  254.         /* Save our position, the match length, and the string
  255.          * matched if we are query-replacing, as we may undo
  256.          * the replacement. If we are not querying, check to
  257.          * make sure that we didn't replace an empty string
  258.          * (possible in MAGIC mode), because we'll infinite loop.
  259.          */
  260.         if (kind) {
  261.             if (c == 'l' || c == 'L')
  262.                 break;
  263.             lastline = curwp->w_dotp;
  264.             lastoff = curwp->w_doto;
  265.             oldmatchlen = matchlen;    /* Save the length for un-do.*/
  266.  
  267.             if ((oldpatmatch = reroom(oldpatmatch, matchlen + 1)) == NULL) {
  268.                 mlabort(TEXT94);
  269. /*                    "%%Out of memory" */
  270.                 mmove_flag = TRUE;
  271.                 return(ABORT);
  272.             }
  273.             strcpy(oldpatmatch, patmatch);
  274.         }
  275.         else if (matchlen == 0) {
  276.             mlwrite(TEXT91);
  277. /*                "Empty string replaced, stopping." */
  278.             mmove_flag = TRUE;
  279.             return (FALSE);
  280.         }
  281.     }
  282.  
  283.     /* And report the results.
  284.      */
  285.     mlwrite(TEXT92, numsub);
  286. /*        "%d substitutions" */
  287.     mmove_flag = TRUE;
  288.     return (TRUE);
  289. }
  290.  
  291. /*
  292.  * mlrquery -- The prompt for query-replace-string.
  293.  */
  294. VOID PASCAL NEAR mlrquery()
  295. {
  296.     register int    tcol;
  297. #if    MAGIC
  298.     register RMC    *rmcptr;
  299. #endif
  300.  
  301.     mlwrite(TEXT87);
  302. /*        "Replace '" */
  303.  
  304.     tcol = echostring(patmatch, strlen(TEXT87), NPAT / 2);
  305.  
  306.     mlputs(TEXT88);
  307. /*        "' with '" */
  308.     tcol += strlen(TEXT88);
  309.  
  310. #if    MAGIC
  311.     if (rmagical && (curwp->w_bufp->b_mode & MDMAGIC)) {
  312.         rmcptr = &rmcpat[0];
  313.  
  314.         while (rmcptr->mc_type != MCNIL && tcol < NPAT - 8) {
  315.             if (rmcptr->mc_type == LITSTRING)
  316.                 tcol = echostring(rmcptr->u.rstr, tcol, NPAT - 8);
  317.             else if (rmcptr->mc_type == DITTO)
  318.                 tcol = echostring(patmatch, tcol, NPAT - 8);
  319.             else
  320.                 tcol = echostring(grpmatch[rmcptr->u.group_no],
  321.                     tcol, NPAT - 8);
  322.             rmcptr++;
  323.         }
  324.     }
  325.     else
  326. #endif
  327.         echostring((char *) rpat, tcol, NPAT - 8);
  328.  
  329.     mlputs("'? ");
  330. }
  331.  
  332. /*
  333.  * delins -- Delete a specified length from the current point
  334.  *    then either insert the string directly, or make use of
  335.  *    replacement meta-array.
  336.  */
  337. int PASCAL NEAR delins(dlength, instr, use_rmc)
  338. int    dlength;
  339. char    *instr;
  340. int    use_rmc;
  341. {
  342.     register int    status;
  343.     register char    *rstr;
  344. #if    MAGIC
  345.     register RMC    *rmcptr;
  346. #endif
  347.  
  348.     replen = 0;
  349.  
  350.     /* Zap what we gotta,
  351.      * and insert its replacement.
  352.      */
  353.     if ((status = ldelete((long) dlength, FALSE)) != TRUE)
  354.         mlwrite(TEXT93);
  355. /*            "%%ERROR while deleting" */
  356.     else
  357. #if    MAGIC
  358.         if (use_rmc && (curwp->w_bufp->b_mode & MDMAGIC)) {
  359.             rmcptr = &rmcpat[0];
  360.             while (rmcptr->mc_type != MCNIL && status == TRUE) {
  361.                 if (rmcptr->mc_type == LITSTRING)
  362.                     status = linstr(rstr = rmcptr->u.rstr);
  363.                 else if (rmcptr->mc_type == DITTO)
  364.                     status = linstr(rstr = patmatch);
  365.                 else
  366.                     status = linstr(rstr = fixnull(grpmatch[rmcptr->u.group_no]));
  367.                 replen += strlen(rstr);
  368.                 rmcptr++;
  369.             }
  370.         }
  371.         else
  372. #endif
  373.         {
  374.             status = linstr(instr);
  375.             replen = strlen(instr);
  376.         }
  377.  
  378.     return (status);
  379. }
  380. #if MAGIC
  381. /*
  382.  * rmcstr -- Set up the replacement 'magic' array.  Note that if there
  383.  *    are no meta-characters encountered in the replacement string,
  384.  *    the array is never actually created - we will just use the
  385.  *    character array rpat[] as the replacement string.
  386.  */
  387. int PASCAL NEAR rmcstr()
  388. {
  389.     RMC    *rmcptr;
  390.     char    *patptr;
  391.     int    pchr;
  392.     int    status = TRUE;
  393.     int    mj;
  394.  
  395.     patptr = (char *) &rpat[0];
  396.     rmcptr = &rmcpat[0];
  397.     mj = 0;
  398.     rmagical = FALSE;
  399.  
  400.     while (*patptr && status == TRUE) {
  401.         switch (*patptr) {
  402.         case MC_DITTO:
  403.  
  404.             /* If there were non-magical characters in
  405.              * the string before reaching this character
  406.              * plunk it in the replacement array before
  407.              * processing the current meta-character.
  408.              */
  409.             if (mj != 0) {
  410.                 rmcptr->mc_type = LITSTRING;
  411.                 if ((rmcptr->u.rstr = room(mj + 1)) == NULL) {
  412.                     mlabort(TEXT94);
  413. /*                            "%%Out of memory" */
  414.                     status = FALSE;
  415.                     break;
  416.                 }
  417.                 bytecopy(rmcptr->u.rstr, patptr - mj, mj);
  418.                 rmcptr++;
  419.                 mj = 0;
  420.             }
  421.             rmcptr->mc_type = DITTO;
  422.             rmcptr++;
  423.             rmagical = TRUE;
  424.             break;
  425.  
  426.         case MC_ESC:
  427.             pchr = *(patptr + 1);    /* peek at next char.*/
  428.             if (pchr <= '9' && pchr >= '1') {
  429.                 if (mj != 0) {
  430.                     rmcptr->mc_type = LITSTRING;
  431.                     if ((rmcptr->u.rstr = room(mj + 1)) == NULL) {
  432.                         mlabort(TEXT94);
  433. /*                            "%%Out of memory" */
  434.                         status = FALSE;
  435.                         break;
  436.                     }
  437.                     bytecopy(rmcptr->u.rstr, patptr - mj, mj);
  438.                     rmcptr++;
  439.                     mj = 0;
  440.                 }
  441.                 rmcptr->mc_type = GROUP;
  442.                 rmcptr->u.group_no = pchr - '0';
  443.                 patptr++;
  444.             }
  445.             else
  446.             {
  447.                 rmcptr->mc_type = LITSTRING;
  448.  
  449.                 /* We room mj plus two here, instead
  450.                  * of one, because we have to count the
  451.                  * current character.
  452.                  */
  453.                 if ((rmcptr->u.rstr = room(mj + 2)) == NULL) {
  454.                     mlabort(TEXT94);
  455. /*                        "%%Out of memory" */
  456.                     status = FALSE;
  457.                     break;
  458.                 }
  459.  
  460.                 bytecopy(rmcptr->u.rstr, patptr - mj, mj + 1);
  461.  
  462.                 /* If MC_ESC is not the last character
  463.                  * in the string, find out what it is
  464.                  * escaping, and overwrite the last
  465.                  * character with it.
  466.                  */
  467.                 if (pchr != '\0') {
  468.                     *((rmcptr->u.rstr) + mj) = pchr;
  469.                     patptr++;
  470.                 }
  471.                 mj = 0;
  472.             }
  473.  
  474.             rmcptr++;
  475.             rmagical = TRUE;
  476.             break;
  477.  
  478.         default:
  479.             mj++;
  480.         }
  481.         patptr++;
  482.     }
  483.  
  484.     if (rmagical && mj > 0) {
  485.         rmcptr->mc_type = LITSTRING;
  486.         if ((rmcptr->u.rstr = room(mj + 1)) == NULL) {
  487.             mlabort(TEXT94);
  488. /*                "%%Out of memory" */
  489.             status = FALSE;
  490.         }
  491.         bytecopy(rmcptr->u.rstr, patptr - mj, mj);
  492.         rmcptr++;
  493.     }
  494.  
  495.     rmcptr->mc_type = MCNIL;
  496. #if DEBUG_SEARCH
  497.     rmc_list(0,0);
  498. #endif
  499.     return (status);
  500. }
  501.  
  502. /*
  503.  * rmcclear -- Free up any strings, and MCNIL the RMC array.
  504.  */
  505. VOID PASCAL NEAR rmcclear()
  506. {
  507.     register RMC    *rmcptr;
  508.  
  509.     rmcptr = &rmcpat[0];
  510.  
  511.     while (rmcptr->mc_type != MCNIL) {
  512.         if (rmcptr->mc_type == LITSTRING)
  513.             free(rmcptr->u.rstr);
  514.         rmcptr++;
  515.     }
  516.  
  517.     rmcpat[0].mc_type = MCNIL;
  518.     rmagical = FALSE;
  519.     if (oldpatmatch != NULL)
  520.         free(oldpatmatch);
  521.     oldpatmatch = NULL;
  522. }
  523. #endif
  524.