/*
 * SORT.C
 *
 * This module contains the sorting routines that read sorting order from
 * the command line, and sort the file database according to that order.
 *
 */

#ifndef LATTICE_50
#include "system.h"
#endif

#include "bbsindex.h"


/*
 *		Arrays used to determine sorting order for SORT.
 */

int i_order[MAXINDEX+1];
int i_ascend[MAXINDEX+1];


/*
 *		sortcmp()
 *		---------
 *		This function is called by qsort. It compares the two specified
 *		elements, and returns -ve, 0 or +ve to indicate whether the second
 *		record is greater than, equal or less than the first, using the
 *		sorting criteria defined in SORT.
 */

/*
 *		DOCMP is a macro which sets cmp equal to the value of the enclosed
 *		expression if i_ascend[i] is true, or the negative of the expression
 *		if i_ascend is false.
 */
#define DOCMP(x)	(cmp = (i_ascend[i] ? (x) : -(x)))
int sortcmp(ptr1,ptr2)
UDHEAD **ptr1, **ptr2;
{
	UDHEAD *p1 = *ptr1, *p2 = *ptr2;
	int i, cmp = 0;

	/*
	 *		Note safety exit - last element of i_order is guaranteed == I_ANY
	 */
	for (i = 0; !cmp; i++) {
		switch (i_order[i]) {

			case I_ANY:			return(0);

			case I_ACCESS:		DOCMP(p1->accesses - p2->accesses);
								break;
			case I_BINARY:		DOCMP(p2->bin - p1->bin);
								break;
			case I_COMMENT:		DOCMP(stricmp(p1->desc, p2->desc));
								break;
			case I_DISKNAME:	DOCMP(stricmp(p1->disk_name, p2->disk_name));
								break;
			case I_SECTION:		DOCMP(p1->section - p2->section);
								break;
			case I_ONLINE:		DOCMP(p2->online - p1->online);
								break;
			case I_LOCAL:		DOCMP(p2->local - p1->local);
								break;
			case I_NAME:		DOCMP(strcmp(p1->cat_name, p2->cat_name));
								break;
			case I_OWNER:		DOCMP(strcmp(p1->owner, p2->owner));
								break;
			case I_PATHNAME:	DOCMP(strcmp(dirnames[p1->dirnum],
											 dirnames[p2->dirnum]));
								break;
			case I_DIRECTORY:	DOCMP(p1->dir - p2->dir);
								break;
			case I_DISKDIRNUM:	DOCMP(p1->dirnum - p2->dirnum);
								break;
			case I_VALID:		DOCMP(p2->valid - p1->valid);
								break;
			case I_DATE:		DOCMP(p1->date - p2->date);
								break;
			case I_SIZE:		DOCMP(p1->length - p2->length);
								break;
			case I_KSIZE:		DOCMP(BTOK(p1->length) - BTOK(p2->length));
								break;
		}
	}
	return (cmp);
}


/*
 *		com_sort()
 *		----------
 *		This command sorts the file database into order, according to
 *		the indexes specified. Each index may be optionally followed by
 *		a + or - to indirect sorting direction (ascending or descending).
 *		There must be no space between the direction and the +/-.
 */
void com_sort()
{
	char *index, *p;
	int i, j;
	int ascend;

	CHECKDATABASE();

	sorted = TRUE;
	for (i = 0; i < MAXINDEX && compos < comlen; i++) {
		index = getstring();
		p = index + strlen(index) - 1;

		/*
		 *		Now check to see if sorting direction specified, and adjust
		 *		string if it was. Set 'ascend' to TRUE if ascending,
		 *		else FALSE.
		 */
		ascend = TRUE;
		if (*p == CHAR_ASCEND || *p == CHAR_DESCEND) {
			if (*p == CHAR_DESCEND)
				ascend = FALSE;
			*p = CHAR_NULL;
		}

		/*
		 *		Now match index, and setup appropriate entry in array
		 */

		for (j = 0; j < MAXINDEX && strcmp(index,indexes[j].name); j++)
			;
		if (j == MAXINDEX) {
			scripterror("unknown index ");
			print2(index, "\n");
			Cleanup(10);
		}
		i_order[i]	= indexes[j].tag;
		i_ascend[i]	= ascend;
	}
	if (i == 0) {
		i_order[i] = I_NAME;
		i_ascend[i++] = TRUE;
	}
	i_order[i] = I_ANY;

	/* Finally, do the sort! */
	qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp);
}
