home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / dwnsrs59.zip / DOWNPAR.C < prev    next >
C/C++ Source or Header  |  1993-12-18  |  25KB  |  589 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_NOPMAPI
  9. #define INCL_DOSNLS
  10. #include <os2.h>
  11.  
  12. #include <ctype.h>
  13. #include <memory.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <time.h>
  18.  
  19. #include "..\max\mstruct.h"
  20. #include "downsort.h"
  21. #include "downfpro.h"
  22.  
  23. /*  Symbolic names of keyword parameters */
  24. enum _keyword { K_CMT, K_TIT, K_DAT, K_ALL, K_NEW, K_GBL, K_BBS,
  25.                 K_FIL, K_ORP, K_PRE, K_SUB, K_BOT, K_NDS, K_ODS, K_IPF,
  26.                 K_OFF, K_AIN, K_AEX, K_DUP, K_OK,  K_IP2, K_ASQ, K_EMI,
  27.                 K_AVA, K_NDE, K_FEX, K_GRP, K_END};
  28.  
  29. /* prototypes of local functions */
  30.  
  31. void    add_ext_pair(char *, DUPCHAIN **);
  32. void    add_file_array(char [][MAXFN], char *);
  33. void    add_str(char *, STRCHAIN **);
  34. void    add_title(char *, STRCHAIN **);
  35. void    add_tok(char *, STRCHAIN **);
  36. short int conv_priv(char [], ULONG *);
  37. void    list_parm(short int, char *);
  38. void    list_path(short int, char *);
  39. short int parse_keyword(char [], char **);
  40. void    read_cfg(char *);
  41.  
  42.  
  43. /* ----------------------------------------- */
  44. /* Process commandline and system parameters */
  45. /* ----------------------------------------- */
  46. void get_parm(unsigned short int k,
  47.               char *p[])
  48. {
  49.   unsigned short int i;                 /* counters                      */
  50.   LISTPARM  *ls;                        /* list specs */
  51.  
  52. #ifndef __32BIT__
  53.   USHORT x;                             /* returned length               */
  54.   DosGetCtryInfo(sizeof(COUNTRYINFO), &c_code, &c_info, &x);
  55. #else
  56.   ULONG  x;                             /* returned length               */
  57.   DosQueryCtryInfo(sizeof(COUNTRYINFO), &c_code, &c_info, &x);
  58. #endif
  59.                                         /* for date format, etc          */
  60.   sys_date(today);                      /* start timestamp               */
  61.  
  62.   for (i=1; i<k; ++i) {                 /* scan commandline              */
  63.     if (p[i][0]=='@')                   /* config filespec               */
  64.       strncpy(cfg_path,strupr(&p[i][1]),127); /* copy filespec           */
  65.     else if (p[i][0] == '/' || p[i][0] == '-') { /* options              */
  66.       switch(toupper(p[i][1])) {
  67.         case VERBOSE   : oper_mode = VERBOSE;   break;
  68.         case QUIET     : oper_mode = QUIET;     break;
  69.         case HELP      : oper_mode = HELP;      break;
  70.         case QMARK     : oper_mode = HELP;      break;
  71.         }
  72.       }
  73.     }
  74.  
  75.   if (oper_mode != QUIET)
  76.     show_welcome();                     /* display DOWNSORT 'logo' */
  77.   if (oper_mode == HELP) {
  78.     show_help();                        /* display help and exit */
  79.     return;                             /* quit program */
  80.     }
  81.  
  82.   read_cfg(cfg_path);                   /* process configuration file */
  83.  
  84.   for (i=0; i<=P_MAX; i++) {            /* all list types */
  85.     ls = lp[i].next;                    /* pointer to list specs */
  86.     while (ls != NULL) {                /* all list of same type */
  87.       if (ABS_MAX_priv < ls->priv  &&   /* higher than before */
  88.               HIDDEN+1 > ls->priv)      /* but only requested reports */
  89.         ABS_MAX_priv = ls->priv;        /* revise if needed */
  90.       areakeys |= ls->userkeys;         /* cumulative userkeys */
  91.       if (keepseq!=KEEPSEQ && ls->sortflag==KEEPSEQ)
  92.         keepseq = KEEPSEQ;              /* any KEEPSEQ: collect comments */
  93.       ls = ls->next;                    /* next report of this type */
  94.       }
  95.     }
  96.  
  97.   if (oper_mode == VERBOSE)
  98.     fprintf(stdout, MSG_PAR);           /* parameters processed */
  99.   }
  100.  
  101. /* ------------------------------------------------------ */
  102. /* Process first character of a privilege parameterstring */
  103. /* Returns privilege value of first character of string.  */
  104. /* Remainder of string will be searched for userkeys(char)*/
  105. /* These will be returned in a 32-bits string (ULONG), if */
  106. /* not found the bitstring will be all zeroes.            */
  107. /* ------------------------------------------------------ */
  108. short int conv_priv(char c[],           /* privilege string */
  109.                     ULONG *u)           /* userkeys (to be returned) */
  110. {
  111.   char  cu;                             /* privilege character */
  112.   char  *k;                             /* pointer to userkeys string */
  113.   short int p;                          /* privilege value */
  114.  
  115.   cu = (char)toupper(c[0]);             /* get priv letter upper case */
  116.   p = SYSOP;                            /* init to default */
  117.   if (cu == '*')                        /* asterisk specified? */
  118.     p = SYSOP - TWIT;                   /* default (with offset corr.) */
  119.   else                                  /* search table */
  120.     for (p=0; p<=HIDDEN-TWIT && priv_name[p][0] != cu; p++);  /* search */
  121.  
  122.   *u = 0L;                              /* set all keys off */
  123.   k = strchr(c, '/');                   /* search leftmost slash */
  124.   if (k != NULL) {                      /* found: userkeys specified */
  125.     k = asciiz(k);                      /* make it an ASCIIZ string */
  126.     cu = (char)toupper(*++k);           /* first key character */
  127.     while (cu!='\0') {                  /* userkey characters */
  128.       if (cu == '*') {                  /* all keys */
  129.         *u = 0XFFFFFFFF;                /* returned userkey field */
  130.         break;                          /* remaining keys unimportant */
  131.         }
  132.       else if (cu>='1' && cu<='8')      /* keys 1..8 */
  133.         *u |= (1 << (cu-'1'));          /* add to userkeys */
  134.       else if (cu>='A' && cu<='X')      /* keys A..X */
  135.         *u |= (1 << (8 + (cu-'A')));    /* add to userkeys */
  136.       cu = (char)toupper(*++k);         /* next key character */
  137.       }
  138.     }
  139.   return(p + TWIT);                     /* return privilege value */
  140.   }
  141.  
  142. /* =================================== */
  143. /* Process DOWNSORT Configuration File */
  144. /* =================================== */
  145. void read_cfg(char ds_cfg[])
  146. {
  147.   FILE *prm;
  148.   char buf[256];
  149.   char *value;                          /* ptr to parameter value        */
  150.   short int kwd;
  151.  
  152.   if ((prm = fopen(ds_cfg,"r")) == NULL )
  153.     fprintf(stderr, MSG_OPI, ds_cfg, 2);  /* dummy rc 'file not found'!*/
  154.  
  155.   else {
  156.     if (oper_mode != QUIET)
  157.       fprintf(stdout, MSG_CFG, cfg_path);
  158.  
  159.     while (fgets(buf,sizeof(buf)-1,prm)) {  /* process 1 line at a time */
  160.  
  161.       kwd = parse_keyword(buf, &value);
  162.       switch(kwd) {
  163.  
  164.         case K_CMT:                     /* Comment and empty lines */
  165.           break;
  166.  
  167.         case K_TIT:                     /* block title (ALL, NEW, GBL) */
  168.           strncpy(list_title, value, 20);
  169.           break;
  170.  
  171.         case K_PRE:                     /* pre-title */
  172.           add_title(value, &pre_title);
  173.           break;
  174.  
  175.         case K_SUB:                     /* sub-title */
  176.           add_title(value, &sub_title);
  177.           break;
  178.  
  179.         case K_BOT:                     /* bottom line */
  180.           add_title(value, &bot_title);
  181.           break;
  182.  
  183.         case K_ODS:                     /* Orphan Description */
  184.           strncpy(ORPHAN,value,45);     /* copy file text */
  185.           break;
  186.  
  187.         case K_NDS:                     /* Missing Description */
  188.           strncpy(NDS,value,45);        /* copy file text */
  189.           break;
  190.  
  191.         case K_OFF:                     /* Offline Description */
  192.           OFFLINE[0] = '\0';            /* erase default string */
  193.           strncat(OFFLINE,value,14);    /* copy(!) text */
  194.           strcat(OFFLINE," ");          /* 1 trailing blank */
  195.           break;
  196.  
  197.         case K_DAT:                     /* Area.Dat */
  198.           strncpy(areadat_path, strupr(value),80);  /* copy file spec */
  199.           break;
  200.  
  201.         case K_AIN:                     /* AreaINclude */
  202.           add_tok(value, &incl_area);   /* add include string  */
  203.           break;
  204.  
  205.         case K_AEX:                     /* AreaEXclude */
  206.           add_tok(value, &excl_area);   /* add exclude strings */
  207.           break;
  208.  
  209.         case K_FEX:                     /* FileEXclude */
  210.           add_str(value, &excl_file);   /* add FILE-exclude strings */
  211.           break;
  212.  
  213.         case K_NDE:                     /* non duplicate extension pairs */
  214.           add_ext_pair(value, &non_dup_ext);    /* add ext pairs */
  215.           break;
  216.  
  217.         case K_ASQ:                     /* AreaSequence */
  218.           area_seq = (char) toupper(value[0]);  /* take 1st char upperc. */
  219.           break;
  220.  
  221.         case K_AVA:                     /* Strip AVATAR graphics */
  222.           strip_ava = (char) toupper(value[0]);   /* set switch */
  223.           break;
  224.  
  225.         case K_ALL:                     /* create ALL-list(s) */
  226.           list_parm(P_ALL, value);
  227.           break;
  228.  
  229.         case K_IPF:                     /* create IPF-list(s) */
  230.           list_parm(P_IPF, value);
  231.           break;
  232.  
  233.         case K_IP2:                     /* create IPF2-list(s) */
  234.           list_parm(P_IP2, value);
  235.           break;
  236.  
  237.         case K_BBS:                     /* create BBS-list */
  238.           list_parm(P_BBS, value);
  239.           break;
  240.  
  241.         case K_GBL:                     /* create GBL-list */
  242.           list_parm(P_GBL, value);
  243.           break;
  244.  
  245.         case K_NEW:                     /* create NEW-list(s) */
  246.           list_parm(P_NEW,value);
  247.           break;
  248.  
  249.         case K_EMI:                     /* create EMI-list(s) */
  250.           list_parm(P_EMI, value);
  251.           break;
  252.  
  253.         case K_DUP:                     /* create of DUP-list */
  254.           list_parm(P_DUP, value);
  255.           break;
  256.  
  257.         case K_OK:                      /* create OKfile */
  258.           list_parm(P_OK, value);
  259.           break;
  260.  
  261.         case K_ORP:                     /* create of ORP-list */
  262.           list_parm(P_ORP, value);
  263.           break;
  264.  
  265.         case K_FIL:                     /* create Files.Bbs files */
  266.           list_path(P_FIL, value);
  267.           break;
  268.  
  269.         case K_END:                     /* Keyword not found */
  270.         default:                        /* undefined */
  271.           fprintf(stderr, MSG_KWD, buf); /* keyword or value problem */
  272.           break;
  273.         }
  274.       }
  275.     fclose(prm);                        /* close downsort.cfg */
  276.     }
  277.   }
  278.  
  279. /* =============================== */
  280. /* Process xxxFileList parameters. */
  281. /* =============================== */
  282. void list_parm(short int k,             /* list type */
  283.                char  *v)                /* parm string */
  284. {
  285.   short int  t,j;                       /* intermediate int value */
  286.   char *nv;                             /* moving string pointer */
  287.   char c;                               /* single input character */
  288.   LISTPARM *ls, *ols;                   /* list specs */
  289.  
  290.   ols = &lp[k];                         /* pointer to default list specs */
  291.   while (ols->next != NULL)             /* search for last */
  292.     ols = ols->next;                    /* get pointer to next */
  293.   ls = (LISTPARM *)malloc(sizeof(struct _listparm));  /* mem for specs */
  294.   if (ls == NULL) {                     /* not obtained */
  295.               /* ===> error message */
  296.     return;                             /* ignore this list request */
  297.     }
  298.   ols->next = ls;                       /* chain pointer to new specs */
  299.   memcpy((void *)ls, (void *)&lp[k], sizeof(struct _listparm)); /* dflts */
  300.   ls->next = NULL;                      /* current end-of-chain */
  301.  
  302.   strupr(v);                            /* whole string uppercase */
  303.   ls->priv = conv_priv(v, &ls->userkeys);   /* determine priv/userkeys  */
  304.   if ((nv = next_word(v)) != NULL  &&   /* 1st expected: filename */
  305.        strcmp(nv,"*") != 0)             /* not asterisk */
  306.     strncpy(ls->name, asciiz(nv), 8);   /* customised filename */
  307.   while ((nv = next_word(nv)) != NULL) { /* remaining parm(s) */
  308.     if (nv[0] == '/' || nv[0] == '-') { /* option flag */
  309.       switch(nv[1]) {
  310.         case TRUNC     : ls->wrapflag = TRUNC;     break;
  311.         case WRAP      : ls->wrapflag = WRAP;      break;
  312.         case ALPHA     : ls->sortflag = ALPHA;     break;
  313.         case GROUP     : ls->sortflag = GROUP;     break;
  314.         case TIMESTAMP : ls->sortflag = TIMESTAMP; break;
  315.         case KEEPSEQ   : if (k==K_ALL || k!=K_IPF || k!=K_IP2)
  316.                            ls->sortflag = KEEPSEQ;   /* only some lists */
  317.                          break;
  318.         case LONGLIST  : ls->longflag = LONGLIST;  break;
  319.         case RUBBDATE  : ls->rubbflag = ~RUBBDATE;  break;
  320.         case FONT      : t = atoi(nv+2);
  321.                          if (t >= FONT0 && t <= FONT4) /* range check    */
  322.                            ls->tfont = t;
  323.                          break;
  324.         case CONT      : t = atoi(nv+2);
  325.                          ls->desc_indent = t;
  326.                          break;
  327.         case EXCLPRIV  : ls->exclflag = EXCLPRIV;  break;
  328.         case INCLUDE   : ls->incl_fspec =
  329.                                   (char *)malloc(strlen(asciiz(nv+2))+1);
  330.                          if (ls->incl_fspec == NULL) {
  331.                            fprintf(stderr, MSG_MEM, PROGNAME);  /* mem   */
  332.                            exit(14);
  333.                            }
  334.                          else
  335.                            strcpy(ls->incl_fspec, asciiz(nv+2));
  336.                          break;
  337.         default        : break;         /* invalid parm: ignored */
  338.         }
  339.       }
  340.     else if (0 < atoi(nv)) {            /* numeric: 'NEW'-list length */
  341.       ls->max_fil = atoi(nv);           /* (for IPF-list: pagesize) */
  342.       ls->listflag = ' ';               /* set to (nullify previous) per.*/
  343.       j = strlen(asciiz(nv)) - 1;       /* offset to last character */
  344.       c = nv[j];                        /* last character */
  345.       if (c == 'D' || c == 'W' || c == 'M')
  346.         ls->listflag = c;               /* copy listflag */
  347.       }
  348.     }
  349.   }
  350.  
  351. /* =============================== */
  352. /* Process FILFilePath parameters. */
  353. /* =============================== */
  354. void list_path(short int k,             /* list type (should be P_FIL) */
  355.                char  *v)                /* parm string */
  356. {
  357.   short int  t,j;                       /* intermediate int value        */
  358.   char *nv;                             /* moving string pointer         */
  359.   LISTPARM *ls, *ols;                   /* list specs                    */
  360.  
  361.   ols = &lp[k];                         /* pointer to default list specs */
  362.   while (ols->next != NULL)             /* search for last */
  363.     ols = ols->next;                    /* get pointer to next */
  364.   ls = (LISTPARM *)malloc(sizeof(struct _listparm));  /* mem for specs */
  365.   if (ls == NULL) {                     /* not obtained */
  366.               /* ===> error message */
  367.     return;                             /* ignore this list request */
  368.     }
  369.   ols->next = ls;                       /* chain pointer to new specs */
  370.   memcpy((void *)ls, (void *)&lp[k], sizeof(struct _listparm)); /* dflts */
  371.   ls->next = NULL;                      /* current end-of-chain */
  372.  
  373.   strupr(v);                            /* all upper case                */
  374.   ls->priv = conv_priv(v, &ls->userkeys);
  375.   nv = v;                               /* copy pointer                 */
  376.   while ((nv = next_word(nv)) != NULL) {  /* remaining prms*/
  377.     if (nv[0] == '/' || nv[0] == '-') {  /* option flag    */
  378.       switch(nv[1]) {
  379.         case ALPHA     : ls->sortflag = ALPHA;     break;
  380.         case GROUP     : ls->sortflag = GROUP;     break;
  381.         case TIMESTAMP : ls->sortflag = TIMESTAMP; break;
  382.         case KEEPSEQ   : ls->sortflag = KEEPSEQ;   break;
  383.         case EXCLPRIV  : ls->exclflag = EXCLPRIV;  break;
  384.         case LONGLIST  : ls->longflag = LONGLIST;  break;
  385.         case FONT      : t = atoi(nv+2);
  386.                          if (t >= FONT0 && t <= FONT4) /* range check    */
  387.                            ls->tfont = t;
  388.                          break;
  389.         case INCLUDE   : ls->incl_fspec =
  390.                             (char *)malloc(strlen(asciiz(nv+2))+1);
  391.                          if (ls->incl_fspec == NULL) {
  392.                            fprintf(stderr,MSG_MEM,PROGNAME);
  393.                            exit(14);
  394.                            }
  395.                          else
  396.                            strcpy(ls->incl_fspec, asciiz(nv+2));
  397.                          break;
  398.         default        : break;
  399.         }
  400.       }
  401.     else {                      /* assume 'nv' is pathname    */
  402.       strncpy(filesbbs_path, asciiz(nv), 80); /* spec'd PATH    */
  403.       j = strlen(filesbbs_path);
  404.       if (j>0 && filesbbs_path[j-1] != '\\')
  405.         filesbbs_path[j] = '\\';    /* add backslash if needed   */
  406.       }
  407.     }
  408.   }
  409.  
  410. /* =============================================== */
  411. /* Build and/or extend a chain of characterstrings */
  412. /* Chain element consists of 2 pointers:           */
  413. /*   - ptr to next element (or NULL in last)       */
  414. /*   - ptr to character string                     */
  415. /* =============================================== */
  416. void  add_str(char *v,                  /* title string */
  417.               STRCHAIN **h)             /* ptr to ptr to head of chain */
  418. {
  419.   STRCHAIN *s, *t;                      /* chain pointers */
  420.  
  421.   t = (STRCHAIN *)malloc(sizeof(struct _strchain)); /* new chain element */
  422.   if (t == NULL) {
  423.     fprintf(stderr,MSG_MEM, PROGNAME);  /* not enough memory          */
  424.     exit(14);
  425.     }
  426.   t->next = NULL;                       /* end of chain */
  427.   s = *h;                               /* pointer to head of chain */
  428.   if (s != NULL) {                      /* not first lement */
  429.     while (s->next != NULL)             /* search last entry */
  430.       s = s->next;
  431.     s->next = t;                        /* build chain */
  432.     }
  433.   else                                  /* first element */
  434.     *h = t;                             /* start of chain */
  435.   t->str = (char *)malloc(strlen(v)+2); /* obtain memory */
  436.   if (t->str == NULL) {
  437.     fprintf(stderr,MSG_MEM, PROGNAME);  /* not enough memory */
  438.     exit(14);
  439.     }
  440.   else
  441.     strcpy(t->str, v);                  /* copy string */
  442.   }
  443.  
  444. /* ==================================== */
  445. /* Tokenize a string (parameter line)   */
  446. /* and add each token to a string chain */
  447. /* ==================================== */
  448. void  add_tok(char  *v,
  449.               STRCHAIN **h)
  450. {
  451.   while (v != NULL) {                   /* all tokens in string */
  452.     add_str(asciiz(v), h);              /* add to string */
  453.     v = next_word(v);                   /* search next code              */
  454.     }
  455.   }
  456.  
  457. /* ============================================ */
  458. /* Translate title-line and add to string chain */
  459. /* ============================================ */
  460. void  add_title(char  *v,
  461.                 STRCHAIN **h)
  462. {
  463.   int   i;
  464.   if (v != NULL) {                   /* value present */
  465.     for (i=0; v[i]; i++)             /* until end-of string */
  466.       v[i] = (char)((v[i] == '~') ? ' ' : v[i]);  /* copy+translate */
  467.     add_str(v, h);                      /* add to string */
  468.     }
  469.   }
  470.  
  471. /* ================================ */
  472. /* Process Non Duplicate Extensions */
  473. /* ================================ */
  474. void  add_ext_pair(char *v,            /* ptr to first ext. */
  475.                    DUPCHAIN **h)       /* ptr to ptr first element */
  476. {
  477.   short int j;                          /* counters */
  478.   DUPCHAIN *s, *t;                      /* pointers */
  479.  
  480.   s = *h;                               /* pointer to head of chain */
  481.   if (s != NULL)                        /* not first element */
  482.     while (s->next != NULL)             /* search last entry */
  483.       s = s->next;
  484.   while (v != NULL) {                   /* any ext specified */
  485.     t = (DUPCHAIN *)malloc(sizeof(struct _dupchain)); /* new chain element */
  486.     if (t == NULL) {
  487.       fprintf(stderr,MSG_MEM, PROGNAME);  /* not enough memory */
  488.       exit(14);
  489.       }
  490.     t->next = NULL;                     /* end of chain */
  491.  
  492.     if (*h != NULL)                     /* not very first element */
  493.       s->next = t;                      /* build chain */
  494.     else                                /* first element */
  495.       *h = t;                           /* start of chain */
  496.  
  497.     for (j=0; v[j] != ' ' && v[j] != '\0' && j < 3; ++j)
  498.       t->ext1[j] = v[j];                /* copy dup-string to element */
  499.     for ( ; j < 4; ++j)
  500.       t->ext1[j] = '\0';                /* trailing zero's */
  501.     v = next_word(v);                   /* next extension */
  502.     if (v != NULL) {                    /* second of pair specified */
  503.       for (j=0; v[j] != ' ' && v[j] != '\0' && j < 3; ++j)
  504.         t->ext2[j] = v[j];              /* copy dup-string to element */
  505.       v = next_word(v);                 /* next extension */
  506.       }
  507.     else                                /* no second of pair specified */
  508.       j = 0;
  509.     for ( ; j < 4; ++j)
  510.       t->ext2[j] = '\0';                /* trailing zero's */
  511.     s = t;                              /* shift 1 element */
  512.     }
  513.   }
  514.  
  515. /* ===================================== */
  516. /* Find the number of the config options */
  517. /* Returns the keyword symbolic number,  */
  518. /* and pointer to the keyword value.     */
  519. /* ===================================== */
  520. short int parse_keyword(char line[],
  521.                         char **value)
  522. {
  523.   short int i,p;                        /* counters                      */
  524.  
  525.   static struct parse_config {          /* Keyword Parameter Spec        */
  526.        unsigned char id;                /* parameter identifier          */
  527.        unsigned char len;               /* keyword length                */
  528.        char *key;                       /* keyword                       */
  529.        } cfg[] = {                      /* table of keyword parameters   */
  530.                                         /* NOTE: most significant first! */
  531.            {K_ALL, 11, "AllFileList"},
  532.            {K_DAT,  7, "AreaDat"},
  533.            {K_AEX, 11, "AreaEXclude"},
  534.            {K_AIN, 11, "AreaINclude"},
  535.            {K_ASQ,  9, "AreaOrder"},
  536.            {K_AVA,  8, "AVAstrip"},
  537.            {K_BBS, 11, "BbsFileList"},
  538.            {K_BOT, 10, "BottomLine"},
  539.            {K_DUP, 11, "DupFileList"},
  540.            {K_EMI, 11, "EmiFileList"},
  541.            {K_FEX, 11, "FileEXclude"},
  542.            {K_FIL, 11, "FilFilePath"},
  543.            {K_GBL, 11, "GblFileList"},
  544.            {K_IPF, 11, "IpfFileList"},
  545.            {K_IP2, 11, "Ip2FileList"},
  546.            {K_NEW, 11, "NewFileList"},
  547.            {K_NDE,  9, "NonDupEXT"},
  548.            {K_OK,  10, "OKFileList"},
  549.            {K_NDS, 12, "NotFoundDesc"},
  550.            {K_OFF, 11, "OfflineDesc"},
  551.            {K_ORP, 11, "OrpFileList"},
  552.            {K_ODS, 10, "OrphanDesc"},
  553.            {K_PRE,  8, "PreTitle"},
  554.            {K_SUB,  8, "SubTitle"},
  555.            {K_TIT,  5, "Title"},
  556.            {K_GRP,  9, "Areagroup"},
  557.            {K_END,  0, ""},             /* end of table: keyw. not found */
  558.              };
  559.  
  560.   *value = NULL;                        /* init: default return          */
  561.  
  562.   for (i=0; line[i]==' '; ++i);         /* skip leading blanks           */
  563.   line = line+i;                        /* new local pointer             */
  564.  
  565.   if (line[0] == '%'  ||                /* comment                       */
  566.       line[0] == ';'  ||                /* comment                       */
  567.       line[0] == '*'  ||                /* comment                       */
  568.       line[0] == '\r' ||                /* CR character                  */
  569.       line[0] == '\n' ||                /* LF character                  */
  570.       line[0] == '\0')                  /* end of string                 */
  571.     return(K_CMT);                      /* return as comment line        */
  572.  
  573.   for (i=0; cfg[i].id < K_END &&        /* search keyword                */
  574.            strnicmp(line,cfg[i].key,cfg[i].len) != 0 ; i++);
  575.   p = cfg[i].id;                        /* return identification value   */
  576.  
  577.   *value = next_word(line);             /* search value string           */
  578.   if (*value == NULL)                   /* no keyword value              */
  579.     return(K_END);                      /* treat as invalid keyword      */
  580.  
  581.   i = strlen(*value);                   /* length of value string        */
  582.   if ((*value)[i-1] == '\n'  ||         /* line feed or                  */
  583.       (*value)[i-1] == '\r')            /* carriage return               */
  584.     (*value)[i-1] = '\0';               /* replaced by end of string     */
  585.  
  586.   return(p);                            /* return the keyword number     */
  587.   }
  588.  
  589.