/* ListIFF.c       Compileraufrufe : cc ListIFF.c , ln ListIFF.o -lc */
/* Autor: Thomas Kern 
          Auwaldstr. 95
          7800 Freiburg i. Br. */
          
#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 "stdio.h"
#include "ctype.h"

#define anfleer 0           /* # Leerzeichen bei Rekursionstiefe 0 */
#define tol(c) tolower(c)   /* Abkürzung */
char *nix = "";             /* Leerstring */
char *copyziel;             /* Zieldirectory bei copy */
BOOL rekursiv = FALSE,fren = FALSE,freb = FALSE,print = FALSE,copy = FALSE;
struct ren_files { /* Rename- bzw. Copy-Liste */
       char name_old[256],name_new[256]; /* bei Copy name_new[]=zielname */
       struct ren_files *next;
       } *anfang,*naechster;
FILE *drucker;

main(argc,argv)
int argc;
char *argv[];
{
 void readdir(),rename_them(),fehler(),copy_them();
 FILE *fopen();
 char *malloc(),*kompl();
 int i,all=0,ren=0,reb=0,pr=0,kopie=0; /* Poszeiger für Kommandozeile */
 anfang = (struct ren_files *)malloc(sizeof(struct ren_files));
     /* Anfangszeiger auf Rename-Liste */
 if (anfang == NULL) fehler(1);
 naechster = anfang;
 naechster->next = NULL;
 if (argc>1) {
     if (argv[1][0]=='?') { /* Schön bunten Hilfetext ausgeben */
         printf("\033[1;33mUSAGE:\033[31m ListIFF\033[0m "); 
         printf("[file/S|dir/S] [ALL/S] [PRN] [REN/S|REB/S|CPY dir/K]\n");
         printf("       ListIFF zeigt zusätzliche Informationen zu List an:\n");
         printf("         Filelänge in Bytes und Blocks, Art der (IFF-) Datei\n");
         printf("         Bei ILBM zusätzlich Größe des Bildes und ");
         printf("Anzahl der Bitplanes\n");
         printf("       ALL = alle Subdirectories werden untersucht\n");
         printf("       REN = an ILBM-Files wird die Größe und Zahl der ");
         printf("Bitplanes angehängt\n");
         printf("             (als Extension, z.B.: <filename>.320x200_5)\n");
         printf("       REB = RENAME BACK d.h. Extension wieder entfernen\n");
         printf("       CPY = alle ILBM-Files werden nach dir kopiert\n");
         printf("       PRN = Ausgabe auf Drucker (besser nicht >prt:");
         printf(" benutzen)\n");
         printf("  \033[32mAutor: Thomas Kern\033[31m\n\n");
         exit();
         }
     for (i=1;i<argc;i++) /* Test auf all-Option */
       if((tol(argv[i][0])=='a')&&(tol(argv[i][1])=='l')&&(tol(argv[i][2])=='l'))
             { rekursiv = TRUE; /* Flag setzen */
               all = i; /* Position in Kommandozeile merken */
               break;   /* und Schleife verlassen */
             }
     for (i=1;i<argc;i++) /* Test auf rename-Option */
       if((tol(argv[i][0])=='r')&&(tol(argv[i][1])=='e')&&(tol(argv[i][2])=='n'))
             { fren = TRUE;
               ren = i;
               break; 
             }
     if (!fren)
      for (i=1;i<argc;i++) /* Test auf rename-back Option */
       if((tol(argv[i][0])=='r')&&(tol(argv[i][1])=='e')&&(tol(argv[i][2])=='b'))
             { freb = TRUE;
               reb = i;
               break;
             }
     if (!fren && !freb)
      for (i=1;i<argc;i++) /* Test auf CPY Option */
       if((tol(argv[i][0])=='c')&&(tol(argv[i][1])=='p')&&(tol(argv[i][2])=='y'))
             {
             if (i+1<argc) { /* Zieldirectory angegeben ? */
                     copy = TRUE;
        	     copyziel=kompl(argv[i+1],nix); /* evtl : oder / anhängen */
		     kopie = i;
                     }
             break;
             }
     for (i=1;i<argc;i++) /* Druckerausgabe ? */
       if((tol(argv[i][0])=='p')&&(tol(argv[i][1])=='r')&&(tol(argv[i][2])=='n'))
             { print = TRUE;
               pr = i;
               break; 
             }
     if (print)
        if ((drucker=fopen("prt:","w"))==NULL) {
             printf("Konnte prt: nicht öffnen\n");
             free(anfang);
             exit(5);
             }
     if ((all!=1)&&(ren!=1)&&(reb!=1)&&(pr!=1)&&(kopie!=1)) /* nur nicht aus Versehen */
           readdir(argv[1],anfleer); /* etwa das Dirctory "all" untersuchen */
       else readdir(nix,anfleer); /* nix = "" =current directory */
     }
   else readdir(nix,anfleer);
 if (fren||freb) rename_them(); /* zum Schluß u.U. renamen */
 else if (copy) copy_them();    /* oder Kopieren */
 free(anfang);
 fclose(drucker);
 exit(0);
}

