#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#ifndef DEMO
#include "config.h"
#include "global.h"
#include "hardware.h"
#include "commands.h"
#include "proc.h"
#else
#ifdef  __STDC__
#define __ARGS(x)       x
#else
#define __ARGS(x)       ()
#endif
#endif
#ifdef __MSDOS__
#undef MSDOS
#define MSDOS 1
#endif
#ifdef MSDOS
#include <io.h>
#include <alloc.h>
#endif

#define USEXMS 1

#define ENDING ((size_t) -1)

int expired;

struct entries {
#if defined(MSDOS) && defined(USEXMS)
	char name[13];
#else
	char *name;
#endif
	long theindex;
	size_t nextindex;
};

void sortit (char *fname,int entrysize, int searchsize, int strsize,time_t age);

extern char *skipwhite (char *cp);
#if !defined(MSDOS) || !defined(USEXMS)
struct entries *e;
#else
void VMSsortStow (char far *buf, size_t index);
void VMSsortFetch (char far *buf, size_t index);
int VMSsortInit (unsigned long size, unsigned long number);
void VMSsortTerm (void);
#endif
static int count;
static size_t current;
static char name[16];
static int result, same;
static size_t theindex;
static long currentindex;
int sortdups, wassorted;
static size_t sorthead;
static size_t lastindex;

struct entries far *temp;
struct entries far *temp2;


static void search __ARGS((void));
static void insert __ARGS((void));
static void makesortname __ARGS((char *buf, char *origname));


