
/*

sumspace - Sum space needed for lDOS comloader process
 2025 by E. C. Masloch

Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.

DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>

uint16_t getwordfromarray(uint8_t* p) {
	uint16_t w;
	w = p[0];
	w += p[1] * 256;
	return w;
}

int main(int argc, char **argv)
{
#define BUFFER_SIZE 32
  FILE* ff;
  static uint8_t buffer[BUFFER_SIZE];
  uint32_t comloadbinsize, comloadersize, largest;
  int ii;
  if (argc < 4) {
    fprintf(stderr,"Usage: sumspace comload.bin comloadersize [filename.exe ...]\n");
    return 255;
  }
  ii = 1;
  ff = fopen(argv[ii], "rb");
  if (!ff) {
    fprintf(stderr,"Error: Failed to open comload.bin file: %s\n", argv[ii]);
    return 2;
  }
  fseek(ff, 0, SEEK_END);
  comloadbinsize = ftell(ff);
  fclose(ff);
  ff = NULL;
  largest = comloadbinsize;
  fprintf(stderr,"Allocation of comload.bin %04"PRIX32"h=%"PRIu32" for executable file: %s\n", comloadbinsize, comloadbinsize, argv[ii]);
  ++ ii;
  comloadersize = strtoul(argv[ii], NULL, 10);
  if (! comloadersize) {
    fprintf(stderr,"Error: Invalid comloader size: %s\n", argv[ii]);
    return 3;
  }
  fprintf(stderr,"Comloader size %04"PRIX32"h=%"PRIu32"\n", comloadersize, comloadersize);
  for (++ii; ii < argc; ++ii) {
    uint32_t filesize;
    uint32_t allocation;
    ff = fopen(argv[ii], "rb");
    if (!ff) {
      fprintf(stderr,"Error: Failed to open executable file: %s\n", argv[ii]);
      return 4;
    }
    if (fread(buffer, 1, BUFFER_SIZE, ff) >= 0x1A) {
      uint16_t sign = getwordfromarray(&buffer[0]);
      if (sign == 0x4D5A || sign == 0x5A4D) {
        uint32_t filepages = getwordfromarray(&buffer[4]);
        uint32_t filebytes = filepages * 512;
        uint32_t maxallocparas = getwordfromarray(&buffer[12]);
        uint32_t minallocparas = getwordfromarray(&buffer[10]);
        uint32_t headersizeparas = getwordfromarray(&buffer[8]);
        uint32_t headersizebytes = headersizeparas * 16;
        uint32_t minallocbytes = minallocparas * 16;
        if (! filepages) {
          fprintf(stderr,"Error: Zero pages in executable file: %s\n", argv[ii]);
          return 5;
        }
        if (! maxallocparas) {
          fprintf(stderr,"Error: Zero max alloc (unsupported) in executable file: %s\n", argv[ii]);
          return 6;
        }
        if (filebytes <= headersizebytes) {
          fprintf(stderr,"Error: Below-or-equal zero size in executable file image: %s\n", argv[ii]);
          return 7;
        }
        allocation = 256 + (filebytes - headersizebytes) + minallocbytes;
        fprintf(stderr,"Allocation %04"PRIX32"h=%"PRIu32" for MZ executable file: %s\n", allocation, allocation, argv[ii]);
        allocation += comloadersize;
        if (allocation > largest) largest = allocation;
        fclose(ff);
        ff = NULL;
        continue;
      }
    }
    fseek(ff, 0, SEEK_END);
    filesize = ftell(ff);
    fclose(ff);
    ff = NULL;
    if (filesize == 0) {
      fprintf(stderr,"Error: Zero file size in executable file: %s\n", argv[ii]);
      return 8;
    }
    if (filesize >= 0xFF00) {
      fprintf(stderr,"Error: Too large file size in flat executable file: %s\n", argv[ii]);
      return 9;
    }
    /* allocation = (filesize + 15) & ~15; */
    allocation = 64 * 1024;
    fprintf(stderr,"Allocation %04"PRIX32"h=%"PRIu32" for flat executable file: %s\n", allocation, allocation, argv[ii]);
    allocation += comloadersize;
    if (allocation > largest) largest = allocation;
  }
  fprintf(stderr, "Largest=%05"PRIX32"h=%"PRIu32"\n", largest, largest);
  printf("%"PRIu32"\n", largest);
  return 0;
}
