#define NAME	 "Change"
#define VERSION  "2"
#define REVISION "10"
//#define DEBUG
//#define DEBUG_LOOP

/* Programmheader

	Name:		Change
	Author:		SDI
	Distribution:	PD
	Description:	sucht und tauscht Zeichen in Dateien aus
	Compileropts:	-
	Linkeropts:	-

 1.20	: Fehler mit NOCHANGE und Pattern behoben
 1.21	: PATH ergänzt jetzt das \0 am Ende
 1.22	: Parameterüberprüfung ins Hauptprogramm
 1.23	: Bug bei zwei gleichen Anfangsbuchstaben des Suchstrings entfernt
 1.24	: InfoText Bearbeitung verbessert, Fehlermeldungen eingebaut
 1.25	: BUG durch InOutSDI.h entfernt
 1.26	: defsSDI.h, InOutSDI.h, ConvertSDI.h neu
 1.27	: bei ? am Anfang des Suchstrings beschleunigt
 1.28	: Quelltext kommentiert
 1.29	: Programm ein wenig beschleunigt / verbessert
 1.30	: BUG entfernt (If-Abfrage falsch)
 1.31	: BUG bei PATTERN-Angabe entfernt
 1.32	: verbesserte Includes, einige Programmverbesserungen
 1.35	: auf vollkommen neue Includes umgestellt
 2.0	: einige Verbesserungen, GUI komplett
 2.1	: Text optimiert, Trennungen eingefügt
 2.2	: Fehler mit NOCHANGE und HEX behoben
 2.3	: Parameter auf Standard C= Format umgestellt und ReadArgs für
	Lesen eingesetzt, dadurch Parameterreihenfolge geändert.
 2.4	: Funktion end jetzt nach Text WieProgrammieren.TXT
 2.5   06.08.95 : Fehler in Funktion Ausgabe (jetzt 1.4) behoben
 2.6   15.10.95 : return-Codes geordnet
 2.7   31.10.95 : kleinere Fehler behoben
 2.8   10.12.95 : Fehler mit PATTERN_BACK behoben
 2.9   25.12.95 : Window-Flags verbessert, jetzt auch Public-Screen tauglich
 2.10  31.12.95 : Oeffnen-Funktion der Includes neu, etwas kürzer, FileReq
	statt eigener ASl-Funktion, jetzt Englisch
*/
 
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <libraries/asl.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <exec/execbase.h>
#include <pragma/intuition_lib.h>
#include <pragma/gadtools_lib.h>
#include <pragma/asl_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/exec_lib.h>
#include "SDI_protos.h"
#include "SDI_structures.h"
#include "SDI_defines.h"
#include "FileReq.h"
#include "Oeffnen.h"
#include "ChangeGUI.h"
#include "ChangeTexts.h"

#define FOUND     args.found
#define HEX       args.hex
#define LENGTH    args.length
#define NOCHANGE  args.nochange
#define NOSIZE    args.nosize
#define OVERWRITE args.overwrite
#define PATH      args.path
#define POSITION  args.position

#define PARAM "FROM/A,SSTRING/A,TO,RSTRING,FOUND/S,HEX/S,LENGTH/S,"       \
"NOCHANGE/S,NOSIZE/S,OVERWRITE/S,PATH/S,POS=POSITION/K"
struct {
  STRPTR	from;
  STRPTR	sstring;
  STRPTR	to;
  STRPTR	rstring;
  LONG		found;
  LONG		hex;
  LONG		length;
  LONG		nochange;
  LONG		nosize;
  LONG		overwrite;
  LONG		path;
  STRPTR	position
  } args = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

struct RDArgs *rda = 0;

struct IntuitionBase	*IntuitionBase	= 0;
struct Library		*GadToolsBase	= 0;
struct Library		*UtilityBase	= 0;
struct Library		*AslBase	= 0;

struct Screen		*Scr		= 0;
APTR			VisualInfo	= 0;
struct Window		*ChangeWnd	= 0;
struct Gadget		*ChangeGList	= 0;
struct IClass		*getClass	= 0;
struct _Object		*getImage	= 0;
struct Gadget		*gadg		= 0;
struct TagItem		_TagItem;

UWORD	 str[2][BACK_MAX]; // umgew. strings
ULONG             l[2]; // Länge der Strings
struct SDI_InOut in = {0, 0, 0, 0, 0}, out = {0, 0, 0, 0, 0};

