/* 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 MAS, SEITE, sei, 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 Menu Menue1;
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, sicher;

char *FrageText[4];
char *FehlerTextI[] = {
   "Textanfang!",
   "Textende!",
   "Textspeicherende!" };

Meldung()      /* Meldung ausgeben und ZSDisplay() durchführen */
{
   UBYTE string[80];

   sprintf(string, "                                                ");
   Move(RPforte, 10, 31);
   Text(RPforte, string, strlen(string));
   Move(RPforte, 10, 31);
   Text(RPforte, buffer, strlen(buffer));
   sprintf(buffer, "SEITE %2d  ZEILE %2d  SPALTE %2d", s+1, z+1, x);
   Move(RPforte, 395, 31);
   Text(RPforte, buffer, strlen(buffer));
}
NamenSetzen(FName)
UBYTE *FName;
{
   UBYTE string[80];

   sprintf(string, "                                                ");
   Move(RPforte, 10, 20);
   Text(RPforte, string, strlen(string));
   Move(RPforte, 10, 20);
   Text(RPforte, FName, strlen(FName));
   strcpy(titel, FName);
}
Einfuegen()
{
   if(ein==TRUE) {
      sprintf(buffer, "EINFÜGEN AUS");
      ein = FALSE;
   }
   else {
      sprintf(buffer, "EINFÜGEN AN ");
      ein = TRUE;
   }
   Move(RPforte, 395, 20);
   Text(RPforte, buffer, strlen(buffer));
}
Laden(prgname)         /* Routine zum allgemeinen Laden eines Programms */
char *prgname;
{
   struct FileHandle *handle;
   register int ln, s1=se, x1=0, z1=ze ;
   int trans = GROESSE-1, zaehler=0, flaggy=FALSE;
   UBYTE *basis;

   if(!(handle=Open(prgname,MODE_OLDFILE)))
   {
      sprintf(buffer, "Kann %s nicht öffnen!", prgname);
      Meldung();
      return(FALSE);
   }
   basis = a[s1] [z1];
   FOREVER {
      if((ln = Read(handle,buffer,GROESSE))<GROESSE) {
         trans = ln-1;
         if(!ln) {
            *a[s1] [z1]  = EOS;
            a[s1] [z1] = basis;
            Close(handle);
            break;
         }
      }
      zaehler += trans+1;
      ln = 0;
lab1: do {
         *a[s1] [z1]++ = buffer[ln];
         if(buffer[ln]==9) {
            a[s1] [z1]--;
            *a[s1] [z1]++ = 32; x1+=1;
            if(x1==MAX) break;
            *a[s1] [z1]++ = 32; x1+=1;
            if(x1==MAX) break;
            *a[s1] [z1]++ = 32;
         }
         x1+=1; ln+=1;
      }
      while(x1<MAX && buffer[ln-1]!=LF && ln<=trans);

      if(buffer[ln-1]==LF) {
         a[s1] [z1] = a[s1] [z1] -1;
         *a[s1] [z1] = EOS;
label:   a[s1] [z1] = basis;
         x1=0; z1+=1;
         if(s1==MAS && z1>sei) {
            z1=sei; flaggy=TRUE;
            Close(handle);
            break;
         }
         if(z1>SEITE) {
            z1=0; s1+=1;
            if(s1==MAS+1) {
               s1=MAS; z1=SEITE; flaggy=TRUE;
               Close(handle);
               break;
            } 
         }
         basis = a[s1] [z1];
         if(ln>trans)
            continue;
         goto lab1;
      }
      if(x1==MAX) {
         *a[s1] [z1] = EOS;
         goto label;
      }
   }
   se = s1; ze = z1; xe = x1;
   FOREVER {
      if(*a[se] [ze] == EOS) {
         ze = ze-1;
         if(ze<0) {
            ze=SEITE; se=se-1;
         }
         continue;
      }
      break;
   }
   if(flaggy == TRUE) {
      if(sei<SEITE || MAS<14)
         sprintf(buffer, "Textspeicher ist voll! Blocklänge: %d!", zaehler);
      else
         sprintf(buffer, "Textspeicher ist voll! Textlänge: %d!",zaehler);
   }
   else {
      if(sei<SEITE || MAS<14)
         sprintf(buffer, "Blocklänge: %d Blockende: Seite %d Zeile %d!",
            zaehler, se+1, ze+1);
      else
         sprintf(buffer, "Textlänge: %d Textende: Seite %d Zeile %d!",
            zaehler, se+1, ze+1);
   }
   strcpy(str, buffer);
   Meldung();
   return(TRUE);
}

