/*
 * 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);
}
