/*
** `size' mit AppIcon - Liest Verzeichnisse ein und spuckt die Größe aus
** Autor: Roland Jesse
** Compiler: GNU-C v2.3.3
** Status: Freeware
*/

#include <stdio.h>

#include <dos/dos.h>
#include <dos/dosasl.h>
#include <exec/memory.h>
#include <graphics/gfx.h>
#include <graphics/GfxBase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>

#define PATHLENGTH   (256)
#define APEN (1)

struct DOSBase *DOSBase = NULL;
struct GfxBase *GfxBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct WorkbenchBase *WorkbenchBase = NULL;

char *ver = "$VER: AppSize 1.3 ("__DATE__")";

LONG Bytes = NULL;                        /* Summe der Filelängen */
LONG DirAnz  = NULL;                      /*   "    "  Verz.      */
LONG FileAnz = NULL;                      /*   "    "  Dateien    */
UBYTE ScanDir[ PATHLENGTH ];              /* Name des Scan-Dirs   */

WORD line = NULL;                         /* Fonthöhe */

struct TextFont *myfont = NULL;           /* Ptr. auf Systemfont */
struct Window *win = NULL;                /* Ptr. auf Ausgabefenster */

struct NewWindow nwin = {
 150,50, 0,0, -1,-1,
 IDCMP_CLOSEWINDOW,
 WFLG_DRAGBAR | WFLG_CLOSEGADGET | WFLG_ACTIVATE | WFLG_DEPTHGADGET |
 WFLG_SMART_REFRESH, /* Window->Flags */
 NULL, NULL,
 (UBYTE *) "AppSize 1.3 ("__DATE__")",
 NULL, NULL,
 7,7,7,7,
 WBENCHSCREEN,
};

/* Source Daten für das OriIcon (wichtig, solange der GNU-CC nicht mit
** der IconBase (_IconBase ?) klarkommt.
** wenn doch einmal: GetDiskObjectNew() aus icon.library <
** (Ist latürnich der Compiler schuld :-))
*/

USHORT MyImageData[] =
{
 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0000, 0x0000,
 0x0000, 0x0000, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x07E0, 0x0000, 0x0000,
 0x0000, 0x0000, 0x0FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x1FF8, 0x0000, 0x0000,
 0x0000, 0x0000, 0x3E7C, 0x0000, 0x0000, 0x0000, 0x0000, 0x781E, 0x0000, 0x0000,
 0x0000, 0x0000, 0xFE7F, 0x0000, 0x0000, 0x0000, 0x0001, 0xFFFF, 0x8000, 0x0000,
 0x0000, 0x0003, 0xFFFF, 0xC000, 0x0000, 0x0000, 0x0007, 0xFFFF, 0xE000, 0x0000,
 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0028, 0x0000, 0x1400, 0x0000,
 0x0000, 0x01E0, 0x0000, 0x0780, 0x0000, 0x0000, 0x1FE0, 0x0000, 0x07F8, 0x0000,
 0x0000, 0xFFE0, 0x0000, 0x07FF, 0x0000, 0x0007, 0xF3E0, 0x0000, 0x07E7, 0xE000,
 0x007F, 0xF3E0, 0x0000, 0x07E7, 0xFE00, 0x03FF, 0xC0E0, 0x01C0, 0x0781, 0xFFC0,
 0x007F, 0xF3E0, 0x0000, 0x07E7, 0xFE00, 0x0007, 0xF3E0, 0x0000, 0x07E7, 0xE000,
 0x0000, 0xFFE0, 0x0000, 0x07FF, 0x0000, 0x0000, 0x1FE0, 0x0000, 0x07F8, 0x0000,
 0x0000, 0x01E0, 0x0000, 0x0780, 0x0000, 0x0000, 0x0028, 0x0000, 0x1400, 0x0000,
 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0007, 0xFFFF, 0xE000, 0x0000,
 0x0000, 0x0003, 0xFFFF, 0xC000, 0x0000, 0x0000, 0x0001, 0xFFFF, 0x8000, 0x0000,
 0x0000, 0x0000, 0xFE7F, 0x0000, 0x0000, 0x0000, 0x0000, 0x781E, 0x0000, 0x0000,
 0x0000, 0x0000, 0x3E7C, 0x0000, 0x0000, 0x0000, 0x0000, 0x1FF8, 0x0000, 0x0000,
 0x0000, 0x0000, 0x0FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x07E0, 0x0000, 0x0000,
 0x0000, 0x0000, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0000, 0x0000,
 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0000, 0x0000,
 0x0000, 0x0000, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x07E0, 0x0000, 0x0000,
 0x0000, 0x0000, 0x0FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x1FF8, 0x0000, 0x0000,
 0x0000, 0x0000, 0x3FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFE, 0x0000, 0x0000,
 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0001, 0xFFFF, 0x8000, 0x0000,
 0x0000, 0x0003, 0xFFFF, 0xC000, 0x0000, 0x0000, 0x0007, 0xFFFF, 0xE000, 0x0000,
 0x0000, 0x000F, 0xFFFF, 0xF000, 0x0000, 0x0000, 0x003F, 0xFFFF, 0xFC00, 0x0000,
 0x0000, 0x01F7, 0xFFFF, 0xEF80, 0x0000, 0x0000, 0x1FFF, 0xFFFF, 0xFFF8, 0x0000,
 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000,
 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0,
 0x0FFF, 0xFFFF, 0xFE3F, 0xFFFF, 0xFFF0, 0x03FF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0,
 0x007F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFE00, 0x0007, 0xFFFF, 0xFFFF, 0xFFFF, 0xE000,
 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x1FFF, 0xFFFF, 0xFFF8, 0x0000,
 0x0000, 0x01F7, 0xFFFF, 0xEF80, 0x0000, 0x0000, 0x003F, 0xFFFF, 0xFC00, 0x0000,
 0x0000, 0x000F, 0xFFFF, 0xF000, 0x0000, 0x0000, 0x0007, 0xFFFF, 0xE000, 0x0000,
 0x0000, 0x0003, 0xFFFF, 0xC000, 0x0000, 0x0000, 0x0001, 0xFFFF, 0x8000, 0x0000,
 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFE, 0x0000, 0x0000,
 0x0000, 0x0000, 0x3FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x1FF8, 0x0000, 0x0000,
 0x0000, 0x0000, 0x0FF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x07E0, 0x0000, 0x0000,
 0x0000, 0x0000, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0000, 0x0000,
};

