home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / DWNSRS56.ZIP / DOWNPAR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-10  |  23.8 KB  |  633 lines

  1. /* ============================================================= */
  2. /*  Rob Hamerling's MAXIMUS download file scan and sort utility. */
  3. /*  -> DOWNPAR.C                                                 */
  4. /*  -> Parameter processing routines for DOWNSORT.               */
  5. /* ============================================================= */
  6.  
  7. #define INCL_BASE
  8. #define INCL_DOSNLS
  9. #include <os2.h>
  10.  
  11. #include <ctype.h>
  12. #include <memory.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <time.h>
  17.  
  18. #include "..\max\mstruct.h"
  19. #include "downsort.h"
  20. #include "downfpro.h"
  21.  
  22. /*  Symbolic names of keyword parameters */
  23. #define    K_CMT      0
  24. #define    K_TIT      1
  25. #define    K_FNT      2
  26. #define    K_DAT      3
  27. #define    K_ALL      4
  28. #define    K_NEW      5
  29. #define    K_GBL      6
  30. #define    K_BBS      7
  31. #define    K_FIL      8
  32. #define    K_ORP      9
  33. #define    K_NNN     10
  34. #define    K_PRE     11
  35. #define    K_SUB     12
  36. #define    K_BOT     13
  37. #define    K_NDS     14
  38. #define    K_ODS     15
  39. #define    K_IPF     16
  40. #define    K_OFF     17
  41. #define    K_AIN     18
  42. #define    K_AEX     19
  43. #define    K_DUP     20
  44. #define    K_OK      21
  45. #define    K_IP2     22
  46. #define    K_ASQ     23
  47. #define    K_EMI     24
  48. #define    K_AVA     25
  49. #define    K_END    255
  50.  
  51. /* prototypes of local functions */
  52.  
  53. void    add_sel_area(char *, char [][MAXANAME]);
  54. short int conv_priv(char [], short int [], unsigned short int);
  55. void    list_parm(short int, char *, short int);
  56. short int parse_keyword(char [], char **);
  57. void    read_cfg(char *);
  58. void    title_line(char *, char *[]);
  59.  
  60.  
  61. /* ----------------------------------------- */
  62. /* Process commandline and system parameters */
  63. /* ----------------------------------------- */
  64. void get_parm(unsigned short int k,
  65.               char *p[])
  66. {
  67. #ifndef __32BIT__
  68.   unsigned short int x;                 //
  69. #else
  70.   unsigned long int x;                  //
  71. #endif
  72.   unsigned short int i,j,n;             // counters
  73.   char   c;                             // option letter
  74.  
  75. #ifndef __32BIT__
  76.   DosGetCtryInfo(sizeof(struct _COUNTRYINFO), &c_code, &c_info, &x);
  77. #else
  78.   DosQueryCtryInfo(sizeof(struct _COUNTRYINFO), &c_code, &c_info, &x);
  79. #endif
  80.                                         // for date format, etc
  81.   sys_date(today);                      // start timestamp
  82.  
  83.   for (i=1; i<k; ++i) {                 // pre-scan
  84.     if (p[i][0]=='@')                   // config filespec
  85.       strncpy(cfg_path,strupr(&p[i][1]),127); // copy filespec
  86.     else if (p[i][0] == '/' || p[i][0] == '-') { // options
  87.       switch(c = (char) toupper(p[i][1])) {
  88.         case VERBOSE   : oper_mode = VERBOSE;   break;
  89.         case QUIET     : oper_mode = QUIET;     break;
  90.         case HELP      : oper_mode = HELP;      break;
  91.         case QMARK     : oper_mode = HELP;      break;
  92.         }
  93.       }
  94.     }
  95.  
  96.   if (oper_mode == HELP)
  97.     show_help();                        // display help and exit
  98.   else if (oper_mode != QUIET)
  99.     show_welcome();                     // display DOWNSORT 'logo'
  100.  
  101.   read_cfg(cfg_path);                   // process configuration file
  102.  
  103.   for (i=1; i<k; i++) {                 // all commandline parms
  104.     strupr(p[i]);                       // make string upper case
  105.  
  106.     if (strcmp(p[i],"ORP") == 0)        // ORP-list requested
  107.       lp[P_ORP].priv[0] = SYSOP;        // first/only default: SYSOP
  108.  
  109.     else if (strcmp(p[i],"BBS") == 0 ||
  110.              strncmp(p[i],"BBS:",4) == 0) {  // BBS-list requested
  111.       lp[P_BBS].priv[0] = SYSOP;        // default: SYSOP
  112.       if (p[i][3] == ':')
  113.         if (conv_priv(&p[i][4],lp[P_BBS].priv,1) <= 0)   // convert
  114.           oper_mode = HELP;
  115.       }
  116.  
  117.     else if (strcmp(p[i],"NEW") == 0 ||
  118.              strncmp(p[i],"NEW:",4) == 0) { // NEW-list requested
  119.       lp[P_NEW].priv[0] = SYSOP;        // first/only default: SYSOP
  120.       if (p[i][3] == ':')
  121.         if (conv_priv(&p[i][4],lp[P_NEW].priv,10) <= 0)   // convert to int
  122.           oper_mode = HELP;
  123.       }
  124.  
  125.     else if (strcmp(p[i],"EMI") == 0 ||
  126.              strncmp(p[i],"EMI:",4) == 0) { // EMI-list requested
  127.       lp[P_EMI].priv[0] = SYSOP;        // first/only default: SYSOP
  128.       if (p[i][3] == ':')
  129.         if (conv_priv(&p[i][4],lp[P_EMI].priv,10) <= 0)   // convert to int
  130.           oper_mode = HELP;
  131.       }
  132.  
  133.     else if (strcmp(p[i],"ALL") == 0 ||
  134.              strncmp(p[i],"ALL:",4) == 0) { // ALL-list requested
  135.       lp[P_ALL].priv[0] = SYSOP;        // first/only default: SYSOP
  136.       if (p[i][3] == ':')
  137.         if (conv_priv(&p[i][4],lp[P_ALL].priv,10) <= 0)   // convert to int
  138.           oper_mode = HELP;
  139.       }
  140.  
  141.     else if (strcmp(p[i],"IPF") == 0 ||
  142.              strncmp(p[i],"IPF:",4) == 0) { // IPF-list requested
  143.       lp[P_IPF].priv[0] = SYSOP;        // first/only default: SYSOP
  144.       if (p[i][3] == ':')
  145.         if (conv_priv(&p[i][4],lp[P_IPF].priv,10) <= 0)   // convert to int
  146.           oper_mode = HELP;
  147.       }
  148.  
  149.     else if (strcmp(p[i],"IP2") == 0 ||
  150.              strncmp(p[i],"IP2:",4) == 0) { // IPF2-list requested
  151.       lp[P_IP2].priv[0] = SYSOP;        // first/only default: SYSOP
  152.       if (p[i][3] == ':')
  153.         if (conv_priv(&p[i][4],lp[P_IP2].priv,10) <= 0)   // convert to int
  154.           oper_mode = HELP;
  155.       }
  156.  
  157.     else if (strcmp(p[i],"GBL") == 0 ||
  158.              strncmp(p[i],"GBL:",4) == 0) { // GBL-list requested
  159.       lp[P_GBL].priv[0] = SYSOP;        // first/only default: SYSOP
  160.       if (p[i][3] == ':')
  161.         if (conv_priv(&p[i][4],lp[P_GBL].priv,10) <= 0)   // convert to int
  162.           oper_mode = HELP;
  163.       }
  164.  
  165.     else if (strcmp(p[i],"DUP") == 0 ||
  166.              strncmp(p[i],"DUP:",4) == 0) {  // DUP-list requested
  167.       lp[P_DUP].priv[0] = SYSOP;        // default: SYSOP
  168.       if (p[i][3] == ':')
  169.         if (conv_priv(&p[i][4],lp[P_DUP].priv,1) <= 0)   // convert
  170.           oper_mode = HELP;
  171.       }
  172.  
  173.     else if (strcmp(p[i],"OK") == 0 ||
  174.              strncmp(p[i],"OK:",3) == 0) {  // OK-file requested
  175.       lp[P_OK].priv[0] = SYSOP;        // default: SYSOP
  176.       if (p[i][2] == ':')
  177.         if (conv_priv(&p[i][3],lp[P_OK].priv,10) <= 0)   // convert
  178.           oper_mode = HELP;
  179.       }
  180.  
  181.     else if (strcmp(p[i],"FIL") == 0 ||
  182.              strncmp(p[i],"FIL:",4) == 0) { // FILES.BBS to be generated
  183.       lp[P_FIL].priv[0] = SYSOP;
  184.       if (p[i][3] == ':') {             // path specified?
  185.         strncpy(filesbbs_path,&p[i][4],79);
  186.         j = strlen(filesbbs_path);
  187.         if (j>0 && filesbbs_path[j-1] != '\\')
  188.           filesbbs_path[j] = '\\';      // add backslash if needed
  189.         }
  190.       }
  191.  
  192.     else if (p[i][0] == '/' || p[i][0] == '-') { // option flag
  193.       switch(c = (char) toupper(p[i][1])) {
  194.         case TRUNC     :
  195.         case WRAP      : for (j=0; j<P_MAX; ++j)
  196.                            lp[j].wrapflag = c;
  197.                          break;
  198.         case ALPHA     :
  199.         case TIMESTAMP :
  200.         case KEEPSEQ   : for (j=0; j<P_MAX; ++j)
  201.                            lp[j].sortflag = c;
  202.                          break;
  203.         case LONGLIST  : for (j=0; j<P_MAX; ++j)
  204.                            lp[j].longflag = c;
  205.                          break;
  206.         case EXCLPRIV  : for (j=0; j<P_MAX; ++j)
  207.                            lp[j].exclflag = c;
  208.                          break;
  209.         case QUIET     :
  210.         case VERBOSE   :
  211.         case HELP      : oper_mode = c;         break;
  212.         case QMARK     : oper_mode = HELP;      break;
  213.  
  214.         default        : oper_mode = HELP;      break;
  215.         }
  216.       }
  217.  
  218.     else if (0 < (n = atoi(p[i]))) {    // num_value: list length
  219.       lp[P_BBS].max_fil = n;            // BBS-list length
  220.       lp[P_BBS].listflag = ' ';         // no period (yet?)
  221.       lp[P_NEW].max_fil = n;            // NEW-list length
  222.       lp[P_NEW].listflag = ' ';         // no period (yet?)
  223.       lp[P_EMI].max_fil = n;            // NEW-list length
  224.       lp[P_EMI].listflag = ' ';         // no period (yet?)
  225.       j = strlen(p[i]) - 1;             // offset to last character
  226.       c = p[i][j];                      // last character
  227.       if (c == 'D' || c == 'W' || c == 'M') {
  228.         lp[P_BBS].listflag = c;         // BBS-list flag
  229.         lp[P_NEW].listflag = c;         // NEW-list flag
  230.         lp[P_EMI].listflag = c;         // EMI-list flag
  231.         }
  232.       }
  233.  
  234.     else if (p[i][0] == '@')            // config filespec
  235.       ;                                 // skip (processed in pre-scan)
  236.  
  237.     else
  238.       printf("\nUnknown Parameter: %-50.50s",p[i]);
  239.     }
  240.  
  241.   for (i=0; i<=P_MAX; i++)              // all report entries
  242.     for (j=0; j<10; j++)                // all privilege entries
  243.       if (ABS_MAX_priv < lp[i].priv[j] &&  // higher than before
  244.               HIDDEN+1 > lp[i].priv[j])  // but only requested reports
  245.         ABS_MAX_priv = lp[i].priv[j];    // revise if needed
  246.   }
  247.  
  248. /* --------------------------------- */
  249. /* Process privilege parameterstring */
  250. /* --------------------------------- */
  251. short int conv_priv(char c[],
  252.                     short int p[],
  253.                     unsigned short int n)
  254. {
  255.   unsigned short int i,j,k;             // counters
  256.  
  257.   for (i=j=0; i<n && c[i]!='\0' && c[i]!=' '; ++i) {
  258.     if (c[i] == '*')                    // asterisk specified?
  259.       p[j] = SYSOP;                     // system default
  260.     else {
  261.       for (k=0; k<HIDDEN-TWIT+1 &&      // search table
  262.                 priv_name[k][0] != (char) toupper(c[i]);
  263.                 k++);
  264.       p[j] = k + TWIT;                  // store real privilege
  265.       }                                 // endif
  266.     if (p[j]<=HIDDEN)                   // hidden or below?
  267.       ++j;                              // count only valid privs
  268.     }                                   // endfor
  269.   for (i=j; i<n; ++i)                   // remaining priv-values
  270.     p[i] = HIDDEN + 1;                  // undo any previous settings
  271.   return(j);                            // number of valid privs
  272.   }
  273.  
  274. /* =================================== */
  275. /* Process DOWNSORT Configuration File */
  276. /* =================================== */
  277. void read_cfg(char ds_cfg[])
  278. {
  279.   FILE *prm;
  280.   char buf[256], c;
  281.   char *value;                          // ptr to parameter value
  282.   short int  i,j,t;
  283.  
  284.   if ((prm = fopen(ds_cfg,"r")) == NULL )
  285.     printf(OPEN_FAIL, ds_cfg, 2);      // dummy rc 'file not found'!
  286.  
  287.   else {
  288.     if (oper_mode != QUIET)
  289.       printf("\nReading configuration file: %s",cfg_path);
  290.  
  291.     while (fgets(buf,255,prm)) {        // process 1 line at a time
  292.  
  293.       switch(parse_keyword(buf,&value)) {
  294.  
  295.         case K_CMT:                     // Comment and empty lines
  296.           break;
  297.  
  298.         case K_TIT:                     // list title (ALL, NEW, GBL)
  299.           for (j=0; j<20 && value[j]!='\0'; j++)
  300.             if (value[j] == '~')        // replace tilde by blank
  301.               value[j] = ' ';
  302.           strncpy(list_title,value,20);
  303.           break;
  304.  
  305.         case K_PRE:                     // pre-title
  306.           title_line(value,pre_title);
  307.           break;
  308.  
  309.         case K_SUB:                     // sub-title
  310.           title_line(value,sub_title);
  311.           break;
  312.  
  313.         case K_BOT:                     // bottom line
  314.           title_line(value,bot_lines);
  315.           break;
  316.  
  317.         case K_ODS:                     // Orphan Description
  318.           strncpy(ORPHAN,value,45);     // copy file text
  319.           break;
  320.  
  321.         case K_NDS:                     // Missing Description
  322.           strncpy(NDS,value,45);        // copy file text
  323.           break;
  324.  
  325.         case K_OFF:                     // Offline Description
  326.           OFFLINE[0] = '\0';            // erase default string
  327.           strncat(OFFLINE,value,14);    // copy(!) text
  328.           strcat(OFFLINE," ");          // 1 trailing blank
  329.           break;
  330.  
  331.         case K_FNT:                     // Font for all lists
  332.           t = atoi(value);              // convert to integer
  333.           if (t < FONT0 || t > FONT4)   // range check
  334.             printf("\n!Error: TitleFont out of range");
  335.           else
  336.             for (i=0; i<P_MAX; i++)
  337.               lp[i].tfont = t;           // to all parmlist entries
  338.           break;
  339.  
  340.         case K_DAT:                     // Area.Dat
  341.           strncpy(areadat_path,strupr(value),80);  // copy file specification
  342.           break;
  343.  
  344.         case K_AIN:                     // AreaINclude
  345.           area_IN_EX = +1;              // inclusion
  346.           add_sel_area(value, selected_area);   // area codes to array
  347.           break;
  348.  
  349.         case K_AEX:                     // AreaEXclude
  350.           area_IN_EX = -1;              // exclusion
  351.           add_sel_area(value, selected_area);   // area codes to array
  352.           break;
  353.  
  354.         case K_ASQ:                     // AreaSequence
  355.           area_seq = (char) toupper(value[0]);  // take 1st char uppercase
  356.           break;
  357.  
  358.         case K_AVA:                     // Strip AVATAR graphics
  359.           strip_ava = (char) toupper(value[0]);   // set switch
  360.           break;
  361.  
  362.         case K_NNN:
  363.           if (0 < (t = atoi(value))) {  // NEW- & BBS-list length
  364.             lp[P_BBS].max_fil = t;      // BBS-list length
  365.             lp[P_BBS].listflag = ' ';   // no period (yet?)
  366.             lp[P_NEW].max_fil = t;      // NEW-list length
  367.             lp[P_NEW].listflag = ' ';   // no period (yet?)
  368.             lp[P_EMI].max_fil = t;      // EMI-list length
  369.             lp[P_EMI].listflag = ' ';   // no period (yet?)
  370.             strupr(value);              // all upper case
  371.             c = value[strlen(asciiz(value))-1]; // last character
  372.             if (c == 'D' || c == 'W' || c == 'M') {
  373.               lp[P_BBS].listflag = c;   // BBS-list flag
  374.               lp[P_NEW].listflag = c;   // NEW-list flag
  375.               lp[P_EMI].listflag = c;   // EMI-list flag
  376.               }
  377.             }
  378.           break;
  379.  
  380.         case K_ALL:                     // create ALL-list(s)
  381.           list_parm(P_ALL,value,10);
  382.           break;
  383.  
  384.         case K_IPF:                     // create IPF-list(s)
  385.           list_parm(P_IPF,value,10);
  386.           break;
  387.  
  388.         case K_IP2:                     // create IPF2-list(s)
  389.           list_parm(P_IP2,value,10);
  390.           break;
  391.  
  392.         case K_BBS:                     // create BBS-list
  393.           list_parm(P_BBS,value,1);
  394.           break;
  395.  
  396.         case K_GBL:                     // create GBL-list
  397.           list_parm(P_GBL,value,10);
  398.           break;
  399.  
  400.         case K_NEW:                     // create NEW-list(s)
  401.           list_parm(P_NEW,value,10);
  402.           break;
  403.  
  404.         case K_EMI:                     // create EMI-list(s)
  405.           list_parm(P_EMI,value,10);
  406.           break;
  407.  
  408.         case K_DUP:                     // naming of DUP-list
  409.           list_parm(P_DUP,value,1);
  410.           break;
  411.  
  412.         case K_OK:                      // create OKfile(s)
  413.           list_parm(P_OK,value,10);
  414.           break;
  415.  
  416.         case K_ORP:                     // naming of ORP-list
  417.           list_parm(P_ORP,value,1);
  418.           break;
  419.  
  420.         case K_FIL:                     // create FILES.bbs files
  421.           strupr(value);                // all upper case
  422.           conv_priv(value,lp[P_FIL].priv,1);
  423.           while ((value = next_word(value)) != NULL) {  // remaining parm(s)
  424.             if (value[0] == '/' || value[0] == '-') {  // option flag
  425.               switch(value[1]) {
  426.                 case ALPHA     : lp[P_FIL].sortflag = ALPHA;     break;
  427.                 case TIMESTAMP : lp[P_FIL].sortflag = TIMESTAMP; break;
  428.                 case KEEPSEQ   : lp[P_FIL].sortflag = KEEPSEQ;   break;
  429.                 case EXCLPRIV  : lp[P_FIL].exclflag = EXCLPRIV;  break;
  430.                 case INCLUDE   : lp[P_FIL].incl_fspec =
  431.                                     (char *)malloc(strlen(asciiz(value+2))+1);
  432.                                  if (lp[P_FIL].incl_fspec == NULL) {
  433.                                    printf(MSG_MEM,PROGNAME);
  434.                                    exit(14);
  435.                                    }
  436.                                  else
  437.                                    strcpy(lp[P_FIL].incl_fspec,
  438.                                                  asciiz(value+2));
  439.                                  break;
  440.                 default        : break;
  441.                 }
  442.               }
  443.             else {                      /* assume 'value' is pathname */
  444.               strncpy(filesbbs_path,asciiz(value),80); // spec'd PATH
  445.               j = strlen(filesbbs_path);
  446.               if (j>0 && filesbbs_path[j-1] != '\\')
  447.                 filesbbs_path[j] = '\\';    // add backslash if needed
  448.               }
  449.             }
  450.           break;
  451.  
  452.         case K_END:                     // Keyword not found
  453.         default:                        // undefined
  454.           printf("\nUnknown Configuration keyword: %-50.50s",buf);
  455.           break;
  456.         }
  457.       }
  458.     fclose(prm);                        // close downsort.cfg
  459.     }
  460.   }
  461.  
  462. /* =============================== */
  463. /* Process xxxFileList parameters. */
  464. /* =============================== */
  465. void list_parm(short int k,
  466.                char  *v,
  467.                short int n)
  468. {
  469.   short int  t,j;                       // intermediate int value
  470.   char *nv;                             // moving string pointer
  471.   char c;                               // single input character
  472.  
  473.   strupr(v);                            // whole string uppercase
  474.   conv_priv(v, lp[k].priv, n);          // privilege string
  475.   if ((nv = next_word(v)) != NULL  &&   // 1st expected: filename
  476.        strcmp(nv,"*") != 0)             // not asterisk
  477.     strncpy(lp[k].name,asciiz(nv),8);   // customised filename
  478.   while ((nv = next_word(nv)) != NULL) { // remaining parm(s)
  479.     if (nv[0] == '/' || nv[0] == '-') { // option flag
  480.       switch(nv[1]) {
  481.         case TRUNC     : lp[k].wrapflag = TRUNC;     break;
  482.         case WRAP      : lp[k].wrapflag = WRAP;      break;
  483.         case ALPHA     : lp[k].sortflag = ALPHA;     break;
  484.         case TIMESTAMP : lp[k].sortflag = TIMESTAMP; break;
  485.         case KEEPSEQ   : lp[k].sortflag = KEEPSEQ;   break;
  486.         case LONGLIST  : lp[k].longflag = LONGLIST;  break;
  487.         case FONT      : t = atoi(nv+2);
  488.                          if (t >= FONT0 && t <= FONT4) // range check
  489.                            lp[k].tfont = t;
  490.                          break;
  491.         case EXCLPRIV  : lp[k].exclflag = EXCLPRIV;  break;
  492.         case INCLUDE   : lp[k].incl_fspec =
  493.                                   (char *)malloc(strlen(asciiz(nv+2))+1);
  494.                          if (lp[k].incl_fspec == NULL) {
  495.                            printf(MSG_MEM,PROGNAME);  // not enough memory
  496.                            exit(14);
  497.                            }
  498.                          else
  499.                            strcpy(lp[k].incl_fspec, asciiz(nv+2));
  500.                          break;
  501.         default        : break;         // invalid parms ignored
  502.         }
  503.       }
  504.     else if (0 < atoi(nv)) {            // numeric: NEW-list length
  505.       lp[k].max_fil = atoi(nv);         // (for IPF-list: pagesize)
  506.       lp[k].listflag = ' ';             // set to (nullify previous) period
  507.       j = strlen(asciiz(nv)) - 1;       // offset to last character
  508.       c = nv[j];                        // last character
  509.       if (c == 'D' || c == 'W' || c == 'M')
  510.         lp[k].listflag = c;             // copy listflag
  511.       }
  512.     }
  513.   }
  514.  
  515. /* ============================ */
  516. /* Process xxxTitle parameters. */
  517. /* ============================ */
  518. void  title_line(char *v,
  519.                  char *t[])
  520. {
  521.   short int i,j;                        // counters
  522.  
  523.   for (i=0; i<MAXTIT && t[i]!=NULL; ++i);  // search 1st free place
  524.   if (i<MAXTIT) {                       // not too many subtitles?
  525.     t[i] = (char *)malloc(strlen(v)+2); // obtain memory (1 too many?)
  526.     if (t[i] == NULL) {
  527.       printf(MSG_MEM,PROGNAME);         // not enough memory
  528.       exit(14);
  529.       }
  530.     else {
  531.       for (j=0; v[j]; j++)              // whole line
  532.         t[i][j] = (char)((v[j] == '~') ? ' ' : v[j]);  // copy/translate
  533.       t[i][j] = '\0';                   // end of string
  534.       }
  535.     }
  536.   }
  537.  
  538. /* ============================ */
  539. /* Process AreaSelect line      */
  540. /* ============================ */
  541. void  add_sel_area(char  *v,
  542.                    char  s[][MAXANAME])
  543. {
  544.   short int i,j;                        // counters
  545.  
  546.   for (i=0; s[i][0] != '\0'; ++i);      // search first empty place
  547.  
  548.   for ( ; v!=NULL && i<200; i++) {      // all entries in array bounds
  549.     for (j=0; v[j] != ' ' && v[j] != '\0' && j < MAXANAME-1; ++j)
  550.        s[i][j] = v[j];                  // copy area name to array
  551.     for ( ; j < MAXANAME; ++j)
  552.        s[i][j] = '\0';                  // trailing zero's
  553.     v = next_word(v);                   // search next code
  554.     }
  555.  
  556.   s[i][0] = '\0';                       // last entry marker
  557.  
  558.   }
  559.  
  560. /* ===================================== */
  561. /* Find the number of the config options */
  562. /* Returns the keyword symbolic number,  */
  563. /* and pointer to the keyword value.     */
  564. /* ===================================== */
  565. short int parse_keyword(char line[],
  566.                         char **value)
  567. {
  568.   short int i,p;                        // counters
  569.  
  570.   static struct parse_config {          // Keyword Parameter Spec
  571.        unsigned char id;                // parameter identifier
  572.        unsigned char len;               // keyword length
  573.        char *key;                       // keyword
  574.        } cfg[] = {                      // table of keyword parameters
  575.                                         // NOTE: most significant first!
  576.            {K_ALL, 11, "AllFileList"},
  577.            {K_DAT,  7, "AreaDat"},
  578.            {K_AEX, 11, "AreaEXclude"},
  579.            {K_AIN, 11, "AreaINclude"},
  580.            {K_ASQ,  9, "AreaOrder"},
  581.            {K_AVA,  8, "AVAstrip"},
  582.            {K_BBS, 11, "BbsFileList"},
  583.            {K_BOT, 10, "BottomLine"},
  584.            {K_DUP, 11, "DupFileList"},
  585.            {K_FIL, 11, "FilFilePath"},
  586.            {K_GBL, 11, "GblFileList"},
  587.            {K_IPF, 11, "IpfFileList"},
  588.            {K_IP2, 11, "Ip2FileList"},
  589.            {K_NNN, 11, "MaxNewFiles"},
  590.            {K_NEW, 11, "NewFileList"},
  591.            {K_EMI, 11, "EmiFileList"},
  592.            {K_OK , 10, "OKFileList"},
  593.            {K_NDS, 12, "NotFoundDesc"},
  594.            {K_OFF, 11, "OfflineDesc"},
  595.            {K_ORP, 11, "OrpFileList"},
  596.            {K_ODS, 10, "OrphanDesc"},
  597.            {K_PRE,  8, "PreTitle"},
  598.            {K_SUB,  8, "SubTitle"},
  599.            {K_FNT,  9, "TitleFont"},
  600.            {K_TIT,  5, "Title"},
  601.            {K_END,  0, ""},             // end of table: keyw. not found
  602.              };
  603.  
  604.   *value = NULL;                        // init: default return
  605.  
  606.   for (i=0; line[i]==' '; ++i);         // skip leading blanks
  607.   line = line+i;                        // new local pointer
  608.  
  609.   if (line[0] == '%'  ||                // comment
  610.       line[0] == ';'  ||                // comment
  611.       line[0] == '*'  ||                // comment
  612.       line[0] == '\r' ||                // CR character
  613.       line[0] == '\n' ||                // LF character
  614.       line[0] == '\0')                  // end of string
  615.     return(K_CMT);                      // return as comment line
  616.  
  617.   for (i=0; cfg[i].id < K_END &&         // not end of table
  618.            strnicmp(line,cfg[i].key,cfg[i].len) != 0 ; i++);
  619.   p = cfg[i].id;                        // return identification value
  620.  
  621.   *value = next_word(line);             // search value string
  622.   if (*value == NULL)                   // no keyword value
  623.     return(K_CMT);                      // treat as comment
  624.  
  625.   i = strlen(*value);                   // length of value string
  626.   if ((*value)[i-1] == '\n'  ||         // line feed or
  627.       (*value)[i-1] == '\r')            // carriage return
  628.     (*value)[i-1] = '\0';               // by end of string
  629.  
  630.   return(p);                            // return the keyword number
  631.   }
  632.  
  633.