
/*

tellsize - Tell size needed for DOS executable's process
 2019 by 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 <string.h>
#include <inttypes.h>

const uint8_t jump_1_a[] = { 0x8C, 0xC8, 0x31, 0xDB, 0x05 };
			/*  mov ax, cs \ xor bx, bx \ add ax, imm16 */
const uint8_t jump_1_b[] = { 0x50, 0x53, 0xCB };
			/* push ax \ push bx \ retf */
const uint8_t jump_2[] = { 0xEB };
			/* jmp rel8 */
const uint8_t jump_3[] = { 0xE9 };
			/* jmp rel16 */

const uint8_t realloc_1_a[] = { 0xBB };
			/* mov bx, imm16 */
const uint8_t realloc_1_b[] = { 0xB4, 0x4A, 0xCD, 0x21 };
			/* mov ah, 4Ah \    int 21h */

int main(int argc, char **argv)
{
#define BUFFER_SIZE 256
  FILE* ff;
  uint8_t buffer[BUFFER_SIZE];
  uint32_t uu, paras = 0;
  int32_t cs = -16, ip = 256 + 64;
  int ii;
  if (argc != 2) {
usage:
    fprintf(stderr,"Usage: tellsize [filename.big|filename.com]\n");
    printf("0\n");
    return 255;
  }
  ff = fopen(argv[1], "rb");
  if (!ff) {
    fprintf(stderr,"Failed to open file: %s\n", argv[1]);
    printf("0\n");
    return 2;
  }
  for (;;) {
    fseek(ff, cs * 16 + ip, SEEK_SET);
    for (ii = 0; ii < BUFFER_SIZE; ++ii) {
      buffer[ii] = 0;
    }
    fread(buffer, 1, BUFFER_SIZE, ff);
    if (!memcmp(buffer, jump_1_a, sizeof(jump_1_a))) {
      if (!memcmp(buffer + sizeof(jump_1_a) + 2, jump_1_b, sizeof(jump_1_b))) {
        uu = buffer[sizeof(jump_1_a)] | (buffer[sizeof(jump_1_a) + 1] << 8);
        ip = 0;
        cs += uu;
        continue;
      } else {
        break;
      }
    } else if (!memcmp(buffer, jump_2, sizeof(jump_2))) {
      uu = buffer[sizeof(jump_2)];
      ip += sizeof(jump_2) + 1 + uu;
      continue;
    } else if (!memcmp(buffer, jump_3, sizeof(jump_3))) {
      uu = buffer[sizeof(jump_3)] | (buffer[sizeof(jump_3) + 1] << 8);
      ip += sizeof(jump_3) + 2 + uu;
      continue;
    } else {
      break;
    }
  }
  for (ii = 0;
        ii <= (BUFFER_SIZE - (sizeof(realloc_1_a) + 2 + sizeof(realloc_1_b)));
        ++ii) {
    if (!memcmp(buffer + ii, realloc_1_a, sizeof(realloc_1_a))
        && !memcmp(buffer + ii + sizeof(realloc_1_a) + 2,
                    realloc_1_b, sizeof(realloc_1_b))) {
      uu = buffer[ii + sizeof(realloc_1_a)]
            | (buffer[ii + sizeof(realloc_1_a) + 1] << 8);
      paras = uu;
      break;
    }
  }
  if (!paras) {
    fprintf(stderr,"Reallocation call not found!\n");
    printf("0\n");
    return 1;
  }
  fprintf(stderr,"paras needed\t\t= %04"PRIX32"h = %"PRIu32" paragraphs (%"PRIu32" bytes)\n",
          paras, paras, paras * 16);
  paras -= 16;
  fprintf(stderr," less PSP size\t\t= %04"PRIX32"h = %"PRIu32" paragraphs (%"PRIu32" bytes)\n",
          paras, paras, paras * 16);
  printf("%"PRIu32"\n", paras);
  return 0;
}
