home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / bbs / downsrt / source / downsrv.c < prev    next >
Text File  |  1991-06-05  |  23KB  |  654 lines

  1. /* ============================================================= */
  2. /*  Rob Hamerling's MAXIMUS download file scan and sort utility. */
  3. /*  -> Collection of general service routines for DOWNSORT.      */
  4. /* ============================================================= */
  5.  
  6. // #define DEBUG_MODE
  7.  
  8. #define INCL_BASE
  9. #include <os2.h>
  10.  
  11. #include "ctype.h"
  12. #include "stdio.h"
  13. #include "stdlib.h"
  14. #include "string.h"
  15. #include "time.h"
  16.  
  17. #include "downsort.h"
  18.  
  19. /* ------------------- */
  20. /* Welcome to the user */
  21. /* ------------------- */
  22. void show_welcome()
  23. {
  24.   printf("\n%15s╔%22.22s╗", "",HD);
  25.   printf("\n╔%14.14s╣ %8.8s version %c.%c%c╠%15.15s╗",
  26.                     HD,PROGNAME,VERSION,SUBVERS,SUFFIX,HD);
  27.   printf("\n║  Copyright   ╚%22.22s╝   Shareware   ║", HD);
  28.   printf("\n║  %s %-38.38s║", MAX,PROGDESC);
  29.   printf("\n║      by %-13.13s, %-29s║", AUTHOR,CITY);
  30.   printf("\n║%-29s%24s║", PHONE, FIDO);
  31.   printf("\n╚%26.26s%27.27s╝\n", HD,HD);
  32.   }
  33.  
  34. /* ======================================================== */
  35. /* Compare two filenames, first call should be with x==0    */
  36. /* First name must be regular "8.3" format filename.        */
  37. /* Second name may contain wildcards, but the compare will  */
  38. /* be against the saved first name when x!=0.               */
  39. /* ======================================================== */
  40. int wild_comp(x,a,b)
  41. char a[],b[];                           // file spec strings
  42. int  x;                                 // x==0 first compare
  43.                                         // x!=0 subsequent compare
  44. {
  45.   int i;
  46.   static char na[11],nb[11];            // formatted filename fields
  47.                                         // keep 'm for subsequent calls
  48.   static char empty_ext[]  = "";     // for compare files without ext.
  49.  
  50.   i = non_wild_init(8,na,a);            // init non-wild string
  51.   switch(a[i]) {                        // after fileNAME
  52.     case ' ' :
  53.     case '\0':
  54.       i = non_wild_init(3,na+8,empty_ext);  // empty extension
  55.       break;
  56.     case '.' :
  57.       i = non_wild_init(3,na+8,a+i+1);  // process extension
  58.       break;
  59.     default:                            // invalid filename
  60.       break;
  61.     }
  62.  
  63.   if (x==0) {                           // first compare with 2nd name
  64.     i = wild_init(8,nb,b);
  65.     switch(b[i]) {
  66.       case ' ' :
  67.       case '\0':
  68.         i = wild_init(3,nb+8,empty_ext);  // empty extension
  69.         break;
  70.       case '.' :
  71.         i = wild_init(3,nb+8,b+i+1);    // process extension
  72.         break;
  73.       default:
  74.         break;
  75.       }
  76.     }
  77. #if defined(DEBUG_MODE)
  78.   printf("\n");                         // debug of wild compare
  79.   for (i=0; i<11; ++i)
  80.     printf("%c",(na[i]!='\0')?na[i]:' ');
  81.   printf(" ");
  82.   for (i=0; i<11; ++i)
  83.     printf("%02X",na[i]);
  84.   printf("   ");
  85.   for (i=0; i<11; ++i)
  86.     printf("%c",(nb[i]!='\0')?nb[i]:' ');
  87.   printf(" ");
  88.   for (i=0; i<11; ++i)
  89.     printf("%02X",nb[i]);
  90. #endif
  91.  
  92.   for (i=0; i<11 && (na[i]==nb[i] || na[i]=='\0' || nb[i]=='\0'); i++);
  93.  
  94.   if (i>=11)                             // strings equal
  95.     return(0);
  96.   else
  97.     return(na[i]-nb[i]);                 //
  98.   }
  99.  
  100. /* =========================================== */
  101. /* Init string for wild-card filenames compare */
  102. /* =========================================== */
  103. int wild_init(n,p,q)
  104. int  n;                                 // max length of strings
  105. char p[],q[];                           // p is destination (length n)
  106.                                         // q is source (MAX length n)
  107. {
  108.   int i,j;
  109.  
  110.   i=j=0;
  111.   while (i<n) {                         // process string 'q'
  112.     switch(q[j]) {
  113.       case '?':                         // single wild char
  114.         p[i++] = '\0';                  // matches with any other char
  115.         j++;                            // proceed with next char
  116.         break;
  117.       case '.':                         // end of filespec-part
  118.       case ' ':                         // logical end of string
  119.       case '\0':                        // end of string
  120.         while (i<n)                     // fill
  121.           p[i++] = '';                 // insert filler chars
  122.         break;
  123.       case '*':                         // wild string
  124.         while (i<n)                     // fill
  125.           p[i++] = '\0';                // matches with any other char
  126.         j++;                            // to next char
  127.         break;
  128.       default:                          // 'normal' characters
  129.         p[i] = toupper(q[i]);           // copy in UPPERcase
  130.         i++; j++;                       // proceed with next char
  131.         break;
  132.       }
  133.     }
  134.  
  135.   return(j);                            // displ. of last examined char
  136.   }
  137.  
  138. /* ==================================================== */
  139. /* Init string for non-wild-card filenames compare      */
  140. /* No wild-cards expected, no trasnlation to upper case */
  141. /* ==================================================== */
  142. int non_wild_init(n,p,q)
  143. int  n;                                 // max length of strings
  144. char p[],q[];                           // p is destination (length n)
  145.                                         // q is source (MAX length n)
  146. {
  147.   int i,j;
  148.  
  149.   i=j=0;
  150.   while (i<n) {                         // process string 'q'
  151.     if (q[j]=='.' || q[j]==' ' || q[j]=='\0') {
  152.       p[i] = '';                       // insert filler char
  153.       i++;                              // rest zeroes (no j-increment!)
  154.       }
  155.     else {
  156.       p[i] = toupper(q[i]);             // copy in UPPER case
  157.       i++; j++;                         // proceed with next char
  158.       }
  159.     }
  160.  
  161.   return(j);                            // displ. of last examined char
  162.   }
  163.  
  164. /* ----------------------------------------------- */
  165. /* Transform file-date into 10-char string         */
  166. /* COUNTRY format mm-dd-yy (USA) or dd-mm-jj (EUR) */
  167. /* ----------------------------------------------- */
  168. char *f_date(dat)
  169. struct _FDATE dat;
  170. {
  171.   static char date[10] = {'\0'};        // work buffer
  172.   sprintf(date,"%2u%s%02u%s%02u%c",
  173.          ((c_info.fsDateFmt == 0) ? dat.month : dat.day),
  174.            c_info.szDateSeparator,
  175.          ((c_info.fsDateFmt == 0) ? dat.day : dat.month),
  176.            c_info.szDateSeparator,
  177.          (dat.year+80)%100,             /* allow 2 digits! */
  178.           '\0');
  179.   return(date);
  180.   }
  181.  
  182. /* -------------------------------------------------------------- */
  183. /* Transform file-time into string (hh:mm:ssa)                    */
  184. /* COUNTRY format hh:mm:ssa (12 hr USA) or hh-mm-ss  (24 hr EUR)  */
  185. /* -------------------------------------------------------------- */
  186. char *f_time(tim)
  187. struct _FTIME tim;
  188. {
  189.   static char time[10] = {'\0'};        // work buffer
  190.   sprintf(time,"%2u%s%02u%s%02u%s%c",
  191.           (c_info.fsTimeFmt==0 && tim.hours>12) ? tim.hours-12 : tim.hours,
  192.            c_info.szTimeSeparator,
  193.           tim.minutes,
  194.            c_info.szTimeSeparator,
  195.           tim.twosecs*2,
  196.           ((c_info.fsTimeFmt==0) ? ((tim.hours>11) ? "p" : "a") : " "),
  197.           '\0');
  198.   return(time);
  199.   }
  200.  
  201. /* ====================================================== */
  202. /* Compare for sort on file-date/time + filename + area   */
  203. /* ====================================================== */
  204. int sort_new(p,q)
  205. struct _filechain **p,**q;
  206. {
  207.   int    rc;
  208.   ULONG  ad,bd,td;
  209.   struct _filechain *a,*b;
  210.  
  211.   a = *p;
  212.   b = *q;
  213.  
  214.   ad = file_time(a->wdate,a->wtime);
  215.   td = file_time(a->cdate,a->ctime);
  216.   if (ad < td)                          // take latest date
  217.     ad = td;
  218.  
  219.   bd = file_time(b->wdate,b->wtime);
  220.   td = file_time(b->cdate,b->ctime);
  221.   if (bd < td)                          // take latest date
  222.     bd = td;
  223.  
  224.   if (bd==ad) {                         // equal timestamps
  225.     rc = strcmp(a->fname,b->fname);
  226.     if (rc)                             // unequal filenames
  227.       return(rc);
  228.     else
  229.       return(strcmp(a->parea->name,b->parea->name));  // area-code
  230.     }
  231.   else
  232.     return((bd<ad) ? -1 : +1);
  233.   }
  234.  
  235. /* ========================================= */
  236. /* Compare for sort on filename + area-code  */
  237. /* ========================================= */
  238. int sort_gbl(p,q)
  239. struct _filechain **p,**q;
  240. {
  241.   int rc;
  242.   struct _filechain *a,*b;
  243.  
  244.   a = *p;
  245.   b = *q;
  246.   rc = strcmp(a->fname,b->fname);
  247.   if (rc)                               // unequal filename
  248.     return(rc);
  249.   else
  250.     return(strcmp(a->parea->name,b->parea->name));    // area-code
  251.   }
  252.  
  253. /* ========================================= */
  254. /* Compare for sort on area code + filename  */
  255. /* ========================================= */
  256. int sort_all(p,q)
  257. struct _filechain **p,**q;
  258. {
  259.   int rc;
  260.   struct _filechain *a,*b;
  261.  
  262.   a = *p;
  263.   b = *q;
  264.   rc = strcmp(a->parea->name,b->parea->name);
  265.   if (rc)                               // unequal areacode
  266.     return(rc);
  267.   else
  268.     return(strcmp(a->fname,b->fname));  // filename
  269.   }
  270.  
  271. /* ====================================================== */
  272. /* Compare for sort on area + file-date/time + filename   */
  273. /* ====================================================== */
  274. int sort_al2(p,q)
  275. struct _filechain **p,**q;
  276. {
  277.   int    rc;
  278.   ULONG  ad,bd,td;
  279.   struct _filechain *a,*b;
  280.  
  281.   a = *p;
  282.   b = *q;
  283.   rc = strcmp(a->parea->name,b->parea->name);
  284.   if (rc)                               // unequal area-name
  285.     return(rc);
  286.   else {
  287.     ad = file_time(a->wdate,a->wtime);
  288.     td = file_time(a->cdate,a->ctime);
  289.     if (ad < td)                        // take latest date
  290.       ad = td;
  291.     bd = file_time(b->wdate,b->wtime);
  292.     td = file_time(b->cdate,b->ctime);
  293.     if (bd < td)                        // take latest date
  294.       bd = td;
  295.     if (bd!=ad)                         // unequal date
  296.       return((bd<ad) ? -1 : +1);
  297.     else
  298.       return(strcmp(a->fname,b->fname));  // filename
  299.     }
  300.   }
  301.  
  302. /* ========================================================= */
  303. /* Compare for sort on area code + FILES.BBS sequence number */
  304. /* ========================================================= */
  305. int sort_akp(p,q)
  306. struct _filechain **p,**q;
  307. {
  308.   int rc;
  309.   struct _filechain *a,*b;
  310.  
  311.   a = *p;
  312.   b = *q;
  313.   rc = strcmp(a->parea->name,b->parea->name);
  314.   if (rc)                               // unequal areacode
  315.     return(rc);
  316.   else {
  317.     if (a->fseq != b->fseq)             // unequal sequence number
  318.       return((a->fseq < b->fseq) ? -1 : +1);
  319.     else
  320.       return(0);                        // equal sequence number */
  321.     }
  322.   }
  323.  
  324. /* ==================================================== */
  325. /* Compare for sort on area code + privilege + filename */
  326. /* No sort on privilege if below area-privilege.        */
  327. /* ==================================================== */
  328. int sort_fil(p,q)
  329. struct _filechain **p,**q;
  330. {
  331.   int rc;
  332.   struct _filechain *a,*b;
  333.  
  334.   a = *p;
  335.   b = *q;
  336.   rc = strcmp(a->parea->name,b->parea->name);
  337.   if (rc)                               // unequal areacode
  338.     return(rc);
  339.   else {
  340.     if (a->priv <= a->parea->priv &&    // both within area priv
  341.         b->priv <= b->parea->priv)
  342.       return(strcmp(a->fname,b->fname));  // sort on filename
  343.     else if (a->priv == b->priv)        // same privilege
  344.       return(strcmp(a->fname,b->fname));  // filename
  345.     else
  346.       return (a->priv - b->priv);       // file priv
  347.     }
  348.   }
  349.  
  350. /* ========================================== */
  351. /* Compare for sort on area code of AREA-info*/
  352. /* ========================================== */
  353. int sort_summ(p,q)
  354. struct _downpath *p,*q;
  355. {
  356.   return(strcmp(p->name,q->name));
  357.   }
  358.  
  359. /* ---------------------------- */
  360. /* Sort file-info pointer array */
  361. /* ---------------------------- */
  362. void    psort(arr, left, right, comp)
  363. struct  _filechain **arr;               // pointer to array
  364. int     left,right;                     // left and right boundaries
  365. int     (*comp)(void *, void *);        // ptr to compare function
  366. {
  367.   int    asc,desc;
  368.   struct _filechain *ref,*tmp;
  369.  
  370.   if ((right-left) < 1)                 // too few elements
  371.     return;
  372.  
  373.   asc   = left;                         // left 'wall'
  374.   desc  = right;                        // right 'wall'
  375.   ref  = arr[(left + right)/2];         // reference value
  376.  
  377.   do {
  378.     while (comp(&arr[asc],&ref) < 0)  // move right
  379.       asc++;
  380.     while (comp(&arr[desc],&ref) > 0) // move left
  381.       desc--;
  382.     if (asc <= desc) {                   // swap
  383.       tmp = arr[desc];
  384.       arr[desc--] = arr[asc];
  385.       arr[asc++] = tmp;
  386.       }
  387.     } while (asc <= desc);
  388.  
  389.   if ((desc-left) < (right-asc)) {      // sort smaller part first
  390.     if (left < desc)
  391.       psort(arr, left, desc, comp);
  392.     if (right > asc)
  393.       psort(arr, asc, right, comp);
  394.     }
  395.   else {
  396.     if (right > asc)
  397.       psort(arr, asc, right, comp);
  398.     if (left < desc)
  399.       psort(arr, left, desc, comp);
  400.     }
  401.   }
  402.  
  403. /* =================== */
  404. /* determine file-age  */
  405. /* =================== */
  406. char  file_age_ind(fd,ft)
  407. struct _FDATE fd;
  408. struct _FTIME ft;
  409. {
  410.   int  age;
  411.  
  412.   age = (int)((time(NULL) - file_time(fd,ft))/86400);  // days
  413.   if (age>30)
  414.     return(' ');                        // older than a month
  415.   else {
  416.     if (age>7)                          // older than 7 days
  417.       return(DAYS_30);
  418.     else {
  419.       if (age>=0)                       // non-negative negative age
  420.         return(DAYS_7);                 // a week
  421.       else
  422.         return('-');                    // negative age
  423.       }
  424.     }
  425.   }
  426.  
  427. /* ============================================ */
  428. /* Compare for newest acquisition in ALL-list   */
  429. /* ============================================ */
  430. struct _filechain *new_acq(a,b)
  431. struct _filechain *a,*b;
  432. {
  433.   long ad,bd,td;
  434.  
  435.   if (b==NULL)                          // right might be not assigned
  436.     return(a);                          // then return first
  437.   ad = file_time(a->wdate,a->wtime);
  438.   td = file_time(a->cdate,a->ctime);
  439.   if (ad < td)                          // take latest date
  440.     ad = td;
  441.   bd = file_time(b->wdate,b->wtime);
  442.   td = file_time(b->cdate,b->ctime);
  443.   if (bd < td)                          // take latest date
  444.     bd = td;
  445.   if (ad==bd)                           // equal dates
  446.     return(b);                          // (either)
  447.   else
  448.     return((ad>bd) ? a : b);            // return most recent
  449.   }
  450.  
  451. /* ============================================================== */
  452. /* reformat file-date into long time-value like C time convention */
  453. /* ============================================================== */
  454. long  file_time(fd,ft)
  455. struct _FDATE fd;                     // file date
  456. struct _FTIME ft;                     // file time
  457. {
  458.   static int mon_tab[] = {0,31,59,90,120,151,181,212,243,273,304,334};
  459.                                       // ignore leapyear February!
  460.   return((((fd.year+10)*1461+1)/4 +
  461.            mon_tab[fd.month-1] +
  462.            fd.day - 1) * 86400L +
  463.           ft.hours * 3600 +
  464.           ft.minutes * 60 +
  465.           ft.twosecs * 2);
  466.   }
  467.  
  468. /* =================================== */
  469. /* include a test file into a report   */
  470. /* output file is supposed to be open! */
  471. /* =================================== */
  472. void file_incl(pfo, fn)
  473. FILE *pfo;                              // output file pointer
  474. char *fn;                               // input filespec
  475. {
  476.   char  buf[MAXRCD];                    // I/O buffer
  477.   FILE *pfi;                            // input file pointer
  478.  
  479.   if ((pfi = fopen(fn,"rt")) != NULL) {
  480.     while (fgets(buf,MAXRCD,pfi) != NULL)  // all records "as is"
  481.       fputs(buf,pfo);
  482.     fclose(pfi);
  483.     }
  484.   else
  485.     printf(MSG_TRL,fn);                 // file not included
  486.   }
  487.  
  488. /* ============================================================== */
  489. /* routine to select a substring while skipping leading blanks    */
  490. /*         and ending within the boundaries on a word-end.        */
  491. /*         Truncate if single word. Respect NL as end of string.  */
  492. /*         Return strlen,  0 for NULL-pointer.                    */
  493. /* ============================================================== */
  494. int strsubw(a,b,m)
  495. char *a,**b;                            // in-string, start-substring
  496. int  m;                                 // max substring length
  497. {
  498.   int i,j,k;                            // counters
  499.  
  500.   if (a==NULL)                          // NULL pointer
  501.     return(0);                          // no string
  502.  
  503.   for (i=0; a[i] == ' '; ++i);          // skip leading blanks
  504.   a = *b = a+i;                         // offset to first non-blank char
  505.   for (i=0; a[i] != '\0' && a[i]!='\n'; ++i); // search end string
  506.   if (i==0)                             // nothing left
  507.     return(0);                          // end!
  508.  
  509.   for (k=0; k<m && k<i; ++k);           // maximum substring
  510.   if (k<i) {                            // there is more in string
  511.     if (a[k]==' ' || a[k]=='\n' || a[k]=='\0');  // word boundary
  512.     else {
  513.       for (j=k-1; j>0 && a[j]!=' '; --j); // try to remove 'split' word
  514.       if (j>0)                          // any space found?
  515.         k = j;                          // OK, else split!
  516.       }
  517.     }
  518.   for (; k>0 && a[k-1] == ' '; --k);    // remove trailing blanks
  519.   return(k);                            // return length of substring
  520.                                         // b contains start-point
  521.   }
  522.  
  523. /* ====================================================== */
  524. /* Function to locate next non-blank character in buffer. */
  525. /* Returns pointer to word or NULL-ptr if no next word.   */
  526. /* ====================================================== */
  527. char *next_word(line)
  528. char *line;                             //
  529. {
  530.   unsigned int i;
  531.  
  532.   for (i=0; line[i]!=' '  &&            // skip non-blanks
  533.             line[i]!='\n' &&
  534.             line[i]!='\0'; ++i);
  535.   for (   ; line[i]==' '; ++i);         // skip blanks
  536.   if (line[i] != '\0' &&
  537.       line[i] != '\n')
  538.     return(line+i);                     // next word found
  539.   else
  540.     return(NULL);                       // NULL if no next word
  541.   }
  542.  
  543. /* =========================================== */
  544. /* Function to make ASCIIZ string of ONE word. */
  545. /* =========================================== */
  546. char *asciiz(buf)
  547. char *buf;
  548. {
  549.   unsigned int i;
  550.   static char buf2[255];                // return buffer
  551.  
  552.   for (i=0; buf[i] != ' '  &&           // end copy at first blank
  553.             buf[i] !='\n'  &&           // or end of line
  554.             buf[i] !='\0'; ++i)         // or end of string
  555.     buf2[i] = buf[i];                   // copy
  556.   buf2[i] = '\0';                       // end of string
  557.   return(buf2);                         // pointer to ASCIIZ string
  558.   }
  559.  
  560. /* ================================== */
  561. /* some marketing below every report! */
  562. /* ================================== */
  563. void signature(pf, now)
  564. FILE *pf;                               // file pointer
  565. char *now;                              // timestamp string
  566. {
  567.   static char *mode[] = {"DOS","OS/2"};
  568.  
  569.   fprintf(pf,"\n\n %-.40s%-.28s",HD,HD);
  570.   fprintf(pf,"\n  %s %c.%c%c by %s, on %s under %s %d.%d ",
  571.                 PROGNAME,VERSION,SUBVERS,SUFFIX,AUTHOR,now,
  572.                 mode[_osmode & 1],
  573.                 _osmajor/((_osmode)?10:1),
  574.                 _osminor/10);
  575.   fprintf(pf,"\n %-.40s%-.28s\n",HD,HD);
  576.   }
  577.  
  578. /* =========================================== */
  579. /* count areas within privilege for top-header */
  580. /* =========================================== */
  581. USHORT count_areas(area, p)
  582. struct  _downpath *area;                // pointer to area array
  583. int  p;                                 // privilege for count
  584. {
  585.   USHORT i,j;
  586.  
  587.   for (i=j=0; i<area_count; i++)        // whole area-array
  588.     if (area[i].priv <= p  &&           // consider only within privilege
  589.         area[i].file_count > 0)         // and only if files present
  590.       ++j;                              // add to count
  591.   return(j);
  592.   }
  593.  
  594. /* =========================================== */
  595. /* count bytes within privilege for top-header */
  596. /* =========================================== */
  597. ULONG  count_bytes(dm, p)
  598. struct  _filechain **dm;                // pointer to file-sort array
  599. int  p;                                 // privilege for count
  600. {
  601.   USHORT i;
  602.   ULONG  b;
  603.  
  604.   for (i=0,b=0L; i<file_count; i++)     // scan whole file-chain
  605.     if (dm[i]->priv <= p)               // consider only within privilege
  606.       b += dm[i]->size;                 // add to count
  607.   return(b);
  608.   }
  609.  
  610. /* =========================================== */
  611. /* count files within privilege for top-header */
  612. /* =========================================== */
  613. USHORT count_files(dm, p)
  614. struct  _filechain **dm;                // pointer to file-sort array
  615. int  p;                                 // privilege for count
  616. {
  617.   USHORT i,j;
  618.  
  619.   for (i=j=0; i<file_count; i++)        // scan whole file-chain
  620.     if (dm[i]->priv <= p)               // consider only within privilege
  621.       ++j;                              // add to count
  622.   return(j);
  623.   }
  624.  
  625. /* ================ */
  626. /* HELP information */
  627. /* ================ */
  628. void show_help()
  629. {
  630.   printf("\nSyntax:  DOWNSORT  [commandline-parameters]\n");
  631.   printf("\n@filespec   - Filespec of Configuration file with processing parameters");
  632.   printf("\nBBS[:p]     - Make BBS-list    ═╗");
  633.   printf("\nNEW[:pp]    - Make NEW-list(s)  ║");
  634.   printf("\nALL[:pp]    - Make ALL-list(s)  ╠═ for 1 or more privilege levels");
  635.   printf("\nIPF[:pp]    - Make IPF-list(s)  ║");
  636.   printf("\nGBL[:pp]    - Make GBL-list(s) ═╝");
  637.   printf("\nORP         - Make ORP-list (if ORPHANS detected)");
  638.   printf("\nFIL[:fpath] - (re-)Create FILES.BBS files");
  639.   printf("\nnnn         - (numeric) List only the first nnn files (NEW- and BBS-list)");
  640.   printf("\n-T|W        - All long file descriptions to be Truncated or Wrapped");
  641.   printf("\n-A|D|K      - Sort files Alphabetically, on Date, or Keep in FILES.BBS-seq.");
  642.   printf("\n-H|Q|V      - Display this HELP-screen, or run Quietly or Verbose");
  643.   printf("\n-X          - eXclude privilege indications in the FileLists");
  644.   printf("\n ───────────");
  645.   printf("\n    · p     : first letter of privilege (i.e. D=Disgrace, N=Normal, etc).");
  646.   printf("\n    · pp    : list generated for each specified privilege.");
  647.   printf("\n    · fpath : output directory of FILES.BBS files.");
  648.   printf("\n\nThese parameters override program and configurationfile values.");
  649.   printf("\nRead documentation or sample configuration file "
  650.          "for details and defaults.\n");
  651.   exit(1);
  652.   }
  653.  
  654.