753 lines
16 KiB
Plaintext
753 lines
16 KiB
Plaintext
%{
|
|
/* $OpenBSD: keynote.l,v 1.24 2017/08/28 17:07:19 millert Exp $ */
|
|
/*
|
|
* The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
|
|
*
|
|
* This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
|
|
* in April-May 1998
|
|
*
|
|
* Copyright (C) 1998, 1999 by Angelos D. Keromytis.
|
|
*
|
|
* Permission to use, copy, and modify this software with or without fee
|
|
* is hereby granted, provided that this entire notice is included in
|
|
* all copies of any software which is or includes a copy or
|
|
* modification of this software.
|
|
*
|
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
|
|
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
|
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
|
* PURPOSE.
|
|
*/
|
|
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <ctype.h>
|
|
#include <regex.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "k.tab.h"
|
|
#include "keynote.h"
|
|
#include "assertion.h"
|
|
|
|
static void mystrncpy(char *, char *, int);
|
|
|
|
struct lex_list
|
|
{
|
|
int lex_type;
|
|
void *lex_s;
|
|
};
|
|
|
|
static struct lex_list *keynote_lex_list = NULL;
|
|
static int keynote_max_lex_list = 32;
|
|
static int keynote_lex_counter = 0;
|
|
static int first_tok = 0;
|
|
%}
|
|
digit [0-9]
|
|
specnumber [1-9][0-9]*
|
|
number {digit}+
|
|
flt {digit}+"."{digit}+
|
|
vstring [a-zA-Z_][a-zA-Z0-9_]*
|
|
litstring \"(((\\\n)|(\\.)|([^\\\n\"]))*)\"
|
|
variable {vstring}
|
|
comment "#"[^\n]*
|
|
%s ACTIONSTRING LOCALINIT KEYPREDICATE SIGNERINIT KEYNOTEVERSION
|
|
%pointer
|
|
%option noinput noyywrap never-interactive yylineno
|
|
%%
|
|
%{
|
|
/*
|
|
* Return a preset token, so we can have more than one grammars
|
|
* in yacc.
|
|
*/
|
|
extern int first_tok;
|
|
|
|
if (first_tok)
|
|
{
|
|
int holdtok = first_tok;
|
|
|
|
first_tok = 0;
|
|
return holdtok;
|
|
}
|
|
%}
|
|
|
|
<KEYPREDICATE>{specnumber}"-of" {
|
|
knlval.intval = atoi(kntext);
|
|
return KOF;
|
|
}
|
|
<ACTIONSTRING,KEYPREDICATE>"(" return OPENPAREN;
|
|
<ACTIONSTRING,KEYPREDICATE>")" return CLOSEPAREN;
|
|
<ACTIONSTRING,KEYPREDICATE>"&&" return AND;
|
|
<ACTIONSTRING,KEYPREDICATE>"||" return OR;
|
|
<ACTIONSTRING>"+" return PLUS;
|
|
<ACTIONSTRING>"->" return HINT;
|
|
<ACTIONSTRING>"{" return OPENBLOCK;
|
|
<ACTIONSTRING>"}" return CLOSEBLOCK;
|
|
<ACTIONSTRING>";" return SEMICOLON;
|
|
<ACTIONSTRING>"!" return NOT;
|
|
<ACTIONSTRING>"~=" return REGEXP;
|
|
<ACTIONSTRING>"==" return EQ;
|
|
<ACTIONSTRING>"!=" return NE;
|
|
<ACTIONSTRING>"<" return LT;
|
|
<ACTIONSTRING>">" return GT;
|
|
<ACTIONSTRING>"<=" return LE;
|
|
<ACTIONSTRING>">=" return GE;
|
|
<ACTIONSTRING>"-" return MINUS;
|
|
<ACTIONSTRING>"*" return MULT;
|
|
<ACTIONSTRING>"/" return DIV;
|
|
<ACTIONSTRING>"%" return MOD;
|
|
<ACTIONSTRING>"^" return EXP;
|
|
"." return DOTT;
|
|
<ACTIONSTRING>"true" return TRUE;
|
|
<ACTIONSTRING>"false" return FALSE;
|
|
{comment} /* eat up comments */
|
|
<LOCALINIT>"=" return EQQ;
|
|
<KEYPREDICATE>"," return COMMA;
|
|
<ACTIONSTRING,KEYPREDICATE,SIGNERINIT,LOCALINIT>{variable} {
|
|
int len;
|
|
if (keynote_exceptionflag ||
|
|
keynote_donteval)
|
|
{
|
|
knlval.string = NULL;
|
|
return VARIABLE;
|
|
}
|
|
|
|
len = strlen(kntext) + 1;
|
|
knlval.string = calloc(len, sizeof(char));
|
|
if (knlval.string == NULL)
|
|
{
|
|
keynote_errno = ERROR_MEMORY;
|
|
return -1;
|
|
}
|
|
strlcpy(knlval.string, kntext, len);
|
|
if (keynote_lex_add(knlval.string,
|
|
LEXTYPE_CHAR) ==
|
|
-1)
|
|
return -1;
|
|
return VARIABLE;
|
|
}
|
|
"$" return DEREF;
|
|
<ACTIONSTRING>"@" return OPENNUM;
|
|
<ACTIONSTRING>"&" return OPENFLT;
|
|
<ACTIONSTRING>{flt} {
|
|
knlval.doubval = atof(kntext);
|
|
return FLOAT;
|
|
}
|
|
<KEYNOTEVERSION>{number} {
|
|
int len;
|
|
|
|
if (keynote_exceptionflag ||
|
|
keynote_donteval)
|
|
{
|
|
knlval.string = NULL;
|
|
return STRING;
|
|
}
|
|
|
|
len = strlen(kntext) + 1;
|
|
knlval.string = calloc(len, sizeof(char));
|
|
if (knlval.string == NULL)
|
|
{
|
|
keynote_errno = ERROR_MEMORY;
|
|
return -1;
|
|
}
|
|
strlcpy(knlval.string, kntext, len);
|
|
if (keynote_lex_add(knlval.string,
|
|
LEXTYPE_CHAR) == -1)
|
|
return -1;
|
|
return STRING;
|
|
}
|
|
<ACTIONSTRING>{number} {
|
|
knlval.intval = atoi(kntext);
|
|
return NUM;
|
|
}
|
|
{litstring} {
|
|
if (keynote_exceptionflag ||
|
|
keynote_donteval)
|
|
{
|
|
knlval.string = NULL;
|
|
return STRING;
|
|
}
|
|
|
|
knlval.string = calloc(strlen(kntext) - 1,
|
|
sizeof(char));
|
|
if (knlval.string == NULL)
|
|
{
|
|
keynote_errno = ERROR_MEMORY;
|
|
return -1;
|
|
}
|
|
|
|
mystrncpy(knlval.string, kntext + 1,
|
|
strlen(kntext) - 2);
|
|
|
|
if (keynote_lex_add(knlval.string,
|
|
LEXTYPE_CHAR) == -1)
|
|
return -1;
|
|
return STRING;
|
|
}
|
|
[ \t\n]
|
|
. { keynote_errno = ERROR_SYNTAX;
|
|
return -1;
|
|
REJECT; /* Avoid -Wall warning. Not reached */
|
|
}
|
|
%%
|
|
|
|
/*
|
|
* Zap everything.
|
|
*/
|
|
static void
|
|
keynote_lex_zap(void)
|
|
{
|
|
int i;
|
|
|
|
if (keynote_lex_counter == 0)
|
|
return;
|
|
|
|
for (i = 0; i < keynote_max_lex_list; i++)
|
|
if (keynote_lex_list[i].lex_s != NULL)
|
|
{
|
|
switch (keynote_lex_list[i].lex_type)
|
|
{
|
|
case LEXTYPE_CHAR:
|
|
free(keynote_lex_list[i].lex_s);
|
|
break;
|
|
}
|
|
|
|
keynote_lex_counter--;
|
|
keynote_lex_list[i].lex_s = NULL;
|
|
keynote_lex_list[i].lex_type = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize.
|
|
*/
|
|
static int
|
|
keynote_lex_init(void)
|
|
{
|
|
if (keynote_lex_list != NULL)
|
|
memset(keynote_lex_list, 0,
|
|
keynote_max_lex_list * sizeof(struct lex_list));
|
|
else
|
|
{
|
|
keynote_lex_list = calloc(keynote_max_lex_list,
|
|
sizeof(struct lex_list));
|
|
if (keynote_lex_list == NULL)
|
|
{
|
|
keynote_errno = ERROR_MEMORY;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return RESULT_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Add the string in a list of allocated but "dangling" memory references.
|
|
* If out of memory, free the string and return -1 (and set keynote_errno).
|
|
*/
|
|
int
|
|
keynote_lex_add(void *s, int type)
|
|
{
|
|
struct lex_list *p;
|
|
int i;
|
|
|
|
if (s == NULL)
|
|
return RESULT_TRUE;
|
|
|
|
for (i = 0; i < keynote_max_lex_list; i++)
|
|
if (keynote_lex_list[i].lex_s == NULL)
|
|
{
|
|
keynote_lex_list[i].lex_s = (void *) s;
|
|
keynote_lex_list[i].lex_type = type;
|
|
keynote_lex_counter++;
|
|
return RESULT_TRUE;
|
|
}
|
|
|
|
/* Not enough space, increase the size of the array */
|
|
keynote_max_lex_list *= 2;
|
|
|
|
p = (struct lex_list *) reallocarray(keynote_lex_list,
|
|
keynote_max_lex_list,
|
|
sizeof(struct lex_list));
|
|
if (p == NULL)
|
|
{
|
|
switch (type)
|
|
{
|
|
case LEXTYPE_CHAR:
|
|
free(s);
|
|
break;
|
|
}
|
|
|
|
keynote_max_lex_list /= 2;
|
|
keynote_errno = ERROR_MEMORY;
|
|
return -1;
|
|
}
|
|
|
|
keynote_lex_list = p;
|
|
keynote_lex_list[i].lex_s = s;
|
|
keynote_lex_list[i++].lex_type = type;
|
|
keynote_lex_counter++;
|
|
|
|
/* Zero out the rest */
|
|
memset(&(keynote_lex_list[i]), 0,
|
|
(keynote_max_lex_list - i) * sizeof(struct lex_list));
|
|
|
|
return RESULT_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Remove string.
|
|
*/
|
|
void
|
|
keynote_lex_remove(void *s)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < keynote_max_lex_list; i++)
|
|
if (keynote_lex_list[i].lex_s == s)
|
|
{
|
|
memset(&(keynote_lex_list[i]), 0, sizeof(struct lex_list));
|
|
keynote_lex_counter--;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return RESULT_TRUE if character is octal digit, RESULT_FALSE otherwise.
|
|
*/
|
|
static int
|
|
is_octal(char c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '0': case '1': case '2': case '3':
|
|
case '4': case '5': case '6': case '7':
|
|
return RESULT_TRUE;
|
|
|
|
default:
|
|
return RESULT_FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return octal value (non-zero) if argument starts with such a
|
|
* representation, otherwise 0.
|
|
*/
|
|
static unsigned char
|
|
get_octal(char *s, int len, int *adv)
|
|
{
|
|
unsigned char res = 0;
|
|
|
|
if (*s == '0')
|
|
{
|
|
if (len > 0)
|
|
{
|
|
if (is_octal(*(s + 1)))
|
|
{
|
|
res = *(s + 1) - '0';
|
|
*adv = 2;
|
|
|
|
if (is_octal(*(s + 2)) && (len - 1 > 0))
|
|
{
|
|
res = res * 8 + (*(s + 2) - '0');
|
|
*adv = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (is_octal(*s) && (len - 1 > 0)) /* Non-zero leading */
|
|
{
|
|
if (is_octal(*(s + 1)) &&
|
|
is_octal(*(s + 2)))
|
|
{
|
|
*adv = 3;
|
|
res = (((*s) - '0') * 64) +
|
|
(((*(s + 1)) - '0') * 8) +
|
|
((*(s + 2)) - '0');
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* Copy at most len characters to string s1 from string s2, taking
|
|
* care of escaped characters in the process. String s1 is assumed
|
|
* to have enough space, and be zero'ed.
|
|
*/
|
|
static void
|
|
mystrncpy(char *s1, char *s2, int len)
|
|
{
|
|
unsigned char c;
|
|
int advance;
|
|
|
|
if (len == 0)
|
|
return;
|
|
|
|
while (len-- > 0)
|
|
{
|
|
if (*s2 == '\\')
|
|
{
|
|
s2++;
|
|
|
|
if (len-- <= 0)
|
|
break;
|
|
|
|
if (*s2 == '\n')
|
|
{
|
|
while (isspace((unsigned char)*(++s2)) && (len-- > 0))
|
|
;
|
|
}
|
|
else
|
|
if ((c = get_octal(s2, len, &advance)) != 0)
|
|
{
|
|
len -= advance - 1;
|
|
s2 += advance;
|
|
*s1++ = c;
|
|
}
|
|
else
|
|
if (*s2 == 'n') /* Newline */
|
|
{
|
|
*s1++ = '\n';
|
|
s2++;
|
|
}
|
|
else
|
|
if (*s2 == 't') /* Tab */
|
|
{
|
|
*s1++ = '\t';
|
|
s2++;
|
|
}
|
|
else
|
|
if (*s2 == 'r') /* Linefeed */
|
|
{
|
|
*s1++ = '\r';
|
|
s2++;
|
|
}
|
|
else
|
|
if (*s2 == 'f') /* Formfeed */
|
|
{
|
|
*s1++ = '\f';
|
|
s2++;
|
|
}
|
|
else
|
|
if ((*s1++ = *s2++) == 0)
|
|
break;
|
|
|
|
continue;
|
|
}
|
|
|
|
if ((*s1++ = *s2++) == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Evaluate an assertion, with as->as_result holding the result.
|
|
* Return RESULT_TRUE if all ok. Also return the result.
|
|
*/
|
|
int
|
|
keynote_evaluate_assertion(struct assertion *as)
|
|
{
|
|
YY_BUFFER_STATE keynote_bs;
|
|
|
|
/* Non-existent Conditions field means highest return value */
|
|
if (as->as_conditions_s == NULL)
|
|
{
|
|
as->as_result = keynote_current_session->ks_values_num - 1;
|
|
return RESULT_TRUE;
|
|
}
|
|
|
|
if (keynote_lex_init() != RESULT_TRUE)
|
|
return -1;
|
|
|
|
keynote_used_variable = 0;
|
|
keynote_init_list = as->as_env; /* Setup the local-init var list */
|
|
|
|
keynote_bs = kn_scan_bytes(as->as_conditions_s,
|
|
as->as_conditions_e - as->as_conditions_s);
|
|
BEGIN(ACTIONSTRING); /* We're doing conditions-string parsing */
|
|
first_tok = ACTSTR;
|
|
as->as_result = 0;
|
|
keynote_returnvalue = 0;
|
|
|
|
switch (knparse())
|
|
{
|
|
case 1: /* Fall through */
|
|
keynote_errno = ERROR_SYNTAX;
|
|
case -1:
|
|
as->as_result = 0;
|
|
break;
|
|
|
|
case 0:
|
|
as->as_result = keynote_returnvalue;
|
|
break;
|
|
}
|
|
|
|
keynote_env_cleanup(&keynote_temp_list, 1);
|
|
keynote_lex_zap();
|
|
kn_delete_buffer(keynote_bs);
|
|
|
|
keynote_used_variable = 0;
|
|
keynote_returnvalue = 0;
|
|
keynote_temp_list = NULL;
|
|
keynote_init_list = NULL;
|
|
|
|
if (keynote_errno != 0)
|
|
return -1;
|
|
else
|
|
return RESULT_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Parse/evaluate a key predicate field.
|
|
* Store keys in key predicate as keylist in as->as_keylist, if second
|
|
* argument is true.
|
|
*/
|
|
int
|
|
keynote_parse_keypred(struct assertion *as, int record)
|
|
{
|
|
YY_BUFFER_STATE keypred_state;
|
|
int p = 0, err;
|
|
|
|
if (as->as_keypred_s == NULL)
|
|
return keynote_current_session->ks_values_num - 1;
|
|
|
|
if (keynote_lex_init() != RESULT_TRUE)
|
|
return -1;
|
|
|
|
keynote_used_variable = 0;
|
|
keynote_returnvalue = 0;
|
|
keynote_justrecord = record; /* Just want the list of keys in predicate */
|
|
keynote_init_list = as->as_env;
|
|
|
|
keypred_state = kn_scan_bytes(as->as_keypred_s,
|
|
as->as_keypred_e - as->as_keypred_s);
|
|
BEGIN(KEYPREDICATE);
|
|
first_tok = KEYPRE;
|
|
|
|
err = knparse();
|
|
if (err != 0)
|
|
if (keynote_errno == 0)
|
|
keynote_errno = ERROR_SYNTAX;
|
|
|
|
kn_delete_buffer(keypred_state);
|
|
keynote_lex_zap();
|
|
keynote_cleanup_kth();
|
|
|
|
keynote_init_list = NULL;
|
|
keynote_justrecord = 0;
|
|
p = keynote_returnvalue;
|
|
keynote_returnvalue = 0;
|
|
|
|
if (record)
|
|
{
|
|
if (keynote_errno != 0)
|
|
{
|
|
keynote_keylist_free(keynote_keypred_keylist);
|
|
keynote_keypred_keylist = NULL;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
/* Mark for re-processing if/when environment changes */
|
|
if (keynote_used_variable)
|
|
{
|
|
keynote_used_variable = 0;
|
|
as->as_internalflags |= ASSERT_IFLAG_WEIRDLICS;
|
|
}
|
|
|
|
if (as->as_keylist)
|
|
keynote_keylist_free(as->as_keylist);
|
|
as->as_keylist = keynote_keypred_keylist;
|
|
keynote_keypred_keylist = NULL;
|
|
return RESULT_TRUE;
|
|
}
|
|
}
|
|
else
|
|
return p;
|
|
}
|
|
|
|
/* Evaluate an authorizer or signature field. Return RESULT_TRUE on success.
|
|
* Store key in as->as_authorizer. Second argument is set only for Authorizer
|
|
* field parsing.
|
|
*/
|
|
int
|
|
keynote_evaluate_authorizer(struct assertion *as, int flag)
|
|
{
|
|
YY_BUFFER_STATE authorizer_state;
|
|
int err;
|
|
|
|
if (keynote_lex_init() != RESULT_TRUE)
|
|
return -1;
|
|
|
|
keynote_init_list = as->as_env;
|
|
keynote_justrecord = 1;
|
|
keynote_used_variable = 0;
|
|
|
|
if ((flag) && (as->as_authorizer != NULL))
|
|
{
|
|
keynote_free_key(as->as_authorizer, as->as_signeralgorithm);
|
|
as->as_authorizer = NULL;
|
|
}
|
|
|
|
if (flag)
|
|
authorizer_state = kn_scan_bytes(as->as_authorizer_string_s,
|
|
as->as_authorizer_string_e -
|
|
as->as_authorizer_string_s);
|
|
else
|
|
authorizer_state = kn_scan_bytes(as->as_signature_string_s,
|
|
as->as_signature_string_e -
|
|
as->as_signature_string_s);
|
|
|
|
BEGIN(SIGNERINIT);
|
|
if (flag)
|
|
first_tok = SIGNERKEY;
|
|
else
|
|
first_tok = SIGNATUREENTRY;
|
|
|
|
err = knparse();
|
|
if ((err != 0) && (keynote_errno == 0))
|
|
keynote_errno = ERROR_SYNTAX;
|
|
|
|
kn_delete_buffer(authorizer_state);
|
|
keynote_lex_zap();
|
|
|
|
keynote_justrecord = 0;
|
|
keynote_init_list = NULL;
|
|
keynote_returnvalue = 0;
|
|
|
|
if (keynote_keypred_keylist != NULL)
|
|
{
|
|
if (flag)
|
|
{
|
|
if (keynote_used_variable)
|
|
as->as_internalflags |= ASSERT_IFLAG_WEIRDAUTH;
|
|
|
|
as->as_authorizer = keynote_keypred_keylist->key_key;
|
|
as->as_signeralgorithm = keynote_keypred_keylist->key_alg;
|
|
}
|
|
else
|
|
{
|
|
if (keynote_used_variable)
|
|
as->as_internalflags |= ASSERT_IFLAG_WEIRDSIG;
|
|
|
|
as->as_signature = keynote_keypred_keylist->key_key;
|
|
}
|
|
|
|
keynote_keypred_keylist->key_key = NULL;
|
|
keynote_keylist_free(keynote_keypred_keylist);
|
|
keynote_keypred_keylist = NULL;
|
|
}
|
|
|
|
keynote_used_variable = 0;
|
|
|
|
if (keynote_errno != 0)
|
|
return -1;
|
|
else
|
|
return RESULT_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Exportable front-end to keynote_get_private_key().
|
|
*/
|
|
char *
|
|
kn_get_string(char *buf)
|
|
{
|
|
return keynote_get_private_key(buf);
|
|
}
|
|
|
|
/*
|
|
* Parse a private key -- actually, it can deal with any kind of string.
|
|
*/
|
|
char *
|
|
keynote_get_private_key(char *buf)
|
|
{
|
|
YY_BUFFER_STATE pkey;
|
|
char *s;
|
|
int err;
|
|
|
|
if (keynote_lex_init() != RESULT_TRUE)
|
|
return NULL;
|
|
|
|
keynote_privkey = NULL;
|
|
pkey = kn_scan_bytes(buf, strlen(buf));
|
|
first_tok = PRIVATEKEY;
|
|
err = knparse();
|
|
kn_delete_buffer(pkey);
|
|
keynote_lex_zap();
|
|
|
|
if (err != 0)
|
|
{
|
|
if (keynote_privkey != NULL)
|
|
{
|
|
free(keynote_privkey);
|
|
keynote_privkey = NULL;
|
|
}
|
|
|
|
if (keynote_errno == 0)
|
|
keynote_errno = ERROR_SYNTAX;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
s = keynote_privkey;
|
|
keynote_privkey = NULL;
|
|
return s;
|
|
}
|
|
|
|
/*
|
|
* Parse Local-Constants and KeyNote-Version fields.
|
|
*/
|
|
struct environment *
|
|
keynote_get_envlist(char *buf, char *bufend, int whichfield)
|
|
{
|
|
struct environment *en = NULL;
|
|
YY_BUFFER_STATE localinit_state;
|
|
int err;
|
|
|
|
if (keynote_lex_init() != RESULT_TRUE)
|
|
return NULL;
|
|
|
|
localinit_state = kn_scan_bytes(buf, bufend - buf);
|
|
if (whichfield == 0)
|
|
{
|
|
BEGIN(LOCALINIT); /* We're doing Local-Constants parsing */
|
|
first_tok = LOCINI;
|
|
}
|
|
else
|
|
{
|
|
BEGIN(KEYNOTEVERSION); /* KeyNote-Version parsing */
|
|
first_tok = KNVERSION;
|
|
}
|
|
|
|
err = knparse();
|
|
if (err != 0)
|
|
if (keynote_errno == 0)
|
|
keynote_errno = ERROR_SYNTAX;
|
|
|
|
kn_delete_buffer(localinit_state);
|
|
keynote_lex_zap();
|
|
|
|
if (!whichfield)
|
|
{
|
|
if (keynote_errno != 0)
|
|
keynote_env_cleanup(&keynote_init_list, 1);
|
|
else
|
|
en = keynote_init_list;
|
|
|
|
keynote_init_list = NULL;
|
|
}
|
|
|
|
/* Avoid compiler (-Wall) warnings. Never reached. */
|
|
if (0)
|
|
{
|
|
yyunput(0, NULL);
|
|
}
|
|
|
|
return en;
|
|
}
|