struct Image MyImage =
{
  0, 0, 76, 39, 2, &MyImageData[0], 3, 0, NULL
};

struct DiskObject Icon =
{
  WB_DISKMAGIC, WB_DISKVERSION,
  {
   NULL, 230, 175, 76, 40,
   GADGIMAGE | GADGHCOMP, RELVERIFY | GADGIMMEDIATE, BOOLGADGET,
   (APTR) &MyImage, (APTR) &MyImage,
   NULL, NULL, NULL, 0, NULL,
  },
  NULL, NULL, NULL, NO_ICON_POSITION, NO_ICON_POSITION,  NULL, NULL, NULL
};

/* Schließt alle Libs */
void CloseAll (void)
{
   if (WorkbenchBase) CloseLibrary (WorkbenchBase);
   if (IntuitionBase) CloseLibrary (IntuitionBase);
   if (GfxBase) CloseLibrary (GfxBase);
   if (DOSBase) CloseLibrary (DOSBase);
}

/* Öffnet alle benötigten Libs */
void OpenAll()
{
   DOSBase = (struct DOSBase *)OpenLibrary ("dos.library", 37);
   GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 37);
   IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 37);
   WorkbenchBase = (struct WorkbenchBase *)OpenLibrary ("workbench.library", 37);
   if (!WorkbenchBase | !IntuitionBase | !GfxBase |!DOSBase)
      CloseAll ();
} /* OpenAll */

OpenDisplay ()
{
 struct TextFont *memfont = NULL;
 struct Screen *ascr = NULL;

   myfont = GfxBase->DefaultFont;
   if (!myfont) CloseAll ();

   nwin.Height = 7 * (myfont->tf_YSize + 2);

   ascr = IntuitionBase->ActiveScreen;
   if (!ascr) CloseAll ();

   Forbid();
   memfont = ascr->RastPort.Font;
   SetFont (ascr->RastPort, myfont);
   nwin.Width = TextLength (&ascr->RastPort, ver, strlen(ver))+100;
   SetFont (ascr->RastPort, memfont);
   Permit();

   if (nwin.TopEdge + nwin.Height > ascr->Height)
      nwin.TopEdge = ascr->Height - nwin.Height;
   if (nwin.Height < 0) CloseAll ();
   if (nwin.LeftEdge + nwin.Width > ascr->Width)
      nwin.LeftEdge = ascr->Width - nwin.Width;
   if (nwin.Width < 0) CloseAll ();

   win = (struct Window *)OpenWindow (&nwin);
   if (!win) CloseAll ();

   SetFont (win->RPort, myfont);
   line = myfont->tf_YSize + 1;
   SetAPen(win->RPort, APEN);
} /* OpenDisplay */

void Print (struct RastPort rp, SHORT x, SHORT y, STRPTR text)
{
   Move (&rp, x, y);
   Text (&rp, text, strlen (text));
} /* Print */

