home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / wp_dtp / xdme1821.lha / XDME / search.c < prev    next >
C/C++ Source or Header  |  1993-03-25  |  11KB  |  473 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     search.c
  5.  
  6.     DESCRIPTION
  7.     Inherits all the search/replace stuff for DME
  8.  
  9.     NOTES
  10.  
  11.     BUGS
  12.  
  13.     TODO
  14.  
  15.     EXAMPLES
  16.  
  17.     SEE ALSO
  18.  
  19.     INDEX
  20.  
  21.     HISTORY
  22.     28. May 1992    ada created
  23.  
  24. ******************************************************************************/
  25.  
  26. /* Includes */
  27. #include "defs.h"
  28. #define MYDEBUG     0
  29. #include <debug.h>
  30.  
  31. /* Globale Variable */
  32.  
  33. /* Interne Defines & Strukturen */
  34.  
  35. /* Interne Variable */
  36. /*static*/ UBYTE Fstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
  37. /*static*/ UBYTE Rstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
  38. static char Srch_sign;
  39. static char Doreplace;
  40.  
  41. /* Interne Prototypes */
  42. Prototype void do_findstr    (void);
  43. Prototype void do_findr     (void);
  44. Prototype void do_find        (void);
  45. Prototype void do_replace    (void);
  46. Prototype void search_operation (void);
  47.  
  48.  
  49. /*****************************************************************************
  50.  
  51.     NAME
  52.     do_findstr
  53.  
  54.     PARAMETER
  55.     av[0]        "find" or "replace"
  56.     av[1]        string to find or replace-string
  57.  
  58.     DESCRIPTION
  59.     Copies the search/replace-string to the internal buffer.
  60.  
  61. ******************************************************************************/
  62.  
  63. void do_findstr (void)
  64. {
  65.     if (av[0][0] == 'f')    /* Check command name */
  66.     strcpy(Fstr, av[1]);    /* "find" */
  67.     else
  68.     strcpy(Rstr, av[1]);    /* "replace" */
  69. } /* do_findstr */
  70.  
  71.  
  72. /*****************************************************************************
  73.  
  74.     NAME
  75.     do_findr
  76.  
  77.     PARAMETER
  78.     av[0]    "findr", "nextr" or "prevr"
  79.     av[1]    find-string
  80.     av[2]    replace-string
  81.  
  82.     DESCRIPTION
  83.     Starts one find/replace-operation with both search- and replace-string
  84.     as arguments.
  85.  
  86. ******************************************************************************/
  87.  
  88. void do_findr (void)
  89. {
  90.     Doreplace = 1;  /* Really replace */
  91.     Srch_sign = 1;  /* Search to EOF */
  92.  
  93.     switch (*av[0])
  94.     {
  95.     case 'f':
  96.         strcpy(Fstr, av[1]);    /* Set strings for "findr" */
  97.         strcpy(Rstr, av[2]);
  98.         break;
  99.  
  100.     case 'p':
  101.         Srch_sign = -1;        /* Search reverse */
  102.         break;
  103.     }
  104.  
  105.     search_operation(); /* Start search */
  106. } /* do_findr */
  107.  
  108.  
  109. /*****************************************************************************
  110.  
  111.     NAME
  112.     do_find
  113.  
  114.     PARAMETER
  115.     av[0]    "find", "next" or "prev"
  116.     av[1]    find-string if av[0] == find
  117.  
  118.     DESCRIPTION
  119.     Looks for a new string or searches forwards/backwars for the old one.
  120.  
  121. ******************************************************************************/
  122.  
  123. void do_find (void)
  124. {
  125.     Doreplace = 0;  /* Don't replace */
  126.     Srch_sign = 1;
  127.  
  128.     switch(av[0][0])
  129.     {
  130.     case 'f':   /* Find: new string */
  131.         strcpy(Fstr, av[1]);
  132.     break;
  133.  
  134.     case 'p':   /* Search reverse */
  135.         Srch_sign = -1;
  136.     break;
  137.     }
  138.  
  139.     search_operation ();
  140. } /* do_find */
  141.  
  142.  
  143. /*****************************************************************************
  144.  
  145.     NAME
  146.     do_replace
  147.  
  148.     PARAMETER
  149.     av[0]    "replace"
  150.  
  151.     DESCRIPTION
  152.     Substitutes the next strlen(search-string) chars with the rep-string.
  153.     This command does no checking ! It always removes strlen(search-
  154.     string) chars and the rep-string is always inserted.
  155.  
  156. ******************************************************************************/
  157.  
  158. void do_replace (void)
  159. {
  160.     ULONG  rlen;
  161.     ULONG  flen;
  162.     Column col;
  163.  
  164.     rlen = strlen (Rstr);
  165.     flen = strlen (Fstr);
  166.  
  167.     text_sync ();
  168.  
  169.     col = Ep->column;
  170.  
  171.     /* Check whether replace-string does fit into the line */
  172.     if (rlen > flen && (Clen+rlen-flen) > MAXLINELEN-1)
  173.     {
  174.     error ("replace:\nLine Too Long");
  175.     } else
  176.     /* This if checks whether the search-pattern does fit into
  177.     the current line at the current position !?!?! */
  178.        if (Clen >= col+flen)
  179.     {
  180.     /* Move rest of line. Make enough place for replace-string */
  181.     movmem (Current+col+flen, Current+col+rlen, Clen-col-flen+1);
  182.  
  183.     /* copy replace-string */
  184.     movmem (Rstr, Current+col, rlen);
  185.  
  186.     /* correct line-length and position after symbol */
  187.     Clen       += rlen-flen;
  188.     Ep->column += rlen -1; /* one position left since we start
  189.                   at Ep->column+1 with searching */
  190.  
  191.     }
  192.  
  193.     /* Check display, since we are not sure, whether the actual
  194.        position is visible on the screen */
  195.     if (!text_adjust (FALSE))
  196.     {
  197.     text_sync ();
  198.     text_redisplaycurrline ();
  199.     }
  200.  
  201. } /* do_replace */
  202.  
  203.  
  204. /******************************************************************************
  205.  
  206.     NAME
  207.     search_operation
  208.  
  209.     PARAMETER
  210.     Fstr        String to look for
  211.     Rstr        String to replace Fsrt with (if Doreplace != 0)
  212.     Doreplace   Replace Fstr with Rstr ?
  213.     Ep        Different fields in this structure
  214.  
  215.     DESCRIPTION
  216.     Searches in the text for Fstr and replaces it with Rstr if Doreplace is
  217.     true. If Ep->ignorecase is true, the string-search is case-insensitive
  218.     else not.
  219.  
  220.     For speed, I did replace the old function with this new one. The
  221.     routine works like Boyer-Moore search but I didn't find a good
  222.     explanation for it in books. You will find some for searching from the
  223.     beginning of a string but none if you try reverse. Sigh.
  224.  
  225. ******************************************************************************/
  226.  
  227. //#define DEBUG
  228. static UBYTE skip[256];         /* Distance for Boyer-Moore */
  229.  
  230. void search_operation (void)
  231. {
  232.     int flen = strlen(Fstr);        /* Length of Search/Replace-String */
  233.     int rlen = strlen(Rstr);
  234.  
  235.     UBYTE * ptr;
  236.     short   j;        /* Counter in Search-Pattern */
  237.     short   col;    /* actual column */
  238.     short   lin;    /* actual line */
  239.     USHORT  linlen; /* length of actual line */
  240.     USHORT  test;   /* result of case(in)sensitive compare */
  241.     ED      * ep;     /* actual editor */
  242.  
  243.     if (!flen)
  244.     {             /* Error if nothing to look for. */
  245.     error ("search:\nNo find pattern");
  246.     return;
  247.     }
  248.  
  249.     /* Note that we do not check for nothing to replace, since the user may
  250.        want to erase the full pattern */
  251.  
  252.     text_sync ();                    /* Save Current */
  253.  
  254.     ep = Ep;
  255.  
  256.     col = ep->column;            /* Actual column ... */
  257.     lin = ep->line;            /* ... and line */
  258.  
  259.     /* initskip() */
  260.     memset (skip, flen, 256);       /* Normally : Skip full length */
  261.  
  262.     if (Srch_sign > 0)
  263.     {     /* Search foreward */
  264.     ptr = Fstr;
  265.  
  266.     /* Special: Skip until characters match. NOTE: Don't calc.
  267.        skip for the LAST character in Fstr */
  268.     for (j=flen-1; j>0; ptr ++, j--)
  269.     {
  270.         if (ep->config.ignorecase)
  271.         {
  272.         skip[tolower(*ptr)] = j;
  273.         skip[toupper(*ptr)] = j;
  274.         } else
  275.         skip[*ptr] = j;
  276.     }
  277.  
  278.     ptr = GETTEXT(ep,lin);          /* Get line contents ... */
  279.     linlen = strlen (ptr);          /* ... and its length */
  280.     col ++; /* Don't find it if we're already on it */
  281.  
  282.     for (; ep; )
  283.     {
  284.         for (;;)
  285.         {
  286.         /* This is the search-loop. Always remeber Boyer-Moore
  287.         begins comparing at the end and scans forward ! */
  288.         j = flen - 1;
  289.         col += flen - 1;
  290.  
  291.         /* Until reached beginning of search-string or EOL */
  292.         while (col < linlen)
  293.         {
  294.             /* if both are equal (case(in)sensitive) */
  295.             if (ep->config.ignorecase)
  296.             test = (tolower (ptr[col]) == tolower (Fstr[j]));
  297.             else
  298.             test = (ptr[col] == Fstr[j]);
  299.  
  300.             if (test)
  301.             {
  302.             if (!j) /* Full Match */
  303.                 goto found;
  304.  
  305.             col --; /* Next position */
  306.             j --;
  307.             } else
  308.             {     /* Determine skip-length */
  309.             if (flen-j >= skip[ptr[col]])
  310.                 col += flen - j;    /* length of match */
  311.             else
  312.                 col += skip[ptr[col]]; /* Adjust to char. */
  313.  
  314.             j = flen - 1;    /* Restart j */
  315.             } /* Compare */
  316.         } /* while in line */
  317.  
  318.         lin ++;
  319.  
  320.         if (lin >= ep->lines)
  321.             break;
  322.  
  323.         ptr = GETTEXT(ep,lin);      /* Contents and Length */
  324.         linlen = strlen (ptr);
  325.  
  326.         col = 0;
  327.         } /* while in text */
  328.  
  329.         if (!globalflags.global_search)
  330.         break;
  331.  
  332.         if (ep = (ED *)GetSucc((struct Node *)ep))
  333.         {
  334.         lin = 0;
  335.         ptr = GETTEXT(ep,0);
  336.         linlen = strlen (ptr);
  337.         }
  338.     } /* for all editors */
  339.     } else
  340.     { /* Search backward */
  341.     /* Special: Skip until characters match. Also don't process last char */
  342.     for (j=flen-1; j>0; j--)
  343.     {
  344.         if (ep->config.ignorecase)
  345.         {
  346.         skip[tolower(Fstr[j])] = j;
  347.         skip[toupper(Fstr[j])] = j;
  348.         } else
  349.         {
  350.         skip[Fstr[j]] = j;
  351.         }
  352.     }
  353.  
  354.     ptr = GETTEXT(ep,lin);          /* Get line contents ... */
  355.     linlen = strlen (ptr);          /* ... and its length */
  356.  
  357.     if (col >= linlen)  /* Beyound End-Of-Line ? */
  358.         col = linlen;
  359.  
  360. D(bug("new search\n"));
  361.  
  362.     for (; ep; )
  363.     {
  364.         for (;;)
  365.         {
  366.         /* Same as above but reverse */
  367.  
  368.         j = 0;
  369.         col -= flen;
  370.  
  371.         while (col >= 0)
  372.         { /* Until BOL */
  373.             /* if both are equal (case(in)sensitive) */
  374.             if (ep->config.ignorecase)
  375.             test = (tolower (ptr[col]) == tolower (Fstr[j]));
  376.             else
  377.             test = (ptr[col] == Fstr[j]);
  378.  
  379. D(bug("[%s]\n[%s]\ncol %2ld j %2ld skip %2ld\n", ptr+col, Fstr+j, col, j,
  380.         skip[ptr[col]]));
  381.  
  382.             if (test)
  383.             {
  384.             if (j == flen-1)
  385.             { /* Full Match */
  386.                 col -= flen - 1;
  387.                 goto found;
  388.             }
  389.  
  390.             col ++; /* Next position */
  391.             j ++;
  392.             } else
  393.             {     /* Determine skip-length */
  394.             j += j;
  395.  
  396.             if (j >= skip[ptr[col]])
  397.             {
  398.                 col -= j;     /* Skip back j chars to beginning of
  399.                         search and j chars to next start */
  400.             } else
  401.             {
  402.                 col -= skip[ptr[col]]; /* Adjust to char. */
  403.             }
  404.  
  405.             j = 0;     /* Restart j */
  406.             } /* Compare */
  407.         } /* while in line */
  408.  
  409.         /* Prev. line */
  410.         if (!lin)   /* Stop on 1. line */
  411.             break;
  412.  
  413.         lin --;
  414. D(bug("new line\n"));
  415.  
  416.         ptr = GETTEXT(ep,lin);      /* Contents and Length */
  417.         linlen = strlen (ptr);
  418.  
  419.         /* Last char. */
  420.         col = linlen;
  421.         } /* while in text */
  422.  
  423.         if (!globalflags.global_search)
  424.         break;
  425.  
  426.         if (ep = (ED *)GetPred((struct Node *)ep))
  427.         {
  428.         lin = ep->lines - 1;
  429.         ptr = GETTEXT(ep,lin);
  430.         col = linlen = strlen (ptr);
  431.         }
  432.     } /* for all editors */
  433.     } /* if foreward/backward */
  434.  
  435.     warn ("Pattern `%s' Not Found", Fstr);
  436.     globalflags.Abortcommand = 1;
  437.     return;
  438.  
  439. found:
  440.     if (ep != Ep)
  441.     {
  442.     switch_ed (ep);
  443.  
  444.     if (ep->iconmode)
  445.     {
  446.         uniconify ();
  447.     } else
  448.     {
  449.         /* Make window active */
  450.         WindowToFront (ep->win);
  451.         ActivateWindow (ep->win);
  452.  
  453.         set_window_params ();
  454.         window_title ();
  455.     }
  456.     }
  457.  
  458.     ep->line = lin;      /* Set Position */
  459.     ep->column = col;
  460.  
  461.     text_load ();        /* Copy Line into Current */
  462.  
  463.     if (Doreplace)
  464.     do_replace ();
  465.     else
  466.     text_adjust (FALSE);
  467. } /* search_operation */
  468.  
  469.  
  470. /******************************************************************************
  471. *****  ENDE search.c
  472. ******************************************************************************/
  473.