#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>

extern BPTR __asm newopen(register __d1 char *,register __d2 long);
extern BPTR __asm newlock(register __d1 char *,register __d2 long);
void main(int,char **);

extern struct DosLibrary *DOSBase;
extern struct ExecBase   *SysBase;
APTR oldOpen,oldLock;

/* Struktur, um Verwaltungsdaten für Extensionen aufzunehmen */

typedef struct
{
   char extension[80];
   long length;
} VINFO;

VINFO *info;
long anzahl;

void main(int argc,char **argv)
{
   struct IntuiMessage send,*receive;
   struct MsgPort      *port;
   BPTR file;
   char buffer[80];
   int i=0;
   VINFO *inf;

   /* Ist ein Message-Port mit Namen "VPort" vorhanden ? Ja, dann Message
      mit der Klasse 0xffffffff absenden
   */
   
   if (port=FindPort("VPort"))
   {
      send.Class=0xffffffff;
      PutMsg(port,(struct Message*)&send);
      FPuts(Output(),"DOS-Open() u. DOS-Lock() Patch aufgehoben\n");
      return;
   }
   else
   {
      if (argc!=2)
      {
         FPuts(Output(),"FORMAT : vpatch <Parameterdatei>\n");
         return;
      }
      
      /* angegebene Parameterdatei einlesen */
      
      if (file=Open(argv[1],MODE_OLDFILE))
      {
         while (FGets(file,buffer,79))
         {
            
            /* Keine Leerzeile */
            
            if (strcmp(buffer,"\n"))
            {
               /* "realloc()" von Hand ... */
               
               inf=info;
               if (info=AllocVec((i+1)*sizeof(VINFO),MEMF_CLEAR|MEMF_PUBLIC))
               {
                  CopyMem(inf,info,i*sizeof(VINFO));
                  FreeVec(inf);
                  
                  /* ... und dann Daten einkopieren */
                  
                  strcpy((*(info+i)).extension,buffer);
                  (*(info+i)).length=strlen(buffer)-1;
                  (*(info+i)).extension[(*(info+i)).length]='\0';
                  i++;
               }
               else
               {
                  FreeVec(info);
                  FPuts(Output(),"Kein freier Speicher für Extensionsliste\n");
                  Close(file);
                  return;
               }
            }
         }
         anzahl=i;
         
         /* Message-Port einrichten, Vektoren verbiegen und auf spezielle
            Message warten, dann Vektoren wiederherstellen und Programm
            beenden.
         */
         
         if (port=CreateMsgPort())
         {
            port->mp_Node.ln_Name="VPort";
            AddPort(port);
            oldOpen=SetFunction((struct Library*)DOSBase,-30,newopen);
            oldLock=SetFunction((struct Library*)DOSBase,-84,newlock);
            FPuts(Output(),"DOS-Open() u. DOS-Lock() gepatcht\n");
            Close(file);
            do
            {
               receive=(struct IntuiMessage*)WaitPort(port);
            } while (receive->Class!=0xffffffff);
            FreeVec(info);
            RemPort(port);
            DeleteMsgPort(port);
            SetFunction((struct Library*)DOSBase,-30,oldOpen);
            SetFunction((struct Library*)DOSBase,-84,oldLock);
         }
      }
      else if (!file)
         FPuts(Output(),"Parameterdatei nicht vorhanden\n");
   }  
   return;
}

