#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <dir.h>
#include "zuncom/common.h"
int readline(char *path, size_t size, FILE* fl) {
	char *pathp;
	if(!fgets(path, size, fl)) return 1;
	if(*path) {
		pathp = path+strlen(path)-1;
		if(*pathp == '\n') *pathp = '\0';
	}
	return 0;
}
#define MAX_COUNT 32
#define DATA_SIZE (2+MAX_COUNT*10+2+3)
static const char moveup[] = {
	0xF3, 0xA4,       /* REP MOVSB    */
	0x58,             /* POP AX       */
	0xB8, 0x00, 0x01, /* MOV AX, 100h */
	0x50,             /* PUSH AX      */
	0xC3,             /* RETN         */
};
int main(int argc, char** argv) {
	static char path[MAXPATH+1];
	static char names[8*MAX_COUNT];
	static int entries[MAX_COUNT+1];
	FILE *fl, *fo;
	int count;
	int size, stubsize;
	int pathpos;
	int i,j;
	int errval;

	if(argc != 4) {
		printf("Usage: zungen zun_stub.bin listfile.txt outfile.bin\n");
		return 1;
	}
	fl = fopen(argv[2],"r");
	if(!fl) {
		printf("Error: couldn't open listfile: %s\n", strerror(errno));
		return 2;
	}
	fo = fopen(argv[3],"wb");
	if(!fo) {
		fclose(fl);
		printf("Error: couldn't open outfile: %s\n", strerror(errno));
		return 3;
	}

	/* read proc count */
	if(readline(path, sizeof(path), fl)) {
		errval = 4; goto err;
	}
	count = atoi(path);
	if(count < 0 || count > MAX_COUNT) {
		printf("Error: count is too big!\n");
		errval = 5; goto err;
	}

	/* write stub and proc count */
	append(argv[1], fo);
	fputw(count, fo);

	/* read proc names */
	memset(names, ' ', sizeof(names));
	for(i=0;i<count;i++) {
		if(readline(path, sizeof(path), fl)) {
			errval = 6; goto err;
		}
		for(j=0;j<8;j++) {
			if(path[j] == 0) {
				break;
			}
			names[j+i*8] = path[j];
		}
	}

	/* write proc names */
	if(sizeof(names) != fwrite(names, 1, sizeof(names), fo)) {
		printf("Error: write error\n");
		errval = 7; goto err;
	}

	/* save list file position for later */
	pathpos = ftell(fl);

	/* calc offset of first entry */
	stubsize = size = filesize(argv[1]);
	if(size == -1) {
		errval = 8; goto err;
	}
	size += DATA_SIZE + 0x100;

	/* build entry table */
	memset(entries, 0, sizeof(entries));
	for(i=0;i<count;i++) {
		entries[i] = size;
		if(readline(path, sizeof(path), fl)) {
			errval = 9; goto err;
		}
		j = filesize(path);
		if(j == -1) { errval = 10; goto err; }
		size += j;
	}
	entries[i] = size;

	/* write entry table */
	if(sizeof(entries) != fwrite(entries, 1, sizeof(entries), fo)) {
		printf("Error: write error\n");
		errval = 11; goto err;
	}

	/* write moveup_indirect */
	fputc('\xE8', fo); /* call rel16 */
	fputw(size - (stubsize + DATA_SIZE + 0x100), fo);

	/* append com files */
	fseek(fl, pathpos, SEEK_SET);
	for(i=0;i<count;i++) {
		if(readline(path, sizeof(path), fl)) {
			errval = 12; goto err;
		}
		if(append(path, fo)) {
			errval = 13; goto err;
		}
	}

	/* append moveup */
	if(sizeof(moveup) != fwrite(moveup, 1, sizeof(moveup), fo)) {
		printf("Error: write error\n");
		errval = 14; goto err;
	}

	fclose(fl);
	if(fclose(fo)) {
		printf("Error: unsuccessful close\n");
		return 15;
	}
	return 0;
err:
	fclose(fl);
	fclose(fo);
	return errval;
}