/*
 * The functions in this file implement commands that search in the forward
 * and backward directions. There are no special characters in the search
 * strings. Probably should have a regular expression search, or something
 * like that.
 *
 * REVISION HISTORY:
 *
 * ?    Steve Wilhite, 1-Dec-85
 *      - massive cleanup on code.
 *
 *	Andy Poggio, 1 Apr 86 - added query replace
 */

#include        <stdio.h>
#include        "ed.h"

/*
 * Compare two characters. The "bc" comes from the buffer. It has it's case
 * folded out. The "pc" is from the pattern.
 */
static int eq(bc, pc)
    int bc;
    int pc;
    {

    if (!casesens) {
     bc = cap(bc);
     pc = cap(pc);
    }

    if ((bc & 0xFF) == (pc & 0xFF))
        return (TRUE);

    return (FALSE);
    }

/*
 * Read a pattern.
 */
static int readpattern(prompt, pat)
char *prompt, *pat;
{
  register int s;
  unsigned char tpat[NPAT+20];

  strcpy(tpat,pat);
  s = mlreply(prompt, tpat, NPAT);

  if (s != ABORT)
    strcpy(pat, tpat);

  return (s);
}

/*
 * Query replace.  Replace pattern with new one at user's discretion.
 * Bound to META-%.
 */
qreplace(f, n)
    {
    register int s;
    short olen, repall;

#ifdef DEUTSCH
    if ((s = readpattern("Ersetze: ", pat)) != TRUE)
#else
    if ((s = readpattern("Replace old string: ", pat)) != TRUE)
#endif
        return (s);
    olen = strlen( pat);
#ifdef DEUTSCH
    if ((s = readpattern("durch: ", reppat)) == ABORT)
#else
    if ((s = readpattern("with new string: ", reppat)) == ABORT)
#endif
	return( s);

    repall = FALSE;
    while( search()) {

	if( repall) s = TRUE;
	else {
#ifdef DEUTSCH
	  mlwrite("ersetzen?");
#else
	  mlwrite("Replace?");
#endif
	  update();
askuser:
	  switch( (unsigned char)GetChar()) {

	    case '\177':
	    case '\010':	/* ^H */
	    case 'n':
	    case 'N':
		s = FALSE; /* don't replace */
		break;

	    case 'a':
	    case 'A':
#ifdef DEUTSCH
                mlwrite("alle");
#else
                mlwrite("all");
#endif
		repall = TRUE;
	    case ' ':
#ifdef DEUTSCH
	    case 'j':
	    case 'J':
#else
	    case 'y':
	    case 'Y':
#endif
		s = TRUE; /* replace */
		break;

	    case '\007':
		s = ABORT;
		break;

	    case 0x9b: /* CSI, skip mouse event */
	        for (; (GetChar() != '|'); );
	    default:
		mlwrite(
#ifdef DEUTSCH
	"j oder <SP>: ersetzen;  n or <DEL>: nicht;  a: alle;  <^G>: aufhören");
#else
	"y or <SP>: replace;  n or <DEL>: don't;  a: all;  <^G>: abort");
#endif
		update();
		goto askuser;
	  }
	}

	if( s == TRUE) {
	    backdel( TRUE, olen); /* delete old string */
	    s = linsertstr( reppat);  /* and insert the new */
	}
	if( s == ABORT) {
#ifdef DEUTSCH
            mlwrite("Abbruch");
#else
            mlwrite("abort");
#endif
	    break;
        }
    }
    if (s != ABORT) mlwrite("ok");
    curwp->w_flag |= WFHARD;
    return( s);
}

/*
 * Search forward. Get a search string from the user, and search, beginning at
 * ".", for the string. If found, reset the "." to be just after the match
 * string, and [perhaps] repaint the display. Bound to "C-S".
 */
forwsearch(f, n)
    {
    register int s;

#ifdef DEUTSCH
    if ((s = readpattern("Suche: ", pat)) != TRUE)
#else
    if ((s = readpattern("Search: ", pat)) != TRUE)
#endif
        return (s);

    s = search();
#ifdef DEUTSCH
    if( ! s) mlwrite("Nicht gefunden"); else mlwrite("ok");
#else
    if( ! s) mlwrite("Not found"); else mlwrite("ok");
#endif
    return( s);
}

search()
{
    register LINE *clp;
    register int cbo;
    register LINE *tlp;
    register int tbo;
    register unsigned int c;
    register unsigned char *pp;

    clp = curwp->w_dotp;
    cbo = curwp->w_doto;

    while (clp != curbp->b_linep)
        {
        if (cbo == llength(clp))
            {
            clp = lforw(clp);
            cbo = 0;
            c = '\n';
            }
        else
            c = lgetc(clp, cbo++);

        if (eq(c, pat[0]) != FALSE)
            {
            tlp = clp;
            tbo = cbo;
            pp  = &pat[1];

            while (*pp != 0)
                {
                if (tlp == curbp->b_linep)
                    goto fail;

                if (tbo == llength(tlp))
                    {
                    tlp = lforw(tlp);
                    tbo = 0;
                    c = '\n';
                    }
                else
                    c = lgetc(tlp, tbo++);

                if (eq(c, *pp++) == FALSE)
                    goto fail;
                }

            curwp->w_dotp  = tlp;
            curwp->w_doto  = tbo;
            curwp->w_flag |= WFMOVE;
            return (TRUE);
            }
fail:;
        }
    return (FALSE);
    }

/*
 * Reverse search. Get a search string from the user, and search, starting at
 * "." and proceeding toward the front of the buffer. If found "." is left
 * pointing at the first character of the pattern [the last character that was
 j matched]. Bound to "C-R".
 */
backsearch(f, n)
    {
    register LINE *clp;
    register int cbo;
    register LINE *tlp;
    register int tbo;
    register unsigned int c;
    register unsigned char *epp;
    register unsigned char *pp;
    register int s;

#ifdef DEUTSCH
    if ((s = readpattern("Suche rückwärts: ", pat)) != TRUE)
#else
    if ((s = readpattern("Reverse Search: ", pat)) != TRUE)
#endif
        return (s);

    for (epp = &pat[0]; epp[1] != 0; ++epp)
        ;

    clp = curwp->w_dotp;
    cbo = curwp->w_doto;

    for (;;)
        {
        if (cbo == 0)
            {
            clp = lback(clp);

            if (clp == curbp->b_linep)
                {
#ifdef DEUTSCH
                mlwrite("Nicht gefunden");
#else
                mlwrite("Not found");
#endif
                return (FALSE);
                }

            cbo = llength(clp)+1;
            }

        if (--cbo == llength(clp))
            c = '\n';
        else
            c = lgetc(clp, cbo);

        if (eq(c, *epp) != FALSE)
            {
            tlp = clp;
            tbo = cbo;
            pp  = epp;

            while (pp != &pat[0])
                {
                if (tbo == 0)
                    {
                    tlp = lback(tlp);
                    if (tlp == curbp->b_linep)
                        goto fail;

                    tbo = llength(tlp)+1;
                    }

                if (--tbo == llength(tlp))
                    c = '\n';
                else
                    c = lgetc(tlp, tbo);

                if (eq(c, *--pp) == FALSE)
                    goto fail;
                }

            curwp->w_dotp  = tlp;
            curwp->w_doto  = tbo;
            curwp->w_flag |= WFMOVE;
	    mlwrite("ok");
            return (TRUE);
            }
fail:;
        }
    }

