/* BlizKick EXTRES allocation API functions - loadresident.

   Written by Harry "Piru" Sintonen, Jan 2000.
   Public Domain.
*/

#include <exec/types.h>
#include <exec/memory.h>

#define __USE_SYSBASE 1

#include <proto/exec.h>
#include <proto/dos.h>

#include "myregargs.h"
#include "bkapi.h"

#define BKMODULE_ID 0x707A4E75

/* protos */
int __saveds main(void);
void makeids(char *, LONG, char *);
LONG installpatches(char **);
LONG __saveds ASM readfunc(REG(d1,BPTR),REG(d2,void *),REG(d3,LONG));


#ifdef __SASC
void __regargs __chkabort(void);
void __regargs _CXBRK(void);

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
#endif

const char *verstring  = "$VER: loadresident 1.0.1 (17.1.00)";

int __saveds main(void) {
  ULONG ver, largest;
  struct RDArgs *rdargs;
  LONG array[2];
  struct Resident *res = NULL;
  ULONG start, len;
  char ids[77];

#ifdef __SASC
  SysBase = *((struct ExecBase **)(4L));
  if ( (DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L))
       == NULL ) return 0;
#endif

  ver = er_init();

  if (ver) {

    /* make sanity check... */
    largest = er_availmem(MEMF_LARGEST);
    if (largest != 0xFFFFFFFF) {

       array[1] = 0;
       if ( (rdargs = ReadArgs("MODULES/M,REBOOT/S",array,NULL)) ) {

         Printf("loadresident 1.0.1 by Harry \"Piru\" Sintonen\n");

         if (array[0]) {
           if (installpatches((char **) array[0])) {
             if (array[1]) {
               Printf("Rebooting in 1 second...\n");
               Delay(50);
               ColdReboot();
             }
           }
         } else {

           start = er_getarea(&len);

           Printf("\nEXTRESBUF at $%08lx - $%08lx\n"
                  "Free: %ld bytes  Largest: %ld bytes\n"
                  "Resident tags:\n\n",
                  start, start + len - 1, er_availmem(0),
                  er_availmem(MEMF_LARGEST));

           er_lock();
           while ( (res = er_nextresident(res)) ) {
             if (res->rt_IdString) {
               makeids(ids, 77, res->rt_IdString);
             } else {
               makeids(ids, 77, res->rt_Name);
             }
             Printf("$%08lx: %s\n", (LONG) res, (LONG) ids);
           }
           er_unlock();

         }

         FreeArgs(rdargs);
       } else {
         PrintFault(IoErr(),NULL);
       }

    } else {

      Printf("BlizKick EXTRES buffer memheader INSANE!!\n");

    }

  } else {

    Printf("BlizKick EXTRES buffer API not found!\nRequires BlizKick 1.20+\n");

  }

#ifdef __SASC
  CloseLibrary( (struct Library *) DOSBase);
#endif
  return 0;
}


void makeids(char *dst, LONG len, char *src) {
  unsigned char *s, *d, c;

  if (--len < 0) return;

  s = (unsigned char *) src;
  d = (unsigned char *) dst;

  while (len && (c = *s++)) {
    if (c>31) { *d++ = c; len--; }
  }
  *d = 0;
}

#define MAXSEGS 64

LONG installpatches(char **patches) {
  BPTR fh, seg, *segsp, segs[MAXSEGS] = {0};
  LONG stack, *pt, r, ret = 1, cnt = 0;
  LONG funcarray[3] = {(LONG) readfunc,
                       (LONG) er_allocmem,
                       (LONG) er_free};

  segsp = segs;

  while ( (cnt<MAXSEGS) && ret && (*patches) ) {

    Printf("Loading resident module %s... ", (LONG) *patches);

    if ( (fh = Open(*patches, MODE_OLDFILE)) ) {

      stack = 4096;
      if ( (seg = InternalLoadSeg(fh, NULL, funcarray, &stack)) ) {

        *segsp++ = seg; cnt++;

        pt = (LONG *) ((ULONG) BADDR(seg) + 4 );

        if (pt[0] == BKMODULE_ID) {

          Printf("failed!\nMust not use BlizKick module here!\n");
          SetIoErr(0);
          ret = 0;

        } else {
          Printf("ok\n");
        }

      } else ret = 0;

      Close(fh);

    } else ret = 0;

    patches++;
  }

  if (cnt >= MAXSEGS) {
    SetIoErr(ERROR_TOO_MANY_ARGS);
    ret = 0;
  }

  if (!ret) {
    PrintFault(IoErr(),NULL);

    for (r = 0; r < MAXSEGS; r++) {
      if (segs[r]) {
        InternalUnLoadSeg(segs[r], er_free);
      }
    }
  }

  return ret;
}


LONG __saveds ASM readfunc(REG(d1,BPTR readhandle),
                           REG(d2,void *buffer),
                           REG(d3,LONG length)) {

  return Read(readhandle, buffer, length);
}