XPlusI()          /* x-Kood. d. Crsrs erhöhen, wenn ein Zeichen eingegeben */
{                 /* wurde */
   UBYTE *basis;

   x = x+1;
   if(x>MAX) {
      basis = a[s] [z];
      a[s] [z] = basis + MAX;
      *a[s] [z] = EOS; a[s] [z] = basis;
      x=MIX; y=y+1;
      z+=1;
      if(z>SEITE) {
         z = 0; s+=1;
         if(s>MAS) {
            s=MAS; z=SEITE; x=MAX; y=y-1;
            sprintf(buffer, "%s", FehlerTextI[2]);
            meld = TRUE;
         }
         if(s>se) {
            se = s; ze = 0;
            *a[s] [z] = EOS;
         }
      }
      if(s==se){
         if(z>ze) {
            ze =z;
            *a[s] [z] = EOS;
         }
      }
      if(y>MAY) {
         y=MAY;
         Hochrollen();
      }
   }
}
XPlus()        /* x-Kood. erhöhen, wenn die Crsr-Tasten benutzt wurden */
{
   x = x+1;
   if(x>MAX) {
      x=MIX;
      Flagge = TRUE;
      YZPlus();
      Flagge = FALSE;
   }
}
YZPlus()      /* y-Kood. und akt. Zeile erhöhen */
{
   z+=1; y=y+1;
   if(z>SEITE) {
      z = 0; s+=1;
      if(s>MAS) {
         s=MAS; z=SEITE; ; y=y-1;
         if(Flagge == TRUE)
            x = MAX;
         sprintf(buffer, "%s", FehlerTextI[2]);
         meld = TRUE;
      }
      if(s>se) {
         s = se; z = ze; y=y-1;
         if(Flagge == TRUE)
            x = MAX;
         sprintf(buffer, "%s", FehlerTextI[1]);
         meld = TRUE;
      }
   }
   if(s==se){
      if(z>ze) {
         z = ze; y = y - 1;
         if(Flagge == TRUE)
            x = MAX;
         sprintf(buffer, "%s", FehlerTextI[1]);
         meld = TRUE;
      }
   }
   if(y>MAY) {
      y = MAY;
      Hochrollen();
   }
}
XMinus()             /* x-Kood. des Crsrs verringern */
{
   x = x-1;
   if(x<MIX) {
      x=MAX;
      Flagge = TRUE;
      YZMinus();
      Flagge = FALSE;
   }
}
YZMinus()           /* y-Kood. u. akt. Zeile verringern */
{
   z=z-1; y=y-1;
   if(z<0) {
      z = SEITE; s=s-1;
      if(s<0) {
         s=0; z=0;  y=MIY;
         if(Flagge==TRUE)
            x=MIX;
         sprintf(buffer,"%s", FehlerTextI[0]);
         meld = TRUE;
      }
   }
   if(y<MIY) {
      y=MIY;
      Runterrollen();
   }
}

TitelZeile()      /* Spalteneinteilung im Fenster darstellen */
{
   int h, var;

   SetAPen(RPforte, 1);
   Move(RPforte, 0, 41);
   Draw(RPforte, 640, 41);
   for(h = 2; h <= 79; h++) {
      var = h * 8 - 5;
      if(h==10||h==20||h==30||h==40||h==50||h==60||h==70) {
         Move(RPforte, var, 35);
         Draw(RPforte, var, 41);
      }
      else {
         if(h==5||h==15||h==25||h==35||h==45||h==55||h==65||h==75) {
            Move(RPforte, var, 37);
            Draw(RPforte, var, 41);
         }
         else {
            Move(RPforte, var, 38);
            Draw(RPforte, var, 41);
         }
      }
   }
}

ZSDisplay()       /* aktuelle Seite, Zeile u. Spalte anzeigen */
{                                                                          
   sprintf(buffer, "SEITE %2d  ZEILE %2d  SPALTE %2d", s+1, z+1, x);
   Move(RPforte, 395, 31);
   Text(RPforte, buffer, strlen(buffer));
   sprintf(buffer, "                                                ");
   Move(RPforte, 10, 31);
   Text(RPforte, buffer, strlen(buffer));
}

Schluss()   /* Speicher frei geben, Fenster, Ports u. alle Libs schliessen */
{
   register int si, zi;

   for(si=0; si<=MAS; si++) {
      for(zi=0; zi<=SEITE; zi++)
         FreeMem(a[si] [zi], MAX);
   }
   CloseDevice(SNachr);
   ClearMenuStrip(Fenster, &Menue1);
   CloseWindow(Fenster);
   DeleteStdIO(LNachr);
   DeletePort(LPforte);
   DeleteStdIO(SNachr);
   DeletePort(SPforte);
   CloseLibrary(GfxBase);
   CloseLibrary(IntuitionBase);
}

/* Console zum Lesen u. Schreiben öffnen */

