/* Load a MS-Windows program.

   Corey Minyard
   minyard@wf-rch.cirr.com
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <linux/ldt.h>

#include "msw.h"
#include "exe.h"
#include "exedat.h"

BYTE data_block[0x10000];

extern int newldt(int size);
extern int setldt(int descriptor,
		  unsigned int base,
		  unsigned int limit, 
		  unsigned int flags);


void
cleanup_segments(
	struct s_oseg_data *oseg_data,
	int	count)
{
	int	i;

	while (i < count)
	{
		setldt(oseg_data[i].desc, 0, 0, 0);
		free(oseg_data[i].data);
		i++;
	}
}

void
print_sized_name(char *name, int minsize)
{
	char buff[21];
	unsigned int size;
	unsigned int offset;

	size = *((unsigned char *) name);
	offset = 0;
	name++;
	while (size > 20)
	{
		memcpy(buff, name, 20);
		buff[20] = '\0';
		printf("%s", buff);
		name = name + 20;
		minsize = minsize - 20;
		size = size - 20;
	}

	memcpy(buff, name, size);
	buff[size] = '\0';
	minsize = minsize - size;
	printf("%s", buff);

	while (minsize > 0)
	{
		printf(" ");
		minsize--;
	}
}
	

int
seek_n_read(
	int file, 
	void *data,
	int offset,
	int size,
	int exact_size)
{
	int retval;


	if (lseek(file, offset, 0) < 0)
	{
		perror("Unable to seek");
		retval = -1;
	}
	else if (read(file, data, size) != size)
	{
		if ((size < 0) || (exact_size))
		{
			perror("Unable to read");
			retval = -1;
		}
		else
		{
			retval = size;
		}
	}
	else
	{
		retval = size;
	}

	return(retval);
}


int
load_entry_table(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_bundle_data	*bundle;
	struct s_entry_table_movable	*movable;
	struct s_entry_table_fixed	*fixed;
	struct s_entry_table_const	*cond;
	struct s_entry_table	*entry_table;
	struct s_resname_table	*names;
	int	count;
	int	i;
	int	j;
	int	retval;

	
	if (seek_n_read(file, 
			data_block,
			info_block->entry_table_off + header_off,
			info_block->entry_table_length,
			TRUE) < 0)
	{
		printf("%s: could not seek or read\n", filename);
		retval = -1;
	}
	else
	{
		bundle = (struct s_bundle_data *) data_block;
		count = 0;
		while (bundle->num_entries != 0)
		{
			if (bundle->type == 0)
			{
				count = count + bundle->num_entries;
				bundle++;
			}
			else if (bundle->type == MOVABLE_SEG)
			{
				count = count + bundle->num_entries;
				bundle = (struct s_bundle_data *)
					 (  ((char *) bundle) +  
					    sizeof(*bundle)
				          + (  bundle->num_entries 
					     * sizeof(*movable)));
			}
			else if (bundle->type != CONST_ENTRY)
			{
				count = count + bundle->num_entries;
				bundle = (struct s_bundle_data *)
					 (  ((char *) bundle) +  
					    sizeof(*bundle)
				          + (  bundle->num_entries 
					     * sizeof(*fixed)));
			}
			else
			{
				count = count + bundle->num_entries;
				bundle = (struct s_bundle_data *)
					 (  ((char *) bundle) +  
					    sizeof(*bundle)
				          + (  bundle->num_entries 
					     * sizeof(*cond)));
			}
		}
		printf("Found %d entry table entries\n", count);

		entry_table = malloc((count+1) * sizeof(*entry_table));
		bundle = (struct s_bundle_data *) data_block;
		count = 1;
		while ((bundle->num_entries != 0) && (entry_table != NULL))
		{
			if (bundle->type == 0)
			{
				for (i=0; i<bundle->num_entries; i++)
				{
					entry_table[count].type = bundle->type;
					count++;
				}
				bundle++;
			}
			else if (bundle->type == MOVABLE_SEG)
			{
				movable = (struct s_entry_table_movable *) (bundle+1);
				for (i=0; i<bundle->num_entries; i++)
				{
					entry_table[count].type = bundle->type;
					entry_table[count].u.seg.flags = movable->flags;
					entry_table[count].u.seg.int3f = *((WORD *) movable->int3f);
					entry_table[count].u.seg.seg_num = movable->seg_num;
					entry_table[count].u.seg.seg_off = movable->seg_off;
					count++;
					movable++;
				}

				bundle = (struct s_bundle_data *)
					 (  ((char *) bundle) +  
					    sizeof(*bundle)
				          + (  bundle->num_entries 
					     * sizeof(*movable)));
			}
			else if (bundle->type != CONST_ENTRY)
			{
				fixed = (struct s_entry_table_fixed *) (bundle+1);
				for (i=0; i<bundle->num_entries; i++)
				{
					entry_table[count].type = bundle->type;
					entry_table[count].u.seg.flags = fixed->flags;
					entry_table[count].u.seg.seg_off = *((WORD *) fixed->seg_off);
					count++;
					fixed++;
				}

				bundle = (struct s_bundle_data *)
					 (  ((char *) bundle) +  
					    sizeof(*bundle)
				          + (  bundle->num_entries 
					     * sizeof(*fixed)));
			}
			else
			{
				cond = (struct s_entry_table_const *) (bundle+1);
				for (i=0; i<bundle->num_entries; i++)
				{
					entry_table[count].type = bundle->type;
					memcpy(entry_table[count].u.data, cond->data, sizeof(cond->data));
					count++;
					cond++;
				}

				bundle = (struct s_bundle_data *)
					 (  ((char *) bundle) +  
					    sizeof(*bundle)
				          + (  bundle->num_entries 
					     * sizeof(*cond)));
			}
		}

		if (entry_table != NULL)
		{
			printf("Entry Table:\n");
			for (i=1; i<count; i++)
			{
				if (entry_table[i].type != CONST_ENTRY)
				{
					printf("  %3d %2.2x %2.2x %4.4x %2.2x %4.4x",
						i,
						entry_table[i].type,
						entry_table[i].u.seg.flags,
						entry_table[i].u.seg.int3f,
						entry_table[i].u.seg.seg_num,
						entry_table[i].u.seg.seg_off);
				}
				else
				{
					printf("  %3d %2.2x %2.2x %2.2x %2.2x       ",
						i,
						entry_table[i].type,
						entry_table[i].u.data[0],
						entry_table[i].u.data[1],
						entry_table[i].u.data[2]);
				}
				names = exe_data->resnames;
				for (j=0; j<exe_data->num_resnames; j++)
				{
					if (names[j].index == i)
					{
						printf(" (res)");
						print_sized_name(names[j].name, 0);
					}
				}
				names = exe_data->nonresnames;
				for (j=0; j<exe_data->num_nonresnames; j++)
				{
					if (names[j].index == i)
					{
						printf(" (non)");
						print_sized_name(names[j].name, 0);
					}
				}
				printf("\n");
			}
		}

		exe_data->entries = entry_table;
		exe_data->num_entries = count;
		retval = 0;
	}

	return retval;
}


int
load_segments(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_segment_table *segments;
	int	i;
	int	retval;


	segments = malloc(info_block->num_seg_table_entries * sizeof(*segments));
	exe_data->oseg_data = malloc(info_block->num_seg_table_entries * sizeof(*(exe_data->oseg_data)));
	if ((segments == NULL) || (exe_data->oseg_data == NULL))
	{
		fprintf(stderr, "Unable to allocate segment memory\n");
		retval = -1;
	}
	else if (seek_n_read(file, 
			segments,
			info_block->seg_table_off + header_off,
			info_block->num_seg_table_entries * sizeof(*segments),
			TRUE)
	    < 0)
	{
		printf("%s: could not seek or read\n", filename);
		retval = -1;
	}
	else
	{
		printf("Segment table:\n");
		for (i=0; i<info_block->num_seg_table_entries; i++)
		{
			printf("  %d: %4.4x %4.4x %4.4x %4.4x\n",
				i,
				segments[i].seg_start_off,
				segments[i].seg_length,
				segments[i].flags,
				segments[i].min_alloc_size);
		}
		retval = 0;
	}

	exe_data->segments = segments;
	exe_data->num_segments = info_block->num_seg_table_entries;
	return(retval);
}


int
load_resources(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_resource_table *resources;
	struct s_typeinfo	*typeinfo;
	int	size;
	int	shift;
	int	count;
	char	*names;
	int	i;
	int	retval;


	if (info_block->resource_table_off == info_block->res_name_table_off)
	{
		exe_data->resource_names = NULL;
		exe_data->resources = NULL;
		retval = 0;
	}
	else if ((size = seek_n_read(file, 
			data_block,
			info_block->resource_table_off + header_off,
			info_block->mod_ref_table_off - info_block->resource_table_off + 1,
			TRUE)) < 0)
	{
		fprintf(stderr, "Unable to get resource data");
		retval = -1;
	}
	else
	{
		shift = *((WORD *) data_block);

		typeinfo = (struct s_typeinfo *) &(data_block[2]);
		count = 0;
		while (typeinfo->typeid != 0)
		{
			count = count + typeinfo->resourcecount;
			typeinfo = (struct s_typeinfo *)
				(((char *) (typeinfo+1)) 
				+ (sizeof(struct s_nameinfo) 
					* (typeinfo->resourcecount-1)));
		}

		resources = malloc(sizeof(struct s_resource_table) * count);
		typeinfo = (struct s_typeinfo *) &(data_block[2]);
		count = 0;
		while (typeinfo->typeid != 0)
		{
			for (i=0; i<typeinfo->resourcecount; i++)
			{
				resources[count].typeid = typeinfo->typeid;
				resources[count].offset = typeinfo->nameinfo[i].offset;
				resources[count].length = typeinfo->nameinfo[i].length;
				resources[count].flags = typeinfo->nameinfo[i].flags;
				resources[count].flags = typeinfo->nameinfo[i].flags;
				resources[count].id = typeinfo->nameinfo[i].id;
				resources[count].handle = typeinfo->nameinfo[i].handle;
				resources[count].usage = typeinfo->nameinfo[i].usage;
				count++;
			}

			typeinfo = (struct s_typeinfo *)
				(((char *) (typeinfo+1)) 
				+ (sizeof(struct s_nameinfo) 
					* (typeinfo->resourcecount-1)));
		}

		names = ((char *) typeinfo) + sizeof(WORD);
		i = 0;
		while (names[i] != 0)
		{
			i = i + names[i] + 1;
		}
		exe_data->resource_names = malloc(i + 1);
		memcpy(exe_data->resource_names, names, i+1);
		exe_data->resources = resources;
		exe_data->num_resources = count;

		printf("Resource Table:\n");
		for (i=0; i<count; i++)
		{
			printf("  %2.2d %4.4x %4.4x %4.4x %4.4x %4.4x %4.4x ",
				i,
				resources[i].offset,
				resources[i].length,
				resources[i].flags,
				resources[i].id,
				resources[i].handle,
				resources[i].usage);
			if ((resources[i].typeid & 0x8000) == 0)
			{
				print_sized_name(&(names[resources[i].typeid]), 0);
				printf("\n");
			}
			else
			{
				printf("%4.4x\n", resources[i].typeid);
			}
		}
		retval = 0;
	}
	
	return(retval);
}


int
load_resname_table(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_resname_table	*resnames;
	char			*resname_strings;
	int	count;
	int	num;
	int	i;
	int	retval;


	if (seek_n_read(file, 
			data_block,
			info_block->res_name_table_off + header_off,
			info_block->mod_ref_table_off - info_block->res_name_table_off + 1,
			TRUE) < 0)
	{
		fprintf(stderr, "Unable to get resident name data");
		retval = -1;
	}
	else
	{
		count = 0;
		num = 0;
		i = 0;
		while (data_block[i] != 0)
		{
			count = count + *((unsigned char *) &(data_block[i])) + 1;
			i = i + *((unsigned char *) &(data_block[i])) + 3;
			num++;
		}

		resnames = malloc(num * sizeof(struct s_resname_table));
		exe_data->resnames = resnames;
		exe_data->num_resnames = num;
		resname_strings = malloc(count);
		exe_data->resname_strings = resname_strings;

		num = 0;
		i = 0;
		while (data_block[i] != 0)
		{
			resnames[num].name = resname_strings;
			*resname_strings = data_block[i];

			resname_strings++;
			memcpy(resname_strings,
			       &(data_block[i+1]), 
			       *((unsigned char *) &(data_block[i])));
			resname_strings = resname_strings + 
				*((unsigned char *) &(data_block[i]));

			i = i + *((unsigned char *) &(data_block[i])) + 1;
			resnames[num].index = *((WORD *) &(data_block[i]));
			i = i + 2;
			num++;
		}

		printf("Resident Name Table:\n");
		for (i=0; i<num; i++)
		{
			printf("  ");
			print_sized_name(resnames[i].name, 30);
			printf(" %4.4x\n", resnames[i].index);
		}

		retval = 0;
	}

	return(retval);
}


int
load_import_name_table(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	char			*import_strings;
	int	count;
	int	retval;


	count =   info_block->nonres_name_table_off
	        - info_block->imported_name_table_off
	        + 1;
	import_strings = malloc(count);

	if (seek_n_read(file, 
			import_strings,
			info_block->imported_name_table_off + header_off,
			count,
			TRUE) < 0)
	{
		fprintf(stderr, "Unable to get imported name data");
		retval = -1;
	}
	else
	{
		exe_data->import_strings = import_strings;
		retval = 0;
	}

	return(retval);
}


int
load_modref_table(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_modref_table	*modrefs;
	int	retval;
	int	i;


	modrefs = malloc(info_block->num_mod_ref_entries * sizeof(*modrefs));
	if (seek_n_read(file, 
			modrefs,
			info_block->mod_ref_table_off + header_off,
			info_block->num_mod_ref_entries * sizeof(*modrefs),
			TRUE) < 0)
	{
		fprintf(stderr, "Unable to get modref data");
		retval = -1;
	}
	else
	{
		printf("Module References:\n");
		for (i=0; i<info_block->num_mod_ref_entries; i++)
		{
			printf("  %4.4x ", modrefs[i].offset);
			print_sized_name(&(exe_data->import_strings[modrefs[i].offset]), 0);
			printf("\n");
		}

		retval = 0;
	}

	return(retval);
}


int
load_nonresname_table(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_resname_table	*nonresnames;
	char			*nonresname_strings;
	int	count;
	int	num;
	int	i;
	int	retval;


	if (seek_n_read(file, 
			data_block,
			info_block->nonres_name_table_off,
			info_block->num_nonres_name_entries,
			TRUE) < 0)
	{
		fprintf(stderr, "Unable to get resident name data");
		retval = -1;
	}
	else
	{
		count = 0;
		num = 0;
		i = 0;
		while (data_block[i] != 0)
		{
			count = count + *((unsigned char *) &(data_block[i])) + 1;
			i = i + *((unsigned char *) &(data_block[i])) + 3;
			num++;
		}

		nonresnames = malloc(num * sizeof(struct s_resname_table));
		exe_data->nonresnames = nonresnames;
		exe_data->num_nonresnames = num;
		nonresname_strings = malloc(count);
		exe_data->nonresname_strings = nonresname_strings;

		num = 0;
		i = 0;
		while (data_block[i] != 0)
		{
			nonresnames[num].name = nonresname_strings;
			*nonresname_strings = data_block[i];

			nonresname_strings++;
			memcpy(nonresname_strings,
			       &(data_block[i+1]), 
			       *((unsigned char *) &(data_block[i])));
			nonresname_strings = nonresname_strings + 
				*((unsigned char *) &(data_block[i]));

			i = i + *((unsigned char *) &(data_block[i])) + 1;
			nonresnames[num].index = *((WORD *) &(data_block[i]));
			i = i + 2;
			num++;
		}

		printf("Non-Resident Name Table:\n");
		for (i=0; i<num; i++)
		{
			printf("  ");
			print_sized_name(nonresnames[i].name, 30);
			printf(" %4.4x\n", nonresnames[i].index);
		}

		retval = 0;
	}

	return(retval);
}


void
relocate_element(
	struct s_exe_data	*exe_data,
	struct s_reloc_data	*reloc,
	BYTE	*data)
{
	switch(reloc->reloc_type)
	{
	}
}


int
relocate_segment(
	int file,
	struct s_exe_data	*exe_data,
	struct s_segment_table	*segment,
	struct s_oseg_data	*oseg_data,
	unsigned int	start_pos)
{
	BYTE	*segptr;
	struct s_reloc_data *reloc;
	WORD	num_relocs;
	int	i;


	segptr = (BYTE *) oseg_data->data;
	if (seek_n_read(file,
			data_block,
			start_pos,
			65536,
			FALSE) < 0)
	{
		perror("Unable to read segment relocation data");
		return(-1);
	}
	else
	{
		num_relocs = *((WORD *) data_block);
		reloc = (struct s_reloc_data *) (&(data_block[2]));
		for (i=0; i<num_relocs; i++)
		{
			relocate_element(exe_data, reloc, segptr);
			reloc++;
		}
	}

	return(0);
}


int
load_segment_data(
	struct s_exe_data *exe_data,
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	struct s_segment_table	*segments;
	struct s_oseg_data	*oseg_data;
	unsigned int	seg_length;
	unsigned int	ldt_flags;
	int		i;

	segments = exe_data->segments;
        oseg_data = exe_data->oseg_data;
	for (i=0; i<exe_data->num_segments; i++)
	{
		if (segments[i].seg_start_off != 0)
		{
			if (segments[i].seg_length == 0)
				seg_length = 0x10000;
			else
				seg_length = segments[i].seg_length;

			if (segments[i].flags & ST_DATASEG)
			{
				ldt_flags = 0x10 << TYPE_SHIFT;
			}
			else
			{
				ldt_flags = 0x18 << TYPE_SHIFT;
			}
	
			if (segments[i].flags & ST_RESTRICT)
			{
				ldt_flags = ldt_flags | (0x02 << TYPE_SHIFT);
			}
			ldt_flags = ldt_flags | P_MASK;
	
			oseg_data[i].data = malloc(seg_length);
			if (oseg_data[i].data == NULL)
			{
				cleanup_segments(oseg_data, i-1);
				perror("Unable to allocate memory");
				return(-1);
			}
	
			oseg_data[i].desc = setldt(-1,
						   (unsigned int) oseg_data[i].data,
						   seg_length,
						   ldt_flags);
			if (oseg_data[i].desc < 0)
			{
				free(oseg_data[i].data);
				cleanup_segments(oseg_data, i-1);
				perror("Unable to map descriptor");
				return(-1);
			}
	
			if (seek_n_read(file,
				        oseg_data[i].data,
					segments[i].seg_start_off * exe_data->seg_mult,
					seg_length,
					TRUE) < 0)
			{
				cleanup_segments(oseg_data, i);
				perror("Unable to read in segment");
				return(-1);
			}
			else if (segments[i].flags & ST_RELOCATE)
			{
				if (relocate_segment(file,
						     exe_data,
						     &(segments[i]),
						     &(oseg_data[i]),
						     (segments[i].seg_start_off * exe_data->seg_mult) + seg_length)
						 < 0)
				{
					cleanup_segments(oseg_data, i);
					perror("Unable to relocate segment");
					return(-1);
				}
			}
		}
	}

	return(0);
}


int
process_msw_header(
	char	*filename,
	int	file,
	struct s_info_block *info_block,
	int	header_off)
{
	int	retval;
	struct s_entry_table	*entry_table;
	struct s_segment_table	*segments;
	struct s_exe_data	exe_data;


	if (info_block->sig != INFO_SIG)
	{
		fprintf(stderr,
			"%s is not a Windows executable file\n",
			filename);
		retval = -1;
	}
	else
	{
		printf("sig:			%4.4x\n", info_block->sig);
		printf("link_version:		%2.2x\n", info_block->link_version);
		printf("link_revision:		%2.2x\n", info_block->link_revision);
		printf("entry_table_off:	%4.4x\n", info_block->entry_table_off);
		printf("entry_table_length:	%4.4x\n", info_block->entry_table_length);
		printf("reserved1[0]:		%4.4x\n", info_block->reserved1[0]);
		printf("reserved1[1]:		%4.4x\n", info_block->reserved1[1]);
		printf("exe_flags:		%4.4x\n", info_block->exe_flags);
		printf("auto_ds_num:		%4.4x\n", info_block->auto_ds_num);
		printf("init_heap_size:		%4.4x\n", info_block->init_heap_size);
		printf("init_stack_size:	%4.4x\n", info_block->init_stack_size);
		printf("init_ip:		%4.4x\n", info_block->init_ip);
		printf("init_cs_segment:	%4.4x\n", info_block->init_cs_segment);
		printf("init_sp:		%4.4x\n", info_block->init_sp);
		printf("init_ss_segment:	%4.4x\n", info_block->init_ss_segment);
		printf("num_mod_ref_entries:	%4.4x\n", info_block->num_mod_ref_entries);
		printf("num_nonres_name_entries:%4.4x\n", info_block->num_nonres_name_entries);
		printf("seg_table_off:		%4.4x\n", info_block->seg_table_off);
		printf("resource_table_off:	%4.4x\n", info_block->resource_table_off);
		printf("res_name_table_off:	%4.4x\n", info_block->res_name_table_off);
		printf("mod_ref_table_off:	%4.4x\n", info_block->mod_ref_table_off);
		printf("imported_name_table_off:%4.4x\n", info_block->imported_name_table_off);
		printf("nonres_name_table_off:	%8.8x\n", info_block->nonres_name_table_off);
		printf("num_movable_entry_points:%4.4x\n", info_block->num_movable_entry_points);
		printf("log_sector_size_log2:	%4.4x\n", info_block->log_sector_size_log2);
		printf("num_resource_seg:	%4.4x\n", info_block->num_resource_seg);
		printf("target_os:		%2.2x\n", info_block->target_os);
		printf("additional_exe_info:	%2.2x\n", info_block->additional_exe_info);
		printf("fast_load_offset:	%4.4x\n", info_block->fast_load_offset);
		printf("fast_load_size:		%4.4x\n", info_block->fast_load_size);
		printf("reserved2:		%4.4x\n", info_block->reserved2);
		printf("win_version:		%4.4x\n", info_block->win_version);

		exe_data.seg_mult = 1 << info_block->log_sector_size_log2;

		load_resname_table(&exe_data, filename, file, info_block, header_off);
		load_nonresname_table(&exe_data, filename, file, info_block, header_off);
		load_entry_table(&exe_data, filename, file, info_block, header_off);
		load_segments(&exe_data, filename, file, info_block, header_off);
		load_resources(&exe_data, filename, file, info_block, header_off);
		load_import_name_table(&exe_data, filename, file, info_block, header_off);
		load_modref_table(&exe_data, filename, file, info_block, header_off);

		load_segment_data(&exe_data, filename, file, info_block, header_off);

		retval = 0;
	}
}


int
loadfile(char *filename)
{
	int 	file;
	int 	retval;
	struct s_exe_header exe_header;
	struct s_info_block info_block;


	file = open(filename, O_RDONLY);
	if (file < 0)
	{
		retval = file;
	}
	else
	{
		if (read(file, (char *) &exe_header, sizeof(exe_header))
                    != sizeof(exe_header))
		{
			fprintf(stderr,
				"%s: unable to read from file\n",
				filename);
			retval = -1;
		}
		else if (exe_header.sig != EXE_SIG)
		{
			fprintf(stderr,
				"%s is not an executable MS-DOS file\n",
				filename);
			retval = -1;
		}
		else if (exe_header.ident < IDENT_MIN_MSW)
		{
			fprintf(stderr,
				"%s is not a Windows executable file\n",
				filename);
			retval = -1;
		}
		else
		{
			if (lseek(file, exe_header.msw_header_off, 0) < 0)
			{
				fprintf(stderr,
					"%s: unable to seek to MSW header\n",
					filename);
				retval = -1;
			}
			else if (read(file, (char *) &info_block, 
                                      sizeof(info_block)) != sizeof(info_block))
			{
				fprintf(stderr,
					"%s: unable to read header from file\n",
					filename);
				retval = -1;
			}
			else
			{
				retval = process_msw_header(
						filename,
						file, 
						&info_block,
						exe_header.msw_header_off);
			}
		}
	}

	return(retval);
}

int
main(int argc, char *argv[])
{
	if (newldt(100) < 0)
	{
		perror("Unable to create descriptor table");
		exit(1);
	}

	exit(loadfile(argv[1]));
}