void fehler(code) /* etwas abstruse Fehler-"Behandlung" (s.u.) */
int code; /* war nur zum Debuggen nötig */
{
 printf("ES IST ZU WENIG SPEICHERPLATZ VORHANDEN\n");
 printf("mögliche Abhilfe: mit STACK-Befehl dem aktuellen CLI-Prozess mehr\n");
 printf("Stapelspeicher zuweisen und nochmals probieren.\n");
 exit(10); /* "rauher Abgang" (kommt eh selten vor) */
}

void readdir(directory,leerzeichen) /* liest ein Directory fileweise */
char *directory;         /* und ruft sich u.U. selbst (rekursiv) auf */
int leerzeichen;         /* gibt die Einrückung vom linken Rand an */
{
 struct FileLock *lock,*Lock();
 struct FileInfoBlock *f_info;
 char *kompl(),*malloc();
 char *newdir,zusatzinfo[20],*newfile;
 void fausgabe(),dausgabe(),untersuche(),rename_them();
 if ((lock = (struct FileLock *) malloc(sizeof(struct FileLock))) == NULL)
	fehler(2);
 if ((f_info = (struct FileInfoBlock *) malloc(sizeof(struct FileInfoBlock))) == NULL) {
	fehler(3);
	}
 if ((lock = Lock(directory,ACCESS_READ)) == NULL) {
	exit(4);
	}
 if ((Examine(lock,f_info)) == NULL) { /* FileInfoBlock holen */
	UnLock(lock);
	exit(5);
	}
 if (f_info->fib_DirEntryType < 0) { /* "directory" ist gar keines!*/
	     untersuche(directory,zusatzinfo,f_info->fib_FileName);
	     fausgabe(f_info,zusatzinfo,leerzeichen);
 	     }
    else {
     dausgabe(f_info->fib_FileName,leerzeichen);
     while ((ExNext(lock,f_info)) !=0) { /* nächster FileInfoBlock */
       if (f_info->fib_DirEntryType < 0) { /* es ist ein File */
	     newfile = kompl(directory,f_info->fib_FileName);
	     untersuche(newfile,zusatzinfo,f_info->fib_FileName);
	     fausgabe(f_info,zusatzinfo,leerzeichen);
 	     free(newfile);
 	     } /* sonst ist es ein Directory */
	     else if (rekursiv) { /* bei all-Option Rekursion vorbereiten */
 	            newdir = kompl(directory,f_info->fib_FileName);
	            readdir(newdir,leerzeichen+2); /* Rekursion aufrufen */
	            free(newdir);          /* mit zwei Leerzeichen mehr */
                    }
       }
     }
 UnLock(lock); /* wieder freigeben, sonst gehen pro Lock 24 Byte verloren */
}

void fausgabe(info,zusatz,spaces) /* Informationen über File ausgeben */
 struct FileInfoBlock *info;
 char *zusatz;
 int spaces;
{
 int i;
 FILE *ziel;
 if (print) ziel=drucker;
    else ziel=stdout;
 for (i=0;i<spaces;i++) putc(' ',ziel);
 fprintf(ziel,"%-30s ",info->fib_FileName); /* Filename */
 fprintf(ziel,"%6ld ",info->fib_Size);      /* Größe in Bytes */
 fprintf(ziel,"%4ld ",info->fib_NumBlocks); /* und Blocks */
 fprintf(ziel,"%s\n",zusatz);               /* Art der Datei */
 if (info->fib_Comment[0] != '\0') {
    for (i=0;i<spaces;i++) putc(' ',ziel);
    fprintf(ziel,": %-80s\n",info->fib_Comment); /* falls vorhanden Kommentar */
    }
}

