/* INCLUDE FILES */
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <exec/ports.h>
#include <exec/interrupts.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>

/* DEFINES */
#define INTUITION_REV 29
#define GRAPHICS_REV 29
#define NL 0
#define ESC 27
#define MIX 1
#define MIY 5
#define MAY 27
#define EOS '\0'
#define LF 10
#define GROESSE 512

/* VARIABLEN */
int SEITE, MAS, MAX;
struct Library *OpenLibrary();
struct IntuitionBase *IntuitionBase;
struct Window *Fenster, *OpenWindow();
struct Screen *Skrien, *OpenScreen();
struct GfxBase *GfxBase;
struct RastPort *RPforte;
struct IntuiMessage *nachricht, *GetMsg();
extern struct FileHandle *Open();
struct IOStdReq message, *LNachr, *SNachr;
struct MsgPort *LPforte, *SPforte;
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
char einzeichen, buffer[512], titel[232], str[79];
UBYTE *a[15] [72], *AllocMem();
ULONG class;
USHORT code, qualif;
SHORT x, y, z, s, se, ze, xe, Flagge, meld, ein, blo, bes, bas, bez, baz;
char *FehlerText[2];

/* Speicherung eines Buchstabens */
Buchstabe(c)
UBYTE c;
{
   UBYTE *basis;
   int len, i, r;

   basis = a[s] [z];
   if(ein==FALSE) {                  /* Einfügen aus */
      if((i=strlen(a[s] [z])) < x) {   /* Crsr außerhalb des zur akt. */
         if(c!=32) {                   /* Zeile gehörigen Strings */
            a[s] [z] = basis + i;      /* Wenn Space dann keine Spei- */
            for(len=i;len<x; len++)    /* erung, sonst bis x-Kood. Auf- */
               *a[s] [z]++ = 32;       /* füllen mit Space */
            a[s] [z] = basis + x;
            *a[s] [z]--  = EOS;
            *a[s] [z] = c;
            a[s] [z] = basis;
         }
      }
      else {                           /* Überschreiben des alten Inhalts */
         a[s] [z] = basis + x-1;
         *a[s] [z] = c;
         a[s] [z] = basis;
      }
   }
   else {                              /* Einfügen an */
      if((i=strlen(a[s] [z])) < x-1) {  /* Wenn x-1 größer als String */
         if(c!=32) {                    /* Speierung wie oben */
            a[s] [z] = basis + i;
            for(len=i;len<x; len++)
               *a[s] [z]++ = 32;
            a[s] [z] = basis +x;
            *a[s] [z]-- = EOS;
            *a[s] [z] = c;
            a[s] [z] = basis;
         }
      }
      else {
         if(x<MAX) {        /* kein Zeilensprung */
            if(i<MAX-1) {   
               if(i>=x) {
                  buffer[i-x+2] = EOS; /* Speicherung des Zeichens incl. */
                  a[s] [z] = basis +i; /* des Weiterrückens der Zeichen */
                  for(len=i, r=i-x+1; len>=x-1; len--, r--) {
                    buffer[r] = *a[s] [z]++; /* rechts vom Crsr, im RAM */
                    *a[s] [z] = buffer[r];   /* sowie im Textfenster */
                    a[s] [z] = a[s] [z] - 2;
                  }
                  a[s] [z] = basis +x -1;
                  *a[s] [z] = c;
                  a[s] [z] = basis +i+2;
                  *a[s] [z] = EOS;
                  a[s] [z] = basis;
                  CursorAus();
                  Move(RPforte, x*8+4, (y+1)*8+1);
                  Text(RPforte, buffer, strlen(buffer));
                  CursorAn();
               }
               else {
                  a[s] [z] = basis +x-1;
                  buffer[0] = *a[s] [z]++;
                  *a[s] [z]++ = buffer[0];
                  *a[s] [z] = EOS;
                  a[s] [z] = basis +x-1;
                  *a[s] [z] = c;
                  buffer[1] = EOS;
                  a[s] [z] = basis;
                  CursorAus();
                  Move(RPforte, x*8+4, (y+1)*8+1);
                  Text(RPforte, buffer, strlen(buffer));
                  CursorAn();
               }
            }
            else {
               a[s] [z] = basis + x-1;
               *a[s] [z] = c;
               a[s] [z] = basis;
            }
         }
      }
      if(x==MAX) {       /* Zeilensprung */
         if(i<x-1) {     /* Text bis zum letzten Space in die neue Zeile */
            a[s] [z] = basis + i;  /* mitnehmen */
            for(len=i;len<x; len++)
               *a[s] [z]++ = 32;
            i = MAX-2;
         }
         a[s] [z] = basis +x-1;
         *a[s] [z]++ =c;
         *a[s] [z] = EOS;
         a[s] [z] = basis +i+1;
         for(len=i+1; len>=0;len--) {
            if(*a[s] [z]--  == 32) {
               x = len+2;
               break;
            }
         }
         if(x>MAX)
            x=MAX;
         if(len<0)
            x=MAX;
         a[s] [z] = basis;
         CarRet();
         StrEnde();
         x=x-1;
      }
   }
}
Allocieren()        /* Textspeicher belegen */
{
   register int si, zi;
   int ss, zz;

   for(si=0; si<=MAS; si++) {
      for(zi=0; zi<=SEITE; zi++) {
         if((a[si] [zi] =
            AllocMem(MAX, MEMF_PUBLIC|MEMF_CLEAR))==NULL){
            printf("Zu weinig Speicher!");
            if(si==0 && zi==0) Exit(); /* Falls zu wenig Speicher */
            for(ss=0; ss<=si; ss++) {  /* schon belegten Speicher wieder */
               for(zz=0; zz<=SEITE; zz++) { /* frei geben und Exit() */
                  FreeMem(a[ss] [zz] , MAX);
                  if(ss==si && zz==zi) Exit();
               }
            }
         }
      }
   }
}
FastText()
{
   int len;

   CursorAus(); /* Text auf einer Bildschirmseite darstellen unter */
   SetAPen(RPforte, 0);   /* Berücksichtigung des Blockmodus */
   RectFill(RPforte, 4, 43, 632, 226);
   SetAPen(RPforte, 1);
   for(len=0; len<=22; len++) {
      Move(RPforte, 4, ((len+MIY+1)*8)+1);
      if(blo>2) {
         if(BloPruef()==TRUE)
            SetDrMd(RPforte, COMPLEMENT);
      }
      Text(RPforte, a[s] [z], strlen(a[s] [z]));
      if(blo>2)
         SetDrMd(RPforte, JAM2);
      if(len<22)
         YZPlus();
      if(meld == TRUE)
         break;
   }
}
CrsrTop()           /* y-Kood. und aktuelle Zeile in die oberste Zeile */
{                   /* des Textbildschirms befördern */
   int len;

   for(len=y;len>MIY;len--)
      YZMinus();
}
CrsrHoch()  /* aktuelle Zeile um 23 Stellen verringern */
{
   int len, fahne = FALSE;

   for(len=0; len<22; len++)
   {
      y=MIY+1;
      YZMinus();
      if(meld==TRUE) {
         fahne = TRUE;
         meld = FALSE;
         break;
      }
   }
   y=MIY;
   FastText();
   CrsrTop();
   if(fahne == TRUE) {
      meld = TRUE;
      sprintf(buffer, "%s", FehlerText[0]);
   }
}
CrsrBot()         /* y-Kood. und akt. Zeile in die unterste Zeile */
{                 /* des Textbildschirms befördern */
   int len;
   for(len=y;len<MAY;len++) {
      YZPlus();
      if(meld == TRUE)
         break;
   }
}

