home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / DLMST260.ZIP / DLMASTER.C next >
C/C++ Source or Header  |  1993-08-18  |  65KB  |  1,941 lines

  1. /**********************************************************************
  2. *  DLMASTER version 2.60  - Make Downloadable List of RBBS files      *
  3. *  compiled with Borland C/C++ v 2.0  using Large memory model        *
  4. *  Copyright (c) 1990-93 by Bob Hampton                               *
  5. *  S3-Tech BBS (703) 451-9509                                         *
  6. *  all rights reserved                                                *
  7. **********************************************************************/
  8.  
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <alloc.h>
  13. #include <dir.h>
  14. #include <dos.h>
  15. #include <conio.h>
  16. #include <process.h>
  17. #include <io.h>
  18. #include <mem.h>
  19. #include <stdarg.h>
  20. #include "doswdw.h"
  21.  
  22. #define FALSE 0
  23. #define TRUE !FALSE
  24. #define OFF 0
  25. #define ON !OFF
  26. #define MAXLINE 161        /* - maximum length of FMS file line   */
  27. #define MAXCATS 10        /* - maximum number of codes/category  */
  28. #define MAXFMS 50        /* - maximum number of FMS directories */
  29. #define SINGLE 1        /* - used in windows to specify single */
  30. #define DOUBLE 2                /*   or double-line borders            */
  31. #define COLOR 1            /* - used for color display mode       */
  32. #define BW 0                /* -  "    "   b&w     "      "        */
  33.  
  34. typedef struct ltag        /* structure for linked-list created   */
  35. {                /* in initial read of FMS file(s):     */
  36.     char lname[13];            /* - name of file                   */
  37.     long lsize,            /* - size of file (in bytes)        */
  38.          ldate,            /* - date of file                   */
  39.          lpos;            /* - position of description in FMS */
  40.     int  lseclvl,            /* - security level needed          */
  41.          lfms;            /* - FMS array index                */
  42.     char lcode[4];            /* - category code of file          */
  43.     struct ltag *lnext;        /* - pointer to next node           */
  44. } LDATA;
  45.  
  46.  
  47. typedef struct            /* structure for temporary files.  Same as  */
  48. {                /* LDATA but without category code or next  */
  49.     char tname[13];        /* node pointer.                            */
  50.     long tsize,
  51.          tdate,
  52.          tpos;
  53.     int  tseclvl,
  54.          tfms;
  55. } TDATA;
  56.  
  57. typedef    struct ptag        /* structure for print buffer   */
  58. {                /*    linked-list.  Includes:   */
  59.     char prtline[MAXLINE];    /*  - line buffer               */
  60.     struct ptag *pnext;    /*  - pointer to next node      */
  61. } PDATA;
  62.  
  63.  
  64. typedef struct            /* structure for config record: */
  65. {
  66.     char fmsname[MAXPATH],        /* - FMS filename               */
  67.          dcatname[MAXPATH],        /* - DIR.CAT filename           */
  68.          outname[MAXPATH],        /* - output file path/name      */
  69.          bbsname[65],        /* - name of BBS                */
  70.          sorttype,            /* - A)lpha or D)ate sort       */
  71.          revsort,            /* - flag for reverse sort      */
  72.          hdrname[MAXPATH],        /* - name of header file        */
  73.          ftrname[MAXPATH],        /* - name of footer file        */
  74.          zippath[MAXPATH];        /* - path to compression util   */
  75.     int  minseclvl,            /* - minimum security level to process  */
  76.          maxseclvl;            /* - maximum    "       "    "    "     */
  77. } CNFGREC;
  78.  
  79. typedef struct dtag        /* structure of linked-list for */
  80. {                /* info from DIR.CAT file:      */
  81.     char dname[9],            /* - name of directory          */
  82.          dcode[MAXCATS][4],        /* - category code              */
  83.          ddesc[65];            /* - directory description      */
  84.     struct dtag *dnext;        /* - pointer to next node       */
  85. } DCATINFO;
  86.  
  87.  
  88. typedef struct ctag        /* structure of linked-list for valid */
  89. {                /* category codes, includes:          */
  90.     char code[4];        /*    - code                        */
  91.     struct ctag *cnext;    /*    - pointer to next node        */
  92. } CATCODE;
  93.  
  94.  
  95. typedef struct            /* structure for array of info     */
  96. {                /* about FMS file(s):              */
  97.     char name[MAXPATH];        /* - FMS filename                  */
  98.     int top;            /* - if \FMS TOP used in this file */
  99. } FMSFILE;
  100.  
  101. typedef struct             /* structure containing info about */
  102. {                /* current window:                 */
  103.     int left,            /* - left coordinate               */
  104.         top,            /* - top coordinate                */
  105.         right,            /* - right coordinate              */
  106.         bottom,            /* - bottom coordinate             */
  107.         fore,            /* - normal foreground color       */
  108.         back,            /* - normal background color       */
  109.         hifore,            /* - hilight foreground color      */
  110.         hiback,            /* - hilight background color      */
  111.         bstyle,            /* - border style                  */
  112.         bcolor,            /* - border color                  */
  113.         shadow;            /* - flag for 3-D shadow           */
  114. } WININFO;
  115.  
  116. void  make_wallpaper   (unsigned char c, int fore, int back);
  117. void  make_window      (WININFO *win);
  118. void  read_cnfgfile    (char *cnfgname, CNFGREC *crec, WININFO *win);
  119. void  read_dircatfile  (char *dcatname, DCATINFO **dfirst, WININFO *win);
  120. int   create_cats      (DCATINFO *dnode, CATCODE **cfirst);
  121. void  make_temps       (CATCODE *cnode, WININFO *win);
  122. void  searchfms        (char *fmsname, FMSFILE *fmsdata, int *linelength);
  123. void  readfms          (FMSFILE *fmsdata, int num_cats, WININFO *win, CATCODE *cfirst, int *totalfiles, long *totalbytes, int *zip_fms_index, long *zip_fms_pos, char *zipname, int minseclvl, int maxseclvl);
  124. void  make_sortfiles   (LDATA *lnode[], WININFO *win, CATCODE *cnode);
  125. void  process_list     (DCATINFO *dnode, CATCODE *cnode, CNFGREC *crec, int linelength, int totalfiles, long totalbytes, FMSFILE *fmsdata, WININFO *win);
  126. void  print_buffer     (FILE *outfile, PDATA *pnode);
  127. void  print_listheader (CNFGREC *crec, FILE *outfile);
  128. void  print_dirheader  (DCATINFO *dnode, int tempfiles, long tempbytes, FILE *outfile);
  129. void  print_listfooter (int totalfiles, long totalbytes, FILE *outfile);
  130. void  printfile        (char *filename, char *message, FILE *outfile);
  131. void  make_zip         (char *zippath, char *textname, WININFO *win);
  132. int   afcompare        (TDATA huge **elem1, TDATA huge **elem2);
  133. int   arcompare        (TDATA huge **elem1, TDATA huge **elem2);
  134. int   dfcompare        (TDATA huge **elem1, TDATA huge **elem2);
  135. int   drcompare        (TDATA huge **elem1, TDATA huge **elem2);
  136. void  cursor           (int cmnd);
  137. int   check_catcode    (char *code, CATCODE *cnode);
  138. void  fail             (char *message, char *filename);
  139. int   set_colors       (WININFO *header, WININFO *center, WININFO *bottom);
  140. void  clear_status     (WININFO *win);
  141.  
  142. extern unsigned _stklen = 49152;    /* set stack size to 48K           */
  143.  
  144. void main (int argc, char **argv)
  145. {
  146.     CNFGREC crec;            /* DLMASTER config file info       */
  147.     DCATINFO *dfirst = NULL;    /* head pointer for directory list */
  148.     CATCODE *cfirst = NULL;        /*  "      "     "  catcodes   "   */
  149.     FMSFILE fmsdata[MAXFMS];    /* array of FMS file info          */
  150.     char cnfgname[MAXPATH];        /* DLMASTER config file path/name  */
  151.     int linelength = 0,        /* FMS line length                 */
  152.         totalfiles,            /* total number of files           */
  153.         num_cats,            /* number of categories            */
  154.         dispmode,            /* current display mode            */
  155.         zip_fms_index,        /* index to FMS file containing
  156.                        description of Zip file         */
  157.         i;                /* work variable                   */
  158.     long totalbytes,        /* total number of bytes           */
  159.          zip_fms_pos;        /* byte position of Zipfile descr.
  160.                        in FMS file containing descr.   */
  161.     WININFO header,            /* info for top window             */
  162.         center,            /*  "    "  center "               */
  163.         bottom;            /*  "    "  bottom "               */
  164.  
  165.     switch (argc)
  166.     {
  167.         case 1:            /* no config file specified in command line */
  168.             strcpy (cnfgname, "DLMASTER.CFG");
  169.             break;
  170.         case 2:            /* config file specified in command line */
  171.             strcpy (cnfgname, *(argv + 1));
  172.             break;
  173.         default:
  174.             fprintf (stderr, "\nInvalid command line\n\n");
  175.             fprintf (stderr, "Usage: DLMASTER <config file>\n");
  176.             exit(1);
  177.     }
  178.  
  179.     /***************************************************
  180.     *  determine the display mode (color or b&w), and  *
  181.     *  set the colors for the windows accordingly.     *
  182.     ***************************************************/
  183.     dispmode = set_colors (&header, ¢er, &bottom);
  184.  
  185.     /************************************************************
  186.     *  set text to white-on-black, clear the screen, paint the  *
  187.     *  wallpaper, create the top window, and display the title  *
  188.     ************************************************************/
  189.     cursor (OFF);
  190.     textattr (7);
  191.     clrscr();
  192.     if (dispmode == COLOR)
  193.         make_wallpaper('.', LIGHTGRAY, BLUE);
  194.     make_window (&header);
  195.     cputs ("  DLMASTER version 2.60                       (c) 1990-93 by Bob Hampton");
  196.  
  197.     /**********************************
  198.     *  create the bottom window, and  *
  199.     *  read the DLMASTER config file  *
  200.     **********************************/
  201.     make_window (&bottom);
  202.     read_cnfgfile (cnfgname, &crec, &bottom);
  203.  
  204.     /**********************************
  205.     *  create the middle window, and  *
  206.     *  read the DIR.CAT file.  Create *
  207.     *  list of categories, and create *
  208.     *  the temp files.                *
  209.     **********************************/
  210.     make_window (¢er);
  211.     read_dircatfile (crec.dcatname, &dfirst, ¢er);
  212.     num_cats = create_cats (dfirst, &cfirst);
  213.     make_temps (cfirst, ¢er);
  214.  
  215.     /****************************************
  216.     *  create array of info on FMS file(s)  *
  217.     ****************************************/
  218.     searchfms (crec.fmsname, fmsdata, &linelength);
  219.  
  220.     /***************************************************
  221.     *  read the FMS file(s) and create the temp files  *
  222.     ***************************************************/
  223.     readfms (fmsdata, num_cats, ¢er, cfirst, &totalfiles, &totalbytes, &zip_fms_index, &zip_fms_pos, crec.outname, crec.minseclvl, crec.maxseclvl);
  224.  
  225.     /*************************************
  226.     *  create the output text file from  *
  227.     *  the temp and FMS files            *
  228.     *************************************/
  229.     process_list (dfirst, cfirst, &crec, linelength,
  230.               totalfiles, totalbytes, fmsdata, ¢er);
  231.  
  232.     /***************************************
  233.     *  create the ZIP file, if requested,  *
  234.     *  deleting the text file afterwards   *
  235.     ***************************************/
  236.     if (strcmp (crec.zippath, ""))
  237.         make_zip (crec.zippath, crec.outname, ¢er);
  238.  
  239.     /****************************************
  240.     *  set screen to white-on-black, clear  *
  241.     *  the screen, and restore the cursor   *
  242.     ****************************************/
  243.     textattr (7);
  244.     window (1,1,80,25);
  245.     clrscr();
  246.     cursor (ON);
  247. }
  248.  
  249.  
  250.  
  251. void read_cnfgfile (char *cnfgname, CNFGREC *crec, WININFO *win)
  252. {
  253. /*******************************************************************
  254. *  This function will read the config file specified in *cnfgname  *
  255. *  and modify the config file record *crec to contain information  *
  256. *  from the configuration file.                                    *
  257. *******************************************************************/
  258.  
  259.     FILE *cnfgfile;            /* pointer to config file    */
  260.     char buffer[MAXLINE];        /* buffer for file read      */
  261.  
  262.     /*********************
  263.     *  open config file  *
  264.     *********************/
  265.     if ((cnfgfile = fopen (cnfgname, "r")) == NULL)
  266.         fail ("Error opening config file", cnfgname);
  267.  
  268.     /********************************
  269.     *  read name of first FMS file  *
  270.     ********************************/
  271.     fgets (buffer, MAXLINE, cnfgfile);
  272.     strcpy (crec->fmsname, strtok (buffer, "\n"));
  273.  
  274.     /******************************
  275.     *  read name of DIR.CAT file  *
  276.     ******************************/
  277.     fgets (buffer, MAXLINE, cnfgfile);
  278.     strcpy (crec->dcatname, strtok (buffer, "\n"));
  279.  
  280.     /*****************************
  281.     *  read name of output file  *
  282.     *****************************/
  283.     fgets (buffer, MAXLINE, cnfgfile);
  284.     strcpy (crec->outname, strtok (buffer, "\n"));
  285.  
  286.     /*********************
  287.     *  read name of BBS  *
  288.     *********************/
  289.     fgets (buffer, MAXLINE, cnfgfile);
  290.     strcpy (crec->bbsname, strtok (buffer, "\n"));
  291.  
  292.  
  293.     /****************************
  294.     *  read sort type (A or D)  *
  295.     ****************************/
  296.     crec->sorttype = fgetc (cnfgfile);
  297.     fgetc (cnfgfile);
  298.  
  299.     /***************************
  300.     *  read reverse sort flag  *
  301.     ***************************/
  302.     crec->revsort = fgetc (cnfgfile);
  303.     fgetc (cnfgfile);
  304.  
  305.     /*****************************************
  306.     *  optionally, read name of header file  *
  307.     *****************************************/
  308.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  309.         strcpy (crec->hdrname, strtok (buffer, "\n"));
  310.     else
  311.         strcpy (crec->hdrname, "");
  312.  
  313.     /*****************************************
  314.     *  optionally, read name of footer file  *
  315.     *****************************************/
  316.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  317.         strcpy (crec->ftrname, strtok (buffer, "\n"));
  318.     else
  319.         strcpy (crec->ftrname, "");
  320.  
  321.     /********************************
  322.     *  optionally, read PKZIP path  *
  323.     ********************************/
  324.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  325.         strcpy (crec->zippath, strtok (buffer, "\n"));
  326.     else
  327.         strcpy (crec->zippath, "");
  328.  
  329.     /**********************************************
  330.     *  optionally, read security screening level  *
  331.     **********************************************/
  332.     if (fgets (buffer, MAXLINE, cnfgfile) != NULL && *buffer != '\n')
  333.     {
  334.         crec->minseclvl = atoi (strtok (buffer, ","));
  335.         crec->maxseclvl = atoi (strtok (NULL, ""));
  336.     }
  337.     else
  338.     {
  339.         crec->minseclvl = 0;
  340.         crec->maxseclvl = 32767;
  341.     }
  342.  
  343.     /***********************************
  344.     *  close config file, and display  *
  345.     *  runtime parameters in window    *
  346.     ***********************************/
  347.     fclose (cnfgfile);
  348.     gotoxy (3,1);
  349.     cputs ("sort type - ");
  350.     textcolor (win->hifore);
  351.     if (toupper (crec->sorttype) == 'A')
  352.         cputs ("Alpha");
  353.     else
  354.         cputs ("Date");
  355.  
  356.     textcolor (win->fore);
  357.     gotoxy (30,1);
  358.     cputs ("reverse sort - ");
  359.     textcolor (win->hifore);
  360.     if (toupper (crec->revsort) == 'Y')
  361.         cputs ("Yes");
  362.     else
  363.         cputs ("No");
  364.  
  365.     textcolor (win->fore);
  366.     gotoxy (59,1);
  367.     cputs ("auto ZIP - ");
  368.     textcolor (win->hifore);
  369.     if (strcmp (crec->zippath, ""))
  370.         cputs ("Yes");
  371.     else
  372.         cputs ("No");
  373.     textcolor (win->fore);
  374. }
  375.  
  376.  
  377.  
  378. void read_dircatfile (char *dcatname, DCATINFO **dfirst, WININFO *win)
  379. {
  380. /*********************************************************************
  381. *  This function will read the DIR.CAT file specified in *dcatname   *
  382. *  and will modify the pointer *dfirst to point to the first node    *
  383. *  in the linked-list of info about the file categories.   It will   *
  384. *  also create the temp files for the categories using the category  *
  385. *  name, and will save 0 at the beginning of each file as the count  *
  386. *  for the number of files in that category.                         *
  387. *********************************************************************/
  388.  
  389.     FILE *dirfile;            /*  pointer to DIR.CAT file   */
  390.     DCATINFO *dnode,        /*  pointer to current node   */
  391.          *dprev;        /*    "     "  previous  "    */
  392.     char buffer[MAXLINE],        /*  buffer for file read      */
  393.          tempcat[65],        /*  work buffer for cat desc  */
  394.          *temp;            /*  work pointer              */
  395.     int  i;                /*  work variable             */
  396.  
  397.     /********************************
  398.     *  display directory file name  *
  399.     ********************************/
  400.     gotoxy (16,3);
  401.     cputs ("Reading directory file: ");
  402.     textattr (win->hifore + (win->hiback << 4));
  403.     cprintf ("%s", dcatname);
  404.     textattr (win->fore + (win->back << 4));
  405.     clreol();
  406.  
  407.     /********************************************
  408.     *  open DIR.CAT file, allocate first node,  *
  409.     *  and set head of linked-list              *
  410.     ********************************************/
  411.     if ((dirfile = fopen (dcatname, "r")) == NULL)
  412.         fail ("Error opening category file", dcatname);
  413.     dnode = (DCATINFO far *) farmalloc ( (unsigned long) sizeof (DCATINFO));
  414.     if (dnode == NULL)
  415.         fail ("Unable to create","dnode");
  416.     *dfirst = dnode;
  417.  
  418.     /***************************************
  419.     *  for each line in the DIR.CAT file,  *
  420.     ***************************************/
  421.     while (fgets (buffer, MAXLINE, dirfile) != NULL)
  422.     {
  423.         /******************************************
  424.         *  get directory name from buffer, strip  *
  425.         *  next seperating comma.                 *
  426.         ******************************************/
  427.         strcpy (dnode->dname, strtok (buffer, "\""));
  428.         temp = strtok (NULL, "\"");
  429.  
  430.         /**************************************
  431.         *  get category code(s) from buffer,  *
  432.         *  and strip next separating comma.   *
  433.         **************************************/
  434.         strcpy (tempcat, strtok (NULL, "\""));
  435.         temp = strtok (NULL, "\"");
  436.  
  437.         /******************************************
  438.         *  get directory description from buffer  *
  439.         ******************************************/
  440.         strcpy (dnode->ddesc, strtok (NULL, "\""));
  441.  
  442.  
  443.         /*********************************************
  444.         *  separate category code(s) from tempcat[]  *
  445.         *********************************************/
  446.         i = 0;
  447.         strcpy (dnode->dcode[i++], strtok (tempcat, ", "));
  448.         while (i < MAXCATS && (temp = strtok (NULL, ", ")) != NULL)
  449.             strcpy (dnode->dcode[i++], temp);
  450.         if (i != MAXCATS)
  451.             strcpy (dnode->dcode[i], "###");
  452.  
  453.         /*****************************************************
  454.         *  create the next node, set previous node pointer   *
  455.         *  to the current node, and set the current pointer  *
  456.         *  to new node                                       *
  457.         *****************************************************/
  458.         dnode->dnext = (DCATINFO far *) farmalloc ( (unsigned long) sizeof (DCATINFO));
  459.         if (dnode->dnext == NULL)
  460.             fail ("Unable to create","dnode->dnext");
  461.         dprev = dnode;
  462.         dnode = dnode->dnext;
  463.     }
  464.  
  465.     /*******************************************************
  466.     *  set previous node's pointer-to-next to NULL, free   *
  467.     *  the unneeded node from memory, close DIR.CAT file,  *
  468.     *  and return the number of categories                 *
  469.     *******************************************************/
  470.     dprev->dnext = NULL;
  471.     farfree (dnode);
  472.     fclose (dirfile);
  473. }
  474.  
  475.  
  476.  
  477. int create_cats (DCATINFO *dnode, CATCODE **cfirst)
  478. {
  479. /***********************************************************************
  480. *  This function will create a linked-list of valid category codes by  *
  481. *  scanning through the dcodes in the linked-list of dnode info.  It   *
  482. *  will eliminate any duplicate codes, making a list we can use for    *
  483. *  tempfile maintenance.                                               *
  484. ***********************************************************************/
  485.  
  486.     CATCODE *cnode = NULL,
  487.         *cprev = NULL;
  488.     int catfound = FALSE,
  489.         num_cats = 0,
  490.         i;
  491.  
  492.     /*********************************
  493.     *  for each node in linked-list  *
  494.     *  of DIR.CAT entries            *
  495.     *********************************/
  496.     while (dnode)
  497.     {
  498.         /****************************
  499.         *  scan each category code  *
  500.         ****************************/
  501.         for (i = 0; i < MAXCATS && strcmp (dnode->dcode[i], "###"); i++)
  502.         {
  503.             cnode = *cfirst;
  504.             while (cnode && catfound == FALSE)
  505.             {
  506.                 if (strcmp (dnode->dcode[i], cnode->code) == 0)
  507.                     catfound = TRUE;
  508.                 cprev = cnode;
  509.                 cnode = cnode->cnext;
  510.             }
  511.  
  512.             /***********************************
  513.             *  if code not already in list of  *
  514.             *  codes, add to list              *
  515.             ***********************************/
  516.             if (catfound == FALSE)
  517.             {
  518.                 num_cats++;
  519.                 cnode = (CATCODE far *) farmalloc ( (unsigned long) sizeof (CATCODE));
  520.                 if (cnode == NULL)
  521.                     fail ("Unable to create","cnode->cnext");
  522.                 if (cprev)
  523.                     cprev->cnext = cnode;
  524.                 cnode->cnext = NULL;
  525.                 strcpy (cnode->code, dnode->dcode[i]);
  526.                 if (*cfirst == NULL)
  527.                     *cfirst = cnode;
  528.             }
  529.             catfound = FALSE;
  530.         }
  531.     dnode = dnode->dnext;
  532.     }
  533.  
  534.     /*******************************
  535.     *  return the number of codes  *
  536.     *******************************/
  537.     return (num_cats);
  538. }
  539.  
  540.  
  541.  
  542. void make_temps (CATCODE *cnode, WININFO *win)
  543. {
  544. /**********************************************************
  545. *  This function creates the temp files from info in the  *
  546. *  cnode linked-list of category names.                   *
  547. **********************************************************/
  548.  
  549.     FILE *tempfile;
  550.     char tempname[MAXPATH];
  551.     int tempfiles = 0,
  552.         i;
  553.  
  554.     /******************************
  555.     *  for every category code..  *
  556.     ******************************/
  557.     while (cnode)
  558.     {
  559.         /**************************************************
  560.         *  make tempfilename and display it.  Open file,  *
  561.         *  write 0 to beginning of file (for number of    *
  562.         *  tempfiles), and close tempfile                 *
  563.         **************************************************/
  564.         strcpy (tempname, "$DLTEMP.");
  565.         strcat (tempname, cnode->code);
  566.         gotoxy (16,3);
  567.         cputs ("Creating temporary file: ");
  568.         textattr (win->hifore + (win->hiback << 4));
  569.         cprintf ("%s", tempname);
  570.         textattr (win->fore + (win->back << 4));
  571.         clreol();
  572.  
  573.         if ( (tempfile = fopen (tempname, "wb")) == NULL)
  574.             fail ("Unable to open tempfile - ", tempname);
  575.         fwrite (&tempfiles, 2, 1, tempfile);
  576.         fclose (tempfile);
  577.         cnode = cnode->cnext;
  578.     }
  579. }
  580.  
  581.  
  582.  
  583.  
  584. void searchfms (char *fmsname, FMSFILE *fmsdata, int *linelength)
  585. {
  586. /******************************************************************
  587. *  This function will read file information from the FMS file(s), *
  588. *  starting with the filename passed in *fmsname.  It will        *
  589. *  modify the *fmsdata array to hold info about each of the       *
  590. *  FMS files, and will set *linelength to the length of the       *
  591. *  FMS line.                                                      *
  592. ******************************************************************/
  593.  
  594.  
  595.     int i = 0,               /*  work variable for indexing  */
  596.         chain = TRUE;        /*  flag for chained FMS        */
  597.     char buffer[MAXLINE],        /*  buffer for file read        */
  598.          *work,            /*  work pointer                */
  599.          *fmsarg;            /*  pointer to FMS header arg   */
  600.     FILE *fp;            /*  pointer to FMS file         */
  601.  
  602.     /***********************
  603.     *  for each FMS file,  *
  604.     ***********************/
  605.     while (chain && i < MAXFMS)
  606.     {
  607.  
  608.         /***********************
  609.         *  set flags to FALSE  *
  610.         ***********************/
  611.         chain = FALSE;
  612.         (fmsdata + i)->top = FALSE;
  613.  
  614.         /*****************************************
  615.         *  copy FMS filename to array, open FMS  *
  616.         *  file, and read first line             *
  617.         *****************************************/
  618.         strcpy ((fmsdata + i)->name, fmsname);
  619.         if ((fp = fopen ((fmsdata + i)->name, "r")) == NULL)
  620.             fail ("Unable to open FMS file", fmsname);
  621.         fgets (buffer, MAXLINE, fp);
  622.  
  623.         /*********************************
  624.         *  if linelength is not already  *
  625.         *  set, then set it              *
  626.         *********************************/
  627.         if (*linelength == 0)
  628.             *linelength = strlen (buffer) + 1;
  629.  
  630.  
  631.         /***************************
  632.         *  if line is FMS header,  *
  633.         ***************************/
  634.         if (strncmp (buffer, "\\FMS", 4) == 0)
  635.         {
  636.             /**************************************
  637.             *  set work pointer to next argument  *
  638.             *  and get next argument              *
  639.             **************************************/
  640.             work = strtok (buffer, "\n");
  641.             work += 4;
  642.             fmsarg = strtok (work, " ");
  643.  
  644.             /*********************************
  645.             *  for each remaining argument,  *
  646.             *********************************/
  647.             while (fmsarg)
  648.             {
  649.                 /***************************************
  650.                 *  if "CH()" command, get the name of  *
  651.                 *  the file to chain to, and set the   *
  652.                 *  chain flag to TRUE                  *
  653.                 ***************************************/
  654.                 if (strncmp (fmsarg, "CH(", 3) == 0)
  655.                 {
  656.                     fmsarg += 3;
  657.                     strcpy (fmsname, fmsarg);
  658.                     fmsname[strlen(fmsarg)-1] = '\0';
  659.                     chain = TRUE;
  660.                 }
  661.  
  662.                 /*******************************************
  663.                 *  otherwise, if argument is TOP command,  *
  664.                 *  set the TOP flag to TRUE                *
  665.                 *******************************************/
  666.                 else if (strcmp (fmsarg, "TOP") == 0)
  667.                     (fmsdata + i)->top = TRUE;
  668.  
  669.                 /**************************
  670.                 *  get the next argument  *
  671.                 **************************/
  672.                 fmsarg = strtok (NULL, " ");
  673.             }
  674.         }
  675.  
  676.         /***************************
  677.         *  close the FMS file and  *
  678.         *  increment the index     *
  679.         ***************************/
  680.         fclose (fp);
  681.         i++;
  682.     }
  683.  
  684.     /**********************************
  685.     *  if the FMS array is not full,  *
  686.     *  set the next filename to NULL  *
  687.     ***********************************/
  688.     if (i < MAXFMS)
  689.         strcpy ( (fmsdata + i)->name, "");
  690. }
  691.  
  692.  
  693. void readfms (FMSFILE *fmsdata, int num_cats, WININFO *win, CATCODE *cfirst, int *totalfiles, long *totalbytes, int *zip_fms_index, long *zip_fms_pos, char *outname, int minseclvl, int maxseclvl)
  694. {
  695. /***************************************************************************
  696. *  This function will read the FMS file(s) listed in the *fmsdata          *
  697. *  array and builds an array of linked-lists of file info using the LDATA  *
  698. *  structure.  This array will be filled to memory, then purged and        *
  699. *  refilled as necessary to finish reading the FMS file(s).  At each       *
  700. *  purge, the temp files will be written to using the make_sortfiles()     *
  701. *  function.                                                               *
  702. ***************************************************************************/
  703.  
  704.  
  705.     LDATA **lnode,        /* array of pointers to current node    */
  706.           **lfirst;        /*   "   "     "      " beg. of arrays  */
  707.     char *buffer,        /* buffer for file read          */
  708.          tempbuf[MAXLINE],  /* temp. workspace for buffer manipulation */
  709.          namebuff[14],    /* buffer for name/ext parsing   */
  710.          zipname[MAXPATH],    /* ZIP name to look for in FMS   */
  711.          lext[9],        /* extension for file name       */
  712.          testcode[4],    /* test buffer for category code */
  713.          tempdate[9],    /* work variable for file date   */
  714.          tempsize[9];    /* work variable for file size   */
  715.     FILE *fp;        /* pointer to FMS file           */
  716.     int i,            /* work variable for indexing    */
  717.         filesec,         /* security level of file        */
  718.         process_file,    /* flag for whether to process file */
  719.         lndx,        /* index to lnode array          */
  720.         fndx = 0;        /* index to FMS array            */
  721.     long fpos;        /* file position                 */
  722.  
  723.  
  724.     buffer = (char *) malloc (MAXLINE);
  725.  
  726.     /****************************************************
  727.     *  strip path and extension from output text file   *
  728.     *  name to yield name to search for in FMS file(s)  *
  729.     *  to locate current file/position of description   *
  730.     *  for the ZIPfile                                  *
  731.     ****************************************************/
  732.     strcpy (zipname, outname);
  733.     strrev (zipname);
  734.     strtok (zipname, "\\");
  735.     strrev (zipname);
  736.     strtok (strupr (zipname), ".");
  737.  
  738.     /******************************************************
  739.     *  allocate first nodes for arrays, set variable and  *
  740.     *  array values, and display template in window       *
  741.     ******************************************************/
  742.     lnode = (LDATA far **) farmalloc ( (unsigned long) sizeof (LDATA *) * num_cats);
  743.     lfirst = (LDATA far **) farmalloc ( (unsigned long) sizeof (LDATA *) * num_cats);
  744.     *totalfiles = 0;
  745.     *totalbytes = 0L;
  746.     for (i = 0; i < num_cats; i++)
  747.     {
  748.         lnode[i] = NULL;
  749.         lfirst[i] = NULL;
  750.     }
  751.     gotoxy (50,5);
  752.     cputs ("Total files:");
  753.     gotoxy (50,6);
  754.     cputs ("Total bytes:");
  755.  
  756.     /********************************
  757.     *  for each file in FMS array,  *
  758.     ********************************/
  759.     while ( strcmp( (fmsdata + fndx)->name, "") && fndx < MAXFMS)
  760.     {
  761.         /******************************************
  762.         *  set file position,  display filename,  *
  763.         *  and seek to beginning of file          *
  764.         ******************************************/
  765.         fpos = 0L;
  766.         gotoxy (16,3);
  767.         cputs ("Reading FMS file: ");
  768.         textattr (win->hifore + (win->hiback << 4));
  769.         cprintf ("%s", (fmsdata + fndx)->name);
  770.         textattr (win->fore + (win->back << 4));
  771.         clreol();
  772.         if ((fp = fopen ((fmsdata + fndx)->name, "r")) == NULL)
  773.             fail ("Unable to open FMS file", (fmsdata+fndx)->name);
  774.         fseek (fp, 0L, SEEK_SET);
  775.  
  776.         /*******************************
  777.         *  for each line of FMS file,  *
  778.         *******************************/
  779.         while (fgets (buffer, MAXLINE, fp) != NULL)
  780.         {
  781.             process_file = FALSE;
  782.             textcolor (win->hifore);
  783.  
  784.             /*********************************
  785.             *  if filename present in line,  *
  786.             *********************************/
  787.             if (strchr (" \\*", (int) *buffer) == NULL)
  788.             {
  789.  
  790.                 /************************************
  791.                 *  test for security level of file  *
  792.                 ************************************/
  793. /* (remember - want to add */
  794. /*  true security process- */
  795. /*  ing later...)          */
  796.                 if ( (int) *buffer == '=')
  797.                 {
  798.                     strcpy (tempbuf, buffer+33);
  799.                     filesec = atoi (strtok (tempbuf, " "));
  800.                     if (filesec >= minseclvl && filesec <= maxseclvl)
  801.                     {
  802.                         process_file = TRUE;
  803.                         strcpy (buffer, buffer+1);
  804.                     }
  805.                 }
  806.                 else
  807.                     /**********************************************
  808.                     *  if this line contains the current Zipfile  *
  809.                     *  description, set the FMS array index and   *
  810.                     *  file position into the holding variables   *
  811.                     *  so we can use them later to update the     *
  812.                     *  description.  Otherwise, process as a      *
  813.                     *  normal file.                               *
  814.                     **********************************************/
  815. /* future development */        if (strncmp (zipname, buffer, strlen (zipname)) == 0)
  816.                     {
  817.                         *zip_fms_index = fndx;
  818.                         *zip_fms_pos = fpos;
  819.                     }
  820.                     else
  821.                         if (minseclvl == 0)
  822.                             process_file = TRUE;
  823.  
  824.                 if (process_file)
  825.                 {
  826.                     /*************************************
  827.                     *  put category code in work buffer  *
  828.                     * and strip from end of buffer       *
  829.                     *************************************/
  830.                     strncpy (testcode, buffer+strlen(buffer)-4, 3);
  831.                     testcode[3] = '\0';
  832.                     buffer[strlen(buffer)-4] = '\0';
  833.  
  834.                     /****************************
  835.                     *  if valid category code,  *
  836.                     ****************************/
  837.                     if ( (i = check_catcode (testcode, cfirst)) != -1)
  838.                     {
  839.                         /******************************
  840.                         *  set index for lnode array  *
  841.                         ******************************/
  842.                         lndx = i;
  843.  
  844.                         /*********************************
  845.                         *  if less than 1K memory left,  *
  846.                         *********************************/
  847.                         if (coreleft() < 1000L)
  848.                         {
  849.                             /**********************************
  850.                             *  append info to tempfiles,      *
  851.                             *  freeing memory in the process, *
  852.                             *  and redisplay the template     *
  853.                             **********************************/
  854.                             make_sortfiles (lfirst, win, cfirst);
  855.                             for (i = 0; i < num_cats; i++)
  856.                             {
  857.                                 lnode[i] = NULL;
  858.                                 lfirst[i] = NULL;
  859.                             }
  860.  
  861.  
  862.                             gotoxy (16,3);
  863.                             cputs ("Reading FMS file: ");
  864.                             textattr (win->hifore + (win->hiback << 4));
  865.                             cprintf ("%s", (fmsdata + fndx)->name);
  866.                             textattr (win->fore + (win->back << 4));
  867.                             clreol();
  868.                         }
  869.  
  870.                         /*************************************
  871.                         *  if first node of this cat empty,  *
  872.                         *  allocate the first node           *
  873.                         *************************************/
  874.                         if (lnode[lndx] == NULL)
  875.                         {
  876.                             lnode[lndx] = (LDATA far *) farmalloc ( (unsigned long) sizeof (LDATA));
  877.                             if (lnode[lndx] == NULL)
  878.                                 fail ("Unable to create", "lnode");
  879.                             lfirst[lndx] = lnode[lndx];
  880.                         }
  881.  
  882.                         /******************************************
  883.                         *  otherwise, allocate the next node and  *
  884.                         *  set current node pointer to next node  *
  885.                         ******************************************/
  886.                         else
  887.                         {
  888.                             lnode[lndx]->lnext = (LDATA far *) farmalloc ( (unsigned long) sizeof (LDATA));
  889.                             if (lnode[lndx]->lnext == NULL)
  890.                                 fail ("Unable to create", "lnode");
  891.                             lnode[lndx] = lnode[lndx]->lnext;
  892.                         }
  893.  
  894.                         /*********************************************
  895.                         *  set file position and next node pointer,  *
  896.                         *  and copy category code from work buffer   *
  897.                         *********************************************/
  898.                         lnode[lndx]->lpos = fpos;
  899.                         lnode[lndx]->lnext = NULL;
  900.                         strcpy (lnode[lndx]->lcode, testcode);
  901.  
  902.                         /******************************************
  903.                         *  get file name/ext in work buffer, and  *
  904.                         *  strip from beginning of line buffer    *
  905.                         ******************************************/
  906.                         strncpy (namebuff, buffer, 13);
  907.                         namebuff[13] = '\0';
  908.                         strrev (buffer);
  909.                         buffer[strlen(buffer)-13] = '\0';
  910.                         strrev (buffer);
  911.  
  912.                         /*********************************************
  913.                         *  get filename, and extension (if there is  *
  914.                         *  one) from work buffer, and reformat it    *
  915.                         *********************************************/
  916.                         strcpy (lnode[lndx]->lname, strtok (namebuff, " ."));
  917.                         strcpy (lext, strtok (NULL, " ."));
  918.                         if (strcmp (lext, ""))
  919.                         {
  920.                             strcat (lnode[lndx]->lname, ".");
  921.                             strcat (lnode[lndx]->lname, lext);
  922.                         }
  923.  
  924.                         /**************************************
  925.                         *  get filesize, add to total bytes   *
  926.                         **************************************/
  927.                         strcpy (tempsize, strtok (buffer, " "));
  928.                         lnode[lndx]->lsize = atol (tempsize);
  929.                         *totalbytes += lnode[lndx]->lsize;
  930.  
  931.                         /************************************************
  932.                         *  get file date and convert to numeric YYMMDD  *
  933.                         ************************************************/
  934.                         strcpy (tempdate, strtok (NULL, " -"));
  935.                         strcat (tempdate, strtok (NULL, "-"));
  936.                         strcat (tempdate, strtok (NULL, " "));
  937.                         lnode[lndx]->ldate = atol (tempdate);
  938.                         strncpy (tempdate, "0000", 4);
  939.                         lnode[lndx]->ldate = (atol (tempdate) * 10000) + (lnode[lndx]->ldate / 100);
  940.  
  941.                         /****************************
  942.                         *  set index for FMS array  *
  943.                         ****************************/
  944.                         lnode[lndx]->lfms = fndx;
  945.  
  946.                         /**************************************
  947.                         *  increment and display total files  *
  948.                         *  and total bytes every              *
  949.                         **************************************/
  950.                         (*totalfiles)++;
  951.                         gotoxy (63,5);
  952.                         cprintf ("%d", *totalfiles);
  953.                         gotoxy (63,6);
  954.                         cprintf ("%ld", *totalbytes);
  955.                     }
  956.                 }
  957.             }
  958.  
  959.             /**********************
  960.             *  get file position  *
  961.             **********************/
  962.             fpos = ftell (fp);
  963.         }
  964.  
  965.         /******************************
  966.         *  close current FMS file and *
  967.         *  increment FMS array index  *
  968.         ******************************/
  969.         fclose (fp);
  970.         fndx++;
  971.         textcolor (win->fore);
  972.     }
  973.  
  974.     /*********************************************
  975.     *  append info to tempfiles, freeing memory  *
  976.     *********************************************/
  977.     make_sortfiles (lfirst, win, cfirst);
  978.  
  979.  
  980.  
  981. }
  982.  
  983.  
  984.  
  985. void make_sortfiles (LDATA *lnode[], WININFO *win, CATCODE *cnode)
  986. {
  987. /********************************************************************************
  988. *  This function will append file entries to the temporary files created for    *
  989. *  each category.  It will access the array of LDATA structures for the file    *
  990. *  info, but will use a TDATA structure for writing to the files.  It will      *
  991. *  access the DCATINFO structure to get the category names, in order to access  *
  992. *  the temporary files.  It will also free the memory used by the ldata[]       *
  993. *  array, so that more files than can fit in memory may be processed.           *
  994. ********************************************************************************/
  995.  
  996.  
  997.     FILE *tempfile;            /* pointer to current temp file  */
  998.     int i = 0,            /* work variable for indexing    */
  999.         tempfiles;            /* number of files in temp file  */
  1000.     char tempname[MAXPATH];        /* name of temp file             */
  1001.     LDATA *lprev;            /* pointer to previous lnode     */
  1002.  
  1003.  
  1004.     /*******************************
  1005.     *  display template in window  *
  1006.     *******************************/
  1007.     textattr (win->fore + (win->back << 4));
  1008.     gotoxy (16, 3);
  1009.     cprintf ("Appending to tempfile: ");
  1010.  
  1011.     /****************************
  1012.     *  for each category code,  *
  1013.     ****************************/
  1014.     while (cnode)
  1015.     {
  1016.         /***************************************
  1017.         *  set tempfile name,  and display it  *
  1018.         ***************************************/
  1019.         strcpy (tempname, "$DLTEMP.");
  1020.         strcat (tempname, cnode->code);
  1021.         textattr (win->hifore + (win->hiback << 4));
  1022.         gotoxy (39, 3);
  1023.         cprintf ("%s", tempname);
  1024.         textattr (win->fore + (win->back << 4));
  1025.         clreol();
  1026.  
  1027.         /*************************************************
  1028.         *  open tempfile, read current number of files,  *
  1029.         *  and seek to end for appending                 *
  1030.         *************************************************/
  1031.         if ((tempfile = fopen (tempname, "r+b")) == NULL)
  1032.             fail ("Unable to open tempfile", tempname);
  1033.         fread (&tempfiles, 2, 1, tempfile);
  1034.         fseek (tempfile, 0L, SEEK_END);
  1035.  
  1036.         /**************************************************
  1037.         *  for each node in this category's linked-list,  *
  1038.         *  increment the file count, write the node info, *
  1039.         *  go to the next node, and free the previous     *
  1040.         *  node from memory                               *
  1041.         **************************************************/
  1042.         while (lnode[i] && strcmp (lnode[i]->lname, ""))
  1043.         {
  1044.             tempfiles++;
  1045.             fwrite (lnode[i], sizeof (TDATA), 1, tempfile);
  1046.             lprev = lnode[i];
  1047.             lnode[i] = lnode[i]->lnext;
  1048.             farfree (lprev);
  1049.         }
  1050.  
  1051.         /*****************************************
  1052.         *  seek to beginning of file, write new  *
  1053.         *  filecount, and close the file         *
  1054.         *****************************************/
  1055.         fseek (tempfile, 0L, SEEK_SET);
  1056.         fwrite (&tempfiles, 2, 1, tempfile);
  1057.         fclose (tempfile);
  1058.  
  1059.         /**************************************
  1060.         *  increment the category index, and  *
  1061.         *  go to next category                *
  1062.         **************************************/
  1063.         i++;
  1064.         cnode = cnode->cnext;
  1065.     }
  1066. }
  1067.  
  1068.  
  1069.  
  1070. void process_list (DCATINFO *dnode, CATCODE *cnode, CNFGREC *crec, int linelength, int totalfiles, long totalbytes, FMSFILE *fmsdata, WININFO *win)
  1071. {
  1072. /****************************************************************************
  1073. *  The heart of the beast!  This function creates the downloadable file     *
  1074. *  listing from the temp files created previously, along with the FMS       *
  1075. *  files listed in the FMSFILE array (*fmsdata).   Once all records for a   *
  1076. *  category  are loaded into memory, they can be sorted either by filename  *
  1077. *  or by date, in ascending or descending order.                            *
  1078. ****************************************************************************/
  1079.  
  1080.  
  1081.     DCATINFO *dfirst,        /* pointer to head of linked-list       */
  1082.          *dprev;        /*    "    "  previous dnode            */
  1083.     CATCODE *cprev;            /*    "    "  previous cnode            */
  1084.     TDATA huge *tdata;        /*    "    "  array of tempfile records */
  1085.     TDATA huge *tfirst;        /*    "    "  first element of above    */
  1086.     TDATA huge *twork;        /*    "    used when enlarging array    */
  1087.     TDATA **t_array;        /* array of pointers to be sorted       */
  1088.     TDATA **t_first;        /* pointer to first element of above    */
  1089.     FILE *sortfile,            /* pointer to current tempfile  */
  1090.          *outfile,            /* pointer to output file       */
  1091.          *fp;            /* pointer to FMS file          */
  1092.     int count,            /* loop control counter         */
  1093.         loop,            /* flag for extended descr.     */
  1094.         tempfiles,            /* number of files in tempfile  */
  1095.         tworkfiles,            /* number used to enlarge array */
  1096.         i,                /* work variable for indexing   */
  1097.         x;                /* work variable for counting   */
  1098.     long rcnt,            /* number of bytes to backup    */
  1099.                     /*   in file (reverse count)    */
  1100.          prev = 1,            /* position to seek to in file  */
  1101.                     /*   when backing up            */
  1102.          tempbytes;            /* number of bytes in category  */
  1103.     char sfilename[MAXPATH],    /* temp filename                */
  1104.          buffer[MAXLINE],        /* buffer for read/write        */
  1105.          graph[51],            /* graph to display             */
  1106.          *buffptr;            /* buffer pointer               */
  1107.     PDATA *pnode = NULL,        /* linked-list pointers         */
  1108.           *pfirst = NULL;
  1109.  
  1110.     /*************************************************
  1111.     *  open output file, print the list header and,  *
  1112.     *  optionally, the user's header                 *
  1113.     *************************************************/
  1114.     if ((outfile = fopen (crec->outname, "w")) == NULL)
  1115.         fail ("Unable to open output file", crec->outname);
  1116.     print_listheader (crec, outfile);
  1117.     if (strcmp (crec->hdrname, "") != 0)
  1118.         printfile (crec->hdrname, "header", outfile);
  1119.  
  1120.     /******************************************************
  1121.     *  set head pointer to list of categories, calculate  *
  1122.     *  rcnt from linelength, and display template         *
  1123.     ******************************************************/
  1124.     dfirst = dnode;
  1125.     rcnt = (long) linelength * 2;
  1126.     gotoxy (12,1);
  1127.     cputs ("0   .    .    .    .    50   .    .    .    .   100");
  1128.     gotoxy (1,3);
  1129.     clreol();
  1130.     gotoxy (5, 4);
  1131.     cputs ("Processing output for directory:");
  1132.     gotoxy (5, 5);
  1133.     cputs ("files this directory:");
  1134.     gotoxy (5, 6);
  1135.     cputs ("bytes this directory:");
  1136.  
  1137.     /***********************
  1138.     *  for each category,  *
  1139.     ***********************/
  1140.     while (dnode)
  1141.     {
  1142.         tdata = tfirst = NULL;
  1143.         t_array = t_first = NULL;
  1144.  
  1145.         /*********************************
  1146.         *  initialize and display graph  *
  1147.         *********************************/
  1148.         textattr (win->fore + (win->back << 4));
  1149.         gotoxy (12,2);
  1150.         strcpy (graph, "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░");
  1151.         cputs (graph);
  1152.  
  1153.         /**************************************************
  1154.         *  set byte count to 0 and display category name  *
  1155.         **************************************************/
  1156.         tempbytes = 0L;
  1157.         textattr (win->hifore + (win->hiback << 4));
  1158.         gotoxy (38,4);
  1159.         cprintf ("%s", dnode->dname);
  1160.         textattr (win->hifore + (win->back << 4));
  1161.         clreol();
  1162.  
  1163.         /**********************************
  1164.         *  for each code in category....  *
  1165.         **********************************/
  1166.         i = tempfiles = 0;
  1167.         while (i < MAXCATS && strcmp (dnode->dcode[i], "###"))
  1168.         {
  1169.             /******************************************
  1170.             *  set tempfile name, open tempfile, read *
  1171.             *  number of files, and add to total.     *
  1172.             ******************************************/
  1173.             strcpy (sfilename, "$DLTEMP.");
  1174.             strcat (sfilename, dnode->dcode[i]);
  1175.             if ((sortfile = fopen (sfilename, "rb")) != NULL)
  1176.                 fread (&tworkfiles, 2, 1, sortfile);
  1177.             tempfiles += tworkfiles;
  1178.             fclose (sortfile);
  1179.             i++;
  1180.         }
  1181.  
  1182.         /********************************
  1183.         *  if this category has files,  *
  1184.         ********************************/
  1185.         if (tempfiles != 0)
  1186.         {
  1187.             /***********************
  1188.             *  allocate the array  *
  1189.             ***********************/
  1190.  
  1191.             tdata = (TDATA huge *) farmalloc ((unsigned long) sizeof (TDATA) * tempfiles);
  1192.             if (tdata == NULL)
  1193.                 fail ("Unable to allocate","tdata");
  1194.  
  1195.             /***********************************
  1196.             *  read tempfile(s) to fill array  *
  1197.             ***********************************/
  1198.             i = tempfiles = 0;
  1199.             while (i < MAXCATS && strcmp (dnode->dcode[i], "###"))
  1200.             {
  1201.                 /******************************************
  1202.                 *  set tempfile name, open tempfile, and  *
  1203.                 *  read number of files                   *
  1204.                 ******************************************/
  1205.                 strcpy (sfilename, "$DLTEMP.");
  1206.                 strcat (sfilename, dnode->dcode[i]);
  1207.                 if ((sortfile = fopen (sfilename, "rb")) != NULL)
  1208.                     fread (&tworkfiles, 2, 1, sortfile);
  1209.                 tempfiles += tworkfiles;
  1210.                 twork = tdata;
  1211.                 for (x=0; x < (tempfiles - tworkfiles); x++, twork++);
  1212.                 fread ((TDATA *) twork, sizeof (TDATA), tworkfiles, sortfile);
  1213.                 fclose (sortfile);
  1214.                 i++;
  1215.             }
  1216.         }
  1217.  
  1218.  
  1219.         /*******************************
  1220.         *  display number of files in  *
  1221.         *  this category               *
  1222.         *******************************/
  1223.         gotoxy (27,5);
  1224.         cprintf ("%d     ", tempfiles);
  1225.  
  1226.  
  1227.         /************************************************
  1228.         *  If there are files for this category, copy   *
  1229.         *  address of array elements into pointer array *
  1230.         *  in order to sort pointers                    *
  1231.         ************************************************/
  1232.         if (tempfiles != 0)
  1233.         {
  1234.             tfirst = tdata;
  1235.             t_array = (TDATA far **) farmalloc ( (unsigned long) sizeof (TDATA *) * tempfiles);
  1236.             if (t_array == NULL)
  1237.                 fail ("Unable to create array","t_array");
  1238.             t_first = t_array;
  1239.             count = 0;
  1240.             while (count < tempfiles)
  1241.             {
  1242.                 *t_array = (TDATA *) tdata;
  1243.                 tempbytes += tdata->tsize;
  1244.                 tdata++;
  1245.                 count++;
  1246.                 t_array++;
  1247.             }
  1248.  
  1249.             /********************************************
  1250.             *  set array pointers back to beginning of  *
  1251.             *  array, and sort the array                *
  1252.             ********************************************/
  1253.             tdata = tfirst;
  1254.             t_array = t_first;
  1255.  
  1256.             if (toupper (crec->sorttype) == 'A')
  1257.             {
  1258.                 if (toupper (crec->revsort) == 'N')
  1259.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) afcompare);
  1260.                 else
  1261.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) arcompare);
  1262.             }
  1263.             else
  1264.             {
  1265.                 if (toupper (crec->revsort) == 'N')
  1266.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) dfcompare);                else
  1267.                     qsort ((void *) t_array, tempfiles, sizeof (TDATA *), (int (*) (const void *, const void *)) drcompare);
  1268.             }
  1269.         }
  1270.  
  1271.         /**************************************************
  1272.         *  display the number of bytes in this category,  *
  1273.         *  and print the directory header to output file  *
  1274.         **************************************************/
  1275.         gotoxy (27,6);
  1276.         cprintf ("%ld      ", tempbytes);
  1277.         print_dirheader (dnode, tempfiles, tempbytes, outfile);    /* print directory header */
  1278.  
  1279.         /*******************************
  1280.         *  for each element of array,  *
  1281.         *******************************/
  1282.         count = 0;
  1283.         while (count < tempfiles)
  1284.         {
  1285.             /*************************
  1286.             *  update graph display  *
  1287.             *************************/
  1288.             textattr (win->fore + (win->back << 4));
  1289.             if (count > 0)
  1290.             {
  1291.                 x = ( (long) count*100/tempfiles);
  1292.                 for (i=0; i <= x/2; graph[i++]='█');
  1293.                 gotoxy (12, 2);
  1294.                 cputs (graph);
  1295.             }
  1296.  
  1297.             /******************
  1298.             *  set loop flag  *
  1299.             ******************/
  1300.             loop = TRUE;
  1301.  
  1302.             /****************************************
  1303.             *  open appropriate FMS file and        *
  1304.             *  seek to proper position in FMS file  *
  1305.             *  and read first line of description   *
  1306.             ****************************************/
  1307.             if ((fp = fopen ((fmsdata + (*t_array)->tfms)->name, "r")) == NULL)
  1308.                 fail ("Unable to open FMS file", (fmsdata + (*t_array)->tfms)->name);
  1309.             fseek (fp, (*t_array)->tpos, SEEK_SET);
  1310.             fgets (buffer, MAXLINE, fp);
  1311.  
  1312.             /*******************************************
  1313.             *  copy buffer to print buffer, stripping  *
  1314.             *  category code and extra spaces at end   *
  1315.             *******************************************/
  1316.             strrev (buffer);
  1317.             buffptr = buffer;
  1318.             buffptr += 4;
  1319.             while (*buffptr == ' ')
  1320.                 buffptr++;
  1321.             strrev (buffptr);
  1322.             strcat (buffptr, "\n");
  1323.             if (pfirst)
  1324.             {
  1325.                 pnode->pnext = (PDATA *) calloc (1, sizeof (PDATA));
  1326.                 pnode = pnode->pnext;
  1327.             }
  1328.             else
  1329.             {
  1330.                 pnode = (PDATA *) calloc (1, sizeof (PDATA));
  1331.                 pfirst = pnode;
  1332.             }
  1333.             strcpy (pnode->prtline, buffptr);
  1334.  
  1335.             /***********************************
  1336.             *  if < 1K memory left, print the  *
  1337.             *  buffer to the file, freeing     *
  1338.             *  memory in the process           *
  1339.             ***********************************/
  1340.             if (coreleft() < 1000L)
  1341.             {
  1342.                 clear_status (win);
  1343.                 print_buffer (outfile, pfirst);
  1344.                 pfirst = pnode = NULL;
  1345.                 clear_status (win);
  1346.             }
  1347.  
  1348.             /**************************************
  1349.             *  keep reading lines to see if part  *
  1350.             *  of extended description            *
  1351.             **************************************/
  1352.             while (loop)
  1353.             {
  1354.                 /******************************************
  1355.                 *  if FMS TOP is FALSE, seek to previous  *
  1356.                 *  line and check if not before file      *
  1357.                 *  beginning, otherwise turn loop off     *
  1358.                 ******************************************/
  1359.                 if (fmsdata[(*t_array)->tfms].top == FALSE)
  1360.                 {
  1361.                     prev = ftell (fp) - rcnt;
  1362.                     if (prev >= 0)
  1363.                         fseek (fp, prev, SEEK_SET);
  1364.                     else
  1365.                         loop = FALSE;
  1366.                 }
  1367.  
  1368.                 /***************************
  1369.                 *  if loop is still TRUE,  *
  1370.                 ***************************/
  1371.                 if (loop)
  1372.                 {
  1373.                     /***************************
  1374.                     *  if not at end of file,  *
  1375.                     ***************************/
  1376.                     if (fgets (buffer, MAXLINE, fp) != NULL)
  1377.                     {
  1378.                         /****************************
  1379.                         *  if next line is part of  *
  1380.                         *  extended description,    *
  1381.                         ****************************/
  1382.                         if (*buffer == ' ')
  1383.                         {
  1384.                             /************************************
  1385.                             *  if not line from RBBSWHO merge,  *
  1386.                             ************************************/
  1387.                             if (strncmp (buffer, "  Uploaded", 10))
  1388.                             {
  1389.  
  1390.                                 /*******************************************
  1391.                                 *  copy buffer to print buffer, stripping  *
  1392.                                 *  final period and extra spaces at end    *
  1393.                                 *******************************************/
  1394.                                 strrev (buffer);
  1395.                                 buffptr = buffer;
  1396.                                 buffptr += 4;
  1397.                                 while (*buffptr == ' ')
  1398.                                     buffptr++;
  1399.                                 strrev (buffptr);
  1400.                                 strcat (buffptr, "\n");
  1401.                                 if (pfirst)
  1402.                                 {
  1403.                                     pnode->pnext = (PDATA *) calloc (1, sizeof (PDATA));
  1404.                                     pnode = pnode->pnext;
  1405.                                 }
  1406.                                 else
  1407.                                 {
  1408.                                     pnode = (PDATA *) calloc (1, sizeof (PDATA));
  1409.                                     pfirst = pnode;
  1410.                                 }
  1411.                                 strcpy (pnode->prtline, buffptr);
  1412.  
  1413.                                 /***********************************
  1414.                                 *  if < 1K memory left, print the  *
  1415.                                 *  buffer to the file, freeing     *
  1416.                                 *  memory in the process           *
  1417.                                 ***********************************/
  1418.                                 if (coreleft() < 1000L)
  1419.                                 {
  1420.                                     print_buffer (outfile, pfirst);
  1421.                                     pfirst = pnode = NULL;
  1422.                                 }
  1423.                             }
  1424.                         }
  1425.  
  1426.                         /****************************************
  1427.                         *  if not part of extended description, *
  1428.                         *  break the loop                       *
  1429.                         ****************************************/
  1430.                         else
  1431.                             loop = FALSE;
  1432.                     }
  1433.  
  1434.                     /******************************
  1435.                     *  if at EOF, break the loop  *
  1436.                     ******************************/
  1437.                     else
  1438.                         loop = FALSE;
  1439.                 }
  1440.             }
  1441.  
  1442.             /****************************************
  1443.             *  close current FMS file and           *
  1444.             *  increment array pointer and counter  *
  1445.             ****************************************/
  1446.             fclose (fp);
  1447.             t_array++;
  1448.             count++;
  1449.         }
  1450.  
  1451.         /********************************
  1452.         *  if not 0 files in category,  *
  1453.         *  free arrays from memory      *
  1454.         ********************************/
  1455.         if (tempfiles != 0)
  1456.         {
  1457.             farfree (t_first);        /* clear pointer array     */
  1458.             farfree ((TDATA *)tfirst);            /* clear array from memory */
  1459.         }
  1460.  
  1461.         /************************
  1462.         *  flush buffer and     *
  1463.         *  go to next category  *
  1464.         ************************/
  1465.         print_buffer (outfile, pfirst);
  1466.         pfirst = pnode = NULL;
  1467.         dnode = dnode->dnext;
  1468.         textcolor (win->fore);
  1469.     }
  1470.  
  1471.     /*********************************
  1472.     *  flush remaining print buffer  *
  1473.     *********************************/
  1474.     clear_status (win);
  1475.     print_buffer (outfile, pfirst);
  1476.     pfirst = pnode = NULL;
  1477.     clear_status (win);
  1478.     textattr (win->hifore + (win->back << 4));
  1479.  
  1480.     /******************************************
  1481.     *  print user's footer (optional), print  *
  1482.     *  list footer, and close output file     *
  1483.     ******************************************/
  1484.     if (strcmp (crec->ftrname, "") != 0)
  1485.         printfile (crec->ftrname, "footer", outfile);
  1486.     print_listfooter (totalfiles, totalbytes, outfile);
  1487.     fclose (outfile);
  1488.  
  1489.     /**************************************
  1490.     *  clear screen, and display message  *
  1491.     *  while deleting temp files and      *
  1492.     *  clearing cnode list from memory    *
  1493.     **************************************/
  1494.     clrscr();
  1495.     gotoxy (20,3);
  1496.     cputs ("Erasing Temp Files.....");
  1497.     while (cnode)
  1498.     {
  1499.         strcpy (sfilename, "$DLTEMP.");
  1500.         strcat (sfilename, cnode->code);
  1501.         unlink (sfilename);
  1502.         cprev = cnode;
  1503.         cnode = cnode->cnext;
  1504.         farfree (cprev);
  1505.     }
  1506.  
  1507.  
  1508.     /*********************************
  1509.     *  clear dnode list from memory  *
  1510.     *********************************/
  1511.     dnode = dfirst;
  1512.     while (dnode)
  1513.     {
  1514.         dprev = dnode;
  1515.         dnode = dnode->dnext;
  1516.         farfree (dprev);
  1517.     }
  1518. }
  1519.  
  1520.  
  1521.  
  1522. void print_buffer (FILE *outfile, PDATA *pnode)
  1523. {
  1524.     PDATA *pprev;
  1525.  
  1526.     while (pnode)
  1527.     {
  1528.         fputs (pnode->prtline, outfile);
  1529.         pprev = pnode;
  1530.         pnode = pnode->pnext;
  1531.         farfree (pprev);
  1532.     }
  1533. }
  1534.  
  1535.  
  1536.  
  1537.  
  1538. void print_listheader (CNFGREC *crec, FILE *outfile)
  1539. {
  1540.     int i,
  1541.         lead;
  1542.     char *ampm = "am",
  1543.          prtdate[40];
  1544.     struct date pdate;
  1545.     struct time ptime;
  1546.  
  1547.     getdate (&pdate);
  1548.     gettime (&ptime);
  1549.     if (ptime.ti_hour > 12)
  1550.     {
  1551.         ptime.ti_hour -= 12;
  1552.         strcpy (ampm, "pm");
  1553.     }
  1554.     sprintf (prtdate, "Last Updated %d/%d/%d at %d:%02d%s",
  1555.          pdate.da_mon, pdate.da_day, pdate.da_year, ptime.ti_hour, ptime.ti_min, ampm);
  1556.     fprintf (outfile, "┌─────────────────────────────────────────────────────────────────────────────┐\n");
  1557.     fprintf (outfile, "│");
  1558.     lead = (78 - strlen(crec->bbsname)) / 2;
  1559.     for (i = 0; i < lead; i++)
  1560.         fprintf (outfile, " ");
  1561.     fprintf (outfile, "%s", crec->bbsname);
  1562.     for (i = 1; i < (78 - lead- strlen(crec->bbsname)); i++)
  1563.         fprintf (outfile, " ");
  1564.     fprintf (outfile, "│\n");
  1565.     fprintf (outfile, "│                        Master List of Download Files                        │\n");
  1566.     fprintf (outfile, "│                                                                             │\n");
  1567.     fprintf (outfile, "│");
  1568.     lead = (78 - strlen(prtdate)) / 2;
  1569.     for (i = 1; i < lead; i++)
  1570.         fprintf (outfile, " ");
  1571.     fprintf (outfile, "%s", prtdate);
  1572.     for (i = 0; i < (78 - lead - strlen(prtdate)); i++)
  1573.         fprintf (outfile, " ");
  1574.     fprintf (outfile, "│\n");
  1575.     fprintf (outfile, "└─────────────────────────────────────────────────────────────────────────────┘\n");
  1576. }
  1577.  
  1578.  
  1579.  
  1580. void print_dirheader (DCATINFO *dnode, int tempfiles, long tempbytes, FILE *outfile)
  1581. {
  1582.     fprintf (outfile, "\n┌───────────────┬─────────────────────────────────────────────────────────────┐\n");
  1583.     fprintf (outfile, "│ %-13s │ %-59s │\n", dnode->dname, dnode->ddesc);
  1584.     fprintf (outfile, "├───────────────┴─────────────────────────────────────────────────────────────┤\n");
  1585.     fprintf (outfile, "│  Number of files: %-4d                          Number of bytes: %-9ld  │\n", tempfiles, tempbytes);
  1586.     fprintf (outfile, "├────────────┬────────┬────────┬──────────────────────────────────────────────┤\n");
  1587.     fprintf (outfile, "│ Filename   │  Size  │  Date  │  Description                                 │\n");
  1588.     fprintf (outfile, "└────────────┴────────┴────────┴──────────────────────────────────────────────┘\n");
  1589. }
  1590.  
  1591.  
  1592. void print_listfooter (int totalfiles, long totalbytes, FILE *outfile)
  1593. {
  1594.     fprintf (outfile, "\n┌─────────────────────────────────────────────────────────────────────────────┐\n");
  1595.     fprintf (outfile, "│       Total number of files in all directories:  %-5d                      │\n", totalfiles);
  1596.     fprintf (outfile, "│       Total number of bytes in all directories:  %-10ld                 │\n", totalbytes);
  1597.     fprintf (outfile, "└─────────────────────────────────────────────────────────────────────────────┘\n");
  1598. }
  1599.  
  1600.  
  1601. void printfile (char *filename, char *message, FILE *outfile)
  1602. {
  1603.     FILE *infile;
  1604.     char buffer[MAXLINE];
  1605.  
  1606.     gotoxy (16,2);
  1607.     cprintf ("Adding %s file to output....", message);
  1608.     clreol();
  1609.     if ((infile = fopen (filename, "r")) == NULL)
  1610.         fail ("Unable to open file", filename);
  1611.     while (fgets (buffer, MAXLINE, infile) != NULL)        /* read file to end   */
  1612.         fputs (buffer, outfile);
  1613.     fclose (infile);
  1614. }
  1615.  
  1616.  
  1617.  
  1618. int afcompare (TDATA huge **elem1, TDATA huge **elem2)
  1619. {
  1620.     return (strcmp ((*elem1)->tname, (*elem2)->tname));
  1621. }
  1622.  
  1623.  
  1624. int arcompare (TDATA huge **elem1, TDATA huge **elem2)
  1625. {
  1626.     return (strcmp ((*elem2)->tname, (*elem1)->tname));
  1627. }
  1628.  
  1629.  
  1630. int dfcompare (TDATA huge **elem1, TDATA huge **elem2)
  1631. {
  1632.     int retval;
  1633.  
  1634.     if ((*elem1)->tdate == (*elem2)->tdate)
  1635.         retval = strcmp ((*elem1)->tname, (*elem2)->tname);
  1636.     else
  1637.         retval = ((*elem1)->tdate < (*elem2)->tdate) ? -1 : 1;
  1638.     return (retval);
  1639. }
  1640.  
  1641.  
  1642. int drcompare (TDATA huge **elem1, TDATA huge **elem2)
  1643. {
  1644.     int retval;
  1645.  
  1646.     if ((*elem1)->tdate == (*elem2)->tdate)
  1647.         retval = strcmp ((*elem2)->tname, (*elem1)->tname);
  1648.     else
  1649.         retval = ((*elem2)->tdate < (*elem1)->tdate) ? -1 : 1;
  1650.     return (retval);
  1651. }
  1652.  
  1653.  
  1654.  
  1655. void make_wallpaper (unsigned char c, int fore, int back)
  1656. {
  1657.     int far *video,
  1658.         row,
  1659.         col,
  1660.         attr,
  1661.         i;
  1662.     struct text_info tinfo;
  1663.  
  1664.     gettextinfo (&tinfo);
  1665.     if (tinfo.currmode == MONO)
  1666.         video = (int far *) 0xB0000000;
  1667.     else
  1668.         video = (int far *) 0xB8000000;
  1669.     attr = fore + (back << 4);
  1670.     textattr (attr);
  1671.     clrscr();
  1672.     for (row = 0; row < 25; row += 2)
  1673.         if (row % 4 == 0)
  1674.             for (col = 0; col < 80; col += 10)
  1675.                 *(video + (row * 80) + col + 2) = c | (attr << 8);
  1676.         else
  1677.             for (col = 5; col < 80; col += 10)
  1678.                 *(video + (row * 80) + col + 2) = c | (attr << 8);
  1679. }
  1680.  
  1681.  
  1682. void make_window (WININFO *win)
  1683. {
  1684.     int row, col, attr, pos,
  1685.         far *video;
  1686.     char *savetext;
  1687.     struct text_info tinfo;
  1688.     struct
  1689.     {
  1690.         int upleft, upright, dnleft, dnright,
  1691.             vert, horiz;
  1692.     } border[3] = {{ 32,  32,  32,  32,  32,  32},
  1693.                {218, 191, 192, 217, 179, 196},
  1694.                {201, 187, 200, 188, 186, 205}};
  1695.  
  1696.     gettextinfo (&tinfo);
  1697.     if (tinfo.currmode == MONO)
  1698.         video = (int far *) 0xB0000000;
  1699.     else
  1700.         video = (int far *) 0xB8000000;
  1701.     attr = (win->bcolor + (win->back << 4)) << 8;
  1702.     *(video + (win->top - 1) * 80 + win->left - 1) = border[win->bstyle].upleft | attr;
  1703.     *(video + (win->top - 1) * 80 + win->right - 1) = border[win->bstyle].upright | attr;
  1704.     *(video + (win->bottom - 1) * 80 + win->left - 1) = border[win->bstyle].dnleft | attr;
  1705.     *(video + (win->bottom - 1) * 80 + win->right - 1) = border[win->bstyle].dnright | attr;
  1706.     for (col = win->left; col < win->right-1; col++)
  1707.     {
  1708.         *(video + ((win->top-1)*80) + col) = border[win->bstyle].horiz | attr;
  1709.         *(video + ((win->bottom-1)*80) + col) = border[win->bstyle].horiz | attr;
  1710.     }
  1711.     for (row = win->top; row < win->bottom-1; row++)
  1712.     {
  1713.         *(video + (row * 80) + win->left-1) = border[win->bstyle].vert | attr;
  1714.         *(video + (row * 80) + win->right-1) = border[win->bstyle].vert | attr;
  1715.     }
  1716.     window (win->left+1, win->top+1, win->right-1, win->bottom-1);
  1717.     textattr (win->fore + (win->back << 4));
  1718.     clrscr();
  1719.     if (win->shadow)
  1720.     {
  1721.         for (row = win->top; row <= win->bottom; row++)
  1722.         {
  1723.             *(video + (row * 80) + win->right) &= 0x00FF;
  1724.             *(video + (row * 80) + win->right) |= (DARKGRAY + (BLACK << 4)) << 8;
  1725.             *(video + (row * 80) + win->right + 1) &= 0x00FF;
  1726.             *(video + (row * 80) + win->right + 1) |= (DARKGRAY + (BLACK << 4)) << 8;
  1727.         }
  1728.         for (col = win->left+1; col <= win->right; col++)
  1729.         {
  1730.             *(video + (win->bottom * 80) + col) &= 0x00FF;
  1731.             *(video + (win->bottom * 80) + col) |= (DARKGRAY + (BLACK << 4)) << 8;
  1732.         }
  1733.     }
  1734. }
  1735.  
  1736.  
  1737.  
  1738.  
  1739. void make_zip (char *zippath, char *textname, WININFO *win)
  1740. {
  1741.     char command[MAXLINE],
  1742.          zipname[MAXPATH],
  1743.          *ziputil;
  1744.     int x,
  1745.         y,
  1746.         i;
  1747.  
  1748.     /******************************************************
  1749.     *  copy the path\filename of the compression utility  *
  1750.     *  into the ziputil variable and extract the name     *
  1751.     *  of the compression utility.                        *
  1752.     ******************************************************/
  1753.     ziputil = (char *) malloc (MAXPATH);
  1754.     strcpy (ziputil, zippath);
  1755.     strrev (ziputil);
  1756.     strtok (ziputil, "\\");
  1757.     strrev (ziputil);
  1758.     strtok (ziputil, ".");
  1759.  
  1760.     strcpy (zipname, textname);
  1761.     strtok (zipname, ".");
  1762.  
  1763.     strcpy (command, zippath);
  1764.     if (strcmp (strupr (ziputil), "PKZIP") == 0)
  1765.         strcat (command, " -a ");
  1766.     else
  1767.         strcat (command, " a ");
  1768.     strcat (command, zipname);
  1769.     strcat (command, " ");
  1770.     strcat (command, textname);
  1771.     strcat (command, " > NUL");
  1772.     DoDosWdw (win->left+1, win->top+1,win->right-1,win->bottom-1,
  1773.           (win->fore + (win->back << 4)),command);
  1774.  
  1775.     if (strcmp (strupr (ziputil), "PKZIP") == 0)
  1776.         strcat (zipname, ".ZIP");
  1777.     else if (strcmp (strupr (ziputil), "LHA") == 0)
  1778.         strcat (zipname, ".LZH");
  1779.     else if (strcmp (strupr (ziputil), "ARJ") == 0)
  1780.         strcat (zipname, ".ARJ");
  1781.  
  1782.     if (access (zipname, 0))
  1783.         fail ("Unable to create ZIP file: ", zipname);
  1784.     else
  1785.         unlink (textname);
  1786. }
  1787.  
  1788.  
  1789.  
  1790. void cursor (int cmnd)
  1791. {
  1792.     union REGS regs;
  1793.     int attribute;
  1794.  
  1795.     regs.h.ah = 0x01;
  1796.     if (cmnd == OFF)
  1797.         attribute = 0x01;
  1798.     else
  1799.         attribute = 0x00;
  1800.     regs.h.ch = attribute << 5 | 6;
  1801.     regs.h.cl = 7;
  1802.     int86 (0x10, ®s, ®s);
  1803. }
  1804.  
  1805.  
  1806. int check_catcode (char *code, CATCODE *cnode)
  1807. {
  1808.     int i,
  1809.         cndx = 0;
  1810.  
  1811.     if (strcmp (code, "***") == 0)
  1812.         cndx = -1;
  1813.     else
  1814.         while (cnode && strcmp (cnode->code, code))
  1815.         {
  1816.             cndx++;
  1817.             cnode = cnode->cnext;
  1818.         }
  1819.     if (cnode == NULL)
  1820.         cndx = -1;
  1821.     return (cndx);
  1822. }
  1823.  
  1824.  
  1825.  
  1826. void fail (char *message, char *filename)
  1827. {
  1828.     clrscr();
  1829.     gotoxy (16,2);
  1830.     cprintf ("%s %s ", message, filename);
  1831.     gotoxy (16,3);
  1832.     perror ("");
  1833.     textattr (7);
  1834.     cursor (ON);
  1835.     exit (1);
  1836. }
  1837.  
  1838.  
  1839. int set_colors (WININFO *header, WININFO *center, WININFO *bottom)
  1840. {
  1841.     int dispmode;
  1842.     struct text_info t_info;
  1843.  
  1844.         header->left = 2;
  1845.         header->top = 2;
  1846.         header->right = 77;
  1847.         header->bottom = 4;
  1848.         center->left = 2;
  1849.         center->top = 9;
  1850.         center->right = 77;
  1851.         center->bottom = 16;
  1852.         bottom->left = 2;
  1853.         bottom->top = 20;
  1854.         bottom->right = 77;
  1855.         bottom->bottom = 22;
  1856.  
  1857.     gettextinfo (&t_info);
  1858.     if (t_info.currmode == C40 || t_info.currmode == C80)
  1859.     {
  1860.         dispmode = COLOR;
  1861.         header->fore = YELLOW;
  1862.         header->back = MAGENTA;
  1863.         header->hifore = YELLOW;
  1864.         header->hiback = RED;
  1865.         header->bstyle = DOUBLE;
  1866.         header->bcolor = LIGHTGRAY;
  1867.         header->shadow = ON;
  1868.         center->fore = WHITE;
  1869.         center->back = CYAN;
  1870.         center->hifore = YELLOW;
  1871.         center->hiback = RED;
  1872.         center->bstyle = DOUBLE;
  1873.         center->bcolor = DARKGRAY;
  1874.         center->shadow = ON;
  1875.         bottom->fore = BLACK;
  1876.         bottom->back = GREEN;
  1877.         bottom->hifore = WHITE;
  1878.         bottom->hiback = RED;
  1879.         bottom->bstyle = DOUBLE;
  1880.         bottom->bcolor = DARKGRAY;
  1881.         bottom->shadow = ON;
  1882.     }
  1883.     else
  1884.     {
  1885.         dispmode = BW;
  1886.         header->fore = LIGHTGRAY;
  1887.         header->back = BLACK;
  1888.         header->hifore = LIGHTGRAY;
  1889.         header->hiback = BLACK;
  1890.         header->bstyle = DOUBLE;
  1891.         header->bcolor = LIGHTGRAY;
  1892.         header->shadow = OFF;
  1893.         center->fore = LIGHTGRAY;
  1894.         center->back = BLACK;
  1895.         center->hifore = LIGHTGRAY;
  1896.         center->hiback = BLACK;
  1897.         center->bstyle = DOUBLE;
  1898.         center->bcolor = LIGHTGRAY;
  1899.         center->shadow = OFF;
  1900.         bottom->fore = LIGHTGRAY;
  1901.         bottom->back = BLACK;
  1902.         bottom->hifore = LIGHTGRAY;
  1903.         bottom->hiback = BLACK;
  1904.         bottom->bstyle = DOUBLE;
  1905.         bottom->bcolor = LIGHTGRAY;
  1906.         bottom->shadow = OFF;
  1907.     }
  1908.     return (dispmode);
  1909. }
  1910.  
  1911.  
  1912.  
  1913. void clear_status (WININFO *win)
  1914. {
  1915.     textattr (win->fore + (win->back << 4));
  1916.     gotoxy (1,1);
  1917.     clreol();
  1918. }
  1919.  
  1920.  
  1921. /**********************************************************************
  1922. *  the following code comes from DOSWDW by Edward V. Dong, a Turbo C  *
  1923. *  implementation of EXECWINDOW by Kim Kokkonen, TurboPower Software, *
  1924. *  which was released to the public domain.                           *
  1925. **********************************************************************/
  1926. void far DoDosWdw(int xleft,int ytop,int xrite,int ybottom,int attrib,char *cmd)
  1927. {
  1928.     textattr(attrib);                       /* set text attribute */
  1929.     window(xleft, ytop, xrite, ybottom);    /* make the window */
  1930.     clrscr();                               /* clear the window */
  1931.     wdwpos = ((ytop - 1) * 256) + (xleft - 1);
  1932.     wdwupr = wdwpos;
  1933.     wdwlwr = ((ybottom - 1) * 256) + (xrite - 1);
  1934.     wdwattr = (attrib);
  1935.     oldint21 = getvect(0x21);       /* save old interrupt 21h */
  1936.     setup21(0);            /* move vector into CS (use 0 to scroll screen) */
  1937.     setvect(0x21, newint21);    /* point to dos window */
  1938.     system(cmd);            /* run the command */
  1939.     setvect(0x21, oldint21);    /* restore interrupt 21h */
  1940. }
  1941.