void dausgabe(name,spaces) /* Directory ausgeben */
 char *name;
 int spaces;
{
 int i;
 if (print) {
     for (i=0;i<spaces;i++) putc(' ',drucker);
     fprintf(drucker,"\033[1m%s (dir)\033[0m\n",name);
     }
  else { /* bei Druckerausgabe keine Orange-Umschaltung */
     for (i=0;i<spaces;i++) putchar(' ');
     printf("\033[1;33m%s \033[31m(dir)\033[0m\n",name);
     }
}

char *kompl(argument,append) /* Verbindet Directory und Filenamen zu einem */
 char *argument,*append;     /* neuen String und reserviert Speicher */
{
 char *ziel;*malloc();
 ziel = malloc(strlen(argument)+strlen(append)+1);
 if (ziel == NULL) fehler(6);
 strcpy(ziel,argument);
 if (strlen(ziel)>0)
    if (ziel[strlen(ziel)-1]!=':') /* Regeln für Pfadnamen beachten */
       if (ziel[strlen(ziel)-1]!='/')
          strcat(ziel,"/");  /* Falls nicht schon vorhanden, "/" einfügen */
 strcat(ziel,append);
 return ziel;
}

void untersuche(pfad_name,zurück,nur_name) /* Öffnet File und versucht Typ zu bestimmen */
 char *pfad_name,*zurück,*nur_name;
{
 #define maxbuf 60
 FILE *fopen(),*fname;
 char *fgetsneu();
 char hilf[255],buffer[maxbuf],planes;
 int hoehe,breite,i,pos;
 void prep_rename();
 strcpy(zurück,"????");
 if ((fname=fopen(pfad_name,"r"))==NULL) { strcpy(zurück,"Fehler beim Öffnen");
                                      return ;}
 if (fgetsneu(buffer,4,fname)==NULL) { fclose(fname);
                                    return ;}
 if (strncmp(buffer,"FORM",4)==NULL) {
    strcpy(zurück,"FORM");
    if (fgetsneu(buffer,8,fname)==NULL) { fclose(fname);
                                     return; }
    if (strncmp(buffer+4,"ILBM",4)==NULL) {
       strcpy(zurück,"ILBM ");
       fgetsneu(buffer,maxbuf,fname);
       for (pos=0;pos<maxbuf-24;pos++) 
          if (strncmp(buffer+pos,"BMHD",4)==NULL) {
             hoehe = (BYTE)buffer[pos+8]*256+(UBYTE)buffer[pos+9];
             breite = (BYTE)buffer[pos+10]*256+(UBYTE)buffer[pos+11];
             planes = (BYTE)buffer[pos+16];
             sprintf(hilf,"%4dx%4d %1d",hoehe,breite,(int)planes);
             strcat(zurück,hilf);
             if (fren) { /* einen Filenamen zum Renamen bereitstellen */
                strcpy(hilf,pfad_name);
                sprintf(buffer,".%dx%d_%1d",hoehe,breite,(int)planes);
                strcat(hilf,buffer);
                if (strcmp(buffer,pfad_name+strlen(pfad_name)-strlen(buffer))!=NULL) {
                    /* nicht zweimal eine Extension anhängen */
                    prep_rename(pfad_name,hilf);
                    }
                } 
             if (freb) { /* oder auch zurück */
                strcpy(hilf,pfad_name);
                sprintf(buffer,".%dx%d_%1d",hoehe,breite,(int)planes);
                if (strcmp(buffer,pfad_name+strlen(pfad_name)-strlen(buffer))==NULL) {
                   /* nur passende Extensions entfernen */
                   hilf[strlen(hilf)-strlen(buffer)]='\0';
                   prep_rename(pfad_name,hilf);
                   }
		}
             if (copy) { /* Liste von zu kopierenden Files vervollst. */
                strcpy(hilf,copyziel);
		strcat(hilf,nur_name);
                sprintf(buffer,".%dx%d_%1d",hoehe,breite,(int)planes);
                if (strcmp(buffer,pfad_name+strlen(pfad_name)-strlen(buffer))!=NULL) {
                    /* nicht zweimal eine Extension anhängen */
                    strcat(hilf,buffer);
		    }
                prep_rename(pfad_name,hilf);
                }
             fclose(fname);
             return;
             }
       }
    if (strncmp(buffer+4,"SMUS",4)==NULL) { /* jetzt kommen verschiedene */
       strcpy(zurück,"SMUS");
       }
    if (strncmp(buffer+4,"8SVX",4)==NULL) { /* andere IFF-Typen */
       strcpy(zurück,"8SVX");
       }
    if (strncmp(buffer+4,"ANIM",4)==NULL) { /* (Kein Anspruch auf */
       strcpy(zurück,"ANIM");
       }
    if (strncmp(buffer+4,"ACBM",4)==NULL) { /* Vollständigkeit) */
       strcpy(zurück,"ACBM");
       }
    if (strncmp(buffer+4,"FTXT",4)==NULL) {
       strcpy(zurück,"FTXT");
       }           
    fclose(fname);
    return;
    }
 if (buffer[0]==0)      /* Falls ein File mit 0x000003F3 beginnt, ist es */
    if (buffer[1]==0)   /* wahrscheinlich (!) ein ausführbares Programm */
       if (buffer[2]==(char)3)
          if (buffer[3]==(char)0xf3) {
             strcpy(zurück,"EXEC");
             fclose(fname);
             return;
             }
 fclose(fname);
 return; 
}

