/* ConDev0.c

   richtet eine --- Shell --- fuer die Arbeit mit dem
   Console Device ein.

   Autor: E.G. Meyzis, Mai 1992

   Compile Instr. fuer DICE:                   execute cCon0
   dcc ConDev0.c -c -o t:ConDev0.o

   Link Instr. fuer DICE:                      execute lCon0
   dlink dlib:c.o t:ConDev0.o dlib:c.lib+
   dlib:amigas20.lib dlib:auto.lib dlib:x.o -o ConDev0
*/

#include <Devices/Console.h>
#include <Devices/ConUnit.h>
#include <Dos/Dos.h>
#include <Exec/Exec.h>
#include <Intuition/Intuition.h>
#include <stdlib.h>
#include <stdio.h>
#include <utility/TagItem.h>

/* +++++++++  Definitionen  ++++++++++++
*/
#define TRUE      1   /* um mit Datentyp BOOL zu arbeiten */
#define FALSE     0
#define CSI    0x9B /* Control Sequence Introducer, wie z.B.
                       fuer F-Tasten F1 bis F10 verwendet */
#define OS200    36                  /* mindestens OS 2.0 */


#define ConTitle " Con Dev 0 "    /* Titel Console Window */

/* +++++++++  Datentypen  ++++++++++++
*/
typedef char                BOOL;
typedef char                *CharPtr;
typedef struct IOStdReq     *IOStdReqPtr;
typedef struct Window       *WindowPtr;
typedef struct MessagePort  *MsgPortPtr;


/* ++++++++ Routinen des Basisprogramms ++++++++++ */

BOOL RunningOS2();
void IORequestAbbauen(IOStdReqPtr reqPtr);
void Aufraeumen();
BOOL FensterAngelegt(WindowPtr *win);
BOOL ConsoleEingerichtet(IOStdReqPtr *wrPtr, *rdPtr,
                                  WindowPtr   winPtr);
BOOL IORequestAngelegt(IOStdReqPtr *conPtr);
void ConWriteStr(IOStdReqPtr conPtr, CharPtr str);
void ConWriteBuf(IOStdReqPtr conPtr,
                 CharPtr     bufPtr,
                 int        laenge);
int ConReadSync(IOStdReqPtr conPtr,
                CharPtr     bufPtr,
                int         laenge);
BOOL ConReadASync(IOStdReqPtr conPtr,
                  CharPtr     bufPtr,
                  int         laenge);
void IDCMPCloseClickAbholen(WindowPtr winPtr);

/* ++++++++  Demo- und Test-Routinen ++++++++++ */

/* Hier die Prototypen der Erweiterung- bzw. Testroutinen
   einhaengen: z.B.
      void SchreibTest();  Listing 4-1
      void LeseTest();     Listing 4-2
      void LeseRawEvent(); Listing 4-3
      void EventCloseClickAbholen(IOStdReqPtr conPtr); L 4-4
      void ANSICodeDemo(); Listing 4-5
*/

/* +++++++++  globale Variablen  ++++++++++++
*/
WindowPtr       ourWinPtr;

/* Ein Device, zwei I/O Strukturen */

IOStdReqPtr     conWritePtr, /* Schreiben */
                conReadPtr;  /* Lesen */


int main()
{
  int returnVal = 0; /* erfolgreiche Ausfuehrung annehmen */

  if (RunningOS2())   /* dann haben wir mindestens OS 2.0 */
    {
     if(FensterAngelegt(&ourWinPtr))
       {
        if (ConsoleEingerichtet (&conWritePtr,
                                 &conReadPtr, ourWinPtr))
          {
           /* hier die funktionalen Erweiterungen einfuegen
              z.B.
                  SchreibTest();  Listing 4-1
                  LeseTest();     Listing 4-2
                  LeseRawEvent(); Listing 4-3

                  IDCMPCloseClick... ersetzen durch:
                  EventCloseClickAbholen(conReadPtr); L 4-4
           */
           IDCMPCloseClickAbholen(ourWinPtr);  /*  warten */
          }
        else
          returnVal = 10;  /* Console Dev. nicht anlegbar */
       }                         /* Fenster ... */
     else
       returnVal = 11;           /* Window nicht anlegbar */
     Aufraeumen();
    }                            /* Running ... */
  else
    returnVal = 12;                         /* OS 1.2/1.3 */

  return returnVal;
}


BOOL RunningOS2()        /* lauft Programm unter OS 2.x ? */
{
  long            *systemBasis;
  struct ExecBase *execBasePtr;

  systemBasis = (APTR)4;  /* Adr ExecBase a. Adr. 4 holen */
  execBasePtr = (APTR)*systemBasis;
  if (execBasePtr->LibNode.lib_Version >= OS200) /* OS 2  */
     return TRUE;
  else
     return FALSE;
}


void Aufraeumen()                 /* Ressourcen freigeben */
{
  if (conReadPtr)                   /* Lese- I/O Struktur */
    {
     if (!CheckIO(conReadPtr))    /* laeuft ein I/O Req.? */
       {
        AbortIO(conReadPtr); /* falls ja, diesen abbrechen*/
        WaitIO(conReadPtr);  /* und auf Beendigung warten */
       }
     IORequestAbbauen(conReadPtr);   /* einschl. Msg Port */
    }
  if (conWritePtr)
    {
     if (conWritePtr->io_Device)
       CloseDevice(conWritePtr);
     IORequestAbbauen(conWritePtr);
    }
  if (ourWinPtr)
    {
     CloseWindow(ourWinPtr);
     ourWinPtr = 0;
    }
}