extern struct ExecBase *SysBase;

void End(int);			// Beendet Programm bei Fehler
void GetFileName(STRPTR);	// Aufruf Asl-Library für Filename
void GetGadget(ULONG);		// Adresse eines Gadgets erfahren
void RefreshA(void);		// erneuert Gadgets
void Refresh(struct Gadget *);	// erneuert 1 Gadget
void Tausch (ULONG);		// Tauscht Zeichen aus- Hauptfunktion
void TextOut(STRPTR);		// Gibt Fehlertext ins Gadget aus
void ToogleGadgStat(int, ULONG);// Aktiviert/Deaktiviert Gadget
extern "C" void wbmain(void);   // Workbench-Start

/* ================================ main =============================== */

void main(int argc, char **argv)
{
  TEST_OS(37);

  ULONG h, i; // Hilfsvariablen

  if(argc == 1)
    wbmain();

  if(!(rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
    exit(RETURN_FAIL);
  rda->RDA_ExtHelp = TEXT_CLI_HELP;
  if(!(rda = ReadArgs(PARAM, (LONG *) &args, rda)))
  {
    FreeDosObject(DOS_RDARGS, rda);
    PrintFault(IoErr(), 0);
    exit(RETURN_FAIL);
  }

  for(i = 0; i < 2; i++)                // bestimmt Strings und deren Länge
    l[i] = (HEX ? GetCharHEX(*(&args.sstring+2*i), str[i]) :
    GetCharSTRING(*(&args.sstring+2*i), str[i]));
  // *(&args.sstring+2*i) ist eine etwas unnormale Formulierung !
  // sie funktioniert nur, wenn args.rstring immer 2 Positionen hinter
  // args.sstring ist, da ich auf die Strukturelemente, wie auf ein Feld
  // zugreife
#ifdef DEBUG
  PutStr("Strings umgerechnet\n");
#endif

  if((!NOCHANGE && !args.to) || (l[0] == 0))
  {
    SetIoErr(ERROR_REQUIRED_ARG_MISSING); End(RETURN_FAIL);
  }
  h = 0;
  if(NOCHANGE && !(in.file = Open(args.from, MODE_OLDFILE)) ||     // Files
  (!NOCHANGE && !(h = Oeffnen(args.from, args.to, (char *) 0, &in, &out))))
    End(RETURN_FAIL);					  // öffnen
  if(h == OEFFNEN_WITH_SLASH)
  {
    PutStr(TEXT_NAME_OF_DEST); PutStr(args.from); PutStr("_\n");
  }
#ifdef DEBUG
  PutStr("Files geöffnet, Puffer allociert\n");
#endif
  if(NOCHANGE)
  {
    if(!Puffer(&in, &out, args.from))
      End(RETURN_FAIL);
    Eingabe(&in);
#ifdef DEBUG
  PutStr("NOCHANGE: Puffer allociert, eingelesen\n");
#endif
  } /* End of if(NOCHANGE) */
  for(h = 0; h < 2; ++h)
  {
    PutStr(h == 0 ? TEXT_SEARCH_STR : TEXT_REPLACE_STR);
    for(i = 0; i < l[h]; ++i)			     // Ausgabe der Strings
      if(str[h][i] == PATTERN_BACK)
      {
        PutStr("\033[7m");
        FPutC(Output(), PATTERN_BACK);
        PutStr("\033[27m");
      }
      else if(isprintSDI(str[h][i]))
        FPutC(Output(), str[h][i]);
      else
        PutStr("\033[7m.\033[27m");
      PutStr("'\n");
    if(NOCHANGE) break;
  } /* End of for(h=0; ...) */
  Tausch((unsigned long) (POSITION ? strtol(args.position, 0, 16) : 0));
  End(RETURN_OK);
}

/* =============================== wbmain ============================== */

extern "C" void wbmain(void)
{
  struct IntuiMessage  *msg;
  STRPTR in_str[2] = {0, 0};	// Original-Strings
  UBYTE out_str[2][BACK_MAX];	// Ausgabe-Strings
  ULONG 		 fh;	// Ausgabe-Filehandle
  ULONG		       i, j;	// Hilfsvariable
  STRPTR	     quelle;	// Zeiger auf Namen von Dateien
  ULONG		     _Class;	// IDCMP-Klasse für Gadget-Auswertung

  version += 6; // kill $VER:

  if(
  !(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37)) ||
  !(GadToolsBase = OpenLibrary("gadtools.library",37)) ||
  !(UtilityBase = OpenLibrary("utility.library",37)) ||
  !(Scr = LockPubScreen(0)) ||
  !(VisualInfo = GetVisualInfo(Scr, 0)) ||
  !(getClass = initGet()) ||
  !(getImage = (struct _Object *) NewObject(getClass, NULL, GT_VisualInfo, VisualInfo, TAG_DONE )) ||
  OpenChangeWindow()
  )
    End(RETURN_FAIL);
  GetGadget(GD_Search_String);
  in_str[0] = ((struct StringInfo *) gadg->SpecialInfo)->Buffer;
  GetGadget(GD_Replace_String);
  in_str[1] = ((struct StringInfo *) gadg->SpecialInfo)->Buffer;

  do
  {
    _Class = 0;
    if(Wait((1L<<ChangeWnd->UserPort->mp_SigBit)|SIGBREAKF_CTRL_C)
    == SIGBREAKF_CTRL_C)
      _Class = IDCMP_CLOSEWINDOW;
    else
    {
      msg = GT_GetIMsg(ChangeWnd->UserPort);
      _Class = msg->Class;
      gadg = (struct Gadget *) msg->IAddress;
      GT_ReplyIMsg(msg);
    }

    switch(_Class)
    {
    case IDCMP_GADGETUP:
      if((i = gadg->GadgetID) >= GD_FOUND_CheckBox &&
      i <= GD_POSITION_CheckBox)
        *(&args.found + i - GD_FOUND_CheckBox) =
        (gadg->Flags & GFLG_SELECTED);
      // *(&args.found + i - GD_FOUND_CheckBox) wacklige Konstruktion, da
      // wie in main die Struktur als Feld behandelt wird
      // nur, wenn CheckBox-Gadgets in der richtigen Reihenfolge
      switch(i)
      {
      case GD_Search_String: j = 0;
      case GD_Replace_String:
        in_str[j] = ((StringInfo *)gadg->SpecialInfo)->Buffer;
	((StringInfo *)gadg->SpecialInfo)->BufferPos = 0;
        l[j] = (HEX ? GetCharHEX(in_str[j], str[j]) :
        GetCharSTRING(in_str[j], str[j]));
        for(i = 0; i < l[j]; ++i)
          out_str[j][i] = str[j][i];
        out_str[j][i] = '\0';
        ((struct StringInfo*) gadg->SpecialInfo)->Buffer = (STRPTR)
          out_str[j];
        Refresh(gadg);
        break;
      case GD_Load_File_String:
      case GD_Save_File_String:
	((StringInfo *)gadg->SpecialInfo)->BufferPos = 0; Refresh(gadg);
	break;
      case GD_Load_File_GetFile: case GD_Save_File_GetFile:
        GetGadget(gadg->GadgetID + GD_Load_File_String);
        // läuft nur, wenn die 2 String-Gadgets und die GetFile-Gadgets
        // in der selben Reihenfolge und direkt hintereinander sind.
	FileReq(((StringInfo *)gadg->SpecialInfo)->Buffer,
	  ((StringInfo *)gadg->SpecialInfo)->MaxChars, FILEREQ_MODE_OPEN,
	  TEXT_CHOOSE_A_FILE);
        Refresh(gadg);
        break;
      case GD_POSITION_CheckBox:
        ToogleGadgStat(GD_Position_String, (ULONG) !POSITION);
        break;
      case GD_LENGTH_CheckBox: case GD_PATH_CheckBox:
      case GD_OVERWRITE_CheckBox:
        PATH = OVERWRITE = LENGTH = 0;
        *(&args.found + i - GD_FOUND_CheckBox) =
        (gadg->Flags & GFLG_SELECTED);
        GetGadget(GD_OVERWRITE_CheckBox);
        (gadg->Flags) = (gadg->Flags & ~GFLG_SELECTED) +
        (OVERWRITE ? GFLG_SELECTED : 0);
        GetGadget(GD_PATH_CheckBox);
        (gadg->Flags) = (gadg->Flags & ~GFLG_SELECTED) +
        (PATH ? GFLG_SELECTED : 0);
        GetGadget(GD_LENGTH_CheckBox);
        (gadg->Flags) = (gadg->Flags & ~GFLG_SELECTED) +
        (LENGTH ? GFLG_SELECTED : 0);
        // Length muß als letztes kommen, sonst werden andere nicht
	// refreshed
        RefreshA();
        break;
      case GD_NOCHANGE_CheckBox:
        ToogleGadgStat(GD_FOUND_CheckBox, (ULONG) NOCHANGE);
        ToogleGadgStat(GD_LENGTH_CheckBox, (ULONG) NOCHANGE);
        ToogleGadgStat(GD_OVERWRITE_CheckBox, (ULONG) NOCHANGE);
        ToogleGadgStat(GD_PATH_CheckBox, (ULONG) NOCHANGE);
        ToogleGadgStat(GD_POSITION_CheckBox, (ULONG) NOCHANGE);
        ToogleGadgStat(GD_Position_String,
        (ULONG) (NOCHANGE || !POSITION));
        ToogleGadgStat(GD_Save_File_String, (ULONG) NOCHANGE);
        ToogleGadgStat(GD_Replace_String, (ULONG) NOCHANGE);
        break;
      case GD_START_Button:
        if(l[0] == 0)
          { TextOut(TEXT_NO_SEARCH_STRING); break; }
        GetGadget(GD_Load_File_String);
        quelle = ((StringInfo *) gadg->SpecialInfo)->Buffer;
        GetGadget(GD_Save_File_String); // Wichtig für Öffnens 2. Para.
        i = 0;
        if(NOCHANGE && !(in.file = Open(quelle, MODE_OLDFILE)) ||
        (!NOCHANGE && !(i = Oeffnen(quelle,
        ((StringInfo *) gadg->SpecialInfo)->Buffer, 0, &in, &out))))
        {
          if(in.file)
            Close(in.file);
          if(out.file)
            Close(out.file);
          if(in.buf)
            Free(&in);
          if(out.buf)
            Free(&out);
          in.file = out.file = 0;
          TextOut(TEXT_CANT_OPEN_FILE);
          break;
        }
        if(i == OEFFNEN_WITH_SLASH)
          TextOut(TEXT_SLASH_AT_END);
        if (NOCHANGE)
        {
          if(!Puffer(&in, &out, quelle))
          {
            Close(in.file); in.file = 0;
	    Fault(ERROR_NO_FREE_STORE, 0, texts_fault, TEXT_FAULT_SIZE);
            TextOut(texts_fault);
            break;
          }
          Eingabe(&in);
        }
        if(!(fh = Open("CON:0/11/640/190/Change Report/WAIT/CLOSE",
        MODE_NEWFILE)))
        {
          TextOut(TEXT_CANT_OPEN_REPORT_WINDOW);
          fh = Open("NIL:", MODE_NEWFILE);
        }
        SelectOutput((BPTR) fh);
        GetGadget(GD_Position_String);
        Tausch((unsigned long) strtol(((StringInfo *) gadg->SpecialInfo)
        ->Buffer, 0,  16));
        GetGadget(GD_FOUND_CheckBox);
        FOUND = (gadg->Flags & GFLG_SELECTED);
        GetGadget(GD_LENGTH_CheckBox);
        LENGTH = (gadg->Flags & GFLG_SELECTED);
        GetGadget(GD_OVERWRITE_CheckBox);
        OVERWRITE = (gadg->Flags & GFLG_SELECTED);
        GetGadget(GD_POSITION_CheckBox);
        POSITION = (char *) (gadg->Flags & GFLG_SELECTED);
        GetGadget(GD_PATH_CheckBox);
        PATH = (gadg->Flags & GFLG_SELECTED);
        Close(fh); Close(in.file); in.file = 0;
        if(out.file) { Close(out.file); out.file = 0; }
        Free(&in); Free(&out);
        break;
      } /* End of switch(...) */
      break;
    case IDCMP_GADGETDOWN:
      switch(gadg->GadgetID)
      {
      case GD_Search_String: ((StringInfo*) gadg->SpecialInfo)->Buffer
        = (STRPTR) in_str[0];
        Refresh(gadg);
        break;
      case GD_Replace_String: ((StringInfo*) gadg->SpecialInfo)->Buffer
        = (STRPTR) in_str[1];
        break;
      }
      break;
    } /* switch(_Class) */
    while((msg = GT_GetIMsg(ChangeWnd->UserPort)))
      GT_ReplyIMsg(msg);
  } while(_Class != IDCMP_CLOSEWINDOW);
  GetGadget(GD_Search_String);
    ((StringInfo*) gadg->SpecialInfo)->Buffer = (STRPTR) in_str[0];
  GetGadget(GD_Replace_String);
    ((StringInfo*) gadg->SpecialInfo)->Buffer = (STRPTR) in_str[1];
  End(RETURN_OK);
}

/* ============================== Refresh ============================== */

void RefreshA(void)
{
  RefreshGadgets(gadg, ChangeWnd, 0);
}

void Refresh(struct Gadget *a)
{
  RefreshGList(a, ChangeWnd, 0, 1);
}

/* ============================= GetGadget ============================= */

void GetGadget(ULONG ID)
{
  gadg = ChangeWnd->FirstGadget;
  while(gadg->GadgetID != ID)
    gadg = gadg->NextGadget;
}

/* ============================== TextOut ============================== */

void TextOut(STRPTR text)
{
  GetGadget(GD_Error_Text);
  _TagItem.ti_Tag = GTTX_Text;
  _TagItem.ti_Data = (ULONG) text;
  GT_SetGadgetAttrsA(gadg, ChangeWnd, NULL, &_TagItem);
}

/* =========================== ToogleGadgStat ========================== */

void ToogleGadgStat(int ID, ULONG real)
{
  GetGadget(ID);
  _TagItem.ti_Tag = GA_Disabled;
  _TagItem.ti_Data = real;
  GT_SetGadgetAttrsA(gadg, ChangeWnd, NULL, &_TagItem);
}

#define c_q (in.count + in.buf - in.pos)
#define l_z (out.size + out.buf - out.pos)
#define qz  str[0]
#define zz  str[1]
#define IF_PATT_BACK(a) (a >= PATTERN_BACK ? PATTERN_BACK : 0)

/* =============================== Tausch ============================== */
/* ====== Ersetzt QuellString aus Quelle durch ZielString in Ziel ====== */

void Tausch (ULONG chpos)
{

  ULONG       zae = 0;  // Zähler
  LONG          p = 0;  // <> 0 - bis Null warten 0 - nicht
  ULONG    Stelle = 0;  // Stelle + in.pos - in.buf -> Position
  ULONG        st = 0;  // Stelle der Überprüfung
  ULONG founddata[2] = {0, 0};
  UBYTE Ausg_Soll = 0; // 0 = found, 1 = gewechselt (Soll)
  UBYTE Ausg_Ist  = 2; // 0 = found, 1 = gewechselt (Ist)
  ULONG           max;  // maximale Füllung von z
  STRPTR	    m;  // verkürzt Schleife (Bearbeitungszeit)
  UBYTE both_first_same; // bei zwei gleichen ersten Zeichen 1
  UBYTE        ff = 0;  // Anzahl der PATTERN_BACK am Anfang

  if(l[0] == l[1]) OVERWRITE = LENGTH = PATH = 0;            // sind unnütz
  if(PATH) OVERWRITE = LENGTH = 0;                   // paßt nicht zusammen
  if(OVERWRITE) LENGTH = 0;
  if(NOCHANGE)
  {
    FOUND = 1; POSITION = 0; PATH = OVERWRITE = LENGTH = 0;
  }
#ifdef DEBUG
  if (FOUND)	{PutStr("FOUND     = "); PutNum(FOUND, 2);	PutStr("\n");}
  if (HEX)	{PutStr("HEX       = "); PutNum(HEX, 2);	PutStr("\n");}
  if (LENGTH)	{PutStr("LENGTH    = "); PutNum(LENGTH, 2);	PutStr("\n");}
  if (NOCHANGE) {PutStr("NOCHANGE  = "); PutNum(NOCHANGE, 2);	PutStr("\n");}
  if (NOSIZE)	{PutStr("NOSIZE    = "); PutNum(NOSIZE, 2);	PutStr("\n");}
  if (OVERWRITE){PutStr("OVERWRITE = "); PutNum(OVERWRITE, 2);	PutStr("\n");}
  if (PATH)	{PutStr("PATH      = "); PutNum(PATH, 2);	PutStr("\n");}
  if (POSITION) {PutStr("POSITION  = "); PutNum(chpos, 10);	PutStr("\n");}
#endif

  max = 2 + ((l[1] < l[0]) ? l[0] : l[1]);
  while(ff < l[0] && qz[ff] == PATTERN_BACK)
    { ++ff; *(out.pos++) = *(in.pos++); }
  if (ff == l[0])
    { out.pos = out.buf; in.pos = in.buf; ff = 0; }
  if (l[0] > 1)
    both_first_same = (NOSIZE?tolower(qz[ff]) == tolower(qz[ff+1]) :
                               qz[ff] == qz[ff+1]);

  do
  {
#ifdef DEBUG_LOOP
    PutStr("Tausch: Haupt-Schleife\n");
#endif
    if(!st && qz[ff] < PATTERN_BACK)
    {                       // Schleife sucht erstes Zeichen des Suchstring
      m = (c_q < l_z-max ? c_q : l_z-max) + out.pos;
      if(NOSIZE) qz[ff] = tolower(qz[ff]);    // verkürzt Schleife
      while(m-out.pos && !(p && !(*in.pos)) && (NOSIZE ? tolower(*in.pos):
      *in.pos) != qz[ff])
        *(out.pos++) = *(in.pos++);
    }
    if(in.pos >= in.buf + in.count)			// Lese-Puffer voll
    {
      Stelle += in.count;
      Eingabe(&in);
#ifdef DEBUG
      PutStr("Tausch: Einlesen\n");
#endif
    }
    if(out.pos >= out.buf + out.size - max)				     // Schreib-Puffer voll
    {
#ifdef DEBUG
      PutStr("Tausch: Ausgeben\n");
#endif
      if(NOCHANGE)
        out.pos = out.buf;
      else
        Ausgabe(&out, ff+1);
    }
    if(in.count)
    {
      if(p && !(*in.pos))			// Pfad-Ausgleich ist aktiv
      {
#ifdef DEBUG
        PutStr("Tausch: Pfad-Ausgleich\n");
#endif
        if(p < 0)
          { ++in.pos; *(out.pos++) = '\0'; }
        for(; p < 0; ++p)
          ++in.pos;
        for(; p > 0; --p)
          *(out.pos++) = '\0';
      }
      while(c_q > 0 && (ff+st) < l[0] && (qz[ff+st] >= PATTERN_BACK ||
        (NOSIZE ? tolower(*in.pos) == tolower(qz[ff+st]) :
        *in.pos == qz[ff+st])))  // testet nach Suchstring (ab char 2)
      {
        if(qz[ff+st] >= PATTERN_BACK)
          qz[ff+st] = PATTERN_BACK + *in.pos;
        else if(NOSIZE)
          qz[ff+st] = *in.pos;
        ++st; ++in.pos;
      }
    }
    if(st)
    {
#ifdef DEBUG
      PutStr("Tausch: Zielstring gefunden\n");
#endif
      if(ff)         // gleicht die übersprungenen PATTERN_BACK wieder aus
      {
        for(zae = ff; zae > 0; --zae)
          qz[zae-1] = PATTERN_BACK + *(--out.pos);
        st += ff;
      }
      if(st == l[0])
      {
#ifdef DEBUG
        PutStr("Tausch: Zielstring ist komplett\n");
#endif
        if(LENGTH && out.pos != out.buf)
          *(out.pos-1) += l[1] - l[0];
        ++founddata[0];	// gefundene Zeichen
        if(!NOCHANGE && (!POSITION || chpos == Stelle-l[0]
            + (in.buf - in.pos)))
        {
#ifdef DEBUG
          PutStr("Tausch: Zielstring wird ersetzt\n");
#endif
          ++founddata[1]; Ausg_Soll = 1; // gewechselte Zeichen
          for(zae = 0; zae < l[1]; ++zae)	    // Zielstring einsetzen
            if(zz[zae] != PATTERN_BACK)
              *(out.pos++) = zz[zae];
            else if(zae < l[0]) 	           // PATTERN_BACK ersetzen
              *(out.pos++) = qz[zae] - IF_PATT_BACK(qz[zae]);
          if(PATH)			      // wenn nötig Pfad anschalten
            p = l[0] - l[1];
          if(OVERWRITE) 		  // Überschreiben mit Text oder \0
          {
#ifdef DEBUG
            PutStr("Tausch: Overwrite ist aktiv\n");
#endif
            if(l[0] > l[1])
              for(zae = l[1]; zae < l[0]; ++zae)
                *(out.pos++) = 0;
            else
              *in.pos += (l[1] - l[0]);
          }
        } // if(!NOCHANGE ...)
        else if(POSITION) // gefunden an falscher Position (kein Ersetzen)
          for(zae = 0; zae < l[0]; ++zae)
            *(out.pos++) = qz[zae] - IF_PATT_BACK(qz[zae]);
        if(FOUND)				// Ausgabe bei Option FOUND
        {
          if(Ausg_Soll != Ausg_Ist && Ausg_Ist != 2)
            PutStr("\n");
          if(Ausg_Soll == 0 && Ausg_Ist != 0)
          {
            PutStr(TEXT_STRING_FOUND_AT);
            Ausg_Ist = 0;
          }
          else if(Ausg_Soll == 1 && Ausg_Ist != 1)
          {
            PutStr(TEXT_STRING_CHANGED_AT);
            Ausg_Ist = 1;
          }
          zae = Stelle - l[0] + (in.pos - in.buf);
	  VPrintf(" %lx", &zae);
          Ausg_Soll = 0;
        } // if (FOUND)
        st = 0;
      } // if (st == l[0])
      else
      {
#ifdef DEBUG
        PutStr("Tausch: Zielstring ist nicht komplett, wird nicht ersetzt\n");
#endif
        if(st > 1 && both_first_same) 	// wenn erste zwei Zeichen gleich mit einem
	{
#ifdef DEBUG
	  PutStr("Tausch: Beide erste gleich? Neuer Test mit Versatz.\n");
#endif
          for(zae = 1; zae < st && (qz[zae-1] >= PATTERN_BACK ||
          (NOSIZE ? tolower(qz[zae-1]) == tolower(qz[zae] -
          IF_PATT_BACK(qz[zae])) : qz[zae-1] ==  qz[zae] -
          IF_PATT_BACK(qz[zae]))); ++zae)
          ;				    // Versatz von 1 nochmal testen
	}
        if(st > 1 && both_first_same && zae == st)
        {
#ifdef DEBUG
	  PutStr("Tausch: Versatz scheint zu stimmen!\n");
#endif
           *(out.pos++) = qz[0] - IF_PATT_BACK(qz[0]);
           for(st = 1; st < zae; ++st)
           qz[st-1] = qz[st] - IF_PATT_BACK(qz[st])
           + IF_PATT_BACK(qz[st-1]);
           --st;
	   if(ff)
	   {
	     for(zae = 0; zae < ff; ++zae)
	       *(out.pos++) = qz[zae] - IF_PATT_BACK(qz[0]);
	     st -= ff;
	   }
         }
        else
        {
#ifdef DEBUG
	  PutStr("Tausch: Schreibe Teile in Zielpuffer.\n");
#endif
          for(zae = 0; zae < st; ++zae)
            *(out.pos++) = qz[zae] - IF_PATT_BACK(qz[zae]);
          st = 0;
        }
      }
    } // if(st)
  } while(in.count && !CTRL_C);
#ifdef DEBUG
  PutStr("Tausch: nach Haupt-Schleife\n");
#endif
  if(!NOCHANGE)
    Ausgabe(&out, 0);
  if(CTRL_C)
    PrintFault(ERROR_BREAK, 0);
  else
  {
#ifdef DEBUG
    PutStr("Tausch: vor Endausgabe\n");
#endif
    if(FOUND)
      PutStr("\n");
    VPrintf(TEXT_STATUS_OUTPUT, &founddata);
  }
#ifdef DEBUG
  PutStr("Tausch: am Ende\n");
#endif
}

/* ================================ End ================================ */

void End(int err)
{
#ifdef DEBUG
    PutStr("End: am Anfang\n");
#endif
  if(err != RETURN_OK)	PrintFault(IoErr(), 0);

  if(ChangeWnd) 	CloseWindow(ChangeWnd);
  if(ChangeGList)	FreeGadgets(ChangeGList);
  if(getImage)		DisposeObject(getImage);
  if(getClass)		FreeClass(getClass);
  if(VisualInfo)	FreeVisualInfo(VisualInfo);
  if(Scr)		UnlockPubScreen(0, Scr);
#ifdef DEBUG
    PutStr("End: nach GUI-Sachen\n");
#endif
  if(rda)
  {
    FreeArgs(rda);
    FreeDosObject(DOS_RDARGS, rda);
  }
  if(in.file)		Close(in.file);
  if(out.file)		Close(out.file);
  Free(&in);
  Free(&out);
#ifdef DEBUG
    PutStr("End: vor Libraries\n");
#endif
  if(UtilityBase)	CloseLibrary(UtilityBase);
  if(GadToolsBase)	CloseLibrary(GadToolsBase);
  if(IntuitionBase)	CloseLibrary((struct Library *) IntuitionBase);
  exit(err);
}