char *fgetsneu(eing,zahl,name) /* Wie fgets(), nur werden auch 0-Bytes und CR */
 char *eing;               /* etc. in den String eing */
 int zahl;                 /* bis zur Länge zahl übernommen*/
 FILE *name;
{
 int i;
 for (i=0;i<zahl;i++) {
     eing[i]=getc(name);
     if (feof(name)) return NULL;
     }
 eing[zahl]='\0'; /* mit Nullbyte abschließen */
 return eing;
}

void prep_rename(alt,neu) /* neuen Kandidaten an die Rename-Liste */
char *alt,*neu;           /* anhängen */
{
 char *malloc();
 naechster->next = (struct ren_files *)malloc(sizeof(struct ren_files));
 if (naechster->next == NULL) fehler(7);
 naechster = naechster->next;
 strcpy(naechster->name_old,alt);
 strcpy(naechster->name_new,neu);
 naechster->next = NULL;
}

void rename_them() /* Rename durchführen und Speicherplatz freigeben */
{
 struct ren_files *aktuell;
 long IoErr();
 FILE *ziel;
 if (print) ziel=drucker;
    else ziel=stdout;
 aktuell = anfang;
 fprintf(ziel,"Renaming...\n");
 while (aktuell->next != NULL) { /* Schleife zum Renamen */
       aktuell = aktuell->next;
       fprintf(ziel,"%s..",aktuell->name_new);
       if (Rename(aktuell->name_old,aktuell->name_new))
               fprintf(ziel," O.K.!\n");
          else {
               if (IoErr()==ERROR_DISK_WRITE_PROTECTED) {
                  fprintf(ziel," User-Break\n");
                  break;
                  }
                  else fprintf(ziel," FEHLER!\n");
               }
       }
 aktuell = anfang;
 while (aktuell->next != NULL) { /* Schleife zum Freigeben */
       aktuell = aktuell->next;
       free(aktuell);
       }
 naechster = anfang;	
}

void copy_them()
{
 struct ren_files *aktuell;
 long IoErr();
 FILE *ziel;
 if (print) ziel=drucker;
    else ziel=stdout;
 aktuell = anfang;
 fprintf(ziel,"Copying...\n");
 while (aktuell->next != NULL) { /* Schleife zum Kopieren */
       aktuell = aktuell->next;
       fprintf(ziel,"%s..",aktuell->name_old);
       if (kopieren(aktuell->name_old,aktuell->name_new)==0)
               fprintf(ziel," O.K.!\n");
          else {
               if (IoErr()==ERROR_DISK_WRITE_PROTECTED) {
                  fprintf(ziel," User-Break\n");
                  break;
                  }
                  else fprintf(ziel," FEHLER!\n");
               }
       }
 aktuell = anfang;
 while (aktuell->next != NULL) { /* Schleife zum Freigeben */
       aktuell = aktuell->next;
       free(aktuell);
       }
 naechster = anfang;	
}

short kopieren(source,target) /* kopiert */
char *source,*target;
{
FILE *s,*t,*fopen();
char c;
if ((s=fopen(source,"r"))==NULL) return 1;
if ((t=fopen(target,"w"))==NULL) {
	fclose(s);
	return 2;
	}
for(;;) { /* Byteweise kopieren */
	c=getc(s);
	if (ferror(s)) {
		fclose(t);
		fclose(s);
		return 3;
		}
	if (!feof(s)) putc(c,t); /* zum Schluß nichts mehr! */
	else break;
	if (ferror(t)) {
		fclose(t);
		fclose(s);
		DeleteFile(target);
		return 4;
		}
	}
fclose(t);
fclose(s);
return 0;
}
