home *** CD-ROM | disk | FTP | other *** search
- #ifndef NO_IDENT
- static char *Id = "$Id: flsort.c,v 1.11 1995/10/25 13:39:18 tom Exp $";
- #endif
-
- /*
- * Title: flsort.c - "FLIST" sorting
- * Author: T.E.Dickey
- * Created: 04 May 1984
- * Last update:
- * 24 Oct 1995 added USER-sort
- * 18 Mar 1995 prototypes
- * 18 Feb 1995 port to AXP (DATENT mods).
- * 02 Jan 1989 modified to use 'qsort' instead of my selection-
- * sort.
- * 04 Nov 1988 added sort for expired-date.
- * 24 Sep 1985 don't need to upper-case 'xdcl_' stuff
- * 29 Aug 1985 corrected handling of /SWEEK if applied to the
- * backup date.
- * 29 Jul 1985 assume 'filelink' pointer is unique for resetting
- * selection-entry.
- * 03 Jul 1985 cleanup 'filelist' definition.
- * 04 May 1985 renamed from 'dirsrt', made it called from
- * 'dircmd' rather than indirectly via main-code.
- * 22 Mar 1985 added IDENTIFIER, LENGTH
- * 09 Jan 1985 nailed down column-suppression, fixed ordering
- * for TYPE-sort.
- * 29 Dec 1984 added BACKUP, CREATED, REVISED and WEEK
- * 22 Dec 1984 renamed ATTRIBUTE to XAB (for ALLOC).
- * 11 Dec 1984 added FORMAT, ATTRIBUTE sorting, moved HOUR
- * decoding into this module.
- * 13 Sep 1984 corrected permission to sort OWNER
- * 03 Sep 1984 use "import"
- * 27 Aug 1984 corrected no-action exit
- * 15 Aug 1984 separated CREATED,BACKUP,REVISED dates
- * 06 Aug 1984 added sort-by-hour
- * 05 Aug 1984 use VMS-C structure-copy feature.
- * 15 Jul 1984 sort paths via sequence key
- * 14 Jul 1984 added OWNER-sort, enhanced warnings
- * 20 Jun 1984 Do fixed-point sort (uses 'dircmd_select()')
- * 19 Jun 1984 to add "Sorting..." message.
- * 14 May 1984
- *
- * Function: This module performs the directory-sorting operations for
- * the "FLIST" program. The following fields are sortable:
- *
- * P path,name,type,vers
- * N name,type,vers,path (normal)
- * T type,name,vers,path
- * V vers,name,type,path
- *
- * A alloc [,name,type,vers,path]
- * B backup [,name,type,vers,path]
- * C created [,name,type,vers,path]
- * D date [,name,type,vers,path]
- * E expir [,name,type,vers,path]
- * F format [,name,type,vers,path]
- * H hour [,name,type,vers,path]
- * M protect [,name,type,vers,path]
- * O owner [,name,type,vers,path]
- * R revised [,name,type,vers,path]
- * S size [,name,type,vers,path]
- * U user [,name,type,vers,path]
- * W week [,name,type,vers,path]
- * X xab [,name,type,vers,path]
- *
- * Parameters: opt - alphabetic code (see above)
- * order - normal/reverse flag (TRUE = reverse).
- * curfile - index into 'filelist[]' of current file
- * fix - temporarily "fix" the current location, restoring the
- * original file-entry which may have been selected.
- *
- * Returns: The index into 'filelist[]' at which the cursor should be
- * placed after the sort. If the sort is not applicable (because
- * no data was read for this purpose), the original index is
- * returned. Because a 'dds_pack' is performed for all applicable
- * sort operations, the file-index may be adjusted even if no
- * changes result directly from the sort.
- */
-
- #include <stdlib.h> /* declares 'qsort()' */
- #include <ctype.h>
- #include <string.h>
-
- #include <lib$routines.h>
- #include <rmsdef.h>
-
- #include "flist.h"
- #include "dircmd.h"
- #include "dds.h"
-
- #include "sysutils.h"
-
- import(filelist); import(numfiles);
- import(A_opt); import(D_opt); import(M_opt); import(O_opt);
-
- static
- char *full_opt[] = {
- "PATH", "NAME", "TYPE", "VERSION",
- "ALLOC", "BACKUP", "CREATED", "DATE",
- "EXPIRED",
- "FORMAT", "HOUR", "MASK", "OWNER",
- "REVISED", "SIZE", "USER",
- "XAB"};
- static
- int by_hour = 0; /* Last HOUR-mode used */
-
- static int flsort_fix (FLINK *f_);
-
- /*
- * The following sort-definitions return -1 if the first argument is lower,
- * 0 if equal, +1 if greater. Definitions are used rather than procedures
- * to try to make this code run as rapidly as possible (though larger).
- *
- * Notes:
- * 1. Strings are sorted in the opposite sense (increasing order)
- * to the sense of the size, date, protection codes.
- * 2. Even though the filetype is only three bytes, I must use 'strcmp'
- * to compare it, because the ordering of bytes on VAX puts the left
- * character in the least significant position.
- */
-
- #define LSS -1
- #define GTR 1
- #define EQL 0
-
- #define hi(z) (z.date64[1])
- #define lo(z) (z.date64[0])
-
- #define sort_FWD(n1,n2) (cmp = ((n1 < n2) ? LSS : ((n1 > n2) ? GTR : EQL)))
- #define sort_NUM(n1,n2) (cmp = ((n1 < n2) ? GTR : ((n1 > n2) ? LSS : EQL)))
-
- #define sort_STR(s1,s2) (cmp = strcmp(s1, s2))
-
- #define sort_P(z1,z2) sort_FWD(z1->fpath_->path_sort, z2->fpath_->path_sort)
- #define sort_N(z1,z2) sort_STR(z1->fname, z2->fname)
- #define sort_T(z1,z2) sort_STR(z1->ftype, z2->ftype)
- #define sort_U(z1,z2) sort_STR(z1->f_user, z2->f_user)
-
- #define sort_V(z1,z2) sort_NUM(z1->fvers, z2->fvers)
-
- #ifdef __alpha
- #define sort_D(z1,z2) sort_NUM(z1,z2)
- #else
- #define sort_D(z1,z2) (sort_NUM(hi(z1),hi(z2)) ? cmp :\
- sort_NUM(lo(z1),lo(z2)))
- #endif
-
- #define sort_H(z1,z2) sort_NUM(z1->fhour, z2->fhour)
-
- #define sort_S(z1,z2) sort_NUM(z1->fsize, z2->fsize)
- #define sort_A(z1,z2) sort_NUM(z1->fallc, z2->fallc)
- #define sort_M(z1,z2) sort_NUM(z1->fprot, z2->fprot)
- #define sort_O(z1,z2) (sort_FWD(z1->f_grp, z2->f_grp) ? cmp :\
- sort_FWD(z1->f_mbm, z2->f_mbm))
- #define sort_F(z1,z2) sort_NUM(z1->f_rfm, z2->f_rfm)
- #define sort_X(z1,z2) sort_NUM(z1->f_rat, z2->f_rat)
-
- /*
- * Define sorting for file entries which cannot be fully displayed, due to
- * privilege violation (SIZE, DATE, MASK and OWNER are affected):
- */
- #define sortPRV(z1,z2) (cmp = (zNOPRIV(z1) ? (zNOPRIV(z2) ? EQL : GTR)\
- : (zNOPRIV(z2) ? LSS : EQL) ))
-
- static int sortopt, /* copy of 'opt' */
- sortord; /* copy of 'order' */
-
- static
- int compare(const void *p1, const void *p2)
- {
- register FILENT *f1 = &((*(FLINK **)p1)->fk),
- *f2 = &((*(FLINK **)p2)->fk);
- register int cmp = 0;
-
- switch (sortopt)
- {
- case 'P':
- if (sort_P(f1,f2)) break;
- if (sort_N(f1,f2)) break;
- if (sort_T(f1,f2)) break;
- sort_V(f1,f2);
- break;
- case 'T':
- if (sort_T(f1,f2)) break;
- if (sort_N(f1,f2)) break;
- if (sort_P(f1,f2)) break;
- sort_V(f1,f2);
- break;
- case 'V':
- if (sort_V(f1,f2)) break;
- goto by_name;
- case 'S':
- if (sortPRV(f1,f2)) break;
- if (sort_S(f1,f2)) break;
- goto by_name;
-
- case 'A':
- if (sortPRV(f1,f2)) break;
- if (sort_A(f1,f2)) break;
- goto by_name;
-
- case 'C': /* CREATED */
- if (sortPRV(f1,f2)) break;
- if (sort_D(f1->fdate,f2->fdate)) break;
- goto by_name;
- case 'B': /* BACKUP */
- if (sortPRV(f1,f2)) break;
- if (sort_D(f1->fback,f2->fback)) break;
- goto by_name;
- case 'R': /* REVISED */
- if (sortPRV(f1,f2)) break;
- if (sort_D(f1->frevi,f2->frevi)) break;
- goto by_name;
- case 'E': /* EXPIRED */
- if (sortPRV(f1,f2)) break;
- if (sort_D(f1->fexpr,f2->fexpr)) break;
- goto by_name;
-
- case 'H':
- if (sortPRV(f1,f2)) break;
- if (sort_H(f1,f2)) break;
- goto by_name;
- case 'M':
- if (sortPRV(f1,f2)) break;
- if (sort_M(f1,f2)) break;
- goto by_name;
- case 'O':
- if (sortPRV(f1,f2)) break;
- if (sort_O(f1,f2)) break;
- goto by_name;
- case 'U':
- if (sortPRV(f1,f2)) break;
- if (sort_U(f1,f2)) break;
- goto by_name;
- case 'I':
- #define sort_ID(n) sort_NUM(f1->fidnum[n],f2->fidnum[n])
- if (sort_ID(0)) break;
- if (sort_ID(1)) break;
- if (sort_ID(2)) break;
- goto by_name;
-
- case 'L':
- if (sort_NUM(f1->f_recl,f2->f_recl)) break;
- goto by_name;
-
- case 'F':
- if (sortPRV(f1,f2)) break;
- if (sort_F(f1,f2)) break;
- goto by_name;
- /* Sort XAB within FORMAT for better ordering */
- case 'X':
- if (sortPRV(f1,f2)) break;
- if (sort_F(f1,f2)) break;
- if (sort_X(f1,f2)) break;
- /* Continue into NAME after numeric sorts: */
- by_name:
- default:
- if (sort_N(f1,f2)) break;
- if (sort_T(f1,f2)) break;
- if (sort_P(f1,f2)) break;
- if (sortopt != 'V') sort_V(f1,f2);
- }
- return ((sortord > 0) ? cmp : -cmp);
- }
-
- tDIRCMD(flsort)
- {
- FLINK *cmpFIX, *cmpTMP;
- int opt = xdcl_->dcl_text[1],
- order = (xdcl_->dcl_text[0] == 'S') ? GTR : LSS,
- fixpoint = dircmd_select(-2), /* Save original selection-index */
- j0, j1,
- k0 = numfiles-1, k1,
- cmp, got,
- didsome = 0,
- lpp2 = crt_lpp() - 1;
- DATENT *c_;
-
- /* Verify that the option is legal one: */
- if (! isprint (opt))
- opt = 'N';
-
- for (j0 = 0; j0 < SIZEOF(full_opt); j0++)
- {
- if (opt == *full_opt[j0])
- break;
- }
- if (j0 == SIZEOF(full_opt)) j0 = 1; /* Coerce to NAME */
-
- if ((strchr("AS", opt) && !A_opt)
- || (strchr("BCDEHRW", opt) && !D_opt)
- || (strchr("M", opt) && !M_opt)
- || (strchr("OU", opt) && !O_opt) )
- {
- warn ("Sort (%s) is not applicable", full_opt[j0]);
- return;
- }
-
- if (opt == 'D')
- {
- switch (D_opt)
- {
- case 3: opt = 'R'; break;
- case 2: opt = 'B'; break;
- default: opt = 'C';
- }
- }
-
- if (numfiles > 24) dds_while (nullC);
-
- /*
- * If we do a sort-by-hour, update the '.fhour' components to match
- * the current date-selection option. We use the same field for
- * sort-by-day-of-week, since the two can't be combined anyway.
- */
- if (strchr("HW", opt))
- {
- got = (opt == 'H') ? D_opt : -D_opt;
- cmp = (by_hour != got);
- for (j0 = 0; j0 < numfiles; j0++)
- {
- if (!DELETED(j0) && !NOPRIV(j0))
- {
- switch (D_opt)
- {
- case 4: c_ = &(FK(j0).fexpr); break;
- case 3: c_ = &(FK(j0).frevi); break;
- case 2: c_ = &(FK(j0).fback); break;
- default: c_ = &(FK(j0).fdate);
- }
- if (cmp || ! FK(j0).fhour)
- {
- if (isBigDate(c_))
- FK(j0).fhour = 0xffff; /* biggest possible */
- else
- {
- if (opt == 'H')
- FK(j0).fhour = syshour(c_) >> 16;
- else
- {
- lib$day (&j1, c_);
- FK(j0).fhour = ((j1 + 3) % 7) + 1;
- }
- }
- }
- }
- }
- by_hour = got;
- opt = 'H';
- }
-
- if (fixpoint >= 0) cmpFIX = filelist[fixpoint];
- if (fix) cmpTMP = filelist[*curfile_];
-
- didsome = dds_pack (curfile_, TRUE); /* Get rid of all deleted files */
- sortopt = opt; /* set global needed in 'compare()' */
- sortord = order;
-
- qsort(filelist, numfiles, sizeof(filelist[0]), compare);
- didsome++; /* for this sort, always scroll to beginning */
-
- /*
- * If I did a fixed-point search, find the new position of the entry,
- * and:
- * (a) Reset the index to the new position, and
- * (b) Reset (if required) the top/bottom file indices to permit
- * me to show this screen next. The screen refresh is made
- * complicated because of the compaction which may have been
- * made with 'dds_pack()'.
- *
- * If I didn't do a fixed-sort, reset the current-file to the top-of
- * list.
- */
- if (didsome)
- {
- if (fixpoint >= 0 || fix)
- {
- if (fixpoint >= 0)
- dircmd_select (*curfile_ = flsort_fix (cmpFIX));
- if (fix)
- *curfile_ = flsort_fix (cmpTMP);
-
- k0 = lpp2 * (*curfile_ / lpp2); /* Nominal top-screen */
- k1 = numfiles - lpp2; /* Try a better estimate */
- if (k1 >= 0 && k1 <= *curfile_) k0 = k1;
- dds_all (k0, *curfile_);
- }
- else
- dds_all (0, *curfile_ = 0);
- }
- else
- warn ("No change in sort-order");
- }
-
- /*
- * Return the present index of a particular FILENT entry in the 'filelist[]'
- * array.
- */
- static
- int flsort_fix (FLINK *f_)
- {
- int j;
-
- for (j = 0; j < numfiles; j++)
- if (f_ == filelist[j]) return (j);
- return (-1);
- }