/* asn1-parse.y - ASN.1 grammar
* Copyright (C) 2000, 2001 Fabio Fiorina
* Copyright (C) 2001 Free Software Foundation, Inc.
* Copyright (C) 2002, 2003, 2006, 2007, 2010, 2012 g10 Code GmbH
*
* This file is part of KSBA.
*
* KSBA is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* KSBA is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copies of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, see .
*/
/*****************************************************/
/* File: x509_ASN.y */
/* Description: input file for 'bison' program. */
/* The output file is a parser (in C language) for */
/* ASN.1 syntax */
/*****************************************************/
%{
#ifndef BUILD_GENTOOLS
# include
#endif
#include
#include
#include
#include
#include
#include
#ifdef BUILD_GENTOOLS
# include "gen-help.h"
#else
# include "util.h"
# include "ksba.h"
#endif
#include "asn1-func.h"
/* It would be better to make yyparse static but there is no way to do
this. Let's hope that this macros works. */
#define yyparse _ksba_asn1_yyparse
/* #define YYDEBUG 1 */
#define MAX_STRING_LENGTH 129
/* constants used in the grammar */
enum {
CONST_EXPLICIT = 1,
CONST_IMPLICIT
};
struct parser_control_s {
FILE *fp;
int lineno;
int debug;
int result_parse;
AsnNode parse_tree;
AsnNode all_nodes;
};
#define PARSECTL ((struct parser_control_s *)parm)
%}
%param {void *parm}
%define api.pure full
%define parse.error verbose
//%expect 1
%union {
unsigned int constant;
char str[MAX_STRING_LENGTH];
AsnNode node;
}
%{
static AsnNode new_node (struct parser_control_s *parsectl, node_type_t type);
#define NEW_NODE(a) (new_node (PARSECTL, (a)))
static void set_name (AsnNode node, const char *name);
static void set_str_value (AsnNode node, const char *text);
static void set_ulong_value (AsnNode node, const char *text);
static void set_right (AsnNode node, AsnNode right);
static void append_right (AsnNode node, AsnNode right);
static void set_down (AsnNode node, AsnNode down);
static int yylex (YYSTYPE *lvalp, void *parm);
static void yyerror (void *parm, const char *s);
%}
%token ASSIG "::="
%token NUM
%token IDENTIFIER
%token OPTIONAL "OPTIONAL"
%token INTEGER "INTEGER"
%token SIZE "SIZE"
%token OCTET "OCTET"
%token STRING "STRING"
%token SEQUENCE "SEQUENCE"
%token BIT "BIT"
%token UNIVERSAL "UNIVERSAL"
%token PRIVATE "PRIVATE"
%token DEFAULT "DEFAULT"
%token CHOICE "CHOICE"
%token OF "OF"
%token OBJECT "OBJECT"
%token STR_IDENTIFIER "IDENTIFIER"
%token ksba_BOOLEAN "BOOLEAN"
%token ksba_TRUE "TRUE"
%token ksba_FALSE "FALSE"
%token APPLICATION "APPLICATION"
%token ANY "ANY"
%token DEFINED "DEFINED"
%token SET "SET"
%token BY "BY"
%token EXPLICIT "EXPLICIT"
%token IMPLICIT "IMPLICIT"
%token DEFINITIONS "DEFINITIONS"
%token TAGS "TAGS"
%token ksba_BEGIN "BEGIN"
%token ksba_END "END"
%token UTCTime "UTCTime"
%token GeneralizedTime "GeneralizedTime"
%token FROM "FROM"
%token IMPORTS "IMPORTS"
%token TOKEN_NULL "NULL"
%token ENUMERATED "ENUMERATED"
%token UTF8STRING "UTF8String"
%token NUMERICSTRING "NumericString"
%token PRINTABLESTRING "PrintableString"
%token TELETEXSTRING "TeletexString"
%token IA5STRING "IA5String"
%token UNIVERSALSTRING "UniversalString"
%token BMPSTRING "BMPString"
%type octet_string_def constant constant_list type_assig_right
%type integer_def type_assig type_assig_list sequence_def type_def
%type bit_string_def default size_def choise_def object_def
%type boolean_def any_def size_def2 obj_constant obj_constant_list
%type constant_def type_constant type_constant_list definitions
%type definitions_id Time bit_element bit_element_list set_def
%type /* identifier_list */ imports_def tag_type tag type_assig_right_tag
%type type_assig_right_tag_default enumerated_def string_def
%type utf8_string_def numeric_string_def printable_string_def
%type teletex_string_def ia5_string_def universal_string_def
%type bmp_string_def
%type pos_num neg_num pos_neg_num pos_neg_identifier num_identifier
%type class explicit_implicit
%%
input: /* empty */
| input definitions
;
pos_num : NUM { strcpy($$,$1); }
| '+' NUM { strcpy($$,$2); }
;
neg_num : '-' NUM
{
strcpy($$,"-");
strcat($$,$2);
}
;
pos_neg_num : pos_num { strcpy($$,$1); }
| neg_num { strcpy($$,$1); }
;
num_identifier : NUM {strcpy($$,$1);}
| IDENTIFIER {strcpy($$,$1);}
;
pos_neg_identifier : pos_neg_num {strcpy($$,$1);}
| IDENTIFIER {strcpy($$,$1);}
;
constant: '(' pos_neg_num ')'
{
$$ = NEW_NODE (TYPE_CONSTANT);
set_str_value ($$, $2);
}
| IDENTIFIER'('pos_neg_num')'
{
$$ = NEW_NODE (TYPE_CONSTANT);
set_name ($$, $1);
set_str_value ($$, $3);
}
;
constant_list: constant { $$=$1; }
| constant_list ',' constant
{
$$ = $1;
append_right ($1, $3);
}
;
/*
identifier_list : IDENTIFIER
{
$$ = NEW_NODE (TYPE_IDENTIFIER);
set_name($$,$1);
}
| identifier_list IDENTIFIER
{
AsnNode node;
$$=$1;
node = NEW_NODE (TYPE_IDENTIFIER);
set_name (node, $2);
append_right ($$, node);
}
;
*/
obj_constant: num_identifier
{
$$ = NEW_NODE (TYPE_CONSTANT);
set_str_value ($$, $1);
}
| IDENTIFIER '(' NUM ')'
{
$$ = NEW_NODE (TYPE_CONSTANT);
set_name ($$, $1);
set_str_value ($$, $3);
}
;
obj_constant_list: obj_constant
{ $$=$1;}
| obj_constant_list obj_constant
{
$$=$1;
append_right ($$, $2);
}
;
class : UNIVERSAL { $$ = CLASS_UNIVERSAL; }
| PRIVATE { $$ = CLASS_PRIVATE; }
| APPLICATION { $$ = CLASS_APPLICATION; }
;
tag_type : '[' NUM ']'
{
$$ = NEW_NODE (TYPE_TAG);
$$->flags.class = CLASS_CONTEXT;
set_ulong_value ($$, $2);
}
| '[' class NUM ']'
{
$$ = NEW_NODE (TYPE_TAG);
$$->flags.class = $2;
set_ulong_value ($$, $3);
}
;
tag : tag_type
{ $$ = $1; }
| tag_type EXPLICIT
{
$$ = $1;
$$->flags.explicit = 1;
}
| tag_type IMPLICIT
{
$$ = $1;
$$->flags.implicit = 1;
}
;
default : DEFAULT pos_neg_identifier
{
$$ = NEW_NODE (TYPE_DEFAULT);
set_str_value ($$, $2);
}
| DEFAULT ksba_TRUE
{
$$ = NEW_NODE (TYPE_DEFAULT);
$$->flags.is_true = 1;
}
| DEFAULT ksba_FALSE
{
$$ = NEW_NODE (TYPE_DEFAULT);
$$->flags.is_false = 1;
}
;
integer_def: INTEGER
{
$$ = NEW_NODE (TYPE_INTEGER);
}
| INTEGER '{' constant_list '}'
{
$$ = NEW_NODE (TYPE_INTEGER);
$$->flags.has_list = 1;
set_down ($$, $3);
}
| integer_def '(' num_identifier '.' '.' num_identifier ')'
{
$$ = NEW_NODE (TYPE_INTEGER);
$$->flags.has_min_max = 1;
/* the following is wrong. Better use a union for the value*/
set_down ($$, NEW_NODE (TYPE_SIZE) );
set_str_value ($$->down, $6);
set_name ($$->down, $3);
}
;
boolean_def: ksba_BOOLEAN
{
$$ = NEW_NODE (TYPE_BOOLEAN);
}
;
Time: UTCTime
{
$$ = NEW_NODE (TYPE_UTC_TIME);
}
| GeneralizedTime
{
$$ = NEW_NODE (TYPE_GENERALIZED_TIME);
}
;
size_def2: SIZE '(' num_identifier ')'
{
$$ = NEW_NODE (TYPE_SIZE);
$$->flags.one_param = 1;
set_str_value ($$, $3);
}
| SIZE '(' num_identifier '.' '.' num_identifier ')'
{
$$ = NEW_NODE (TYPE_SIZE);
$$->flags.has_min_max = 1;
set_str_value ($$, $3);
set_name ($$, $6);
}
;
size_def: size_def2
{
$$=$1;
}
| '(' size_def2 ')'
{
$$=$2;
}
;
octet_string_def : OCTET STRING
{
$$ = NEW_NODE (TYPE_OCTET_STRING);
}
| OCTET STRING size_def
{
$$ = NEW_NODE (TYPE_OCTET_STRING);
$$->flags.has_size = 1;
set_down ($$,$3);
}
;
utf8_string_def: UTF8STRING { $$ = NEW_NODE (TYPE_UTF8_STRING); }
| UTF8STRING size_def
{
$$ = NEW_NODE (TYPE_UTF8_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
numeric_string_def: NUMERICSTRING { $$ = NEW_NODE (TYPE_NUMERIC_STRING); }
| NUMERICSTRING size_def
{
$$ = NEW_NODE (TYPE_NUMERIC_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
printable_string_def: PRINTABLESTRING
{ $$ = NEW_NODE (TYPE_PRINTABLE_STRING); }
| PRINTABLESTRING size_def
{
$$ = NEW_NODE (TYPE_PRINTABLE_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
teletex_string_def: TELETEXSTRING
{ $$ = NEW_NODE (TYPE_TELETEX_STRING); }
| TELETEXSTRING size_def
{
$$ = NEW_NODE (TYPE_TELETEX_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
ia5_string_def: IA5STRING { $$ = NEW_NODE (TYPE_IA5_STRING); }
| IA5STRING size_def
{
$$ = NEW_NODE (TYPE_IA5_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
universal_string_def: UNIVERSALSTRING
{ $$ = NEW_NODE (TYPE_UNIVERSAL_STRING); }
| UNIVERSALSTRING size_def
{
$$ = NEW_NODE (TYPE_UNIVERSAL_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
bmp_string_def: BMPSTRING { $$ = NEW_NODE (TYPE_BMP_STRING); }
| BMPSTRING size_def
{
$$ = NEW_NODE (TYPE_BMP_STRING);
$$->flags.has_size = 1;
set_down ($$,$2);
}
;
string_def: utf8_string_def
| numeric_string_def
| printable_string_def
| teletex_string_def
| ia5_string_def
| universal_string_def
| bmp_string_def
;
bit_element : IDENTIFIER'('NUM')'
{
$$ = NEW_NODE (TYPE_CONSTANT);
set_name ($$, $1);
set_str_value ($$, $3);
}
;
bit_element_list : bit_element
{
$$=$1;
}
| bit_element_list ',' bit_element
{
$$=$1;
append_right ($$, $3);
}
;
bit_string_def : BIT STRING
{
$$ = NEW_NODE (TYPE_BIT_STRING);
}
| BIT STRING '{' bit_element_list '}'
{
$$ = NEW_NODE (TYPE_BIT_STRING);
$$->flags.has_list = 1;
set_down ($$, $4);
}
;
enumerated_def : ENUMERATED '{' bit_element_list '}'
{
$$ = NEW_NODE (TYPE_ENUMERATED);
$$->flags.has_list = 1;
set_down ($$, $3);
}
;
object_def : OBJECT STR_IDENTIFIER
{
$$ = NEW_NODE (TYPE_OBJECT_ID);
}
;
type_assig_right: IDENTIFIER
{
$$ = NEW_NODE (TYPE_IDENTIFIER);
set_str_value ($$, $1);
}
| IDENTIFIER size_def
{
$$ = NEW_NODE (TYPE_IDENTIFIER);
$$->flags.has_size = 1;
set_str_value ($$, $1);
set_down ($$, $2);
}
| integer_def {$$=$1;}
| enumerated_def {$$=$1;}
| boolean_def {$$=$1;}
| string_def {$$=$1;}
| Time
| octet_string_def {$$=$1;}
| bit_string_def {$$=$1;}
| sequence_def {$$=$1;}
| object_def {$$=$1;}
| choise_def {$$=$1;}
| any_def {$$=$1;}
| set_def {$$=$1;}
| TOKEN_NULL
{
$$ = NEW_NODE(TYPE_NULL);
}
;
type_assig_right_tag : type_assig_right
{
$$ = $1;
}
| tag type_assig_right
{
/* $2->flags.has_tag = 1; */
/* $$ = $2; */
/* set_right ($1, $$->down ); */
/* set_down ($$, $1); */
$$ = $1;
set_down ($$, $2);
}
;
type_assig_right_tag_default : type_assig_right_tag
{
$$ = $1;
}
| type_assig_right_tag default
{
$1->flags.has_default = 1;
$$ = $1;
set_right ($2, $$->down);
set_down ($$, $2);
}
| type_assig_right_tag OPTIONAL
{
$1->flags.is_optional = 1;
$$ = $1;
}
;
type_assig : IDENTIFIER type_assig_right_tag_default
{
set_name ($2, $1);
$$ = $2;
}
;
type_assig_list : type_assig
{ $$=$1; }
| type_assig_list ',' type_assig
{
$$=$1;
append_right ($$, $3);
}
;
sequence_def : SEQUENCE '{' type_assig_list '}'
{
$$ = NEW_NODE (TYPE_SEQUENCE);
set_down ($$, $3);
}
| SEQUENCE OF type_assig_right
{
$$ = NEW_NODE (TYPE_SEQUENCE_OF);
set_down ($$, $3);
}
| SEQUENCE size_def OF type_assig_right
{
$$ = NEW_NODE (TYPE_SEQUENCE_OF);
$$->flags.has_size = 1;
set_right ($2,$4);
set_down ($$,$2);
}
;
set_def : SET '{' type_assig_list '}'
{
$$ = NEW_NODE (TYPE_SET);
set_down ($$, $3);
}
| SET OF type_assig_right
{
$$ = NEW_NODE (TYPE_SET_OF);
set_down ($$, $3);
}
| SET size_def OF type_assig_right
{
$$ = NEW_NODE (TYPE_SET_OF);
$$->flags.has_size = 1;
set_right ($2, $4);
set_down ($$, $2);
}
;
choise_def : CHOICE '{' type_assig_list '}'
{
$$ = NEW_NODE (TYPE_CHOICE);
set_down ($$, $3);
}
;
any_def : ANY
{
$$ = NEW_NODE (TYPE_ANY);
}
| ANY DEFINED BY IDENTIFIER
{
AsnNode node;
$$ = NEW_NODE (TYPE_ANY);
$$->flags.has_defined_by = 1;
node = NEW_NODE (TYPE_CONSTANT);
set_name (node, $4);
set_down($$, node);
}
;
type_def : IDENTIFIER "::=" type_assig_right_tag
{
set_name ($3, $1);
$$ = $3;
}
;
constant_def : IDENTIFIER OBJECT STR_IDENTIFIER "::=" '{' obj_constant_list '}'
{
$$ = NEW_NODE (TYPE_OBJECT_ID);
$$->flags.assignment = 1;
set_name ($$, $1);
set_down ($$, $6);
}
| IDENTIFIER IDENTIFIER "::=" '{' obj_constant_list '}'
{
$$ = NEW_NODE (TYPE_OBJECT_ID);
$$->flags.assignment = 1;
$$->flags.one_param = 1;
set_name ($$, $1);
set_str_value ($$, $2);
set_down ($$, $5);
}
| IDENTIFIER INTEGER "::=" NUM
{
$$ = NEW_NODE (TYPE_INTEGER);
$$->flags.assignment = 1;
set_name ($$, $1);
set_str_value ($$, $4);
}
;
type_constant: type_def { $$ = $1; }
| constant_def { $$ = $1; }
;
type_constant_list : type_constant
{ $$ = $1; }
| type_constant_list type_constant
{
$$ = $1;
append_right ($$, $2);
}
;
definitions_id : IDENTIFIER '{' obj_constant_list '}'
{
$$ = NEW_NODE (TYPE_OBJECT_ID);
set_down ($$, $3);
set_name ($$, $1);
}
;
imports_def : /* empty */
{ $$=NULL;}
/*
| IMPORTS identifier_list FROM IDENTIFIER
{
AsnNode node;
$$ = NEW_NODE (TYPE_IMPORTS);
node = NEW_NODE (TYPE_OBJECT_ID);
set_name (node, $4);
set_down (node, $5);
set_down ($$, node);
set_right ($$, $2);
}
*/
;
explicit_implicit : EXPLICIT { $$ = CONST_EXPLICIT; }
| IMPLICIT { $$ = CONST_IMPLICIT; }
;
definitions: definitions_id
DEFINITIONS explicit_implicit TAGS "::=" ksba_BEGIN imports_def
type_constant_list ksba_END
{
AsnNode node;
$$ = node = NEW_NODE (TYPE_DEFINITIONS);
if ($3 == CONST_EXPLICIT)
node->flags.explicit = 1;
else if ($3 == CONST_IMPLICIT)
node->flags.implicit = 1;
if ($7)
node->flags.has_imports = 1;
set_name ($$, $1->name);
set_name ($1, "");
if (!node->flags.has_imports)
set_right ($1,$8);
else
{
set_right ($7,$8);
set_right ($1,$7);
}
set_down ($$, $1);
_ksba_asn_set_default_tag ($$);
_ksba_asn_type_set_config ($$);
PARSECTL->result_parse = _ksba_asn_check_identifier($$);
PARSECTL->parse_tree=$$;
}
;
%%
struct token_table_s {
const char *word;
int token;
};
static struct token_table_s token_table[] = {
{ "::=", ASSIG },
{ "ANY", ANY },
{ "APPLICATION", APPLICATION },
{ "BEGIN", ksba_BEGIN },
{ "BIT", BIT },
{ "BMPString", BMPSTRING },
{ "BOOLEAN", ksba_BOOLEAN },
{ "BY", BY },
{ "CHOICE", CHOICE },
{ "DEFAULT", DEFAULT },
{ "DEFINED", DEFINED },
{ "DEFINITIONS", DEFINITIONS },
{ "END", ksba_END },
{ "ENUMERATED", ENUMERATED },
{ "EXPLICIT", EXPLICIT },
{ "FALSE", ksba_FALSE },
{ "FROM", FROM },
{ "GeneralizedTime", GeneralizedTime },
{ "IA5String", IA5STRING },
{ "IDENTIFIER", STR_IDENTIFIER },
{ "IMPLICIT", IMPLICIT },
{ "IMPORTS", IMPORTS },
{ "INTEGER", INTEGER },
{ "NULL", TOKEN_NULL },
{ "NumericString", NUMERICSTRING },
{ "OBJECT", OBJECT },
{ "OCTET", OCTET },
{ "OF", OF },
{ "OPTIONAL", OPTIONAL },
{ "PRIVATE", PRIVATE },
{ "PrintableString", PRINTABLESTRING },
{ "SEQUENCE", SEQUENCE },
{ "SET", SET },
{ "SIZE", SIZE },
{ "STRING", STRING },
{ "TAGS", TAGS },
{ "TRUE", ksba_TRUE },
{ "TeletexString", TELETEXSTRING },
{ "UNIVERSAL", UNIVERSAL },
{ "UTCTime", UTCTime },
{ "UTF8String", UTF8STRING },
{ "UniversalString", UNIVERSALSTRING },
};
/*************************************************************/
/* Function: yylex */
/* Description: looks for tokens in file_asn1 pointer file. */
/* Return: int */
/* Token identifier or ASCII code or 0(zero: End Of File) */
/*************************************************************/
static int
yylex (YYSTYPE *lvalp, void *parm)
{
int c,counter=0,k;
char string[MAX_STRING_LENGTH];
FILE *fp = PARSECTL->fp;
if (!PARSECTL->lineno)
PARSECTL->lineno++; /* start with line one */
while (1)
{
while ( (c=fgetc (fp))==' ' || c=='\t')
;
if (c =='\n')
{
PARSECTL->lineno++;
continue;
}
if(c==EOF)
return 0;
if ( c=='(' || c==')' || c=='[' || c==']'
|| c=='{' || c=='}' || c==',' || c=='.' || c=='+')
return c;
if (c=='-')
{
if ( (c=fgetc(fp))!='-')
{
ungetc(c,fp);
return '-';
}
else
{
/* A comment finishes at the end of line */
counter=0;
while ( (c=fgetc(fp))!=EOF && c != '\n' )
;
if (c==EOF)
return 0;
else
continue; /* repeat the search */
}
}
do
{
if (counter >= DIM (string)-1 )
{
fprintf (stderr,"%s:%d: token too long\n", "myfile:",
PARSECTL->lineno);
return 0; /* EOF */
}
string[counter++]=c;
}
while ( !((c=fgetc(fp))==EOF
|| c==' '|| c=='\t' || c=='\n'
|| c=='(' || c==')' || c=='[' || c==']'
|| c=='{' || c=='}' || c==',' || c=='.'));
ungetc (c,fp);
string[counter]=0;
/*fprintf (stderr, "yylex token `%s'\n", string);*/
/* Is STRING a number? */
for (k=0; k=counter)
{
strcpy (lvalp->str,string);
if (PARSECTL->debug)
fprintf (stderr,"%d: yylex found number `%s'\n",
PARSECTL->lineno, string);
return NUM;
}
/* Is STRING a keyword? */
for (k = 0; k < DIM (token_table); k++)
{
if (!strcmp (token_table[k].word, string))
return token_table[k].token;
}
/* STRING is an IDENTIFIER */
strcpy(lvalp->str,string);
if (PARSECTL->debug)
fprintf (stderr,"%d: yylex found identifier `%s'\n",
PARSECTL->lineno, string);
return IDENTIFIER;
}
}
static void
yyerror (void *parm, const char *s)
{
(void)parm;
/* Sends the error description to stderr */
fprintf (stderr, "%s\n", s);
/* Why doesn't bison provide a way to pass the parm to yyerror?
Update: Newer bison versions allow for this. We need to see how
we can make use of it. */
}
static AsnNode
new_node (struct parser_control_s *parsectl, node_type_t type)
{
AsnNode node;
node = xcalloc (1, sizeof *node);
node->type = type;
node->off = -1;
node->link_next = parsectl->all_nodes;
parsectl->all_nodes = node;
return node;
}
static void
release_all_nodes (AsnNode node)
{
AsnNode node2;
for (; node; node = node2)
{
node2 = node->link_next;
xfree (node->name);
if (node->valuetype == VALTYPE_CSTR)
xfree (node->value.v_cstr);
else if (node->valuetype == VALTYPE_MEM)
xfree (node->value.v_mem.buf);
xfree (node);
}
}
static void
set_name (AsnNode node, const char *name)
{
_ksba_asn_set_name (node, name);
}
static void
set_str_value (AsnNode node, const char *text)
{
if (text && *text)
_ksba_asn_set_value (node, VALTYPE_CSTR, text, 0);
else
_ksba_asn_set_value (node, VALTYPE_NULL, NULL, 0);
}
static void
set_ulong_value (AsnNode node, const char *text)
{
unsigned long val;
if (text && *text)
val = strtoul (text, NULL, 10);
else
val = 0;
_ksba_asn_set_value (node, VALTYPE_ULONG, &val, sizeof(val));
}
static void
set_right (AsnNode node, AsnNode right)
{
return_if_fail (node);
node->right = right;
if (right)
right->left = node;
}
static void
append_right (AsnNode node, AsnNode right)
{
return_if_fail (node);
while (node->right)
node = node->right;
node->right = right;
if (right)
right->left = node;
}
static void
set_down (AsnNode node, AsnNode down)
{
return_if_fail (node);
node->down = down;
if (down)
down->left = node;
}
/**
* ksba_asn_parse_file:
* @file_name: Filename with the ASN module
* @pointer: Returns the syntax tree
* @debug: Enable debug output
*
* Parse an ASN.1 file and return an syntax tree.
*
* Return value: 0 for okay or an ASN_xx error code
**/
int
ksba_asn_parse_file (const char *file_name, ksba_asn_tree_t *result, int debug)
{
struct parser_control_s parsectl;
*result = NULL;
parsectl.fp = file_name? fopen (file_name, "r") : NULL;
if ( !parsectl.fp )
return gpg_error_from_syserror ();
parsectl.lineno = 0;
parsectl.debug = debug;
parsectl.result_parse = gpg_error (GPG_ERR_SYNTAX);
parsectl.parse_tree = NULL;
parsectl.all_nodes = NULL;
/* yydebug = 1; */
if ( yyparse ((void*)&parsectl) || parsectl.result_parse )
{ /* error */
fprintf (stderr, "%s:%d: parse error\n",
file_name?file_name:"-", parsectl.lineno );
release_all_nodes (parsectl.all_nodes);
parsectl.all_nodes = NULL;
}
else
{ /* okay */
ksba_asn_tree_t tree;
_ksba_asn_change_integer_value (parsectl.parse_tree);
_ksba_asn_expand_object_id (parsectl.parse_tree);
tree = xmalloc ( sizeof *tree + (file_name? strlen (file_name):1) );
tree->parse_tree = parsectl.parse_tree;
tree->node_list = parsectl.all_nodes;
strcpy (tree->filename, file_name? file_name:"-");
*result = tree;
}
if (file_name)
fclose (parsectl.fp);
return parsectl.result_parse;
}
void
ksba_asn_tree_release (ksba_asn_tree_t tree)
{
if (!tree)
return;
release_all_nodes (tree->node_list);
tree->node_list = NULL;
xfree (tree);
}
void
_ksba_asn_release_nodes (AsnNode node)
{
/* FIXME: it does not work yet because the allocation function in
asn1-func.c does not link all nodes together */
release_all_nodes (node);
}