/* :ts=3
** PicSize - determines picture size, depth and format
**
** written & © Ralph Reuchlein <amiga@rripley.de> 1999
*/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include <exec/types.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/datatypes.h>
#include <proto/iffparse.h>
#include <datatypes/pictureclass.h>
#include <exec/memory.h>

const UBYTE ver_string[] = "$VER: Picsize 1.2 (26.12.99)Copyright © 1999 by Ralph Reuchlein";


/* ReadArgs defines ----------------------------------------------- */
#define ARGS_TEMPLATE   "FILE/A,"\
                        "FORMAT=FMT,"\
                        "INTRODUCER=INTR/K"

enum {
   OPT_FILE = 0,
   OPT_FMT,
   OPT_INTR,

   OPT_COUNT
};
LONG args[OPT_COUNT];

#define ARG_FILE  ((STRPTR)args[OPT_FILE])
#define ARG_FMT   ((STRPTR)args[OPT_FMT])
#define ARG_INTR  ((STRPTR)args[OPT_INTR])

#define DEFAULT_FORMAT        "%f: %wx%hx%d [%t,%s bytes]"
#define DEFAULT_INTRODUCER    '%'


/* Prototypes ----------------------------------------------------- */
void     error(STRPTR,...);
STRPTR   dupstr(STRPTR);
void     freestr(STRPTR);
BPTR     testFile(STRPTR);
void     printFmt(STRPTR,struct BitMapHeader *,struct DataType *,BPTR);



/* Global variables ----------------------------------------------- */

BOOL  fileOk=FALSE;
ULONG fileSize=0;
#define FILENAMESIZE 512
UBYTE fileName[FILENAMESIZE];
int   errReturnValue=0;


/* ---------------------------------------------------------------- */
int main(UWORD argc,STRPTR argv[]) {
   struct RDArgs *rdargs;
   Object        *picobj;
   BPTR           fl;

   /* process arguments */
   if (rdargs=ReadArgs(ARGS_TEMPLATE,args,NULL)) {
      /* test if we really have a file */
      if (fl=testFile(ARG_FILE)) {
         /* we now create new DataType object ... */
         if (picobj=NewDTObject(ARG_FILE,TAG_DONE))
         {
            /* get all information we need */
            struct BitMapHeader *bmhdr;
            struct DataType     *dt;
            ULONG                id;
            GetDTAttrs(picobj,DTA_DataType,&dt,TAG_DONE);
            id = dt->dtn_Header->dth_GroupID;
            /* ... which must be a still picture */
            if (id == GID_PICTURE) {
               SetDTAttrs(picobj,NULL,NULL,PDTA_FreeSourceBitMap,TRUE,TAG_DONE);
               GetDTAttrs(picobj,PDTA_BitMapHeader,&bmhdr,TAG_DONE);

               /* make formatted output */
               if (ARG_FMT) {
                  printFmt(ARG_FMT,bmhdr,dt,fl);
               }
               else {
                  STRPTR fmt=dupstr(DEFAULT_FORMAT);
                  printFmt(fmt,bmhdr,dt,fl);
                  freestr(fmt);
               }
            }
            else {
               error("%s: File is not of type '%s' (but is '%s')!\n",ARG_FILE,GetDTString(GID_PICTURE),GetDTString(id));
            }
            /* dipose DataType object */
            DisposeDTObject(picobj);
         }
         else {
            long err=IoErr();
            error("%s: Couldn't create DataType object, Error %i: ",ARG_FILE,err);
            PrintFault(err,"");
            error("\n");
         }
         UnLock(fl);
      }
      FreeArgs(rdargs);
   }
   else {
      error("Usage: %s %s\n",argv[0],ARGS_TEMPLATE);
   }
   return errReturnValue;
}



/* ---------------------------------------------------------------- */
void error(STRPTR fmt,...) {
   va_list args;
   va_start(args,fmt);
   vfprintf(stdout,fmt,args);
   va_end(args);
   errReturnValue=1;
}


STRPTR dupstr(STRPTR src) {
   STRPTR dup=(STRPTR)AllocVec(strlen(src)+1,MEMF_PUBLIC|MEMF_REVERSE);
   if (dup) {
      strcpy(dup,src);
      return dup;
   }
   error("Couldn't allocate %u bytes memory for dupstr()\n",strlen(src)+1);
   return NULL;
}

void freestr(STRPTR dup) {
   if (dup) FreeVec(dup);
}


/* ---------------------------------------------------------------- */
BPTR testFile(STRPTR filename) {
   BOOL ok=FALSE;
   BPTR l=NULL;
   struct FileInfoBlock *fib=AllocDosObject(DOS_FIB,NULL);
   if (fib) {
      /* lock the file */
      if (l=Lock(filename,ACCESS_READ)) {
         /* examine file */
         if (Examine(l,fib)) {
            /* test for file */
            switch(fib->fib_DirEntryType) {
               case ST_SOFTLINK:       /* dangerous, because SOFTLINK can point to a directory */
               case ST_LINKFILE:
               case ST_FILE:
                  fileOk   = TRUE;                    /* stored global */
                  fileSize = (ULONG)fib->fib_Size;    /* stored global */
                  ok=TRUE;
                  break;
               default:
                  break;
            }
         }
         else {
            error("%s: Couldn't examine file information!\n",filename);
         }
      }
      else {
         error("%s: Couldn't access to this file (maybe not found?)!\n",filename);
      }
      FreeDosObject(DOS_FIB,fib);
   }
   else {
      error("%s: Couldn't allocate FileInfoBlock memory!\n",filename);
   }
   if (ok) {
      /* we return the file lock if ok */
      return l;
   }
   else {
      if (l) UnLock(l);
   }
   return NULL;
}



