home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / kerberosIV / krb / kparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-01-21  |  18.5 KB  |  765 lines

  1. /*
  2.  * $Source: /mit/kerberos/src/lib/krb/RCS/kparse.c,v $
  3.  * $Author: jtkohl $
  4.  *
  5.  * Copyright 1988 by the Massachusetts Institute of Technology.
  6.  *
  7.  * For copying and distribution information, please see the file
  8.  * <mit-copyright.h>.
  9.  *
  10.  * Purpose:
  11.  * This module was developed to parse the "~/.klogin" files for
  12.  * Kerberos-authenticated rlogin/rcp/rsh services.  However, it is
  13.  * general purpose and can be used to parse any such parameter file.
  14.  *
  15.  * The parameter file should consist of one or more entries, with each
  16.  * entry on a separate line and consisting of zero or more
  17.  * "keyword=value" combinations.  The keyword is case insensitive, but
  18.  * the value is not.  Any string may be enclosed in quotes, and
  19.  * c-style "\" literals are supported.  A comma may be used to
  20.  * separate the k/v combinations, and multiple commas are ignored.
  21.  * Whitespace (blank or tab) may be used freely and is ignored.
  22.  *
  23.  * Full error processing is available.  When PS_BAD_KEYWORD or
  24.  * PS_SYNTAX is returned from fGetParameterSet(), the string ErrorMsg
  25.  * contains a meaningful error message.
  26.  *
  27.  * Keywords and their default values are programmed by an external
  28.  * table.
  29.  *
  30.  * Routines:
  31.  * fGetParameterSet()      parse one line of the parameter file
  32.  * fGetKeywordValue()      parse one "keyword=value" combo
  33.  * fGetToken()             parse one token
  34.  */
  35.  
  36. #ifndef    lint
  37. static char rcsid_kparse_c[] =
  38. "$Header: kparse.c,v 4.5 89/01/21 17:20:39 jtkohl Exp $";
  39. #endif    lint
  40.  
  41. #include <mit-copyright.h>
  42. #include <stdio.h>
  43. #include <ctype.h>
  44. #include <kparse.h>
  45.  
  46. #ifndef FALSE
  47. #define FALSE 0
  48. #define TRUE 1
  49. #endif
  50.  
  51. #define void int
  52.  
  53. #define MAXKEY          80
  54. #define MAXVALUE        80
  55.  
  56. char *malloc();
  57. char *strcpy();
  58.  
  59. int LineNbr=1;        /* current line nbr in parameter file */
  60. char ErrorMsg[80];    /* meaningful only when KV_SYNTAX, PS_SYNTAX,
  61.                          * or PS_BAD_KEYWORD is returned by
  62.                          * fGetKeywordValue or fGetParameterSet */
  63.  
  64. int fGetParameterSet( fp,parm,parmcount )
  65.     FILE *fp;
  66.     parmtable parm[];
  67.     int parmcount;
  68. {
  69.     int rc,i;
  70.     char keyword[MAXKEY];
  71.     char value[MAXVALUE];
  72.  
  73.     while (TRUE) {
  74.         rc=fGetKeywordValue(fp,keyword,MAXKEY,value,MAXVALUE);
  75.  
  76.         switch (rc) {
  77.  
  78.         case KV_EOF:
  79.             return(PS_EOF);
  80.  
  81.         case KV_EOL:
  82.             return(PS_OKAY);
  83.  
  84.         case KV_SYNTAX:
  85.             return(PS_SYNTAX);
  86.  
  87.         case KV_OKAY:
  88.             /*
  89.              * got a reasonable keyword/value pair.  Search the
  90.              * parameter table to see if we recognize the keyword; if
  91.              * not, return an error.  If we DO recognize it, make sure
  92.              * it has not already been given.  If not already given,
  93.              * save the value.
  94.              */
  95.             for (i=0; i<parmcount; i++) {
  96.                 if (strcmp(strutol(keyword),parm[i].keyword)==0) {
  97.                     if (parm[i].value) {
  98.                         sprintf(ErrorMsg,"duplicate keyword \"%s\" found",
  99.                                 keyword);
  100.                         return(PS_BAD_KEYWORD);
  101.                     }
  102.                     parm[i].value = strsave( value );
  103.                     break;
  104.                 }
  105.             }
  106.             if (i >= parmcount) {
  107.                 sprintf(ErrorMsg, "unrecognized keyword \"%s\" found",
  108.             keyword);
  109.                 return(PS_BAD_KEYWORD);
  110.             }
  111.             break;
  112.  
  113.         default:
  114.             sprintf(ErrorMsg,
  115.             "panic: bad return (%d) from fGetToken()",rc);
  116.             break;
  117.         }
  118.     }
  119. }
  120.  
  121. /*
  122.  * Routine: ParmCompare
  123.  *
  124.  * Purpose:
  125.  * ParmCompare checks a specified value for a particular keyword.
  126.  * fails if keyword not found or keyword found but the value was
  127.  * different. Like strcmp, ParmCompare returns 0 for a match found, -1
  128.  * otherwise
  129.  */
  130. int ParmCompare( parm, parmcount, keyword, value )
  131.     parmtable parm[];
  132.     int parmcount;
  133.     char *keyword;
  134.     char *value;
  135. {
  136.     int i;
  137.  
  138.     for (i=0; i<parmcount; i++) {
  139.         if (strcmp(parm[i].keyword,keyword)==0) {
  140.             if (parm[i].value) {
  141.                 return(strcmp(parm[i].value,value));
  142.             } else {
  143.                 return(strcmp(parm[i].defvalue,value));
  144.             }
  145.         }
  146.     }
  147.     return(-1);
  148. }
  149.  
  150. void FreeParameterSet(parm,parmcount)
  151.     parmtable parm[];
  152.     int parmcount;
  153. {
  154.     int i;
  155.  
  156.     for (i=0; i<parmcount; i++) {
  157.         if (parm[i].value) {
  158.             free(parm[i].value);
  159.             parm[i].value = (char *)NULL;
  160.         }
  161.     }
  162. }
  163.  
  164. int fGetKeywordValue( fp, keyword, klen, value, vlen )
  165.     FILE *fp;
  166.     char *keyword;
  167.     int klen;
  168.     char *value;
  169.     int vlen;
  170. {
  171.     int rc;
  172.     int gotit;
  173.  
  174.     *keyword = *value = '\0';   /* preset strings to NULL */
  175.  
  176.     /*
  177.      * Looking for a keyword.
  178.      *          return an exception for EOF or BAD_QSTRING
  179.      *          ignore leading WHITEspace
  180.      *          ignore any number of leading commas
  181.      *          newline means we have all the parms for this
  182.      *              statement; give an indication that there is
  183.      *              nothing more on this line.
  184.      *          stop looking if we find QSTRING, STRING, or NUMBER
  185.      *          return syntax error for any other PUNKtuation
  186.      */
  187.     gotit = FALSE;
  188.     do {
  189.         rc = fGetToken(fp,keyword,klen);
  190.  
  191.         switch (rc) {
  192.  
  193.         case GTOK_WHITE:
  194.             break;
  195.  
  196.         case GTOK_EOF:
  197.             return(KV_EOF);
  198.  
  199.         case GTOK_BAD_QSTRING:
  200.             sprintf(ErrorMsg,"unterminated string \"%s found",keyword);
  201.             return(KV_SYNTAX);
  202.  
  203.         case GTOK_PUNK:
  204.             if (strcmp("\n",keyword)==0) {
  205.                 return(KV_EOL);
  206.             } else if (strcmp(",",keyword)!=0) {
  207.                 sprintf(ErrorMsg,"expecting rvalue, found \'%s\'",keyword);
  208.             }
  209.             break;
  210.  
  211.         case GTOK_STRING:
  212.         case GTOK_QSTRING:
  213.         case GTOK_NUMBER:
  214.             gotit = TRUE;
  215.             break;
  216.  
  217.         default:
  218.             sprintf(ErrorMsg,"panic: bad return (%d) from fGetToken()",rc);
  219.             return(KV_SYNTAX);
  220.         }
  221.  
  222.     } while (!gotit);
  223.  
  224.     /*
  225.      * now we expect an equal sign.
  226.      *          skip any whitespace
  227.      *          stop looking if we find an equal sign
  228.      *          anything else causes a syntax error
  229.      */
  230.     gotit = FALSE;
  231.     do {
  232.         rc = fGetToken(fp,value,vlen);
  233.  
  234.         switch (rc) {
  235.  
  236.         case GTOK_WHITE:
  237.             break;
  238.  
  239.         case GTOK_BAD_QSTRING:
  240.             sprintf(ErrorMsg,
  241.             "expecting \'=\', found unterminated string \"%s",
  242.                     value);
  243.             return(KV_SYNTAX);
  244.  
  245.         case GTOK_PUNK:
  246.             if (strcmp("=",value)==0) {
  247.                 gotit = TRUE;
  248.             } else {
  249.                 if (strcmp("\n",value)==0) {
  250.                     sprintf(ErrorMsg,"expecting \"=\", found newline");
  251.                     fUngetChar('\n',fp);
  252.                 } else {
  253.                     sprintf(ErrorMsg,
  254.                 "expecting rvalue, found \'%s\'",keyword);
  255.                 }
  256.                 return(KV_SYNTAX);
  257.             }
  258.             break;
  259.  
  260.         case GTOK_STRING:
  261.         case GTOK_QSTRING:
  262.         case GTOK_NUMBER:
  263.             sprintf(ErrorMsg,"expecting \'=\', found \"%s\"",value);
  264.             return(KV_SYNTAX);
  265.  
  266.         case GTOK_EOF:
  267.             sprintf(ErrorMsg,"expecting \'=\', found EOF");
  268.             return(KV_SYNTAX);
  269.  
  270.         default:
  271.             sprintf(ErrorMsg,
  272.             "panic: bad return (%d) from fGetToken()",rc);
  273.             return(KV_SYNTAX);
  274.         }
  275.  
  276.     } while ( !gotit );
  277.  
  278.     /*
  279.      * got the keyword and equal sign, now get a value.
  280.      *          ignore any whitespace
  281.      *          any punctuation is a syntax error
  282.      */
  283.     gotit = FALSE;
  284.     do {
  285.         rc = fGetToken(fp,value,vlen);
  286.  
  287.         switch (rc) {
  288.  
  289.         case GTOK_WHITE:
  290.             break;
  291.  
  292.         case GTOK_EOF:
  293.             sprintf(ErrorMsg,"expecting rvalue, found EOF");
  294.             return(KV_SYNTAX);
  295.  
  296.         case GTOK_BAD_QSTRING:
  297.             sprintf(ErrorMsg,"unterminated quoted string \"%s",value);
  298.             return(KV_SYNTAX);
  299.  
  300.         case GTOK_PUNK:
  301.             if (strcmp("\n",value)==0) {
  302.                 sprintf(ErrorMsg,"expecting rvalue, found newline");
  303.                 fUngetChar('\n',fp);
  304.             } else {
  305.                 sprintf(ErrorMsg,
  306.             "expecting rvalue, found \'%s\'",value);
  307.             }
  308.             return(KV_SYNTAX);
  309.             break;
  310.  
  311.         case GTOK_STRING:
  312.         case GTOK_QSTRING:
  313.         case GTOK_NUMBER:
  314.             gotit = TRUE;
  315.             return(KV_OKAY);
  316.  
  317.         default:
  318.             sprintf(ErrorMsg,
  319.             "panic: bad return (%d) from fGetToken()",rc);
  320.             return(KV_SYNTAX);
  321.         }
  322.  
  323.     } while ( !gotit );
  324.     /*NOTREACHED*/
  325. }
  326.  
  327. /*
  328.  * Routine Name: fGetToken
  329.  *
  330.  * Function: read the next token from the specified file.
  331.  * A token is defined as a group of characters
  332.  * terminated by a white space char (SPACE, CR,
  333.  * LF, FF, TAB). The token returned is stripped of
  334.  * both leading and trailing white space, and is
  335.  * terminated by a NULL terminator.  An alternate
  336.  * definition of a token is a string enclosed in
  337.  * single or double quotes.
  338.  *
  339.  * Explicit Parameters:
  340.  * fp              pointer to the input FILE
  341.  * dest    pointer to destination buffer
  342.  * maxlen  length of the destination buffer. The buffer
  343.  * length INCLUDES the NULL terminator.
  344.  *
  345.  * Implicit Parameters: stderr  where the "token too long" message goes
  346.  *
  347.  * External Procedures: fgetc
  348.  *
  349.  * Side Effects:                None
  350.  *
  351.  * Return Value:                A token classification value, as
  352.  *                defined in kparse.h. Note that the
  353.  *                classification for end of file is
  354.  *                always zero.
  355.  */
  356. int fGetToken(fp, dest, maxlen)
  357.     FILE *fp;
  358.     char *dest;
  359.     int  maxlen;
  360. {
  361.     int ch='\0';
  362.     int len=0;
  363.     char *p = dest;
  364.     int digits;
  365.  
  366.     ch=fGetChar(fp);
  367.  
  368.     /*
  369.      * check for a quoted string.  If found, take all characters
  370.      * that fit until a closing quote is found.  Note that this
  371.      * algorithm will not behave well for a string which is too long.
  372.      */
  373.     if (ISQUOTE(ch)) {
  374.         int done = FALSE;
  375.         do {
  376.             ch = fGetChar(fp);
  377.             done = ((maxlen<++len)||ISLINEFEED(ch)||(ch==EOF)
  378.             ||ISQUOTE(ch));
  379.             if (ch=='\\')
  380.                 ch = fGetLiteral(fp);
  381.             if (!done)
  382.                 *p++ = ch;
  383.             else if ((ch!=EOF) && !ISQUOTE(ch))
  384.                 fUngetChar(ch,fp);
  385.         } while (!done);
  386.         *p = '\0';
  387.         if (ISLINEFEED(ch)) return(GTOK_BAD_QSTRING);
  388.         return(GTOK_QSTRING);
  389.     }
  390.  
  391.     /*
  392.      * Not a quoted string.  If its a token character (rules are
  393.      * defined via the ISTOKENCHAR macro, in kparse.h) take it and all
  394.      * token chars following it until we run out of space.
  395.      */
  396.     digits=TRUE;
  397.     if (ISTOKENCHAR(ch)) {
  398.         while ( (ISTOKENCHAR(ch)) && len<maxlen-1 ) {
  399.             if (!isdigit(ch)) digits=FALSE;
  400.             *p++ = ch;
  401.             len++;
  402.             ch = fGetChar(fp);
  403.         };
  404.         *p = '\0';
  405.  
  406.         if (ch!=EOF) {
  407.             fUngetChar(ch,fp);
  408.         }
  409.         if (digits) {
  410.             return(GTOK_NUMBER);
  411.         } else {
  412.             return(GTOK_STRING);
  413.         }
  414.     }
  415.  
  416.     /*
  417.      * Neither a quoted string nor a token character.  Return a string
  418.      * with just that one character in it.
  419.      */
  420.     if (ch==EOF) {
  421.         return(GTOK_EOF);
  422.     }
  423.     if (!ISWHITESPACE(ch)) {
  424.         *p++ = ch;
  425.         *p='\0';
  426.     } else {
  427.         *p++ = ' ';        /* white space is always the
  428.                  * blank character */
  429.         *p='\0';
  430.         /*
  431.          * The character is a white space. Flush all additional white
  432.          * space.
  433.          */
  434.         while (ISWHITESPACE(ch) && ((ch=fGetChar(fp)) != EOF))
  435.             ;
  436.         if (ch!=EOF) {
  437.             fUngetChar(ch,fp);
  438.         }
  439.         return(GTOK_WHITE);
  440.     }
  441.     return(GTOK_PUNK);
  442. }
  443.  
  444. /*
  445.  * fGetLiteral is called after we find a '\' in the input stream.  A
  446.  * string of numbers following the backslash are converted to the
  447.  * appropriate value; hex (0xn), octal (0n), and decimal (otherwise)
  448.  * are all supported.  If the char after the \ is not a number, we
  449.  * special case certain values (\n, \f, \r, \b) or return a literal
  450.  * otherwise (useful for \", for example).
  451.  */
  452. fGetLiteral(fp)
  453.     FILE *fp;
  454. {
  455.     int ch;
  456.     int n=0;
  457.     int base;
  458.  
  459.     ch = fGetChar(fp);
  460.  
  461.     if (!isdigit(ch)) {
  462.         switch (ch) {
  463.         case 'n':       return('\n');
  464.         case 'f':       return('\f');
  465.         case 'r':       return('\r');
  466.         case 'b':       return('\b');
  467.         default:        return(ch);
  468.         }
  469.     }
  470.  
  471.     /*
  472.      * got a number.  might be decimal (no prefix), octal (prefix 0),
  473.      * or hexadecimal (prefix 0x).  Set the base appropriately.
  474.      */
  475.     if (ch!='0') {
  476.         base=10;                /* its a decimal number */
  477.     } else {
  478.         /*
  479.          * found a zero, its either hex or octal
  480.          */
  481.         ch = fGetChar(fp);
  482.         if ((ch!='x') && (ch!='X')) {
  483.             base=010;
  484.         } else {
  485.             ch = fGetChar(fp);
  486.             base=0x10;
  487.         }
  488.     }
  489.  
  490.     switch (base) {
  491.  
  492.     case 010:                   /* octal */
  493.         while (ISOCTAL(ch)) {
  494.             n = (n*base) + ch - '0';
  495.             ch = fGetChar(fp);
  496.         }
  497.         break;
  498.  
  499.     case 10:                    /* decimal */
  500.         while (isdigit(ch)) {
  501.             n = (n*base) + ch - '0';
  502.             ch = fGetChar(fp);
  503.         }
  504.         break;
  505.     case 0x10:                  /* hexadecimal */
  506.         while (isxdigit(ch)) {
  507.             if (isdigit(ch)) {
  508.                 n = (n*base) + ch - '0';
  509.             } else {
  510.                 n = (n*base) + toupper(ch) - 'A' + 0xA ;
  511.             }
  512.             ch = fGetChar(fp);
  513.         }
  514.         break;
  515.     default:
  516.         fprintf(stderr,"fGetLiteral() died real bad. Fix gettoken.c.");
  517.         exit(1);
  518.         break;
  519.     }
  520.     fUngetChar(ch,fp);
  521.     return(n);
  522. }
  523.  
  524. /*
  525.  * exactly the same as ungetc(3) except that the line number of the
  526.  * input file is maintained.
  527.  */
  528. fUngetChar(ch,fp)
  529.     int ch;
  530.     FILE *fp;
  531. {
  532.     if (ch=='\n') LineNbr--;
  533.     return(ungetc(ch,fp));
  534. }
  535.  
  536.  
  537. /*
  538.  * exactly the same as fgetc(3) except that the line number of the
  539.  * input file is maintained.
  540.  */
  541. fGetChar(fp)
  542.     FILE *fp;
  543. {
  544.     int ch = fgetc(fp);
  545.     if (ch=='\n') LineNbr++;
  546.     return(ch);
  547. }
  548.  
  549.  
  550. /*
  551.  * Routine Name: strsave
  552.  *
  553.  * Function: return a pointer to a saved copy of the
  554.  * input string. the copy will be allocated
  555.  * as large as necessary.
  556.  *
  557.  * Explicit Parameters: pointer to string to save
  558.  *
  559.  * Implicit Parameters: None
  560.  *
  561.  * External Procedures: malloc,strcpy,strlen
  562.  *
  563.  * Side Effects: None
  564.  *
  565.  * Return Value: pointer to copied string
  566.  *
  567.  */
  568. char * strsave(p)
  569.     char *p;
  570. {
  571.     return(strcpy(malloc(strlen(p)+1),p));
  572. }
  573.  
  574.  
  575. /*
  576.  * strutol changes all characters in a string to lower case, in place.
  577.  * the pointer to the beginning of the string is returned.
  578.  */
  579.  
  580. char * strutol( start )
  581.     char *start;
  582. {
  583.     char *q;
  584.     for (q=start; *q; q++)
  585.         if (isupper(*q))
  586.         *q=tolower(*q);
  587.     return(start);
  588. }
  589.  
  590. #ifdef GTOK_TEST         /* mainline test routine for fGetToken() */
  591.  
  592. #define MAXTOKEN 100
  593.  
  594. char *pgm = "gettoken";
  595.  
  596. main(argc,argv)
  597.     int argc;
  598.     char **argv;
  599. {
  600.     char *p;
  601.     int type;
  602.     FILE *fp;
  603.  
  604.     if (--argc) {
  605.         fp = fopen(*++argv,"ra");
  606.         if (fp == (FILE *)NULL) {
  607.             fprintf(stderr,"can\'t open \"%s\"\n",*argv);
  608.         }
  609.     } else
  610.         fp = stdin;
  611.  
  612.     p = malloc(MAXTOKEN);
  613.     while (type = fGetToken(fp,p,MAXTOKEN)) {
  614.         switch(type) {
  615.         case GTOK_BAD_QSTRING:
  616.         printf("BAD QSTRING!\t");
  617.         break;
  618.         case GTOK_EOF:
  619.         printf("EOF!\t");
  620.         break;
  621.         case GTOK_QSTRING:
  622.         printf("QSTRING\t");
  623.         break;
  624.         case GTOK_STRING:
  625.         printf("STRING\t");
  626.         break;
  627.         case GTOK_NUMBER:
  628.         printf("NUMBER\t");
  629.         break;
  630.         case GTOK_PUNK:
  631.         printf("PUNK\t");
  632.         break;
  633.         case GTOK_WHITE:
  634.         printf("WHITE\t");
  635.         break;
  636.         default:
  637.         printf("HUH?\t");
  638.         break;
  639.         }
  640.         if (*p=='\n')
  641.             printf("\\n\n");
  642.     else
  643.             printf("%s\n",p);
  644.     }
  645.     exit(0);
  646. }
  647. #endif
  648.  
  649. #ifdef KVTEST
  650.  
  651. main(argc,argv)
  652.     int argc;
  653.     char **argv;
  654. {
  655.     int rc,ch;
  656.     FILE *fp;
  657.     char key[MAXKEY],valu[MAXVALUE];
  658.     char *filename;
  659.  
  660.     if (argc != 2) {
  661.         fprintf(stderr,"usage: test <filename>\n");
  662.         exit(1);
  663.     }
  664.  
  665.     if (!(fp=fopen(*++argv,"r"))) {
  666.         fprintf(stderr,"can\'t open input file \"%s\"\n",filename);
  667.         exit(1);
  668.     }
  669.     filename = *argv;
  670.  
  671.     while ((rc=fGetKeywordValue(fp,key,MAXKEY,valu,MAXVALUE))!=KV_EOF){
  672.  
  673.         switch (rc) {
  674.  
  675.         case KV_EOL:
  676.             printf("%s, line %d: nada mas.\n",filename,LineNbr-1);
  677.             break;
  678.  
  679.         case KV_SYNTAX:
  680.             printf("%s, line %d: syntax error: %s\n",
  681.                    filename,LineNbr,ErrorMsg);
  682.             while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
  683.             break;
  684.  
  685.         case KV_OKAY:
  686.             printf("%s, line %d: okay, %s=\"%s\"\n",
  687.                    filename,LineNbr,key,valu);
  688.             break;
  689.  
  690.         default:
  691.             printf("panic: bad return (%d) from fGetKeywordValue\n",rc);
  692.             break;
  693.         }
  694.     }
  695.     printf("EOF");
  696.     fclose(fp);
  697.     exit(0);
  698. }
  699. #endif
  700.  
  701. #ifdef PSTEST
  702.  
  703. parmtable kparm[] = {
  704.     /*  keyword, default, found value */
  705.     { "user",       "",    (char *)NULL },
  706.     { "realm",   "Athena", (char *)NULL },
  707.     { "instance",   "",    (char *)NULL }
  708. };
  709.  
  710. main(argc,argv)
  711.     int argc;
  712.     char **argv;
  713. {
  714.     int rc,i,ch;
  715.     FILE *fp;
  716.     char *filename;
  717.  
  718.     if (argc != 2) {
  719.         fprintf(stderr,"usage: test <filename>\n");
  720.         exit(1);
  721.     }
  722.  
  723.     if (!(fp=fopen(*++argv,"r"))) {
  724.         fprintf(stderr,"can\'t open input file \"%s\"\n",filename);
  725.         exit(1);
  726.     }
  727.     filename = *argv;
  728.  
  729.     while ((rc=fGetParameterSet(fp,kparm,PARMCOUNT(kparm))) != PS_EOF) {
  730.  
  731.         switch (rc) {
  732.  
  733.         case PS_BAD_KEYWORD:
  734.             printf("%s, line %d: %s\n",filename,LineNbr,ErrorMsg);
  735.             while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
  736.             break;
  737.  
  738.         case PS_SYNTAX:
  739.             printf("%s, line %d: syntax error: %s\n",
  740.                    filename,LineNbr,ErrorMsg);
  741.             while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
  742.             break;
  743.  
  744.         case PS_OKAY:
  745.             printf("%s, line %d: valid parameter set found:\n",
  746.                    filename,LineNbr-1);
  747.             for (i=0; i<PARMCOUNT(kparm); i++) {
  748.                 printf("\t%s = \"%s\"\n",kparm[i].keyword,
  749.                        (kparm[i].value ? kparm[i].value
  750.             : kparm[i].defvalue));
  751.             }
  752.             break;
  753.  
  754.         default:
  755.             printf("panic: bad return (%d) from fGetParameterSet\n",rc);
  756.             break;
  757.         }
  758.         FreeParameterSet(kparm,PARMCOUNT(kparm));
  759.     }
  760.     printf("EOF");
  761.     fclose(fp);
  762.     exit(0);
  763. }
  764. #endif
  765.