OeffneConsole(SAnforderung,LAnforderung,fenster)
struct IOStdReq *SAnforderung, *LAnforderung;
struct Window *fenster;
{
   int fehler;
   SAnforderung->io_Data = (APTR) fenster;
   SAnforderung->io_Length = sizeof(*fenster);
   fehler = OpenDevice("console.device", 0L, SAnforderung, 0L);
   LAnforderung->io_Device = SAnforderung->io_Device;
   LAnforderung->io_Unit = SAnforderung->io_Unit;
   return(fehler);
}

HolNachr(Puffer)  /* Zeichen einlesen oder Menübetätigung auswerten */
char *Puffer;
{
   register UBYTE temp;
   FOREVER {
      if((GetMsg(LPforte) == NULL)) { /* Wenn kein Zeichen eingegeben wird */
         if((nachricht=(struct IntuiMessage *) /* IDCMP abfragen */
                        GetMsg(Fenster->UserPort))!=0L) {
            class = nachricht->Class;
            code  = nachricht->Code;
            ReplyMsg(nachricht);
            switch(class) {
               case CLOSEWINDOW:        /* Das Closegadget wurde betätigt */
                  if(sicher == TRUE) {  /* Wenn absolute Sicherheit ge-  */
                     Schluss();         /* währleistet ist, dann sofort */
                     exit();            /* Schluss, sonst Sicherheits- */
                  }                     /* abfrage */
                  if(auto_frage(FrageText[0]) == TRUE) {
                     Schluss();
                     exit();
                  }
                  break;
               case MENUPICK:         /* Ein Menüpunkt wurde ausgewählt */
                  if(MENUNUM(code) != MENUNULL)   /* Auswertung */
                     Menueabfrage(MENUNUM(code), ITEMNUM(code));
                  break;
               case MOUSEBUTTONS:
                  break;
               default:
                  break;
            }
         }
         continue;
      }
      break;
   }
   temp = *Puffer;
   Vorbereiten(LNachr, Puffer);
   return(temp);                   /* eingelesenes Zeichen zurückschicken */
}

Vorbereiten(Anforderung, Puffer)   /* Console auf die Eingabe eines */
struct IOStdReq *Anforderung;      /* Zeichens vorbereiten */
char *Puffer;
{
   Anforderung->io_Command = CMD_READ;
   Anforderung->io_Data = (APTR) Puffer;
   Anforderung->io_Length = 1L;
   SendIO(Anforderung);
}

SString()                         /* String auf der Console ausgeben */
{
   SNachr->io_Command = CMD_WRITE;
   SNachr->io_Data = (APTR)buffer;
   SNachr->io_Length = strlen(buffer);
   DoIO(SNachr);
}

Locate(zeile, spalte)            /* Cursor aktualisieren */
int zeile, spalte;
{
   sprintf(buffer, "\x9b%d;%dH", zeile, spalte);
   SString();
}

CursorAus()                     /* Cursor anschalten */
{
   char *string;
   string = "\x9b\x30\x20\x70";
   SNachr->io_Command = CMD_WRITE;
   SNachr->io_Data = (APTR)string;
   SNachr->io_Length = strlen(string);
   DoIO(SNachr);
}
CursorAn()                      /* bzw. ausschalten */
{
   char *string;
   string = "\x9b\x20\x70";
   SNachr->io_Command = CMD_WRITE;
   SNachr->io_Data = (APTR)string;
   SNachr->io_Length = strlen(string);
   DoIO(SNachr);
}

Oeffnen() /* Libs und Ports öffnen, zwar äußerst umständlich programmiert,*/
          /* dafür aber absolut sicher */
{
   if(!(IntuitionBase=(struct IntuitionBase *)
      OpenLibrary("intuition.library",INTUITION_REV))) {
      printf("Kann Intuition-Library nicht öffnen!\n");
      exit(FALSE); }

   if(!(GfxBase=(struct GfxBase *)
      OpenLibrary("graphics.library",GRAPHICS_REV))) {
      printf("Kann Graphics-Library nicht öffnen!\n");
      CloseLibrary(IntuitionBase);
      exit(FALSE); }

   if(!(SPforte = CreatePort("my.con.write",0L))) {
      printf("Kann keinen Write-Port einrichten!\n");
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(FALSE); }

   if(!(SNachr = CreateStdIO(SPforte))) {
      printf("Kann keinen Write-Port öffnen!\n");
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      DeletePort(SPforte);
      exit(FALSE); }

   if(!(LPforte = CreatePort("my.con.read",0L))) {
      printf("Kann keinen Read-Port einrichten!\n");
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      DeleteStdIO(SNachr);
      DeletePort(SPforte);
      exit(FALSE); }

   if(!(LNachr = CreateStdIO(LPforte))) {
      printf("Kann keinen Read-Port öffnen!\n");
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      DeleteStdIO(SNachr);
      DeletePort(SPforte);
      DeleteStdIO(LNachr);
      exit(FALSE); }
}