/* ---------------------------------------------------------------- */
#define FMT_STRING      's'
#define FMT_INTEGER     'i'

void printFmt(STRPTR fmt,struct BitMapHeader *bmhd,struct DataType *dt,BPTR lock) {
   register int tmp0,tmp1,intr;
   STRPTR   fmt_end = fmt + strlen(fmt),tmp_fmt,str2;

   /* if there is no format, return */
   if (!fmt) return;

   /* determine full filename */
   if (!NameFromLock(lock,fileName,FILENAMESIZE)) {
      error("Couldn't examine full filename!\n");
      return;
   }

   /* do we have specified a special introducer? */
   if (ARG_INTR) {
      intr = *ARG_INTR;    /* only the first character */
   }
   else {
      intr = DEFAULT_INTRODUCER;
   }

   /* we process the format string: replace the format types by
      C-format types and process the format portion one by one */
   tmp_fmt=fmt;
   while(fmt<fmt_end) {
      tmp_fmt=fmt;
      /* search for the introducer */
      while ((*fmt!=intr) && (fmt<fmt_end)) fmt++; if (fmt>=fmt_end) break;
      /* write string til introducer */
      *fmt=0; fputs(tmp_fmt,stdout); *fmt='%';     /* fprintf() only uses '%'! */
      tmp_fmt=fmt;
      /* search for the terminating format type character */
      while ((!isalpha(*fmt)) && (fmt<fmt_end)) fmt++; if (fmt>=fmt_end) break;
      tmp0 = *fmt; tmp1=*(fmt+1);
      switch (tmp0) {
         case 'n':      /* basename of file */
            *fmt=FMT_STRING; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,FilePart(fileName));
            fmt++; *fmt=tmp1;
            break;
         case 'f':      /* full name of file */
            *fmt=FMT_STRING; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,fileName);
            fmt++; *fmt=tmp1;
            break;
         case 'P':      /* path name of file including trailing / and : */
            *fmt=FMT_STRING; *(fmt+1)=0;
            str2=FilePart(fileName); tmp0=*str2; *str2=0;
            fprintf(stdout,tmp_fmt,fileName);
            *str2=tmp0;
            fmt++; *fmt=tmp1;
            break;
         case 'p':      /* path name of file excluding trailing / */
            *fmt=FMT_STRING; *(fmt+1)=0;
            str2=PathPart(fileName); tmp0=*str2; *str2=0;
            fprintf(stdout,tmp_fmt,fileName);
            *str2=tmp0;
            fmt++; *fmt=tmp1;
            break;
         case 'o':      /* basename without suffix of file */
            *fmt=FMT_STRING; *(fmt+1)=0;
            str2=fileName+strlen(fileName);
            while ((*str2!='.') && (str2>fileName)) str2--;
            if (*str2=='.')   { *str2=0; } else { str2=NULL; }
            fprintf(stdout,tmp_fmt,FilePart(fileName));
            if (str2) *str2='.';
            fmt++; *fmt=tmp1;
            break;
         case 'e':      /* suffix/extension of file */
            *fmt=FMT_STRING; *(fmt+1)=0;
            str2=fileName+strlen(fileName);
            while ((*str2!='.') && (str2>fileName)) str2--;
            if (*str2=='.')   fprintf(stdout,tmp_fmt,str2);
            fmt++; *fmt=tmp1;
            break;
         case 'w':      /* width of image */
            *fmt=FMT_INTEGER; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,bmhd->bmh_Width);
            fmt++; *fmt=tmp1;
            break;
         case 'h':      /* height of image */
            *fmt=FMT_INTEGER; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,bmhd->bmh_Height);
            fmt++; *fmt=tmp1;
            break;
         case 'd':      /* depth of image */
            *fmt=FMT_INTEGER; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,bmhd->bmh_Depth);
            fmt++; *fmt=tmp1;
            break;
         case 't':      /* image format/type */
            *fmt=FMT_STRING; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,dt->dtn_Header->dth_Name);
            fmt++; *fmt=tmp1;
            break;
         case 's':      /* image file size */
            *fmt=FMT_INTEGER; *(fmt+1)=0;
            fprintf(stdout,tmp_fmt,fileSize);
            fmt++; *fmt=tmp1;
            break;
         default:
            *(fmt+1)=0;
            fputs(tmp_fmt,stdout);
            fmt++; *fmt=tmp1;
      }
      tmp_fmt=fmt;
   }
   if (tmp_fmt<fmt) {
      fputs(tmp_fmt,stdout);
   }
   fputc('\n',stdout);
}