Hochrollen()        /* Text hochrollen unter Berücksichtigung des Block- */
{                   /* modus */
   CursorAus();
   ScrollRaster(RPforte, 0, 8, 4, 43, 632, 226);
   Move(RPforte, 4, 225);
   if(blo>2) {
      if(BloPruef()==TRUE)
         SetDrMd(RPforte, COMPLEMENT);
   }
   Text(RPforte, a[s] [z], strlen(a[s] [z]));
   if(blo>2)
      SetDrMd(RPforte, JAM2);
   CursorAn(); Locate(y,x);
}
Runterrollen()       /* Dasselbe nur nach unten */
{
   CursorAus();
   ScrollRaster(RPforte, 0, -8, 4, 43, 632, 226);
   Move(RPforte, 4, 49);
   if(blo>2) {
      if(BloPruef()==TRUE)
         SetDrMd(RPforte, COMPLEMENT);
   }
   Text(RPforte, a[s] [z], strlen(a[s] [z]));
   if(blo>2)
      SetDrMd(RPforte, JAM2);
   CursorAn(); Locate(y,x);
}
Rollen()   /* einfaches Scrollen nach unten ab der aktuellen y-Kood. */
{
   CursorAus();
   ScrollRaster(RPforte, 0, -8, 4, (y*8+3), 632, 226);
   Move(RPforte, 4, (y*8+9));
   Text(RPforte, a[s] [z], strlen(a[s] [z]));
   CursorAn(); Locate(y,x);
}
RestLoeschen()    /* Löschen der Zeile rechts vom Cursor */
{
   CursorAus();
   a[s] [z] [x-1] = EOS;
   SetAPen(RPforte, 0);
   RectFill(RPforte, (x*8-4), (y*8+3), 632, ((y+1)*8+2));
   SetAPen(RPforte, 1);
}
ZeileLoeschen()    /* Löschen einer ganzen Zeile */
{
   int xalt=x;
   if(ze==z && se==s) {
     x=1;
     RestLoeschen();
     x=xalt;
   }
   else
      BSpaceII();
}
BloPruef()    /* überprüfung, ob die akt. Zeile innerhalb des Blocks liegt*/
{             /* oder nicht */
   if(bas<s && s<bes)
      return(TRUE);
   if(bas==s && baz<=z) {
      if(bes>s)
         return(TRUE);
      if(bes==s && bez>=z)
         return(TRUE);
   }
   if(bes==s && bez>=z && bas<s)
      return(TRUE);
   return(FALSE);
}
CarRet()       /* Carriage Return */
{
   int len, r, i, rz, rs;
   UBYTE *basis;

   CursorAus();
   if((MAS-se+SEITE-ze)>0) {  /* Kein Return, wenn Textspeicherende */
      if((i=strlen(a[s] [z]))>=x) { /* Wenn Crsr innerh. des Strings */
         basis = a[s] [z];          /* Rest der Zeile mit in die neue */
         a[s] [z] = basis+x-1;      /* übernehmen */
         for(len=x-1, r=0; len<=i; len++, r++)
           str[r] = *a[s] [z]++;
         str[r] = EOS;
         a[s] [z] = basis + x-1;
         *a[s] [z] = EOS;
         SetAPen(RPforte, 0);
         RectFill(RPforte, (x*8-4), (y*8+3), 632, (y*8+10));
         SetAPen(RPforte, 1);
         if(x>1) {
            for(len=x-1;len>0;len--){
               a[s] [z]--;
               if(*a[s] [z] == 32)
                  *a[s] [z] = EOS;
               else
                  break;
            }
         }
         a[s] [z] = basis;
      }
      else                       /* sonst nichts übernehmen */
         str[0] = EOS;
      y+=1; z+=1; ze+=1;
      if(z>SEITE) {
         z=0; s+=1;
      }
      if(ze>SEITE) {
         ze=0; se+=1;
      }
      rz=ze; rs=se;
      FOREVER { /* Den gesamten Text um eine Zeile ab der akt. Zeile ver- */
         r=rz; i=rs;  /* schieben, um Platz zu machen */
         rz=rz-1;
         if(rz<0) {
            rz=SEITE;
            rs=rs-1;
         }
         if(rs<=s) {
            if(rz<z) {
               StrKopie(a[s] [z], str);
               x=1; 
               break;
            }
            if(rs<s) {
               x=1;
               StrKopie(a[s] [z], str);
               break ;
            }
         }
         StrKopie(a[i] [r], a[rs] [rz]);
      }
      if(y>MAY) {
         y=MAY;
         Hochrollen();
      }
      Rollen();        /* Rest des Textes unterhalb des Crsrs nach unten */
   }                   /* scrollen */
   else {
      sprintf(buffer, "%s", FehlerText[2]); /* Textspeicherende anzeigen */
      meld = TRUE;
   }
}
BSpace()       /* Backspace */
{
   int len, r, i, rs, rz;
   UBYTE *basis, *basisII;

   if(s==0 && z==0 && x==1) {  /* Textanfang -> Fehlermeldung */
      sprintf(buffer, "%s", FehlerText[0]);
      meld = TRUE;
   }
   else {
      if(x!=1) {  /* wenn nur das linke Zeichen gelöscht wird */
         if((len = strlen(a[s] [z]))>=x-1) {
            basis = a[s] [z];        /* innerhalb des Strings:  */
            a[s] [z] = basis+x-1;    /* Rest der Zeile wird mit nach */
            for(i=x-1, r=0; i<=len; i++, r++) { /* links gezogen */
               str[r] = *a[s] [z]--;
               *a[s] [z] = str[r];
               a[s] [z] +=2;;
            }
            a[s] [z] = basis +len;
            str[r] = EOS; *a[s] [z] = EOS;
            a[s] [z] = basis;
            x=x-1;
            CursorAus();
            Move(RPforte, (x*8-4), (y*8+9));
            Text(RPforte, str, strlen(str));
            SetAPen(RPforte, 0);
            RectFill(RPforte,(strlen(a[s] [z])*8+4),(y*8+3),632,(y*8+10));
            SetAPen(RPforte, 1);
         }
         else
            x=x-1;           /* sonst nur Cursor 1 nach links */
      }
      else {  /* Wenn Zeilensprung nach oben */
         rz= z-1; rs =s;
         if(rz<0) {
            rz=SEITE; rs=rs-1;
         }
         if(((len=strlen(a[s] [z]))+(i=strlen(a[rs] [rz])))<MAX) {
            x=i+1; /* Wenn aktuelle Zeile + obere Zeile nicht zu lang */
            basis=a[rs] [rz]; basisII=a[s] [z];
            a[rs] [rz] = basis+i;
            for(r=0; r<=len; r++) {
               *a[rs] [rz]  = *a[s] [z];      /* Anhängen */
               a[rs] [rz] += 1; a[s] [z] += 1;
            }
            *a[rs] [rz] = EOS;
            a[rs] [rz] = basis; a[s] [z] = basisII;
            BSpaceII();
            y=y-1; z=z-1;
            if(z<0) {
               z=SEITE; s=s-1;
            }
            if(y<MIY) {
               y=MIY;
               Runterrollen();
            }
            else {
               Move(RPforte, 4, (y*8+9));
               Text(RPforte, a[s] [z], strlen(a[s] [z]));
            }
         }
      }
   }
}
BSpaceII()  /* aktuelle Zeile löschen und Speicher entsprechend verändern */
{
   int i, r, rz, rs;

   rz = z; rs = s;
   FOREVER {
      i= rs; r=rz;
      rz+=1;
      if(rz>SEITE) {
         rz=0; rs+=1;
      }
      if(rs>=se) {
         if(rz>ze)
            break;
         if(rs>se)
            break;
      }
      StrKopie(a[i] [r], a[rs] [rz]);
   }
   ze=ze-1;
   if(ze<0) {
      ze=SEITE; se=se-1;
   }
   i=y; rz=z; rs=s;
   if(y<MAY)
      CrsrBot();
   CursorAus();
   ScrollRaster(RPforte, 0, 8, 4, (i*8+3), 632, 226);
   if((s==se && z>ze) || (s>se)) {
      SetAPen(RPforte,0);
      RectFill(RPforte,4,219,632,226);
      SetAPen(RPforte,1);
   }
   else if(meld == TRUE) ;
   else  {
      Move(RPforte, 4, 225);
      Text(RPforte, a[s] [z], strlen(a[s] [z]));
   }
   z=rz; s=rs; y=i; meld=FALSE;
}
Del()  /* Zeichen unter dem Crsr löschen und Text nach links ziehen */
{
   int i, r, len;
   UBYTE *basis;

   if((len=strlen(a[s] [z]))>=x) {
      basis = a[s] [z];
      a[s] [z] = basis+x;
      for(i=x, r=0; i<=len; i++, r++) {
         str[r] = *a[s] [z]--;
         *a[s] [z] = str[r];
         a[s] [z] +=2;
      }
      a[s] [z] = basis + len;
      str[r] = EOS; *a[s] [z] = EOS;
      a[s] [z] = basis;
      CursorAus();
      Move(RPforte, (x*8-4), (y*8+9));
      Text(RPforte, str, strlen(str));
      SetAPen(RPforte, 0);
      RectFill(RPforte, (strlen(a[s] [z])*8+4), (y*8+3), 632, (y*8+10));
      SetAPen(RPforte, 1);
   }
}

StrEnde() /* Cursor an das Ende der aktuellen Zeile */
{
   x = strlen(a[s] [z]) +1;
   if(x>MAX) x=MAX;
   if(x<MIX) x=MIX;
}
StrKopie(nach, von) /* normales strcpy */
register char *nach, *von;
{
   while(*nach++ = *von++) ;
}
