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

typedef unsigned char u_char;
typedef unsigned short u_short;

typedef struct direntry {
	unsigned char une[12];
#define d_user une[0]
#define d_name une[1]
#define d_ext  une[9]
	u_short d_fext;
	u_char d_fill;
	u_char d_last;
	u_short d_blks[8];
} DIR;

#define UNUSED 0xE5

#define DIROFFSET 0x2000
#define DIRBLKS   16
#define BLKSTART  (DIROFFSET+DIRBLKS*128) 
#define CLSTSIZE  2048

typedef struct fileentry {
	char f_name[30];
	u_short f_fext;
	u_char f_last;
	u_short f_blks[200];
} FENTRY;

void makename(char* name, DIR* dir)
{
	int i;
	char *p = name;
	for (i=0; i<8; i++) {
		if ((&dir->d_name)[i]==' ') break;
		*p++ = (&dir->d_name)[i];
	}
	*p++ = '.';
	for (i=0; i<3; i++) {
		if ((&dir->d_ext)[i]==' ') break;
		*p++ = (&dir->d_ext)[i];
	}
	*p = 0;
}

FENTRY* lookup(char* name, FENTRY* files)
{
	FENTRY* nul=0, *p = files;
	int i;
		
	for (i = 0; i<64; i++) {
		if (p->f_name[0]==0) {
			if (nul==0) nul = p;
		} else {
			if (!strcmp(p->f_name,name)) {
				return p;
			}
		}
		p++;
	}
	if (nul==0) {
		printf("File table full!\n");
		exit(1);
	}
	return nul;
}

int main(int argc,char* argv[])
{
	FILE *in,*out;
	unsigned char cpmbuf[2048];
	int i,k,n,s,ls;
	char name[30];
	FENTRY files[64], *fe;
	DIR* dir;
	
	if (argc != 2) {
		fprintf(stderr,"Usage: %s cpmdisk.bin\n",argv[0]);
		exit(1);
	}
	
	for (i=0; i<64; i++) {
		files[i].f_name[0] = 0;
		files[i].f_fext = 0;
		files[i].f_last = 0;
		memset(files[i].f_blks,0,sizeof(u_short)*200);
	}
	
	in = fopen(argv[1],"rb");
	if (!in) { 
		perror("open file"); 
		exit(1);
	}
	fseek(in,DIROFFSET,0);
	for (i=0; i<DIRBLKS; i++) {
		fread(cpmbuf,sizeof(DIR),4,in);
		for (k=0; k<4; k++) {
			dir = (DIR*)(cpmbuf+k*sizeof(DIR));
			if (dir->d_user == UNUSED) continue;
			makename(name,dir);
			fe = lookup(name,files);
			strcpy(fe->f_name,name);
			if (dir->d_fext >= fe->f_fext) {
				fe->f_fext = dir->d_fext;
				fe->f_last = dir->d_last;
			}
			for (n=0; n<8; n++) {
				fe->f_blks[dir->d_fext*8+n] = dir->d_blks[n];
			}
		}
	}
	
	for (i=0; i<64; i++) {
		if (!files[i].f_name[0]) continue;
		printf("File %s: (last=%d)\n",files[i].f_name,files[i].f_last%16);
		FILE* out = fopen(files[i].f_name,"wb");



		for (k=0; k<199; k++) {
			n = files[i].f_blks[k];
			if (n==0) break;
			fseek(in,BLKSTART+CLSTSIZE*(n-1),0);
			fread(cpmbuf,1,2048,in);
			ls = files[i].f_last % 16;
			if (!ls) ls = 16;
			s = files[i].f_blks[k+1]==0 ? ls*128 : CLSTSIZE;
			fwrite(cpmbuf,1,s,out);
			printf("%d ",files[i].f_blks[k]);
		}
		printf("\n");
		fclose(out);
	}
	exit(0);
}
