
/****************************************************/
/*                 TaskMon V0.4                     */
/*                                                  */
/*                  9.3-14.5.88                     */
/*             by Patrick Erpenbeck                 */
/*            Hans-Röhmhild-Str. 41a                */
/*                 3500 Kassel                      */
/*                                                  */
/****************************************************/




#include "defs.h" /* Definitionen/Includes etc. */


VOID       /* Text ausgeben, kompakterer Code als puts() o.ä. */
 print(s)

char *s;
{

  Write((long)Output(),s,(long)strlen(s));

} /* PRINT */


#ifdef HELP         /* Version mit dem längeren Helptext gewünscht ? */
 #include"help.c"
#endif

VOID                     /* Ausgabe eines IntuiTextes */
 printit(s,x,y)

UBYTE *s;        /* Zeiger auf den Ausgabestring */
long x,y;        /* X-Y-Position */
{
  itext.IText = s;
  PrintIText(wrp,&itext,x,y);

} /* PRINTIT */


VOID
 wandlung(quelle,ausgabe,z)  /* Umwandlung in irgendwas Verständliches */

register UBYTE *quelle;      /* Zeiger auf Quelle     */
register char  *ausgabe;    /*   "     "  Zielstring */
register UBYTE z;          /*      Bytezähler       */
{
  register UBYTE *inhalt,hibble,nibble;
  static char    ziffer[] = "0123456789ABCDEF";

  for(inhalt = quelle;inhalt-quelle<z;inhalt++)
   {
     hibble = *inhalt/16;          /* die oberen 4 Bit isolieren */
     nibble = *inhalt-hibble*16;   /* genauso die Unteren;       */
     *ausgabe++ = ziffer[hibble];  /* und die zugehörigen Hex-   */
     *ausgabe++ = ziffer[nibble];  /* zahlen in den Zielstring   */
  }                                /* kopieren.                  */

} /* WANDLUNG */    


VOID
 clear(x1,y1,x2,y2)  /* Bereich im Window löschen */

long x1,y1,x2,y2;
{

  SetAPen(wrp,0L);
  RectFill(wrp,x1,y1,x2,y2);
  SetAPen(wrp,1L);

} /* CLEAR */


VOID
 read_tasks(flags)  /* frei nach AMIGA-Intern (vielen Dank ??!) */

register UBYTE flags;
{

  register int  z,count;  /* Zähler,count = Anzahl der angezeigten Tasks */
  register long x,y;               /* maximal 22 */


  run = (struct Task *) SysBase->ThisTask; /* Zeiger auf meinen Task */

  if(flags & LIST)  /* nur ausführen wenn Darstellung */
   {                /* der Listen eingeschaltet ist   */
    x = 10;
    y = 140;
    count = 1;

    clear(x,y,x+WIDTH/2-10,y+10);
    printit(run->tc_Node.ln_Name,x,y);        /* running Task */
    printit(states[run->tc_State],x+200,y);
  }

  Disable(); /* Keine Interrupts ! */

  /* Tasks im WAIT-state */

  for(z = 1,wtasks[z] = (struct Task *) SysBase->TaskWait.lh_Head;
      wtasks[z] != 0L;z++)
   {
      if((wtasks[z+1] = (struct Task *) wtasks[z]->tc_Node.ln_Succ) == NULL)
       continue;  /* Ende der Liste erreicht. */
                  /* verhindert, daß unsinnige Werte erscheinen. */
      if((flags & LIST) && (count++ < 23))
       {
         clear(x,y+10,x+WIDTH/2-10,y+20);  /* vorher  angezeigten Task 'löschen' */
         printit(wtasks[z]->tc_Node.ln_Name,x,y += 10); /* Namen ausgeben */
         printit(states[wtasks[z]->tc_State],x+200,y);/* Status    "    */
         if(y == 220)         /* passt noch was in die Spalte ?     */
           { x = 292;y = 130;}  /* Nein ,auf der anderen Seite weitermachen */
      }
  } /* FOR */
  wtasks[--z] = NULL; /* Ende der Tasklist markieren  */
                      /* 'invalid' Task am Ende eleminieren */

  /* Tasks im READY-state ermitteln */

  for(z = 1,rtasks[z] = (struct Task *) SysBase->TaskReady.lh_Head;
      rtasks[z] != 0L;z++)
   {
      if((rtasks[z+1] = (struct Task *) rtasks[z]->tc_Node.ln_Succ) == NULL)
       continue;
      if((flags & LIST) && (count++ < 23))
       {
         clear(x,y+10,x+WIDTH/2-10,y+20);
         printit(rtasks[z]->tc_Node.ln_Name,x,y += 10);
         printit(states[rtasks[z]->tc_State],x+200,y);
         if(y == 220)
           { x = 292;y = 130;}
      }
  } /* FOR */

  Enable();  /* Interrupts freigeben */

  rtasks[--z] = NULL; /* s.o. */

  if(flags & LIST)
   clear(x,y+10,WIDTH-5,HEIGHT-5);  /* etwaige Reste löschen */


} /* READ_TASKS */