extern BPTR __asm newopen(register __d1 char *name,register __d2 long mode)
{
   char newname[256],hilfe[256],*p;
   BPTR fh;
   short x=0,len,kenn=-1,pos=0,in=0;
   
   /* Zugriff auf globale Daten, Libraryadressen etc. */
   
   geta4();
   strcpy(newname,name);
   strcpy(hilfe,name);
   strcat(hilfe,".vers");
   len=strlen(name);
   
   /* Jetzt Open() wieder auf DOS-Library umstellen */
   
   SetFunction((struct Library*)DOSBase,-30,oldOpen);
   
   /* um welche Extension handelt es sich ? */
   
   for (x=0;x<anzahl && kenn==-1;x++)
   {
      if (!strnicmp(newname+(len-(*(info+x)).length),(*(info+x)).extension,
                    (*(info+x)).length))
      {
         pos=len-(*(info+x)).length;
         kenn=x;
      }
   }
   
   /* Neue Datei => Wenn keine Version angegeben, höchste lesen */
   
   if (mode==MODE_NEWFILE && kenn!=-1)
   {
      if (p=stpchr(newname,'.'))
      {
         /* Versionsnummer vorhanden ? */
         
         if (!(x=atoi(p+1)))
         {
            if (fh=Open(hilfe,MODE_OLDFILE))
            {
               FRead(fh,&x,sizeof(x),1);
               Seek(fh,0,OFFSET_BEGINNING);
            }
            else
            {
               if (!(fh=Open(hilfe,MODE_NEWFILE)))
                  x=1000;
            }
            
            /* wenn Vers.-Nummer <1000 => Zusatzdatei 'updaten' */
            if (x<999)
            {
               in=1;
               x++;
               FWrite(fh,&x,sizeof(x),1);
               Close(fh);
            }
            else
               return((BPTR)0);
         }
      }
   }
   
   /* wie bei MODE_NEWFILE, nur kein update auf Zusatzdatei */
   
   else if (mode==MODE_OLDFILE && kenn!=-1)
   {
      if (p=stpchr(newname,'.'))
      {
         if (!(x=atoi(p+1)))
         {
            if (fh=Open(hilfe,MODE_OLDFILE))
            {
               in=1;
               FRead(fh,&x,sizeof(x),1);
               Close(fh);
             }
         }
      }
   }
   
   /* Neue Dateinamen mit Versionsnamen erstellen */
   if (x && kenn!=-1 && in)
   {
      sprintf(newname+pos,".%03d",x);
      strcpy(newname+pos+4,(*(info+kenn)).extension);
   }
   fh=Open(newname,mode);
   
   /* Datei öffnen, Vektor auf 'newopen' verbiegen, BPTR zurückgeben */
   
   SetFunction((struct Library*)DOSBase,-30,newopen);
   return(fh);
}

extern BPTR __asm newlock(register __d1 char *name,register __d2 long mode)
{
   BPTR lock,fh;
   char newname[256],hilfe[256],vname[256],*p;
   short version;
   
   /* Zugriff auf globale Daten, Libraryadressen etc. */
   
   geta4();
   strcpy(newname,name);
   strcpy(vname,name);
   
   /* Wenn keine Version angegeben, höchste lesen */
   
   if (p=stpchr(newname,'.'))
   {
      /* Versionsnummer vorhanden ? */
      
      if (!(version=atoi(p+1)))
      {
         strcpy(hilfe,p);
         strcat(vname,".vers");
      
         /* originale Open()-Funktion, dann Versuch Zusatzdatei mit
            Versionsnummer zu lesen
         */
      
         SetFunction((struct Library*)DOSBase,-30,oldOpen);
         if (fh=Open(vname,MODE_OLDFILE))
         {
            FRead(fh,&version,sizeof(version),1);
            Close(fh);
            
            /* Versionsnummer in Dateiname einfügen */
            
            sprintf(p,".%03d",version);
            strcat(newname,hilfe);
         }
         SetFunction((struct Library*)DOSBase,-30,newopen);
      }
   }
   
   /* Lock()-Funktion ausführen den Lock ermitteln, den Vektor wieder
      verbiegen und den Lock zurückgeben
   */
   
   SetFunction((struct Library*)DOSBase,-84,oldLock);
   lock=Lock(newname,mode);
   SetFunction((struct Library*)DOSBase,-84,newlock);
   return(lock);
}
