diff --git a/build-aux/ylwrap b/build-aux/ylwrap index 279f306..8f072a8 100755 --- a/build-aux/ylwrap +++ b/build-aux/ylwrap @@ -1,223 +1,247 @@ #! /bin/sh # ylwrap - wrapper for lex/yacc invocations. -scriptversion=2007-11-22.22 +scriptversion=2013-01-12.17; # UTC -# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, -# 2007 Free Software Foundation, Inc. +# Copyright (C) 1996-2013 Free Software Foundation, Inc. # # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program 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 copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . +get_dirname () +{ + case $1 in + */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; + # Otherwise, we want the empty string (not "."). + esac +} + +# guard FILE +# ---------- +# The CPP macro used to guard inclusion of FILE. +guard () +{ + printf '%s\n' "$1" \ + | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ + -e 's/__*/_/g' +} + +# quote_for_sed [STRING] +# ---------------------- +# Return STRING (or stdin) quoted to be used as a sed pattern. +quote_for_sed () +{ + case $# in + 0) cat;; + 1) printf '%s\n' "$1";; + esac \ + | sed -e 's|[][\\.*]|\\&|g' +} + case "$1" in '') - echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 + echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. -input="$1" +input=$1 shift -case "$input" in +# We'll later need for a correct munging of "#line" directives. +input_sub_rx=`get_dirname "$input" | quote_for_sed` +case $input in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. - input="`pwd`/$input" + input=`pwd`/$input ;; esac +input_rx=`get_dirname "$input" | quote_for_sed` + +# Since DOS filename conventions don't allow two dots, +# the DOS version of Bison writes out y_tab.c instead of y.tab.c +# and y_tab.h instead of y.tab.h. Test to see if this is the case. +y_tab_nodot=false +if test -f y_tab.c || test -f y_tab.h; then + y_tab_nodot=true +fi + +# The parser itself, the first file, is the destination of the .y.c +# rule in the Makefile. +parser=$1 + +# A sed program to s/FROM/TO/g for all the FROM/TO so that, for +# instance, we rename #include "y.tab.h" into #include "parse.h" +# during the conversion from y.tab.c to parse.c. +sed_fix_filenames= -pairlist= -while test "$#" -ne 0; do - if test "$1" = "--"; then +# Also rename header guards, as Bison 2.7 for instance uses its header +# guard in its implementation file. +sed_fix_header_guards= + +while test $# -ne 0; do + if test x"$1" = x"--"; then shift break fi - pairlist="$pairlist $1" + from=$1 + # Handle y_tab.c and y_tab.h output by DOS + if $y_tab_nodot; then + case $from in + "y.tab.c") from=y_tab.c;; + "y.tab.h") from=y_tab.h;; + esac + fi shift + to=$1 + shift + sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" + sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. -prog="$1" +prog=$1 shift # Make any relative path in $prog absolute. -case "$prog" in +case $prog in [\\/]* | ?:[\\/]*) ;; - *[\\/]*) prog="`pwd`/$prog" ;; + *[\\/]*) prog=`pwd`/$prog ;; esac -# FIXME: add hostname here for parallel makes that run commands on -# other machines. But that might take us over the 14-char limit. dirname=ylwrap$$ -trap "cd '`pwd`'; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 +do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' +trap "ret=129; $do_exit" 1 +trap "ret=130; $do_exit" 2 +trap "ret=141; $do_exit" 13 +trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then - set X $pairlist - shift - first=yes - # Since DOS filename conventions don't allow two dots, - # the DOS version of Bison writes out y_tab.c instead of y.tab.c - # and y_tab.h instead of y.tab.h. Test to see if this is the case. - y_tab_nodot="no" - if test -f y_tab.c || test -f y_tab.h; then - y_tab_nodot="yes" - fi - - # The directory holding the input. - input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` - # Quote $INPUT_DIR so we can use it in a regexp. - # FIXME: really we should care about more than `.' and `\'. - input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` - - while test "$#" -ne 0; do - from="$1" - # Handle y_tab.c and y_tab.h output by DOS - if test $y_tab_nodot = "yes"; then - if test $from = "y.tab.c"; then - from="y_tab.c" - else - if test $from = "y.tab.h"; then - from="y_tab.h" - fi - fi - fi + for from in * + do + to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, - # otherwise prepend `../'. - case "$2" in - [\\/]* | ?:[\\/]*) target="$2";; - *) target="../$2";; + # otherwise prepend '../'. + case $to in + [\\/]* | ?:[\\/]*) target=$to;; + *) target=../$to;; esac - # We do not want to overwrite a header file if it hasn't - # changed. This avoid useless recompilations. However the - # parser itself (the first file) should always be updated, - # because it is the destination of the .y.c rule in the - # Makefile. Divert the output of all other files to a temporary - # file so we can compare them to existing versions. - if test $first = no; then - realtarget="$target" - target="tmp-`echo $target | sed s/.*[\\/]//g`" + # Do not overwrite unchanged header files to avoid useless + # recompilations. Always update the parser itself: it is the + # destination of the .y.c rule in the Makefile. Divert the + # output of all other files to a temporary file so we can + # compare them to existing versions. + if test $from != $parser; then + realtarget=$target + target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi - # Edit out `#line' or `#' directives. - # - # We don't want the resulting debug information to point at - # an absolute srcdir; it is better for it to just mention the - # .y file with no path. - # - # We want to use the real output file name, not yy.lex.c for - # instance. - # - # We want the include guards to be adjusted too. - FROM=`echo "$from" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` - TARGET=`echo "$2" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` - - sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ - -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? - - # Check whether header files must be updated. - if test $first = no; then - if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then - echo "$2" is unchanged - rm -f "$target" - else - echo updating "$2" + + # Munge "#line" or "#" directives. Don't let the resulting + # debug information point at an absolute srcdir. Use the real + # output file name, not yy.lex.c for instance. Adjust the + # include guards too. + sed -e "/^#/!b" \ + -e "s|$input_rx|$input_sub_rx|" \ + -e "$sed_fix_filenames" \ + -e "$sed_fix_header_guards" \ + "$from" >"$target" || ret=$? + + # Check whether files must be updated. + if test "$from" != "$parser"; then + if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then + echo "$to is unchanged" + rm -f "$target" + else + echo "updating $to" mv -f "$target" "$realtarget" fi fi else - # A missing file is only an error for the first file. This - # is a blatant hack to let us support using "yacc -d". If -d - # is not specified, we don't want an error when the header - # file is "missing". - if test $first = yes; then + # A missing file is only an error for the parser. This is a + # blatant hack to let us support using "yacc -d". If -d is not + # specified, don't fail when the header file is "missing". + if test "$from" = "$parser"; then ret=1 fi fi - shift - shift - first=no done -else - ret=$? fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" # End: diff --git a/src/asn1-parse.y b/src/asn1-parse.y index 2f739c0..3336c43 100755 --- a/src/asn1-parse.y +++ b/src/asn1-parse.y @@ -1,1044 +1,1046 @@ /* 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 YYERROR_VERBOSE 1 #define MAX_STRING_LENGTH 129 /* Dummy print so that yytoknum will be defined. */ #define YYPRINT(F, N, L) do { } while (0); /* 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) -#define YYPARSE_PARAM parm -#define YYLEX_PARAM parm %} -%pure_parser +%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 (const char *s); +static void yyerror (void *parm, const char *s); %} %token-table %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 obj_constant_list { 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=$$; } ; %% /*************************************************************/ /* 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]; size_t len; 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? */ len = strlen (string); for (k = 0; k < YYNTOKENS; k++) { if (yytname[k] && yytname[k][0] == '\"' && !strncmp (yytname[k] + 1, string, len) && yytname[k][len + 1] == '\"' && !yytname[k][len + 2]) return yytoknum[k]; } /* 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 (const char *s) +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 ??*/ + /* 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); }