struct Task*       
 show_struct(tp)     /* Darstellen der Taskstruktur */

struct Task *tp;

{
  /* Speicher für die Hexzahlen */
  static char inhalt[2*sizeof(struct Task)],text[2*sizeof(struct MemList)];

  static int offset[] =     /* Byteoffsets(*2) inerhalb der Taskstruktur */
   {
    8,8,2,2,8,  /* Node-Struktur */
    2,2,2,2,8,
    8,8,8,4,4,
    8,8,8,8,8,
    8,8,8,8,2*sizeof(struct MemList),
    8
  };         

  register long x,y;
  ULONG    dummy;
  register int z,sp,strz;  /* X-,Y-Pos.,Stackgröße,Namen-,Spalten-,String-Zähler */

  x = 10;
  sp = 0;
  strz = 0;

  Disable();
  if((tp->tc_State < TS_INVALID) || (tp->tc_State > TS_REMOVED))
   {
    Enable();
    return(tp);  /* hat sich wohl was geändert, also alten Task lassen */
  }

  /* gesamte Taskstruktur in Hexzahlen wandeln */

  wandlung(tp,&inhalt[0],sizeof(struct Task));

  for(z = 0;z <= 25;z++)
   {
    y = sp++*10+30;                              /* Zeile berechnen   */
    strncpy(&text[0],&inhalt[strz],offset[z]);   /* String kopieren   */
    text[offset[z]] = 0;                         /* Ende kennzeichnen */
    strz += offset[z];
    if(offset[z] > 8) continue;                  /* MemList weglassen */
    printit(&text,x+100,y);
    if(sp > 8)                                   /* Spalte wechseln   */
     {
      sp = 0;
      x += 190;
    }
  } /* FOR */

  x = 20;y += 20;

  clear(x+50,y,x+200,y+10);               /* Name des Tasks   */
  printit(tp->tc_Node.ln_Name,x+50,y);

  clear(x+260,y,x+332,y+10);
  printit(states[tp->tc_State],x+260,y);  /* Status in Worten */

  dummy = (ULONG)tp->tc_SPUpper - (ULONG)tp->tc_SPLower - 2L; /* Stackgröße berechnen     */
  wandlung(&dummy,&text[0],8);                             /* und als Hexzahl ausgeben */
  text[8] = 0;   /* Ende */
  printit(&text,x+402,y);

  Enable();

  return(tp);

} /* SHOW_STRUCT */


VOID
 maske()    /* Bildschirmmaske für Taskstruktur aufbauen */

