/* 
   Copyright 2002-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include <stdio.h>
#include <string.h>
#include "cmdline.h"
#include "umem.h"
#include "module.h"
#include "lib.h"
#include "libm.h"
#include "errors.h"
#include "dict.h"

extern HASHREC **publichash;
extern long liboffset;
extern int procrevision;
extern BOOL prm_case_sensitive;
extern LIST *objlist;			/* List of object files */
extern LIST *attriblist;
extern MODULE *modules;

extern long dictofs, dictpages, pagesize;

int straccmp(char *one, char *two)
{
	while (*one) {
		if (toupper(*one) != toupper(*two))
			return 1;
		one++;
		two++;
	}
	if (*two)
		return 1;
	return 0;
	
}
void ReadLib(int maxmode,char *libname)
{
	FILE *lib;
	BYTE buf[512];
	liboffset = 0;
	if (!(lib = fopen(libname,"rb"))) {
		if (maxmode & (MD_EXTRACT))
			fatal("Missing library file %s", libname);
		if (maxmode & MD_DELETE && !(maxmode & MD_INSERT))
			fatal("Missing library file %s", libname);
	}
	else {
		uint command;
		long pv;
		int i;
		int done=FALSE;
		long ofs, pages, pagesize;
		char mode;
		fread(buf,1,10,lib);
		if (buf[0] != 0xf0)
			fatal("Not a library %s", libname);
		pagesize = *(short *)(buf+1)+3;
		ofs = *(long *)(buf+3);
    pages = *(short *) (buf+7);
    mode = *(buf+9);
		if (!(mode & 1)) {
			if (prm_case_sensitive)
				Error("Library not case sensitive");
			prm_case_sensitive = FALSE;
		}
		for (i=0; i < pagesize/512-1; i++)
			fread(buf,1,512,lib);
		fread(buf,1,pagesize-10,lib);

		liboffset = pagesize;
		while (!feof(lib) && !done) {
			long t;
			done = ReadModule(lib,libname);
			t = liboffset % pagesize;
			t = t ? pagesize - t : 0;
         liboffset+=t;
			while (t--)
				fgetc(lib);
		}
		if (!done)
			fatal("Missing module end record in library %s",libname);
		if (maxmode & (MD_INSERT | MD_DELETE)) {
			long zero = 0;
			char buffer[100];
			FILE *bakfile;
			char iobuf[512];
			fsetpos(lib,&zero);
			strcpy(buffer, libname);
			StripExt(buffer);
			AddExt(buffer,".bak");
			if (!(bakfile = fopen(buffer,"wb")))
				fatal("Could not open backup file");
			while (!feof(lib)) {
				int size = fread(iobuf,1,512,lib);
				fwrite(iobuf,1,size,bakfile);
			}
			fclose(bakfile);
		}
		fclose(lib);
	}
}
void Extract(int maxmode, char *libname)
{
	LIST *o = objlist, *a = attriblist;
	while (o) {
		int attrib = (int) a->data;
		if (attrib & MD_EXTRACT) {
			char buf[100];
			MODULE *m = modules;
			strcpy(buf,o->data);
			StripExt(buf);
			while(m) {
				if (!straccmp(buf,m->modname))
					break;
				m = m->link;
			}
			if (!m)
				Error("Module %s does not exist in library",buf);
			else {
				FILE *out;
				long size = m->len;
				AddExt(buf, ".obj");
				if (!(out = fopen(buf,"wb")))
					fatal("Can't open %s for write", buf);
				fwrite(m->data,1,size,out);
				fclose(out);
			}
		}
		o = o->link;
	}
}
void Insert(int maxmode, char *libname)
{
	LIST *o = objlist, *a = attriblist;
	while (o) {
		int attrib = (int )a->data;
		if (attrib & MD_INSERT) {
			char buf[100];
			MODULE *m = modules;
			strcpy(buf,o->data);
			StripExt(buf);
			while(m) {
				if (!straccmp(buf,m->modname))
					break;
				m = m->link;
			}
			if (m)
				Error("Module %s exists in library",buf);
			else {
				FILE *f = fopen(o->data, "rb");
				if (!f)
					Error("Can't open input module %s",o->data);
				else {
               if (stristr(o->data,".DEF"))
						CreateImports(f,o->data);
               else if (stristr(o->data,".DLL"))
                  LoadDLL(f,o->data) ;
               else if (stristr(o->data,".OBJ"))
						ReadModule(f,o->data);
					else
                  ReadLib(MD_INSERT,o->data);
					fclose(f);
				}
			}
		}
		o = o->link;
	}
}
void Delete(int maxmode, char *libname)
{
	LIST *o = objlist, *a = attriblist;
	while (o) {
		int attrib = (int) a->data;
		if (attrib & MD_DELETE) {
			char buf[100];
			MODULE *m = modules, **r = &modules;
			strcpy(buf,o->data);
			StripExt(buf);
			while(m) {
				if (!straccmp(buf,m->modname))
					break;
				r = &m->link;
				m = m->link;
			}
			if (!m) {
				if (!(maxmode & MD_INSERT))
					Error("Module %s does not exist in library",buf);
			}
			else {
				int i;
				for (i=0; i < HASH_TABLE_SIZE; i++) {
					HASHREC **p = &publichash[i];
					while (*p) {
						PUBLIC * r = *p;
						if (r->mod == m) {
							*p = r->link;
							DeallocateMemory(r->name);
							DeallocateMemory(r);
						}
						else
							p = &r->link;
					}
				}
				*r = m->link;
				DeallocateMemory(m->name);
				DeallocateMemory(m->data);
				DeallocateMemory(m);
			}
		}
		o = o->link;
	}
}
void OutputLibrary(char *libname)
{
	FILE *lib;
	char buf[10];
	lib = fopen(libname,"wb");
	if (!lib)
		Error("Can't open dictionary %s for write", libname);
	else {
		int i;
		long t;
		MODULE *m = modules;
		long libofs = pagesize;
		buf[0] = 0xf0;
		buf[9] = prm_case_sensitive ? 1 : 0;
		*(short *)(buf+1) = pagesize-3;
		*(long *)(buf+3) = dictofs;
		*(short *)(buf+7) = dictpages;
		fwrite(buf,1,10,lib);
		for (i=10; i < pagesize; i++)
			fputc(0,lib);
		while (m) {
			long size = m->len;
			long t;
			fwrite(m->data,1,size,lib);
			libofs+=size;
			t = libofs % pagesize;
			t = t? pagesize-t : 0;
			while (t--) {
				fputc(0,lib);
				libofs++;
			}
			m = m->link;
		}
		buf[0] = 0xf1;
		buf[1] = (512-3) & 0xff;
		buf[2] = (512-3) >> 8;
		*(short *)(buf+1) = pagesize - 3;
		fwrite(buf,1,3,lib);
		for (i=3; i < pagesize; i++)
			fputc(0,lib);
		libofs +=16;
		t =(libofs & 511);
    t = t ? 512-t : 0;
		for (i=0; i < t; i++)
			fputc(0,lib);
		WriteDictionary(lib);
		fclose(lib);
	}
}