4 * Copyright 1988 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, please see the file
10 * This module was developed to parse the "~/.klogin" files for
11 * Kerberos-authenticated rlogin/rcp/rsh services. However, it is
12 * general purpose and can be used to parse any such parameter file.
14 * The parameter file should consist of one or more entries, with each
15 * entry on a separate line and consisting of zero or more
16 * "keyword=value" combinations. The keyword is case insensitive, but
17 * the value is not. Any string may be enclosed in quotes, and
18 * c-style "\" literals are supported. A comma may be used to
19 * separate the k/v combinations, and multiple commas are ignored.
20 * Whitespace (blank or tab) may be used freely and is ignored.
22 * Full error processing is available. When PS_BAD_KEYWORD or
23 * PS_SYNTAX is returned from fGetParameterSet(), the string ErrorMsg
24 * contains a meaningful error message.
26 * Keywords and their default values are programmed by an external
30 * fGetParameterSet() parse one line of the parameter file
31 * fGetKeywordValue() parse one "keyword=value" combo
32 * fGetToken() parse one token
35 #include "mit-copyright.h"
55 static char *strutol();
58 static char *strsave();
61 extern char *malloc();
64 static int sLineNbr=1; /* current line nbr in parameter file */
65 static char ErrorMsg[80]; /* meaningful only when KV_SYNTAX, PS_SYNTAX,
66 * or PS_BAD_KEYWORD is returned by
67 * fGetKeywordValue or fGetParameterSet */
69 int fGetParameterSet( fp,parm,parmcount )
79 rc=fGetKeywordValue(fp,keyword,MAXKEY,value,MAXVALUE);
94 * got a reasonable keyword/value pair. Search the
95 * parameter table to see if we recognize the keyword; if
96 * not, return an error. If we DO recognize it, make sure
97 * it has not already been given. If not already given,
100 for (i=0; i<parmcount; i++) {
101 if (strcmp(strutol(keyword),parm[i].keyword)==0) {
103 sprintf(ErrorMsg,"duplicate keyword \"%s\" found",
105 return(PS_BAD_KEYWORD);
107 parm[i].value = strsave( value );
111 if (i >= parmcount) {
112 sprintf(ErrorMsg, "unrecognized keyword \"%s\" found",
114 return(PS_BAD_KEYWORD);
120 "panic: bad return (%d) from fGetToken()",rc);
127 * Routine: ParmCompare
130 * ParmCompare checks a specified value for a particular keyword.
131 * fails if keyword not found or keyword found but the value was
132 * different. Like strcmp, ParmCompare returns 0 for a match found, -1
135 int ParmCompare( parm, parmcount, keyword, value )
143 for (i=0; i<parmcount; i++) {
144 if (strcmp(parm[i].keyword,keyword)==0) {
146 return(strcmp(parm[i].value,value));
148 return(strcmp(parm[i].defvalue,value));
155 void FreeParameterSet(parm,parmcount)
161 for (i=0; i<parmcount; i++) {
164 parm[i].value = (char *)NULL;
169 int fGetKeywordValue( fp, keyword, klen, value, vlen )
179 *keyword = *value = '\0'; /* preset strings to NULL */
182 * Looking for a keyword.
183 * return an exception for EOF or BAD_QSTRING
184 * ignore leading WHITEspace
185 * ignore any number of leading commas
186 * newline means we have all the parms for this
187 * statement; give an indication that there is
188 * nothing more on this line.
189 * stop looking if we find QSTRING, STRING, or NUMBER
190 * return syntax error for any other PUNKtuation
194 rc = fGetToken(fp,keyword,klen);
204 case GTOK_BAD_QSTRING:
205 sprintf(ErrorMsg,"unterminated string \"%s found",keyword);
209 if (strcmp("\n",keyword)==0) {
211 } else if (strcmp(",",keyword)!=0) {
212 sprintf(ErrorMsg,"expecting rvalue, found \'%s\'",keyword);
223 sprintf(ErrorMsg,"panic: bad return (%d) from fGetToken()",rc);
230 * now we expect an equal sign.
231 * skip any whitespace
232 * stop looking if we find an equal sign
233 * anything else causes a syntax error
237 rc = fGetToken(fp,value,vlen);
244 case GTOK_BAD_QSTRING:
246 "expecting \'=\', found unterminated string \"%s",
251 if (strcmp("=",value)==0) {
254 if (strcmp("\n",value)==0) {
255 sprintf(ErrorMsg,"expecting \"=\", found newline");
259 "expecting rvalue, found \'%s\'",keyword);
268 sprintf(ErrorMsg,"expecting \'=\', found \"%s\"",value);
272 sprintf(ErrorMsg,"expecting \'=\', found EOF");
277 "panic: bad return (%d) from fGetToken()",rc);
284 * got the keyword and equal sign, now get a value.
285 * ignore any whitespace
286 * any punctuation is a syntax error
290 rc = fGetToken(fp,value,vlen);
298 sprintf(ErrorMsg,"expecting rvalue, found EOF");
301 case GTOK_BAD_QSTRING:
302 sprintf(ErrorMsg,"unterminated quoted string \"%s",value);
306 if (strcmp("\n",value)==0) {
307 sprintf(ErrorMsg,"expecting rvalue, found newline");
311 "expecting rvalue, found \'%s\'",value);
324 "panic: bad return (%d) from fGetToken()",rc);
333 * Routine Name: fGetToken
335 * Function: read the next token from the specified file.
336 * A token is defined as a group of characters
337 * terminated by a white space char (SPACE, CR,
338 * LF, FF, TAB). The token returned is stripped of
339 * both leading and trailing white space, and is
340 * terminated by a NULL terminator. An alternate
341 * definition of a token is a string enclosed in
342 * single or double quotes.
344 * Explicit Parameters:
345 * fp pointer to the input FILE
346 * dest pointer to destination buffer
347 * maxlen length of the destination buffer. The buffer
348 * length INCLUDES the NULL terminator.
350 * Implicit Parameters: stderr where the "token too long" message goes
352 * External Procedures: fgetc
356 * Return Value: A token classification value, as
357 * defined in kparse.h. Note that the
358 * classification for end of file is
361 int fGetToken(fp, dest, maxlen)
374 * check for a quoted string. If found, take all characters
375 * that fit until a closing quote is found. Note that this
376 * algorithm will not behave well for a string which is too long.
382 done = ((maxlen<++len)||ISLINEFEED(ch)||(ch==EOF)
385 ch = fGetLiteral(fp);
388 else if ((ch!=EOF) && !ISQUOTE(ch))
392 if (ISLINEFEED(ch)) return(GTOK_BAD_QSTRING);
393 return(GTOK_QSTRING);
397 * Not a quoted string. If its a token character (rules are
398 * defined via the ISTOKENCHAR macro, in kparse.h) take it and all
399 * token chars following it until we run out of space.
402 if (ISTOKENCHAR(ch)) {
403 while ( (ISTOKENCHAR(ch)) && len<maxlen-1 ) {
404 if (!isdigit(ch)) digits=FALSE;
422 * Neither a quoted string nor a token character. Return a string
423 * with just that one character in it.
428 if (!ISWHITESPACE(ch)) {
432 *p++ = ' '; /* white space is always the
436 * The character is a white space. Flush all additional white
439 while (ISWHITESPACE(ch) && ((ch=fGetChar(fp)) != EOF))
450 * fGetLiteral is called after we find a '\' in the input stream. A
451 * string of numbers following the backslash are converted to the
452 * appropriate value; hex (0xn), octal (0n), and decimal (otherwise)
453 * are all supported. If the char after the \ is not a number, we
454 * special case certain values (\n, \f, \r, \b) or return a literal
455 * otherwise (useful for \", for example).
468 case 'n': return('\n');
469 case 'f': return('\f');
470 case 'r': return('\r');
471 case 'b': return('\b');
477 * got a number. might be decimal (no prefix), octal (prefix 0),
478 * or hexadecimal (prefix 0x). Set the base appropriately.
481 base=10; /* its a decimal number */
484 * found a zero, its either hex or octal
487 if ((ch!='x') && (ch!='X')) {
497 case 010: /* octal */
498 while (ISOCTAL(ch)) {
499 n = (n*base) + ch - '0';
504 case 10: /* decimal */
505 while (isdigit(ch)) {
506 n = (n*base) + ch - '0';
510 case 0x10: /* hexadecimal */
511 while (isxdigit(ch)) {
513 n = (n*base) + ch - '0';
515 n = (n*base) + toupper(ch) - 'A' + 0xA ;
522 fprintf(stderr,"fGetLiteral() died real bad. Fix kparse.c.");
531 * exactly the same as ungetc(3) except that the line number of the
532 * input file is maintained.
534 int fUngetChar(ch,fp)
538 if (ch=='\n') sLineNbr--;
539 return(ungetc(ch,fp));
544 * exactly the same as fgetc(3) except that the line number of the
545 * input file is maintained.
551 if (ch=='\n') sLineNbr++;
557 * Routine Name: strsave
559 * Function: return a pointer to a saved copy of the
560 * input string. the copy will be allocated
561 * as large as necessary.
563 * Explicit Parameters: pointer to string to save
565 * Implicit Parameters: None
567 * External Procedures: malloc,strcpy,strlen
571 * Return Value: pointer to copied string
575 static char * strsave(p)
578 return(strcpy(malloc(strlen(p)+1),p));
584 * strutol changes all characters in a string to lower case, in place.
585 * the pointer to the beginning of the string is returned.
588 static char * strutol( start )
592 for (q=start; *q; q++)
598 #ifdef GTOK_TEST /* mainline test routine for fGetToken() */
602 char *pgm = "gettoken";
613 fp = fopen(*++argv,"ra");
614 if (fp == (FILE *)NULL) {
615 fprintf(stderr,"can\'t open \"%s\"\n",*argv);
620 p = malloc(MAXTOKEN);
621 while (type = fGetToken(fp,p,MAXTOKEN)) {
623 case GTOK_BAD_QSTRING:
624 printf("BAD QSTRING!\t");
665 char key[MAXKEY],valu[MAXVALUE];
669 fprintf(stderr,"usage: test <filename>\n");
673 if (!(fp=fopen(*++argv,"r"))) {
674 fprintf(stderr,"can\'t open input file \"%s\"\n",filename);
679 while ((rc=fGetKeywordValue(fp,key,MAXKEY,valu,MAXVALUE))!=KV_EOF){
684 printf("%s, line %d: nada mas.\n",filename,sLineNbr-1);
688 printf("%s, line %d: syntax error: %s\n",
689 filename,sLineNbr,ErrorMsg);
690 while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
694 printf("%s, line %d: okay, %s=\"%s\"\n",
695 filename,sLineNbr,key,valu);
699 printf("panic: bad return (%d) from fGetKeywordValue\n",rc);
711 parmtable kparm[] = {
712 /* keyword, default, found value */
713 { "user", "", (char *)NULL },
714 { "realm", "Athena", (char *)NULL },
715 { "instance", "", (char *)NULL }
727 fprintf(stderr,"usage: test <filename>\n");
731 if (!(fp=fopen(*++argv,"r"))) {
732 fprintf(stderr,"can\'t open input file \"%s\"\n",filename);
737 while ((rc=fGetParameterSet(fp,kparm,PARMCOUNT(kparm))) != PS_EOF) {
742 printf("%s, line %d: %s\n",filename,sLineNbr,ErrorMsg);
743 while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
747 printf("%s, line %d: syntax error: %s\n",
748 filename,sLineNbr,ErrorMsg);
749 while ( ((ch=fGetChar(fp))!=EOF) && (ch!='\n') );
753 printf("%s, line %d: valid parameter set found:\n",
754 filename,sLineNbr-1);
755 for (i=0; i<PARMCOUNT(kparm); i++) {
756 printf("\t%s = \"%s\"\n",kparm[i].keyword,
757 (kparm[i].value ? kparm[i].value
758 : kparm[i].defvalue));
763 printf("panic: bad return (%d) from fGetParameterSet\n",rc);
766 FreeParameterSet(kparm,PARMCOUNT(kparm));