{

  static char *structnames[] =   /* Taskcontrolblockstrukturnamen */
   {
    "Node.ln_Succ", "Node.ln_Pred", "Node.ln_Type",
    "Node.ln_Pri",  "Node.ln_Name", "Flags",
    "State",        "IDNestCnt",    "TDNestCnt",
    "SigAlloc",     "SigWait",      "SigRecvd",
    "SigExcept",    "TrapAlloc",    "TrapAble",
    "ExecptData",   "ExecptCode",   "TrapData",
    "TrapCode",     "SPReg",        "SPLower",
    "SPUpper",      "Switch",       "Launch",
    "MemEntry",     "UserData"
  };

  static char *names[] =
   {
    "Name:","Status:","Stack:"
  };


  long x,y;
  int  z,sp;  /* X-,Y-Pos.,Namen-,Spalten-Zähler */

  x = 10;
  sp = 0;

  for(z = 0;z <= 25;z++)
   {
      y = sp++*10+30;                   /* Zeile berechnen */
      printit(structnames[z],x,y);
      if(sp > 8)                        /* Spalte wechseln */
       {
        sp = 0;
        x += 190;
      }
  } /* FOR */

    x = 20;y += 20;

    Move(wrp,0L,y+15);
    Draw(wrp,WIDTH,y+15) ;        /* Unterteilung durch eine Linie */
    printit(names[0],x,y);        /* 'Name'   */
    printit(names[1],x += 200,y); /* 'Status' */
    printit(names[2],x += 150,y); /* 'Stack'  */


} /* MASKE */



struct Task *
 auswerten(gad,flags)       /* Welches Gadget wurde gedrückt ??? */
                           /* dazugehörige Funktion ausführen   */
struct Gadget *gad;
UBYTE *flags;

{
  static struct Task *tp;   /* enthält den zuletzt angezeigten Task    */
  static struct Task **ptr; /* Zeiger auf Tasklistenzeigerarray (s.u.) */

  switch(gad->GadgetID)
   {
     case READYGAD:
                     if(rtasks[1] != NULL)      /* leere Liste ?  */
                      {                         /* nein           */
                        ptr = &rtasks[1];
                        tp = show_struct(rtasks[1]);
                        break;
                     }                       /* ja,            */
     case RUNGAD:                            /* running Task   */
                     ptr = NULL;
                     tp = show_struct(run);
                     break;

     case WAITGAD:                             /* waiting Tasks  */
                     ptr = &wtasks[1];         /* sind immer da (?)  */
                     tp = show_struct(wtasks[1]);
                     break;
     case LISTGAD:
                     if(*flags & LIST)
                       {
                         *flags &= VBLANK;       /* Listen aus */
                         SizeWindow(window,0L,140-HEIGHT); /* nur noch Struktur */
                      }
                     else
                       {
                         *flags |= LIST;    /* und wieder ein */
                          /* das Window soll korrekt vergrößert werden, also : */
                         MoveWindow(window,1L-(window->LeftEdge),10L-(window->TopEdge));
                         SizeWindow(window,0L,HEIGHT-140L);
                      }
                     break;
     case PREVGAD:                             /* vorherigen Task */
                     if(ptr == NULL)           /* anzeigen        */
                       show_struct(run);       /* beim running Task geht das natürlich nicht */
                     else
                        if(*(--ptr) == NULL)     /* Ende ? */
                           show_struct(*(++ptr));/* ja, gleicher Task */
                        else
                         tp = show_struct(*ptr); /* nein, weiter */
                     break;
     case NEXTGAD:                          /* nächsten Task */
                     if(ptr == NULL)        /* s.o. */
                       show_struct(run);
                     else
                        if(*(++ptr) == NULL)
                           show_struct(*(--ptr));
                        else
                         tp = show_struct(*ptr);
                     break;
     case WINDOWGAD:             /* Window ganz klein machen */
                     *flags = 0; /* Alles aus */
                     SizeWindow(window,200L-WIDTH,10L-window->Height);
                     break;


  } /* SWITCH */

  return(tp);

} /* AUSWERTEN */


VOID
 window_groß()   /* Window auf alte Größe bringen. Aber erst, wenn der    */
                /* Benutzer aufhört das Window zu bewegen ( auf dem Um-  */
               /* weg über die Mausbewegung).                           */
{
  struct IntuiMessage *msg;
  ULONG  class;

  WaitPort(window->UserPort);
  while(msg = (struct IntuiMessage *) GetMsg(window->UserPort))
    if(msg->Class == MOUSEMOVE) continue;

  MoveWindow(window,1L-(window->LeftEdge),10L-(window->TopEdge));
  SizeWindow(window,WIDTH-200L,HEIGHT-10L);
  RefreshGList(gadgets[0],window,NULL,MAXGADS);  /* alles wiederher- */
  maske();                                       /* stellen          */

} /* WINDOW_GROß */