/* Scannt rekursiv das angegebene Verz. und liefert die Größe zurück
** in: (char) Verzeichnispfad
** out: (long) Größe
*/
BOOL Scannen(STRPTR Pfad)
{
 BOOL GeSized = FALSE;              /* out: TRUE=geScanned!, FALSE=Fehler */
 BOOL NextSucc = TRUE;              /* Testwert für Scan v. Unterverz. */
 BOOL CurrDir = FALSE;              /* Testwert, ob StartDir gesichert */
 BOOL Raus = FALSE;                 /* Ctrl-C gedrückt ? */
 BPTR OldDir;                       /* Alten VerzeichnisLock sichern */
 BPTR VerzLock = NULL;              /* Lock auf ScanVerzeichnis */
 struct FileInfoBlock *FIB = NULL;  /* für Examine() & ExNext() */
 LONG Error;                        /* richtiges IoErr() bei Ctrl-C */

 if(VerzLock = Lock(Pfad, ACCESS_READ))
 {
  NameFromLock (VerzLock, ScanDir, PATHLENGTH);
  Print (*win->RPort, 5, 3*line, ScanDir);
  OldDir = CurrentDir (VerzLock);
  if (!IoErr())
  {
   CurrDir = TRUE;
   DirAnz++;
   if(FIB = (struct FileInfoBlock *)AllocDosObject(DOS_FIB, NULL))
   {
    if(Examine(VerzLock, FIB))
    {
     while( NextSucc && !(Raus = CheckSignal( SIGBREAKF_CTRL_C ) != 0)
           && ExNext(VerzLock, FIB) )
     {
      if(FIB->fib_DirEntryType < 0)
      {
       Bytes += FIB->fib_Size;
       FileAnz++;
      } else if( NextSucc = Scannen( FIB->fib_FileName ));
     }
     if(IoErr() == ERROR_NO_MORE_ENTRIES) GeSized = TRUE;
    }
   }
  }
 }
 if(Raus) Error = ERROR_BREAK;                                     /*>-+ */
 else Error = IoErr();                                             /*>-+ */
                                                                   /*  | */
 if(FIB) FreeDosObject(DOS_FIB, FIB);                              /*  | */
 if(CurrDir) CurrentDir(OldDir);                                   /*  | */
 if(VerzLock) UnLock(VerzLock);                                    /*  | */
                                                                   /*  | */
 SetIoErr(Error);                                                  /*<-+ */
 return(GeSized);
}

main(int argc, char **argv)
{
 struct MsgPort *msgport = NULL;      /* Messageport für AppIcon */
 struct AppIcon *appicon = NULL;      /* Struktur     "  AppIcon */
 struct AppMessage *appmsg = NULL;
 struct IntuiMessage *imsg = NULL;
 struct WBArg *argptr = NULL;
 ULONG IconID = 1, UserData = 0;
 BOOL ABORT = FALSE;
 UBYTE i;
 char bstr[25];                /* Strings für die Ausgabe der Ergebnisse */
 char dstr[25];
 char vstr[25];

 if (argc != 0)
 {
  printf ("Programm bitte von Workbench starten!\n");
  exit (RETURN_WARN);
 }

 OpenAll();
 if (msgport = (struct MsgPort *)CreateMsgPort())
 {
  if (appicon = (struct AppIcon *)AddAppIcon (IconID, UserData,
                "!BITTE bewerfen!", msgport, NULL, &Icon, NULL))
  {
    do
    {
     Wait (1 << msgport->mp_SigBit);
     while (appmsg = (struct AppMessage *)GetMsg (msgport))
     {
      if (!appmsg->am_NumArgs)
      {
       ABORT = TRUE;
       ReplyMsg ((struct Message *)appmsg);
      }
      else
      {
       ABORT = FALSE;
       OpenDisplay();
       Print (*win->RPort, 5, 2*line, "Moment, Scannphase ...");
       argptr = appmsg->am_ArgList;
       for( i=0; i < appmsg->am_NumArgs; i++ )
       {
        NameFromLock (argptr->wa_Lock, ScanDir, PATHLENGTH);
        Scannen (ScanDir);
        argptr++;
       }

       NameFromLock (appmsg->am_ArgList->wa_Lock, ScanDir, PATHLENGTH);
       Print (*win->RPort, 5, 3*line, ScanDir);

       sprintf (bstr, "Bytes: %15ld", Bytes);
       sprintf (dstr, "Dateien: %13ld", FileAnz);
       sprintf (vstr, "Verzeichnisse: %7ld", DirAnz);

       Print (*win->RPort, 5, 4*line, bstr);
       Print (*win->RPort, 5, 5*line, dstr);
       Print (*win->RPort, 5, 6*line, vstr);
       Print (*win->RPort, 5, 7*line, "Bitte CLOSE Gadget betätigen!");

       ReplyMsg ((struct Message *)appmsg);
      } /* kein Doppelklick */
     } /* appmsg = GetMsg(...) */
     appmsg = NULL;
     if (!ABORT)
     {
       Wait (1 << msgport->mp_SigBit | 1 << win->UserPort->mp_SigBit);
       while (appmsg = (struct AppMessage *)GetMsg (msgport))
        ReplyMsg ((struct Message *) appmsg);
       while (imsg = (struct IntuiMessage *)GetMsg (win->UserPort))
        ReplyMsg ((struct Message *) imsg);
       CloseWindow (win);
     }
    } while (FALSE == ABORT); /* AppI-Abfrage */
   RemoveAppIcon (appicon);
  } else fprintf (stderr, "AppSize: Fehler bei AddAppIcon\n");
  DeleteMsgPort (msgport);
 } else fprintf(stderr,"AppSize: Konnte Message-Port nicht einrichten.\n");
 CloseAll ();
} /* main */
