home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / os2 / dwnsrs57.zip / DOWNSRV.C < prev    next >
Text File  |  1993-06-25  |  37KB  |  925 lines

  1.  
  2. /* ============================================================= */
  3. /*  Rob Hamerling's MAXIMUS download file scan and sort utility. */
  4. /*  -> DOWNSRV.C                                                 */
  5. /*  -> Collection of general service routines for DOWNSORT.      */
  6. /* ============================================================= */
  7.  
  8. #define INCL_BASE
  9. #define INCL_NOPMAPI
  10. #include <os2.h>
  11.  
  12. #include <ctype.h>
  13. #include <stdarg.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <time.h>
  18.  
  19. #include "downsort.h"
  20. #include "downfpro.h"
  21.  
  22. /* function prototype of local functions */
  23.  
  24. int  comp_area(DOWNPATH  *, DOWNPATH  *);
  25.  
  26.  
  27. /* ------------------- */
  28. /* Welcome to the user */
  29. /* ------------------- */
  30. void show_welcome(void)
  31. {
  32.   static char HD[22] = "══════════════════════";
  33.   printf("\n%15s╔%.22s╗\n", "", HD);
  34.   printf("╔%.14s╣ %8.8s version %c.%c%c╠%.15s╗\n",
  35.                  HD,PROGNAME,VERSION,SUBVERS,SUFFIX,HD);
  36.   printf("║  Copyright   ╚%.22s╝   Shareware   ║\n", HD);
  37.   printf("║  %s %-38.38s║\n", MAX,PROGDESC);
  38.   printf("║      by %-13.13s, %-29s║\n", AUTHOR,CITY);
  39.   printf("║%-29s%24s║\n", PHONE, FIDO);
  40.   printf("╚%.22s%.22s%.9s╝\n", HD, HD, HD);
  41.   }
  42.  
  43. /* ======================================================== */
  44. /* Compare two filenames.                                   */
  45. /* First name must be regular "8.3" format filename.        */
  46. /* Second name may contain wildcards.                       */
  47. /* ======================================================== */
  48. int wild_comp(char a[],
  49.               char b[])
  50. {
  51.   int i;
  52.   char na[11], nb[11];                  /* formatted filename fields     */
  53.                                         /* keep 'm for subsequent calls  */
  54.   static char empty_ext[]  = { "..." }; /* files without ext.            */
  55.  
  56.   i = non_wild_init(8,na,a);            /* init non-wild string          */
  57.   switch(a[i]) {                        /* after fileNAME                */
  58.     case ' ' :
  59.     case '\0':
  60.       i = non_wild_init(3,na+8,empty_ext);  /* empty extension           */
  61.       break;
  62.     case '.' :
  63.       i = non_wild_init(3,na+8,a+i+1);  /* process extension             */
  64.       break;
  65.     default:                            /* invalid filename              */
  66.       i = non_wild_init(3,na+8,a+i);    /* pseudo extension              */
  67.       break;
  68.     }
  69.  
  70.   i = wild_init(8,nb,b);
  71.   switch(b[i]) {
  72.     case ' ' :
  73.     case '\0':
  74.       i = wild_init(3,nb+8,empty_ext);  /* empty extension               */
  75.       break;
  76.     case '.' :
  77.       i = wild_init(3,nb+8,b+i+1);      /* process extension             */
  78.       break;
  79.     default:                            /* invalid filename              */
  80.       i = wild_init(3,nb+8,b+i);        /* pseaudo extension             */
  81.       break;
  82.     }
  83.  
  84. #if defined(DEBUG2)
  85.   printf("\n");                         /* debug of wild compare         */
  86.   for (i=0; i<11; ++i)
  87.     printf("%c", (na[i] != '\0') ? na[i] : ' ');
  88.   printf(" ");
  89.   for (i=0; i<11; ++i)
  90.     printf("%02.2X", na[i]);
  91.   printf("   ");
  92.   for (i=0; i<11; ++i)
  93.     printf("%c", (nb[i] != '\0') ? nb[i] : ' ');
  94.   printf(" ");
  95.   for (i=0; i<11; ++i)
  96.     printf("%02.2X", nb[i]);
  97. #endif
  98.  
  99. /* for (i=0; i<11 && (na[i]==nb[i] || na[i]=='\0' || nb[i]=='\0'); i++); */
  100.   for (i=0; i<11 && (na[i]==nb[i] || nb[i]=='\0'); i++);
  101.  
  102. #if defined(DEBUG2)
  103.   printf(" =#=%d",i);                    /* debug of wild compare        */
  104. #endif
  105.   if (i>=11)                             /* strings equal                */
  106.     return(0);
  107.   else
  108.     return(na[i]-nb[i]);
  109.   }
  110.  
  111. /* ============================================ */
  112. /* Init string for wild-card filenames compare. */
  113. /* Translation to UPPER case.                   */
  114. /* ============================================ */
  115. int wild_init(short int n,
  116.               char p[],
  117.               char q[])
  118. {
  119.   int i,j;
  120.  
  121.   i=j=0;
  122.   while (i<n) {                         /* process string 'q'            */
  123.     switch(q[j]) {
  124.       case '?':                         /* single wild char              */
  125.         p[i++] = '\0';                  /* matches with any other char   */
  126.         j++;                            /* proceed with next char        */
  127.         break;
  128.       case '.':                         /* end of filespec-part          */
  129.       case ' ':                         /* logical end of string         */
  130.       case '\0':                        /* end of string                 */
  131.         while (i<n)                     /* fill                          */
  132.           p[i++] = '.';                 /* insert filler chars           */
  133.         break;
  134.       case '*':                         /* wild string                   */
  135.         while (i<n)                     /* fill                          */
  136.           p[i++] = '\0';                /* matches with any other char   */
  137.         j++;                            /* to next char                  */
  138.         break;
  139.       default:                          /* 'normal' characters           */
  140.         p[i] = (char) toupper(q[i]);    /* convert to UPPERcase and copy */
  141.         i++; j++;                       /* proceed with next char        */
  142.         break;
  143.       }
  144.     }
  145.  
  146.   return(j);                            /* displ. of last examined char  */
  147.   }
  148.  
  149. /* ==================================================== */
  150. /* Init string for non-wild-card filenames compare.     */
  151. /* No wild-cards expected, translation to upper case.   */
  152. /* ==================================================== */
  153. int non_wild_init(short int n,
  154.                   char p[],
  155.                   char q[])
  156. {
  157.   int i,j;
  158.  
  159.   i=j=0;
  160.   while (i<n) {                         /* process string 'q'            */
  161.     if (q[j]=='.' || q[j]==' ' || q[j]=='\0') {
  162.       p[i] = '.';                       /* insert filler char            */
  163.       i++;                              /* rest filler (no j-increment!) */
  164.       }
  165.     else {
  166.       p[i] = (char) toupper(q[i]);      /* to UPPERcase and copy         */
  167.       i++; j++;                         /* proceed with next char        */
  168.       }
  169.     }
  170.  
  171.   return(j);                            /* displ. of last examined char  */
  172.   }
  173.  
  174. /* ------------------ */
  175. /* Produce time stamp */
  176. /* ------------------ */
  177. char *sys_date(char t[])
  178. {
  179.   long int secs_now;                    /* relative time value           */
  180.   char *buf;                            /* pointer to time string        */
  181.  
  182.   time(&secs_now);                      /* get current time              */
  183.   buf = ctime(&secs_now);               /* convert to char string        */
  184.   strcpy(t,buf);                        /* copy string                   */
  185.   t[16] = '\0';                         /* undo secs, year and newline   */
  186.   return(t);                            /* pointer to buffer             */
  187.   }
  188.  
  189. /* ------------------------------------------------- */
  190. /* Transform file-date into a  9-char string         */
  191. /* COUNTRY format mm-dd-yy (USA) or dd-mm-jj (EUR)   */
  192. /* ------------------------------------------------- */
  193. char *f_date(struct _FDATE date)
  194. {
  195.   static char string[9];                /* work buffer                   */
  196.   sprintf(string,"%2u%s%02u%s%02u",
  197.          ((c_info.fsDateFmt == 0) ? date.month : date.day),
  198.            c_info.szDateSeparator,
  199.          ((c_info.fsDateFmt == 0) ? date.day : date.month),
  200.            c_info.szDateSeparator,
  201.          (date.year+80)%100);           /* allow 2 digits!               */
  202.   return(string);
  203.   }
  204.  
  205. /* =================== */
  206. /* determine file-age  */
  207. /* =================== */
  208. char  file_age_ind(struct _FDATE fd,
  209.                    struct _FTIME ft)
  210. {
  211.   long int age;
  212.  
  213.   age = (time(NULL) - file_time(fd,ft))/86400L;  /* days                 */
  214.   if (age>30)
  215.     return(' ');                        /* older than a month            */
  216.   else {
  217.     if (age>7)                          /* older than 7 days             */
  218.       return(DAYS_30);
  219.     else {
  220.       if (age>=0)                       /* non-negative negative age     */
  221.         return(DAYS_7);                 /* a week                        */
  222.       else
  223.         return('-');                    /* negative age                  */
  224.       }
  225.     }
  226.   }
  227.  
  228. /* -------------------------------------------------- */
  229. /* Transform file-size and date into a 15-byte string */
  230. /* Size in K (rounded to next higher number KBytes)   */
  231. /* Date format as inf_date(), plus age indicator.     */
  232. /* If date zero: pointer to 'offline'-text.           */
  233. /* -------------------------------------------------- */
  234. char *f_size_date(unsigned long int size,
  235.                   struct _FDATE wdate,
  236.                   struct _FDATE cdate,
  237.                   struct _FTIME ctime)
  238. {
  239.   static char string[15];               /* work buffer                   */
  240.   if (wdate.day) {                      /* date non-zero                 */
  241.     sprintf(string,"%4luK ", (size+1023)/1024);  /* format size          */
  242.     strcat(string, f_date(wdate));      /* add formatted date            */
  243.     string[14] = file_age_ind(cdate, ctime);  /* add age ind.            */
  244.     string[15] = '\0';                  /* end of string                 */
  245.     return(string);                     /* for 'online' file             */
  246.     }
  247.   else
  248.     return(OFFLINE);                    /* for 'offline' file            */
  249.   }
  250.  
  251. /* -------------------------------------------------------------- */
  252. /* Transform file-time into string (hh:mm:ssa)                    */
  253. /* COUNTRY format hh:mm:ssa (12 hr USA) or hh-mm-ss  (24 hr EUR)  */
  254. /* -------------------------------------------------------------- */
  255. char *f_time(struct _FTIME tim)
  256. {
  257.   static char time[7] = {'\0'};        /* work buffer                    */
  258.   sprintf(time,"%2u%s%02u%c%c",
  259.           (c_info.fsTimeFmt==0 && tim.hours>12) ? tim.hours-12 : tim.hours,
  260.            c_info.szTimeSeparator,
  261.           tim.minutes,
  262.           ((c_info.fsTimeFmt==0) ? ((tim.hours>11) ? 'p' : 'a') : ' '),
  263.           '\0');
  264.   return(time);
  265.   }
  266.  
  267. /* ------------------------------ */
  268. /* Build pointer-array for sorts  */
  269. /* ------------------------------ */
  270. FILECHAIN **prep_sort(unsigned short int cnt,
  271.                               struct  _filechain *chn)
  272. {
  273.   unsigned short int  i;                /* counter                       */
  274.   FILECHAIN **dm;               /* pointer to file-sort array    */
  275.   FILECHAIN *ca;                /* pointer to fileinfo (chain)   */
  276.  
  277.   dm = (FILECHAIN **)malloc(cnt*sizeof(FILECHAIN *));
  278.   if (dm == NULL) {                     /* not enough memory             */
  279.     printf(MSG_MEM,PROGNAME);
  280.     exit(11);
  281.     }
  282.   ca = chn;                             /* ptr to first file-info        */
  283.   for (i=0; ca != NULL; i++) {          /* init sort array               */
  284.     dm[i] = ca;
  285.     ca = ca->next_element;
  286.     }
  287.   return(dm);
  288.   }
  289.  
  290. /* ====================================================== */
  291. /* Compare for sort on file-date/time + filename + area   */
  292. /* ====================================================== */
  293. int  sort_new(const void *p,
  294.               const void *q)
  295. {
  296.   int    rc;
  297.   unsigned long int ad,bd,td;
  298.   FILECHAIN *a,*b;
  299.  
  300.   a = *(FILECHAIN **)p;
  301.   b = *(FILECHAIN **)q;
  302.  
  303.   ad = file_time(a->wdate,a->wtime);
  304.   td = file_time(a->cdate,a->ctime);
  305.   if (ad < td)                          /* take latest date              */
  306.     ad = td;
  307.  
  308.   bd = file_time(b->wdate,b->wtime);
  309.   td = file_time(b->cdate,b->ctime);
  310.   if (bd < td)                          /* take latest date              */
  311.     bd = td;
  312.  
  313.   if (bd==ad) {                         /* equal timestamps              */
  314.     rc = strcmp(a->fname,b->fname);
  315.     if (rc)                             /* unequal filenames             */
  316.       return(rc);
  317.     else
  318.       return(comp_area(a->parea, b->parea));
  319.     }
  320.   else
  321.     return( (int)((bd<ad) ? -1 : +1) );
  322.   }
  323.  
  324. /* ========================================= */
  325. /* Compare for sort on filename + area-name  */
  326. /* ========================================= */
  327. int  sort_gbl(const void *p,
  328.               const void *q)
  329. {
  330.   int   rc;
  331.   FILECHAIN *a,*b;
  332.  
  333.   a = *(FILECHAIN **)p;
  334.   b = *(FILECHAIN **)q;
  335.   rc = strcmp(a->fname,b->fname);
  336.   if (rc)                               /* unequal filename              */
  337.     return(rc);
  338.   else
  339.     return(comp_area(a->parea, b->parea));
  340.   }
  341.  
  342. /* ======================================== */
  343. /* Compare for sort on areaname + filename  */
  344. /* ======================================== */
  345. int   sort_all(const void *p,
  346.                const void *q)
  347. {
  348.   int   rc;
  349.   FILECHAIN *a,*b;
  350.  
  351.   a = *(FILECHAIN **)p;
  352.   b = *(FILECHAIN **)q;
  353.   rc = comp_area(a->parea, b->parea);
  354.   if (rc)                               /* unequal areacode              */
  355.     return(rc);
  356.   else
  357.     return(strcmp(a->fname,b->fname));  /* filename                      */
  358.   }
  359.  
  360. /* ======================================================== */
  361. /* Compare for sort on areaname + file-date/time + filename */
  362. /* ======================================================== */
  363. int   sort_al2(const void *p,
  364.                    const void *q)
  365. {
  366.   int    rc;
  367.   unsigned long int ad,bd,td;
  368.   FILECHAIN *a,*b;
  369.  
  370.   a = *(FILECHAIN **)p;
  371.   b = *(FILECHAIN **)q;
  372.   rc = comp_area(a->parea, b->parea);
  373.   if (rc)                               /* unequal area-name             */
  374.     return(rc);
  375.   else {
  376.     ad = file_time(a->wdate,a->wtime);
  377.     td = file_time(a->cdate,a->ctime);
  378.     if (ad < td)                        /* take latest date              */
  379.       ad = td;
  380.     bd = file_time(b->wdate,b->wtime);
  381.     td = file_time(b->cdate,b->ctime);
  382.     if (bd < td)                        /* take latest date              */
  383.       bd = td;
  384.     if (bd!=ad)                         /* unequal date                  */
  385.       return( (int)((bd<ad) ? -1 : +1) );
  386.     else
  387.       return(strcmp(a->fname,b->fname));  /* filename                    */
  388.     }
  389.   }
  390.  
  391. /* ======================================================== */
  392. /* Compare for sort on areaname + FILES.BBS sequence number */
  393. /* ======================================================== */
  394. int  sort_akp(const void *p,
  395.               const void *q)
  396. {
  397.   int   rc;
  398.   FILECHAIN *a,*b;
  399.  
  400.   a = *(FILECHAIN **)p;
  401.   b = *(FILECHAIN **)q;
  402.   rc = comp_area(a->parea, b->parea);
  403.   if (rc)                               /* unequal areacode              */
  404.     return(rc);
  405.   else {
  406.     if (a->fseq != b->fseq)             /* unequal sequence number       */
  407.       return( (int)((a->fseq < b->fseq) ? -1 : +1) );
  408.     else
  409.       return(0);                        /* equal sequence number         */
  410.     }
  411.   }
  412.  
  413. /* =================================================== */
  414. /* Compare for sort on areaname + privilege + filename */
  415. /* No sort on privilege if below area-privilege.       */
  416. /* =================================================== */
  417. int  sort_fil(const void *p,
  418.               const void *q)
  419. {
  420.   int   rc;
  421.   FILECHAIN *a,*b;
  422.  
  423.   a = *(FILECHAIN **)p;
  424.   b = *(FILECHAIN **)q;
  425.   rc = comp_area(a->parea, b->parea);
  426.   if (rc)                               /* unequal areacode              */
  427.     return(rc);
  428.   else {
  429.     if (a->priv <= a->parea->priv &&    /* both within area priv         */
  430.         b->priv <= b->parea->priv)
  431.       return(strcmp(a->fname,b->fname));  /* sort on filename            */
  432.     else if (a->priv == b->priv)        /* same privilege                */
  433.       return(strcmp(a->fname,b->fname));  /* filename                    */
  434.     else
  435.       return( (int)(a->priv - b->priv) ); /* file priv                   */
  436.     }
  437.   }
  438.  
  439. /* ========================================= */
  440. /* Compare for sort on areaname of AREA-info */
  441. /* ========================================= */
  442. int  sort_summ(const void *p,
  443.                const void *q)
  444. {
  445.   return( comp_area((DOWNPATH  *)p, (DOWNPATH  *)q) );
  446.   }
  447.  
  448. /* ========================================= */
  449. /* Compare for sort on areaname of AREA-info */
  450. /* ========================================= */
  451. int   comp_area(DOWNPATH  *p,
  452.                 DOWNPATH  *q)
  453. {
  454.   int x,y;                              /* offsets in area_IN_EX         */
  455.  
  456.   switch(area_seq) {
  457.     case KEEPSEQ: return(p->anum - q->anum);
  458.                   break;
  459.     case ALPHA:   return(stricmp(p->name, q->name));
  460.                   break;
  461.     case INCLUDE: if (area_IN_EX == +1) {   /* areaINclude used          */
  462.                     for (x=0; strcmp(selected_area[x], EMPTY) &&
  463.                               stricmp(selected_area[x], p->name);
  464.                                x++);    /* just determine x              */
  465.                     for (y=0; strcmp(selected_area[y], EMPTY) &&
  466.                               stricmp(selected_area[y], q->name);
  467.                                y++);    /* just determine y              */
  468.                     if (x!=y) {         /* if not equal                  */
  469.                       return(x - y);    /* relative position             */
  470.                       break;            /* only if destinctive           */
  471.                       }
  472.                     }
  473.                                         /* may fall back to group-order  */
  474.     case GROUP:                         /* is default                    */
  475.     default:      return(stricmp(p->ename, q->ename));
  476.                   break;
  477.     }
  478.   }
  479.  
  480. /* ---------------------------- */
  481. /* Sort file-info pointer array */
  482. /* ---------------------------- */
  483. void psort(FILECHAIN **arr,
  484.            short int left,
  485.            short int right,
  486.            int (*comp)(const void *, const void *))
  487. {
  488.   int    asc,desc;
  489.   FILECHAIN *ref,*tmp;
  490.  
  491.   if ((right-left) < 1)                 /* too few elements              */
  492.     return;
  493.  
  494.   asc   = left;                         /* left 'wall'                   */
  495.   desc  = right;                        /* right 'wall'                  */
  496.   ref   = arr[(left + right)/2];        /* reference value               */
  497.  
  498.   do {
  499.     while (comp(&arr[asc],&ref) < 0)    /* move right                    */
  500.       asc++;
  501.     while (comp(&arr[desc],&ref) > 0)   /* move left                     */
  502.       desc--;
  503.     if (asc <= desc) {                  /* swap                          */
  504.       tmp = arr[desc];
  505.       arr[desc--] = arr[asc];
  506.       arr[asc++] = tmp;
  507.       }
  508.     } while (asc <= desc);
  509.  
  510.   if ((desc-left) < (right-asc)) {      /* sort smaller part first        */
  511.     if (left < desc)
  512.       psort(arr, left, desc, comp);
  513.     if (right > asc)
  514.       psort(arr, asc, right, comp);
  515.     }
  516.   else {
  517.     if (right > asc)
  518.       psort(arr, asc, right, comp);
  519.     if (left < desc)
  520.       psort(arr, left, desc, comp);
  521.     }
  522.   }
  523.  
  524. /* ============================================ */
  525. /* Compare for newest acquisition in ALL-list   */
  526. /* ============================================ */
  527. FILECHAIN *new_acq(FILECHAIN *a,
  528.                            FILECHAIN *b)
  529. {
  530.   long ad,bd,td;
  531.  
  532.   if (b==NULL)                          /* right might be not assigned   */
  533.     return(a);                          /* then return first             */
  534.   ad = file_time(a->wdate,a->wtime);
  535.   td = file_time(a->cdate,a->ctime);
  536.   if (ad < td)                          /* take latest date              */
  537.     ad = td;
  538.   bd = file_time(b->wdate,b->wtime);
  539.   td = file_time(b->cdate,b->ctime);
  540.   if (bd < td)                          /* take latest date              */
  541.     bd = td;
  542.   if (ad==bd)                           /* equal dates                   */
  543.     return(b);                          /* (either)                      */
  544.   else
  545.     return((ad>bd) ? a : b);            /* return most recent            */
  546.   }
  547.  
  548. /* ============================================================== */
  549. /* reformat file-date into long time-value like C time convention */
  550. /* ============================================================== */
  551. long int file_time(struct _FDATE fd,
  552.                    struct _FTIME ft)
  553. {
  554.   static int mon_tab[] = {0,31,59,90,120,151,181,212,243,273,304,334};
  555.                                       /* ignore leapyear February!       */
  556.   return( 86400L *
  557.            (((fd.year+10)*1461+1)/4 + mon_tab[fd.month-1] + fd.day - 1) +
  558.           ft.hours * 3600 + ft.minutes * 60 + ft.twosecs * 2 );
  559.   }
  560.  
  561. /* =================================== */
  562. /* Include a text file into a report.  */
  563. /* Output file is supposed to be open! */
  564. /* =================================== */
  565. void file_incl(FILE *pfo,               /* output file pointer           */
  566.                unsigned int fl)         /* filelist id                   */
  567. {
  568.   char  buf[MAXRCD];                    /* I/O buffer                    */
  569.   FILE *pfi;                            /* input file pointer            */
  570.  
  571.   if (lp[fl].incl_fspec != NULL) {      /* filespec present              */
  572.     if ((pfi = fopen(lp[fl].incl_fspec,"r")) != NULL) {
  573.       while (fgets(buf, MAXRCD, pfi) != NULL) { /* all records */
  574.         if (fl != P_FIL)                /* all but FILES.BBS */
  575.           fputs(buf, pfo);              /* "asis" */
  576.         else                            /* for FILES.BBS output */
  577.           fprintf(pfo,"%s %s", FILPREFX, buf);  /* special prefix */
  578.         }
  579.       fclose(pfi);
  580.       }
  581.     else {
  582.       if (oper_mode == VERBOSE)         /* report only in verbose mode   */
  583.         printf(MSG_TRL,lp[fl].incl_fspec);  /* file not included         */
  584.       }
  585.     }
  586.   }
  587.  
  588. /* --------------------------------------------------------------- */
  589. /* Produce file description parts for first and continuation lines */
  590. /* --------------------------------------------------------------- */
  591. void desc_part(FILE *pf,                /* output file pointer           */
  592.                char *desc,              /* complete description          */
  593.                unsigned int l1,         /* length 1st part of descr.     */
  594.                unsigned int l2,         /* length of subsequent parts    */
  595.                unsigned int fl)         /* report structure index        */
  596. {
  597.   unsigned int k,n;                     /* length of part of string      */
  598.   char *p;                              /* pointer to output string      */
  599.  
  600.   if (k = strsubw(desc, &p, l1)) {      /* length (max = l1)             */
  601.     if (lp[fl].wrapflag != WRAP) {      /* truncate                      */
  602.       n = strlen(desc);                 /* total string length           */
  603.       k = (l1 > n) ? n : l1;            /* shortest of l1 and n          */
  604.       }
  605.     fprintf(pf,"%-.*s\n", k, p);        /* (1st part of) string          */
  606.     while (k>0 && lp[fl].wrapflag==WRAP)  /* more parts                  */
  607.       if (k = strsubw(p+k, &p, l2))     /* subseq. part                  */
  608.         fprintf(pf,"%*s%-.*s\n", 79-l2,"", k, p); /* 2nd+ descr parts    */
  609.     }
  610.   }
  611.  
  612. /* ============================================================== */
  613. /* routine to select a substring while skipping leading blanks    */
  614. /*         and ending within the boundaries on a word-end.        */
  615. /*         Truncate if single word. Respect NL as end of string.  */
  616. /*         Return strlen,  0 for NULL-pointer.                    */
  617. /* ============================================================== */
  618. short int strsubw(char *a,
  619.                   char **b,
  620.                   short int m)
  621. {
  622.   short int i,j,k;                      /* counters                      */
  623.  
  624.   if (a==NULL)                          /* NULL pointer                  */
  625.     return(0);                          /* no string                     */
  626.  
  627.   for (i=0; a[i] == ' '; ++i);          /* skip leading blanks           */
  628.   a = *b = a+i;                         /* offset to first non-blank char*/
  629.   for (i=0; a[i] != '\0' && a[i]!='\r' && a[i]!='\n'; ++i); /* search end*/
  630.   if (i==0)                             /* nothing left                  */
  631.     return(0);                          /* end!                          */
  632.  
  633.   for (k=0; k<m && k<i; ++k);           /* maximum substring             */
  634.   if (k<i) {                            /* there is more in string       */
  635.     if (a[k]==' ' || a[k]=='\r' || a[k]=='\n' || a[k]=='\0');  /*word end*/
  636.     else {
  637.       for (j=k-1; j>0 && a[j]!=' '; --j); /* try to remove 'split' word  */
  638.       if (j>0)                          /* any space found?              */
  639.         k = j;                          /* OK, else split!               */
  640.       }
  641.     }
  642.   for (; k>0 && a[k-1] == ' '; --k);    /* remove trailing blanks        */
  643.   return(k);                            /* return length of substring    */
  644.                                         /* b contains start-point        */
  645.   }
  646.  
  647. /* ====================================================== */
  648. /* Function to locate next non-blank character in buffer. */
  649. /* Returns pointer to word or NULL-ptr if no next word.   */
  650. /* ====================================================== */
  651. char *next_word(char *line)
  652. {
  653.   unsigned int i;
  654.  
  655.   for (i=0; line[i]!=' '  &&            /* skip non-blanks               */
  656.             line[i]!='\r' &&
  657.             line[i]!='\n' &&
  658.             line[i]!='\0'; ++i);
  659.   for (   ; line[i]==' '; ++i);         /* skip blanks                   */
  660.   if (line[i] != '\0' &&
  661.       line[i] != '\r' &&
  662.       line[i] != '\n')
  663.     return(line+i);                     /* next word found               */
  664.   else
  665.     return(NULL);                       /* NULL if no next word          */
  666.   }
  667.  
  668. /* =========================================== */
  669. /* Function to make ASCIIZ string of ONE word. */
  670. /* =========================================== */
  671. char *asciiz(char *buf)
  672. {
  673.   unsigned short int i;
  674.  
  675.   for (i=0; buf[i] != ' '  &&           /* end copy at first blank       */
  676.             buf[i] !='\r'  &&           /* CR character                  */
  677.             buf[i] !='\n'  &&           /* LF character                  */
  678.             buf[i] !='\0'; ++i)         /* or end of string              */
  679.     buf2[i] = buf[i];                   /* copy                          */
  680.   buf2[i] = '\0';                       /* end of string                 */
  681.   return(buf2);                         /* pointer to ASCIIZ string      */
  682.   }
  683.  
  684. /* ============================================ */
  685. /* Function to strip off AVATAR codes in string */
  686. /* ============================================ */
  687. char *strava(char *buf)
  688. {
  689.   unsigned short int i, j, k, x;        /* counters                      */
  690.  
  691.   k = strlen(buf);                      /* length of source string       */
  692.   for (i=j=0; i < k; ) {                /* whole input string            */
  693.     switch(buf[i]) {
  694.       case AVA_G:
  695.       case AVA_H:
  696.       case AVA_I:
  697.       case AVA_L: ++i; break;
  698.       case AVA_Y: for (x=0; x<buf[i+2]; x++)
  699.                     buf2[j++] = buf[i+1];      /* repeat                 */
  700.                   i += 3;
  701.                   break;
  702.       case AVA_V: switch(buf[i+1]) {
  703.                     case AVA_B:
  704.                     case AVA_C:
  705.                     case AVA_D:
  706.                     case AVA_E:
  707.                     case AVA_F:
  708.                     case AVA_G:
  709.                     case AVA_I:
  710.                     case AVA_N: i += 2; break;
  711.                     case AVA_A: i += 3; break;
  712.                     case AVA_H: i += 4; break;
  713.                     case AVA_L: i += 5; break;
  714.                     case AVA_M: i += 6; break;
  715.                     case AVA_J:
  716.                     case AVA_K: i += 7; break;
  717.                     case AVA_Y: i += 2; break;
  718.                     default: buf2[j++]=buf[i++]; break;
  719.                     }
  720.                   break;
  721.       case '-':   (i==0) ? i++ : (buf2[j++] = buf[i++]);
  722.                   break;
  723.       default:    buf2[j++] = buf[i++];
  724.                   break;
  725.       }
  726.     }
  727.   buf2[j] = '\0';                       /* end of string                 */
  728.   return(buf2);                         /* pointer to ASCIIZ string      */
  729.   }
  730.  
  731. /* ========================================================= */
  732. /* creates filecount and bytecount per area within privilege */
  733. /*   and pointer to most recent file in area                 */
  734. /* returns total filecount all area's within priv.           */
  735. /* should be run before calling other count_functions below. */
  736. /* ========================================================= */
  737. unsigned int preproc_area(DOWNPATH  *area,
  738.                           FILECHAIN **dm,
  739.                           short int priv)
  740. {
  741.   unsigned int i;                       /* counter                       */
  742.   unsigned int fpc;                     /* total filecount within priv   */
  743.  
  744.   for (i=0; i<area_total_count; i++) {  /* all area's in array           */
  745.     area[i].file_count = 0;             /* init filecount per area       */
  746.     area[i].byte_count = 0L;            /* init bytecount per area       */
  747.     area[i].newest = NULL;              /* null most-recent              */
  748.     }
  749.   for (i=0; i<file_total_count; i++) {  /* scan file-chain               */
  750.     if (dm[i]->priv <= priv  &&         /* file within privilege         */
  751.         dm[i]->fname[0] != '\0') {      /* not a 'comment' entry         */
  752.       dm[i]->parea->file_count++;       /* increment area filecount      */
  753.       dm[i]->parea->byte_count += dm[i]->size; /* add filesize           */
  754.       dm[i]->parea->newest = new_acq(dm[i], dm[i]->parea->newest);
  755.       }
  756.     }
  757.   fpc = 0;                              /* init total filecount          */
  758.   for (i=0; i<area_total_count; i++)    /* all area's in array           */
  759.     fpc += area[i].file_count;          /* sum of area file_counts       */
  760.   return(fpc);                          /* return total file_count       */
  761.   }
  762.  
  763. /* =========================================== */
  764. /* count areas within privilege for top-header */
  765. /* works only correctly after count_priv_files */
  766. /* =========================================== */
  767. unsigned int count_areas(DOWNPATH  *area,
  768.                           short int p)
  769. {
  770.   unsigned int i,j;
  771.  
  772.   for (i=j=0; i<area_total_count; i++)  /* whole area-array              */
  773.     if (area[i].priv <= p       &&      /* area within privilege         */
  774.         area[i].file_count > 0)         /* any files                     */
  775.       ++j;                              /* add to area_count             */
  776.   return(j);                            /* return areas within priv.     */
  777.   }
  778.  
  779. /* ================================================ */
  780. /* (re-)Count files within privilege for top-header */
  781. /*   (file_priv_count already returns file-count)   */
  782. /* Works only correctly after preproc_area().       */
  783. /* ================================================ */
  784. unsigned int count_files(DOWNPATH  *area)
  785. {
  786.   unsigned int i,f;
  787.  
  788.   for (i=f=0; i<area_total_count; i++)  /* scan area array               */
  789.     f += area[i].file_count;            /* add to file_count             */
  790.   return(f);                            /* return files within priv.     */
  791.   }
  792.  
  793. /* =========================================== */
  794. /* count bytes within privilege for top-header */
  795. /* works only correctly after count_priv_files */
  796. /* =========================================== */
  797. unsigned long int count_bytes(DOWNPATH _HUGE *area)
  798. {
  799.   unsigned short int i;                 /* counter                       */
  800.   unsigned long b;                      /* byte count                    */
  801.  
  802.   for (i=0,b=0L; i<area_total_count; i++)  /* scan area array            */
  803.     b += area[i].byte_count;            /* add to byte_count             */
  804.   return(b);                            /* return bytes within priv.     */
  805.   }
  806.  
  807. /* ==================================== */
  808. /* insert title lines from DOWNSORT.CFG */
  809. /* ==================================== */
  810. void insert_title(FILE *pf,
  811.                char *title[],
  812.                int  ipf)                /* if not zero: call stripf()    */
  813. {
  814.   int i;
  815.  
  816.   for (i=0; i<MAXTIT && title[i]!=NULL; ++i)  /* all lines               */
  817.     fprintf(pf,"%s\n",
  818.                (ipf) ? stripf(title[i]) : title[i]);  /* 1 line          */
  819.   }
  820.  
  821. /* ============================================================ */
  822. /* insert separator line, variable number, separated by 1 blank */
  823. /* ============================================================ */
  824. void sep_line(FILE *pf,                 /* output file pointer           */
  825.               char c,                   /* separator char                */
  826.               unsigned short int size,...)  /* length(s)                 */
  827. {
  828.   char buf[80];                         /* work buffer                   */
  829.   unsigned short int k,ll;              /* offset and size               */
  830.   va_list mk;                           /* argument marker               */
  831.  
  832.   memset(buf, c, 79);                   /* whole line buffer             */
  833.   buf[79] = '\0';                       /* end of string                 */
  834.   va_start(mk, size);                   /* start variable arg processing */
  835.   k = size;                             /* take first                    */
  836.   while (k < 80) {                      /* all parts of line             */
  837.     buf[k++] = ' ';                     /* replace sepline char by space */
  838.     ll = va_arg(mk, unsigned short int);  /* next argument               */
  839.     if (ll > 0)                         /* more in list                  */
  840.       k += ll;                          /* add to offset                 */
  841.     else {
  842.       buf[k] = '\0';                    /* end of string                 */
  843.       break;                            /* escape from while-loop        */
  844.       }
  845.     }
  846.   fprintf(pf, "%-s\n", buf);            /* output                        */
  847.   va_end(mk);                           /* end variable argument list    */
  848.   }
  849.  
  850. /* ================== */
  851. /* insert BLOCK title */
  852. /* =================== */
  853. void block_title(FILE *pf,
  854.                short int n,
  855.                char *title,
  856.                unsigned int listfile)
  857. {
  858.   unsigned short int i;
  859.  
  860.   for (i=0; i<title_lines[lp[listfile].tfont]; ++i)   /* whole title     */
  861.     fprintf(pf, "%s\n", strnblk(title, n, lp[listfile].tfont,i));
  862.   }
  863.  
  864. /* ================================== */
  865. /* some marketing below every report! */
  866. /* ================================== */
  867. void signature(FILE *pf,
  868.                char *now)
  869. {
  870.   static char *mode[] = {"DOS","OS/2"};
  871.  
  872.   fprintf(pf,"\n\n  ");
  873.   sep_line(pf, '═', 73, 0);
  874.   fprintf(pf,"   This list was created with %s %c.%c%c (%s-bits)  -  by %s\n"
  875.              "                  on %s under %s %d.%d\n  ",
  876.                 PROGNAME,VERSION,SUBVERS,SUFFIX,
  877. #ifndef __32BIT__
  878.                 "16",
  879. #else
  880.                 "32",
  881. #endif
  882.                 AUTHOR, now,
  883.                 mode[_osmode & 1],
  884.                 _osmajor/( (_osmode) ? 10 : 1),
  885.                 _osminor/10);
  886.   sep_line(pf, '═', 73, 0);
  887.   fprintf(pf, "\n");                    /* extra space                   */
  888.   }
  889.  
  890. /* ================ */
  891. /* HELP information */
  892. /* ================ */
  893. void show_help(void)
  894. {
  895.   static char *help[] = {
  896.    "Syntax:  DOWNSORT  [commandline-parameters]\n\n",
  897.    "@filespec   - Filespec of Downsort's processing parameters\n",
  898.    "BBS[:p]     - Make BBS-list ───┐\n",
  899.    "NEW[:pp]    - Make NEW-list(s) │\n",
  900.    "EMI[:pp]    - Make EMI-list(s) │ │for 1 or more privileges, where:\n",
  901.    "ALL[:pp]    - Make ALL-list(s) ├─┤ p  = first letter of privilege\n",
  902.    "IPF[:pp]    - Make IPF-list(s) │ │ pp = max 10 privilege letters\n",
  903.    "IP2[:pp]    -  └-for OS/2 2.0+│ │      (N=Normal, P=Privil, etc)\n",
  904.    "GBL[:pp]    - Make GBL-list(s) │\n",
  905.    "OK[:pp]     - Make OKFile(s)   │\n",
  906.    "DUP[:p]     - Make DUP-list ───┘\n",
  907.    "ORP         - Make ORP-list (if ORPHANS detected)\n",
  908.    "FIL[:fpath] - (re-)Create FILES.BBS files [in directory 'fpath']\n",
  909.    "nnn[P]      - Limit NEW- and BBS-list by number, or age if P=D|W|M\n",
  910.    "-T|W        - Long file descriptions to be Truncated or Wrapped\n",
  911.    "-A|D|K      - Sort files Alphabetically, on Date, or Keep in FILES.BBS-seq.\n",
  912.    "-H|Q|V      - Display this HELP-screen, or run Quietly or Verbose\n",
  913.    "-X          - eXclude privilege indications in the lists\n",
  914.    "───────────\n",
  915.    "Commandline parameters override program and configuration-file values.\n"
  916.    "Read documentation and sample configuration file for details and defaults.\n",
  917.    NULL};
  918.  
  919.   int i;
  920.   for (i=0; help[i]; ++i)
  921.     printf(help[i]);
  922.   exit(1);
  923.   }
  924.  
  925.