void IORequestAbbauen(IOStdReqPtr reqPtr)

{
  if (reqPtr->io_Message.mn_ReplyPort)
    {                                             /* OS 2 */
     DeleteMsgPort(reqPtr->io_Message.mn_ReplyPort);
  }
  DeleteIORequest(reqPtr);                        /* OS 2 */
  reqPtr = 0;
}


BOOL FensterAngelegt(WindowPtr *win)

{
  static struct TagItem tagBuffer[10] =           /* OS 2 */
                   {
                    WA_Left,      20,
  /* DICE ver- */   WA_Top,       20,
  /* langt es, */   WA_Title,    (ULONG*) ConTitle,
  /* die Struk-*/   WA_Width,    500,
  /* tur, glo- */   WA_Height,   200,
  /* bal oder  */   WA_MinWidth, 100,
  /* static an */   WA_MinHeight, 50,
  /* zulegen   */   WA_Flags,  WFLG_SIMPLE_REFRESH |
                               WFLG_CLOSEGADGET |
                               WFLG_DEPTHGADGET |
                               WFLG_DRAGBAR  |
                               WFLG_SIZEGADGET,
                    TAG_DONE
                   };

  *win = (WindowPtr)OpenWindowTagList (NULL, tagBuffer);
  return (*win != NULL);
}


BOOL ConsoleEingerichtet(IOStdReqPtr *wrPtr, *rdPtr,
                                  WindowPtr   winPtr)

{
  IOStdReqPtr writePtr,
              readPtr;
  BOOL done = FALSE;

  if (IORequestAngelegt(&writePtr))    /* 1. I/O struktur */
    {
     writePtr->io_Data = winPtr;      /* Intuition Window */
     writePtr->io_Length = sizeof(struct Window);
     OpenDevice("console.device", CONU_STANDARD,  /* OS 2 */
                 writePtr, CONFLAG_DEFAULT);
     if ((!writePtr->io_Error) &&     /* Device geoeffnet */
                              (IORequestAngelegt(&readPtr)))
       {
        readPtr->io_Unit = writePtr->io_Unit; /* 2. Strukt*/
        readPtr->io_Device = writePtr->io_Device; /* erbt */
        done = TRUE;
        *wrPtr = writePtr;   /* Zeiger auf I/O Strukturen */
        *rdPtr = readPtr;    /* ans rufende Prog. geben */
       }
     else
       Aufraeumen;                 /* mangelte es an RAM? */
    }
  return done;
}

BOOL IORequestAngelegt(IOStdReqPtr *conPtr)

{
  MsgPortPtr portPtr;
  BOOL       done = FALSE;

  portPtr = (MsgPortPtr)CreateMsgPort();           /* OS2 */
  if (portPtr)
    {
     *conPtr = (IOStdReqPtr)
              CreateIORequest(portPtr,            /* OS 2 */
                              sizeof(struct IOStdReq));
     if (*conPtr)
       done = TRUE;
     else
       DeleteMsgPort(portPtr);                    /* OS 2 */
    }
  return done;
}


void ConWriteStr(IOStdReqPtr conPtr, CharPtr str)
{
  conPtr->io_Data = str;
  conPtr->io_Length = -1; /* nur f. mit 0 termin. Strings */
  conPtr->io_Command = CMD_WRITE;
  DoIO(conPtr);
}


void ConWriteBuf(IOStdReqPtr conPtr,
                 CharPtr     bufPtr, /*m. auszugeb. Zeich.*/
                 int        laenge)      /* Zeichenanzahl */
{
  conPtr->io_Data = bufPtr;
  conPtr->io_Length = laenge;         /* beliebige Laenge */
  conPtr->io_Command = CMD_WRITE;
  DoIO(conPtr);
}


int ConReadSync(IOStdReqPtr conPtr,
                CharPtr     bufPtr,     /* dort hin lesen */
                int         laenge) /* Anzahl der Zeichen */
{
  conPtr->io_Data = bufPtr;
  conPtr->io_Length = laenge;
  conPtr->io_Command = CMD_READ;
  SendIO(conPtr);
  WaitIO(conPtr);                /* nur unter OS 2 sicher */
  return conPtr->io_Actual;
}


BOOL ConReadASync(IOStdReqPtr conPtr, /*asynchrones Lesen */
                  CharPtr     bufPtr, /* ist das empfohle-*/
                  int         laenge) /*ne Verfahren */
{
  conPtr->io_Data = bufPtr;
  conPtr->io_Length = laenge;
  conPtr->io_Command = CMD_READ;
  SendIO(conPtr);    /* bewirkt o. WaitIO  Asynchronitaet */
}



void IDCMPCloseClickAbholen(WindowPtr winPtr)

{
  ModifyIDCMP(winPtr, IDCMP_CLOSEWINDOW);/*UserPort einr. */
  WaitPort(winPtr->UserPort);
  ReplyMsg(GetMsg(winPtr->UserPort));
}


/* ++++++++  Demo- und Test-Routinen ++++++++++ */

/* hier anhaengen */


/*
Listing 4-0: Einfache Shell fuer die Arbeit mit dem Console
Device.Das Modul kann durch Listing 4-1 bis 4-5 ausgebaut
werden. Funktionen des neuen OS sind entsprechend markiert.
*/