VOID
 tschau(s)               /* Verabschiedungsroutine */

char *s;
{

  if(!WBenchMsg)   /* läuft das Prog. von der WB ? */
   print(s);       /* Nein, also können wir einen Text ausgeben. */

  if (Time_Req . tr_node . io_Message . mn_ReplyPort) /* Timer Device */
   {                                                  /* schließen    */
    AbortIO((char *) &Time_Req . tr_node) ;
    CloseDevice(&Time_Req) ;
    SetTaskPri(FindTask((char *) 0),old_pri) ;  /* alte Priorität wieder- */
  }                                             /* herstellen */
  if (timer_port)
   DeletePort(timer_port) ;
  if(window)                       /* Fenster schließen  */
   CloseWindow(window);
  FreeRemember(&RememberKey,TRUE); /* Speicher freigeben */
  if(IntuitionBase)
   CloseLibrary(IntuitionBase);    /* Librarys schließen */
  if(GfxBase)
   CloseLibrary(GfxBase);

  exit(0);                         /* Prog. verlassen    */

} /* TSCHAU */


VOID
 init_gadgets()   /* Gadgets initialisieren */

{
  register int z; /* Zähler */

  for(z = 0;z < MAXGADS;z++)
   {

    /* Speicher besorgen */

    if((itexts[z] = (struct IntuiText *)
      AllocRemember(&RememberKey,(long)sizeof(struct IntuiText),MEMF_CLEAR)) == NULL)
    tschau("no memory for intuitext\n");

    if((gadgets[z] = (struct Gadget *)
      AllocRemember(&RememberKey,(long)sizeof(struct Gadget),MEMF_CLEAR)) == NULL)
    tschau("no memory for gadget\n");

    /* Strukturen initialisieren */

    itext.IText = (UBYTE *)gadnames[z];  /* Name */
    gadget.GadgetID = z+1;               /*  ID  */ 
    gadget.GadgetText = itexts[z];       /* Zeiger auf den IText */

    /* und in den vorgesehenen Speicher kopieren */

    CopyMem(&gadget,gadgets[z],(long)sizeof(struct Gadget));
    CopyMem(&itext,itexts[z],(long)sizeof(struct IntuiText));
    gadget.LeftEdge += 80; /* Y-Position+80 */

    if(z == 0) continue;   /* beim ersten Gadget ist natürlich keins davor */
    gadgets[z-1]->NextGadget = gadgets[z];

  } /* FOR */


} /* INIT_GADGETS */


VOID
 init_vblank()   /* timer.device und die Kommunikationsmittel bereitstellen */

{
   if ((timer_port = CreatePort("Timer Port", 0L)) == NULL)
      tschau("Can't create timer port") ;

   if (OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Time_Req, 0L) != NULL)
      tschau("Can't open timer device") ;
   Time_Req . tr_node . io_Message . mn_ReplyPort = timer_port ;
   Time_Req . tr_node . io_Command = TR_ADDREQUEST ;
   Time_Req . tr_node . io_Flags = 0 ;
   Time_Req . tr_node . io_Error = 0 ;

   old_pri = SysBase->ThisTask->tc_Node.ln_Pri; /* alte Priorität merken */
   SetTaskPri(FindTask((char *) 0),19L) ;     

} /* INIT_VBLANK */


VOID
 openall()  /* öffnen all der Schatztruhen im Amiga */