static void
search ()
{
	same = 0;
	lastindex = ENDING;
#if defined(MSDOS) && defined(USEXMS)
	for (theindex = sorthead; theindex != ENDING; theindex = temp->nextindex)		{
		VMSsortFetch((char far *)temp, theindex);
		result = strnicmp (name, temp->name, strlen(name));
#else
	for (theindex = sorthead; theindex != ENDING; theindex = e[theindex].nextindex)		{
		result = strnicmp (name, e[theindex].name, strlen(name));
#endif
		if (!result)	{
			same = 1;
			sortdups++;
			return;
		}
		if (result < 0)
			return;
		lastindex = theindex;
	}
	return;
}


static void
insert ()
{
#if defined(MSDOS) && defined(USEXMS)
	VMSsortFetch((char far *)temp, current);
#else
	temp = &e[current];
#endif
	if (lastindex == ENDING)	{	/* at head of list */
		temp->nextindex = sorthead;
		sorthead = current;
	} else 	{	/* in the midst or tail of file */
#if defined(MSDOS) && defined(USEXMS)
		VMSsortFetch((char far *)temp2, lastindex);
#else
		temp2 = &e[lastindex];
#endif
		if (theindex)		/* in midst of list */
			temp->nextindex = temp2->nextindex;
		temp2->nextindex = current;
#if defined(MSDOS) && defined(USEXMS)
		VMSsortStow((char far *)temp2, lastindex);
#endif
		if (!wassorted && !same && !theindex)
			wassorted = 1;
	}

	strcpy (temp->name, name);
#ifdef DEMO
	if (count)	{
		if (temp->nextindex == ENDING)
			printf ("inserting last record %s\n", temp->name);
		else	{
#if defined(MSDOS) && defined(USEXMS)
			VMSsortFetch((char far *)temp2, temp->nextindex);
#else
			temp2 = &e[e[current].nextindex];
#endif
			printf ("inserting - %s -> %s\n", temp->name, temp2->name);
		}
	} else
		printf ("inserting 1st record %s\n", temp->name);
#endif
	if (!same)
		temp->theindex = currentindex;
	else
		temp->theindex = -1;
#if defined(MSDOS) && defined(USEXMS)
	VMSsortStow((char far *)temp, current);
#endif
	current++;
	count++;
}


static void
makesortname (buf, origname)
char *buf, *origname;
{
char *cp;

	strcpy (buf, origname);
	cp = strchr (buf, '.');
	if (!cp)
		cp = &buf[strlen(buf)];
	strcpy (cp, ".srt");
}


void
sortit (fname, entrysize, searchsize, strsize, date)
char *fname;
int entrysize, searchsize, strsize;
time_t date;
{
char *cp;
unsigned k;
FILE *fp, *out;
char buf[128];
long size0, size;
#if 0
int num;
#endif
time_t now, stamptime;
int newnum = 0;

#ifdef DEMO
	printf ("Filename: '%s', Entrysize=%d, Searchsize=%d\n", fname, entrysize, searchsize);
#endif
	if ((fp = fopen (fname, "rt")) == 0)	{
#ifdef DEMO
		printf ("can't open input file: %s\n", fname);
#endif
		return;
	}
	makesortname (buf, fname);
	if ((out = fopen (buf, "wt")) == 0)	{
#ifdef DEMO
		printf ("can't open output file: %s\n", buf);
#endif
		fclose (fp);
		return;
	}
	size0 = filelength(fileno(fp));
	size = size0 / (long) entrysize;
	size += 1;
#ifdef DEMO
	printf ("File length = %ld\n", size0);
	printf ("%ld Entries found - Allocating structure...\n", size - 1);
#else
	log(-1,"Sort '%s' - %ld Entries originally", fname, size - 1);
#endif
#if defined(MSDOS) && defined(USEXMS)
#ifdef DEMO
	printf ("Using VMS storage....\n");
#endif
	current = VMSsortInit ((unsigned long) sizeof(struct entries), (unsigned long)size);
#ifdef DEMO
	printf ("VMS initialization: %s\n", (current) ? "succeeded" : "failed");
#endif
	if (!current)
		return;
	temp = farmalloc (sizeof(struct entries));
	temp2 = farmalloc (sizeof(struct entries));
	memset (temp->name, 0, 13);
	temp->theindex = -1;
	temp->nextindex = ENDING;
	for (current = 0; current < size; current++)	{
		VMSsortStow ((char far *)temp, (size_t)current);
		pwait (NULL);
	}
	for (current = 0; current < size; current++)	{
		VMSsortFetch ((char far *)temp, (size_t)current);
		pwait (NULL);
		if (temp->name[0] != 0 || temp->theindex != -1)
			printf ("Error clearing entry #%d\n", current);
	}
#else
#ifdef DEMO
	printf ("Using Conventional memory storage....\n");
#endif
	e = (struct entries *) malloc ((unsigned)(size * sizeof(struct entries)));
	for (current = 0; current < size; current++)	{
		e[current].name = (char *)malloc ((unsigned)(searchsize + 1));
		e[current].name[0] = 0;
		e[current].nextindex = ENDING;
		e[current].theindex = -1;
		pwait (NULL);
	}
#endif
	sorthead = ENDING;
	current = count = 0;
	expired = sortdups = wassorted = 0;
	now = time(&now);
	while (!feof (fp))	{
		pwait (NULL);
		currentindex = ftell(fp);
		if (current == size)
			break;
		fgets (buf, entrysize, fp);
#ifdef DEMO
		printf ("Reading Entry %d/%d - ", current, count);
#endif
		if (feof (fp))	{
#ifdef DEMO
			putchar ('\n');
#endif
			continue;
		}
		pwait (NULL);
		if (*buf > ' ' && (strlen(buf) > (entrysize - 2)) && (*buf != '#'))	{
			strncpy (name, buf, (unsigned)searchsize);
			name[searchsize] = 0;
			if ((cp = strpbrk (name, ".@ \t")) != 0)
				*cp = 0;
			search();
			pwait (NULL);
			insert ();
			pwait (NULL);
		} else	{	/* skip it! */
#ifdef DEMO
			putchar ('\n');
#endif
			current++;
			count++;
			continue;
		}
		/* now check for expired date stamp, if used */
		if (date)	{
			cp = strchr (buf, ' ');
			cp = skipwhite (cp);
			stamptime = atol(cp);
			if ((stamptime == 0) || (now - stamptime >= date))	{
#ifdef DEMO
				printf ("Expiring: now=%ld, age=%ld, stamptime=%ld\n", now, date, stamptime);
#endif
				expired++;
#if defined(MSDOS) && defined(USEXMS)
				VMSsortFetch((char far *)temp, current);
				temp->theindex = -2;
				VMSsortStow((char far *)temp, current);
#else
				e[current].theindex = -2;
#endif
			}
		}
	}
#ifdef DEMO
	putchar ('\n');
#endif
	fflush (stdout);
	if (expired || wassorted || sortdups)		{
		for (theindex = sorthead,k=0; k < count && theindex != ENDING; k++,theindex = temp->nextindex)	{
#if defined(MSDOS) && defined(USEXMS)
			VMSsortFetch((char far *)temp, theindex);
#else
			temp = &e[theindex];
#endif
			if (temp->theindex >= 0)	{
#ifdef DEMO
				printf ("Outputing record %d/%d\n", k, count);
#endif
				pwait (NULL);
				fseek (fp, (long) temp->theindex, 0);
				fgets (buf, entrysize, fp);

				if (strsize)	{
					/* we now re-format it, just in case it is bad */
					if ((cp = strpbrk (buf, " \t")) != 0)
						*cp++ = 0;
					cp = skipwhite (cp);
					stamptime = atol(cp);
					buf[strsize] = 0;	/* just in case */
					cp = buf;
					while (*cp)	{
						if (*cp & 0x80)	{
							*cp = 0;
							break;
						}
						cp++;
					}
					if (stamptime && *buf)
				                fprintf(out,"%-*s %-14ld\n",strsize,buf,stamptime);
			        } else
					fputs (buf, out);
				newnum++;
			}
#ifdef DEMO
			else 	{
				if (temp->theindex == -2)
					printf ("Expiring record %d/%d\n", k, count);
				else printf ("Skipping record %d/%d\n", k, count);
			}
#endif
			
		}
	}
#ifndef DEMO
	log(-1,"Sort '%s' - %d Entries at end", fname, newnum);
#else
	printf ("Sort '%s' - %d Entries at end\n", fname, newnum);
#endif	
	fclose (fp);
	fclose (out);
#if defined(MSDOS) && defined(USEXMS)
	VMSsortTerm();
	farfree(temp);
	farfree(temp2);
#else
	for (current = 0; current < size; current++)
		free(e[current].name);
	free (e);
#endif
	makesortname (buf, fname);
	if (expired || wassorted || sortdups)	{
		remove (fname);
		rename (buf, fname);
	} else
		remove (buf);
}



#ifdef DEMO
#define ENTRYSIZE 49

int
pwait (i)
int i;
{
	return i;
}


char *
skipwhite (cp)
char *cp;
{
	while (*cp && (*cp == ' ' || *cp == '\t'))
		cp++;
	return (cp);
}


void
main (argc, argv)
int argc;
char *argv[];
{
unsigned long begincore;

	begincore = coreleft();
	if (argc == 1)
		sortit ("c:/nos/spool/wpagebbs", ENTRYSIZE, 6, 32, (time_t)0);
	else
		sortit (argv[1], atoi (argv[2]), atoi(argv[3]), atoi(argv[2]) - 17, (time_t) 0);
	printf ("\nBeginning coreleft was %ld - Now is %ld\n", begincore, (long) coreleft());
	if (!wassorted && !sortdups)
		printf ("File was already sorted with no duplicates...\nNo further action needed\n");
	else if (sortdups)
		printf ("%d duplicates removed\n", sortdups);
}
#endif