{

  if((IntuitionBase = (struct IntuitionBase *)
      OpenLibrary("intuition.library",0L)) == NULL)
   tschau("no intuition\n");

  if((GfxBase = (struct GfxBase*)
      OpenLibrary("graphics.library",0L)) == NULL)
   tschau("no gfx\n");

  init_vblank();
  init_gadgets();

  newwindow.FirstGadget=gadgets[0]; /* Gadget-Liste einfügen */
  if((window = (struct Window *)OpenWindow(&newwindow)) == NULL)
   tschau("no window\n");

  wrp=window->RPort;

  itext.BackPen = 0;
  itext.DrawMode = JAM2; /* neuer DrawMode erspart das Löschen */

  wtasks[0] = NULL;  /* Anfang der  */
  rtasks[0] = NULL;  /* Tasklisten kennzeichnen */

} /* OPENALL */


main(argc,argv)    /* ENDLICH !!! */

int  argc;
char *argv[];
{
  struct IntuiMessage *msg;
  struct Task         *tp;
  struct MsgPort      *wport;
  static BYTE         send_io = TRUE;       /* s.u. */
  static BYTE         flags = VBLANK|LIST;  /* alle Optionen an */
  static BYTE         wait_time;            /* wie oft soll Liste erneuert werden ? */

  if(argc == 2)
   {
     wait_time = argv[1][0]-'0'; /* zu einer Zahl machen (wenn es geht) */
     if( (wait_time < 1) || (wait_time > 9) || (argc > 2) )
     #ifdef HELP
       help_text();  /* war wohl nix, also Hilfe geben und verabschieden */
     #else
      {
       print("\nSyntax: taskmon (optional Updaterate: 1-9sec)\n\n");
       exit(0);
     }
     #endif
   }
  else
     wait_time = WAIT_TIME; /* Default verwenden, da keine Zeit angegeben */

  openall();          /* Library/Gadgets/Device/Window öffnen      */
  maske();            /* Bildschirm-Maske aufbauen                 */
  read_tasks(flags);  /* Tasklisten einlesen und ausgeben          */
  tp = run;           /* running Task zuerst als Struktur anzeigen */
  wport = window->UserPort;

  FOREVER
   {
    if(flags & VBLANK) /* überhaupt erwünscht ? */
     {
      if(send_io) /* nur wenn Msg ankam, neue Anforderung; nicht bei  */
       {          /* jedem Schleifendurchlauf!! (ENDLOSENDLOSEN....)  */

         Time_Req . tr_time . tv_secs = wait_time;
         Time_Req . tr_time . tv_micro = 0;
         SendIO((char *) &Time_Req . tr_node) ;
         send_io = FALSE;

      } /* IF */

      /* auf Alles warten (s.u.) */
      Wait((1L << wport->mp_SigBit) | (1L << timer_port->mp_SigBit));

      while (Msg = (struct Message *) GetMsg(timer_port))
        {
           send_io = TRUE;         /* nächste Anforderung darf abgeschickt werden */
           read_tasks(flags);      /* Tasklisten einlesen u. ausgeben             */
           if(!(flags & LIST))     /* Listen aus ?  Wenn ja, dann                 */
             tp = show_struct(tp); /* Update der dargestellten Taskstruktur       */

      } /* WHILE */

     } /* IF */

    else

      WaitPort(wport);  /* aber nicht immer !! */


    while(msg = (struct IntuiMessage *) GetMsg(wport))
     {
      switch(msg->Class)
       {
         case CLOSEWINDOW:
                              ReplyMsg(msg);
                              tschau("\n  tschau ! \n\n");
         case GADGETDOWN:
                              tp = auswerten(msg->IAddress,&flags);
                              break;
         case INACTIVEWINDOW:
                              if(!(flags & VBLANK)) /* TaskListen ??   */
                                flags = 0;          /* nein, alles aus */
                              break;
         case ACTIVEWINDOW:
                              if(window->Width < 300) /* nur die Windowleiste ? */
                               {                      /* ja, also alles neu     */
                                window_groß();
                                tp = run;
                              }
                              if(flags == 0)
                                 flags = VBLANK|LIST; /* alles ein */
                              Disable();
                              tp = show_struct(tp);
                              Enable();
                              break;
      } /* SWITCH */

      ReplyMsg(msg); /* immer schön antworten */

    } /* WHILE */

  } /* FOREVER */

} /* MAIN */


/**** END ****/
