3 # yaz-comp: ASN.1 Compiler for YAZ
4 # (c) Index Data 1996-2007
5 # See the file LICENSE for details.
10 # Syntax for the ASN.1 supported:
13 # module -> name skip DEFINITIONS ::= mbody END
14 # mbody -> EXPORTS { nlist }
15 # | IMPORTS { imlist }
19 # type -> SEQUENCE { sqlist }
30 # sqlist -> sqlist , name tmt opt
32 # chlist -> chlist , name tmt
34 # enlist -> enlist , name (n)
36 # imlist -> nlist FROM name
37 # imlist nlist FROM name
40 # mod -> IMPLICIT | EXPLICIT | e
41 # tag -> [tagtype n] | [n] | e
44 # name identifier/token
46 # skip one token skipped
48 # tagtype APPLICATION, CONTEXT, etc.
50 # lex: moves input file pointer and returns type of token.
51 # The globals $type and $val are set. $val holds name if token
52 # is normal identifier name.
53 # sets global var type to one of:
56 # \} right curly brace
65 while {![string length $inf(str)]} {
67 set inf(cnt) [gets $inf(inf) inf(str)]
72 lappend inf(asn,$inf(asndef)) $inf(str)
73 set l [string first -- $inf(str)]
76 set inf(str) [string range $inf(str) 0 $l]
78 set inf(str) [string trim $inf(str)]
80 set s [string index $inf(str) 0]
90 \[ { regexp {^\[[ ]*(.+)[ ]*\]} $inf(str) s val }
91 : { regexp {^::=} $inf(str) s }
93 regexp "^\[^,\t :\{\}();\]+" $inf(str) s
98 set off [string length $s]
99 set inf(str) [string trim [string range $inf(str) $off end]]
103 # lex-expect: move pointer and expect token $t
104 proc lex-expect {t} {
107 if {[string compare $t $type]} {
108 asnError "Got $type '$val', expected $t"
112 # lex-name-move: see if token is $name; moves pointer and returns
113 # 1 if it is; returns 0 otherwise.
114 proc lex-name-move {name} {
116 if {![string compare $type n] && ![string compare $val $name]} {
123 # asnError: Report error and die
124 proc asnError {msg} {
127 puts "Error in line $inf(lineno) in module $inf(module)"
133 # asnWarning: Report warning and return
134 proc asnWarning {msg} {
137 puts "Warning in line $inf(lineno) in module $inf(module)"
141 # asnEnum: parses enumerated list - { name1 (n), name2 (n), ... }
142 # Uses $name as prefix. If there really is a list, $lx holds the C
143 # preprocessor definitions on return; otherwise lx isn't set.
144 proc asnEnum {name lx} {
147 if {[string compare $type \{]} return
150 set pq [asnName $name]
151 set id [lindex $pq 0]
154 lappend l "#define $inf(dprefix)$id $val"
157 if {[string compare $type ,]} break
159 if {[string compare $type \}]} {
160 asnError "Missing \} in enum list got $type '$val'"
165 # asnMod: parses tag and modifier.
166 # $xtag and $ximplicit holds tag and implicit-indication on return.
167 # $xtag is empty if no tag was specified. $ximplicit is 1 on implicit
168 # tagging; 0 otherwise.
169 proc asnMod {xtag ximplicit xtagtype} {
173 upvar $ximplicit implicit
174 upvar $xtagtype tagtype
178 if {![string compare $type \[]} {
179 if {[regexp {^([a-zA-Z]+)[ ]+([0-9]+)$} $val x tagtype tag]} {
180 set tagtype ODR_$tagtype
181 } elseif {[regexp {^([0-9]+)$} $val x tag]} {
182 set tagtype ODR_CONTEXT
184 asnError "bad tag specification: $val"
188 set implicit $inf(implicit-tags)
189 if {![string compare $type n]} {
190 if {![string compare $val EXPLICIT]} {
193 } elseif {![string compare $val IMPLICIT]} {
200 # asnName: moves pointer and expects name. Returns C-validated name.
201 proc asnName {name} {
204 if {[info exists inf(membermap,$inf(module),$name,$val)]} {
205 set nval $inf(membermap,$inf(module),$name,$val)
207 puts " mapping member $name,$val to $nval"
209 if {![string match {[A-Z]*} $val]} {
214 if {![string match {[A-Z]*} $val]} {
218 return [join [split $nval -] _]
221 # asnOptional: parses optional modifier. Returns 1 if OPTIONAL was
222 # specified; 0 otherwise.
223 proc asnOptional {} {
225 if {[lex-name-move OPTIONAL]} {
227 } elseif {[lex-name-move DEFAULT]} {
234 # asnSizeConstraint: parses the optional SizeConstraint.
235 # Currently not used for anything.
236 proc asnSizeConstraint {} {
238 if {[lex-name-move SIZE]} {
243 # asnSubtypeSpec: parses the SubtypeSpec ...
244 # Currently not used for anything. We now it's balanced however, i.e.
246 proc asnSubtypeSpec {} {
249 if {[string compare $type "("]} {
255 if {![string compare $type "("]} {
257 } elseif {![string compare $type ")"]} {
264 # asnType: parses ASN.1 type.
265 # On entry $name should hold the name we are currently defining.
266 # Returns type indicator:
267 # SequenceOf SEQUENCE OF
272 # Simple Basic types.
273 # In this casecalling procedure's $tname variable is a list holding:
274 # {C-Function C-Type} if the type is IMPORTed or ODR defined.
276 # {C-Function C-Type 1} if the type should be defined in this module
277 proc asnType {name} {
282 if {[string compare $type n]} {
283 asnError "Expects type specifier, but got $type"
290 if {[lex-name-move OF]} {
300 if {[lex-name-move OF]} {
313 if {[string length [info commands asnBasic$v]]} {
314 set tname [asnBasic$v]
316 if {[info exists inf(map,$inf(module),$v)]} {
317 set v $inf(map,$inf(module),$v)
319 if {[info exists inf(imports,$v)]} {
320 set tname $inf(imports,$v)
322 set w [join [split $v -] _]
323 set tname [list $inf(fprefix)$w $inf(vprefix)$w 1]
326 if {[lex-name-move DEFINED]} {
327 if {[lex-name-move BY]} {
335 proc mapName {name} {
337 if {[info exists inf(map,$inf(module),$name)]} {
338 set name $inf(map,$inf(module),$name)
340 puts -nonewline " $name ($inf(lineno))"
341 puts " mapping to $name"
345 puts " $name ($inf(lineno))"
351 # asnDef: parses type definition (top-level) and generates C code
352 # On entry $name holds the type we are defining.
356 set name [mapName $name]
357 if {[info exist inf(defined,$inf(fprefix)$name)]} {
358 incr inf(definedl,$name)
359 if {$inf(verbose) > 1} {
360 puts "set map($inf(module),$name) $name$inf(definedl,$name)"
363 set inf(definedl,$name) 0
365 set mname [join [split $name -] _]
366 asnMod tag implicit tagtype
367 set t [asnType $mname]
368 asnSub $mname $t $tname $tag $implicit $tagtype
372 # asnSub: parses type and generates C-code
374 # $name holds the type we are defining.
375 # $t is the type returned by the asnType procedure.
376 # $tname is the $tname set by the asnType procedure.
377 # $tag is the tag as returned by asnMod
378 # $implicit is the implicit indicator as returned by asnMod
379 proc asnSub {name t tname tag implicit tagtype} {
383 set defname defined,$inf(fprefix)$name
384 if {[info exist inf($defname)]} {
385 asnWarning "$name already defined in line $inf($defname)"
388 set inf($defname) $inf(lineno)
390 Sequence { set l [asnSequence $name $tag $implicit $tagtype] }
391 SequenceOf { set l [asnOf $name $tag $implicit $tagtype 0] }
392 SetOf { set l [asnOf $name $tag $implicit $tagtype 1] }
393 Choice { set l [asnChoice $name $tag $implicit $tagtype] }
394 Simple { set l [asnSimple $name $tname $tag $implicit $tagtype] }
395 default { asnError "switch asnType case not handled" }
400 puts $file(outc) "int $inf(fprefix)$name (ODR o, $inf(vprefix)$name **p, int opt, const char *name)"
402 puts $file(outc) [lindex $l 0]
405 set fdef "$inf(cprefix)int $inf(fprefix)$name (ODR o, $inf(vprefix)$name **p, int opt, const char *name);"
408 set decl "typedef [lindex $l 1] $inf(vprefix)$name;"
409 if {![string compare [lindex $tname 2] 1]} {
410 if {![info exist inf(defined,[lindex $tname 0])]} {
414 set inf(var,$inf(nodef)) [join [lindex $l 2] \n]
418 set decl "typedef struct $inf(vprefix)$name $inf(vprefix)$name;"
419 set inf(var,$inf(nodef)) "[lindex $l 1];"
425 puts $file(outh) $decl
426 puts $file(outh) $fdef
427 asnForwardTypes $name
429 lappend inf(forward,code,[lindex $tname 0]) {} $decl $fdef
430 lappend inf(forward,ref,[lindex $tname 0]) $name
434 proc asnForwardTypes {name} {
437 if {![info exists inf(forward,code,$inf(fprefix)$name)]} {
440 foreach r $inf(forward,code,$inf(fprefix)$name) {
443 unset inf(forward,code,$inf(fprefix)$name)
445 while {[info exists inf(forward,ref,$inf(fprefix)$name)]} {
446 set n $inf(forward,ref,$inf(fprefix)$name)
447 set m [lrange $n 1 end]
449 set inf(forward,ref,$inf(fprefix)$name) $m
451 unset inf(forward,ref,$inf(fprefix)$name)
453 asnForwardTypes [lindex $n 0]
457 # asnSimple: parses simple type definition and generates C code
459 # $name is the name we are defining
460 # $tname is the tname as returned by asnType
461 # $tag is the tag as returned by asnMod
462 # $implicit is the implicit indicator as returned by asnMod
465 # Note: Doesn't take care of enum lists yet.
466 proc asnSimple {name tname tag implicit tagtype} {
469 set j "[lindex $tname 1] "
471 if {[info exists inf(unionmap,$inf(module),$name)]} {
472 set uName $inf(unionmap,$inf(module),$name)
478 if {![string length $tag]} {
479 set l "\treturn [lindex $tname 0] (o, p, opt, name);"
480 } elseif {$implicit} {
482 "\treturn odr_implicit_tag (o, [lindex $tname 0], p, $tagtype, $tag, opt, name);"
485 "\treturn odr_explicit_tag (o, [lindex $tname 0], p, $tagtype, $tag, opt, name);" \
487 if {[info exists jj]} {
488 return [list $l $j $jj]
494 # asnSequence: parses "SEQUENCE { s-list }" and generates C code.
496 # $name is the type we are defining
501 proc asnSequence {name tag implicit tagtype} {
504 lappend j "struct $inf(vprefix)$name \{"
507 if {![string length $tag]} {
508 lappend l "\tif (!odr_sequence_begin (o, p, sizeof(**p), name))"
509 lappend l "\t\treturn odr_missing(o, opt, name) && odr_ok (o);"
510 } elseif {$implicit} {
511 lappend l "\tif (!odr_implicit_settag (o, $tagtype, $tag) ||"
512 lappend l "\t\t!odr_sequence_begin (o, p, sizeof(**p), name))"
513 lappend l "\t\treturn odr_missing(o, opt, name);"
515 lappend l "\tif (!odr_constructed_begin (o, p, $tagtype, $tag, name))"
516 lappend l "\t\treturn odr_missing(o, opt, name);"
517 lappend l "\tif (o->direction == ODR_DECODE)"
518 lappend l "\t\t*p = ($inf(vprefix)$name *) odr_malloc (o, sizeof(**p));"
520 lappend l "\tif (!odr_sequence_begin (o, p, sizeof(**p), 0))"
522 lappend l "\t\tif(o->direction == ODR_DECODE)"
523 lappend l "\t\t\t*p = 0;"
524 lappend l "\t\treturn 0;"
529 set p [lindex [asnName $name] 0]
530 asnMod ltag limplicit ltagtype
534 if {[info exists inf(unionmap,$inf(module),$name,$p)]} {
535 set uName $inf(unionmap,$inf(module),$name,$p)
538 if {![string compare $t Simple]} {
539 if {[string compare $uName { }]} {
545 set opt [asnOptional]
546 if {![string length $ltag]} {
547 lappend l "\t\t[lindex $tname 0](o, &(*p)->$p, $opt, \"$p\") &&"
548 } elseif {$limplicit} {
549 lappend l "\t\todr_implicit_tag (o, [lindex $tname 0],"
550 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
552 lappend l "\t\todr_explicit_tag (o, [lindex $tname 0],"
553 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
555 set dec "\t[lindex $tname 1] *$p;"
556 } elseif {![string compare $t SequenceOf] && [string length $uName] &&\
557 (![string length $ltag] || $limplicit)} {
560 if {[llength $uName] < 2} {
561 set uName [list num_$p $p]
563 if {[string length $ltag]} {
567 lappend l "\t\todr_implicit_settag (o, $ltagtype, $ltag) &&"
572 set tmpa "odr_sequence_of(o, (Odr_fun) [lindex $tname 0], &(*p)->$p,"
573 set tmpb "&(*p)->[lindex $uName 0], \"$p\")"
574 lappend j "\tint [lindex $uName 0];"
575 set dec "\t[lindex $tname 1] **[lindex $uName 1];"
578 set subName [mapName ${name}_$level]
579 asnSub $subName $u {} {} 0 {}
581 set tmpa "odr_sequence_of(o, (Odr_fun) $inf(fprefix)$subName, &(*p)->$p,"
582 set tmpb "&(*p)->[lindex $uName 0], \"$p\")"
583 lappend j "\tint [lindex $uName 0];"
584 set dec "\t$inf(vprefix)$subName **[lindex $uName 1];"
588 set opt [asnOptional]
590 lappend l "\t\t($tmpa"
591 lappend l "\t\t $tmpb || odr_ok(o)) &&"
593 lappend l "\t\t$tmpa"
594 lappend l "\t\t $tmpb &&"
596 } elseif {!$nchoice && ![string compare $t Choice] && \
597 [string length $uName]} {
598 if {[llength $uName] < 3} {
599 set uName [list which u $name]
602 lappend j "\tint [lindex $uName 0];"
603 lappend j "\tunion \{"
604 lappend v "\tstatic Odr_arm arm\[\] = \{"
605 asnArm $name [lindex $uName 2] v j
607 set dec "\t\} [lindex $uName 1];"
608 set opt [asnOptional]
611 if {[string length $ltag]} {
613 lappend l "\t\todr_implicit_settag (o, $ltagtype, $ltag) &&"
615 asnWarning "optional handling missing in CHOICE in SEQUENCE"
616 asnWarning " set unionmap($inf(module),$name,$p) to {}"
624 lappend l "\t\t${la}odr_constructed_begin (o, &(*p)->[lindex $uName 1], $ltagtype, $ltag, \"$p\") &&"
629 set ob " || odr_ok(o))"
632 lappend l "\t\t${oa}odr_choice (o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], 0)${ob} &&"
633 if {[string length $ltag]} {
636 set lb ") || odr_ok(o))"
640 lappend l "\t\todr_constructed_end (o)${lb} &&"
644 set subName [mapName ${name}_$level]
645 asnSub $subName $t {} {} 0 {}
646 set opt [asnOptional]
647 if {![string length $ltag]} {
648 lappend l "\t\t$inf(fprefix)${subName} (o, &(*p)->$p, $opt, \"$p\") &&"
649 } elseif {$limplicit} {
650 lappend l "\t\todr_implicit_tag (o, $inf(fprefix)${subName},"
651 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
653 lappend l "\t\todr_explicit_tag (o, $inf(fprefix)${subName},"
654 lappend l "\t\t\t&(*p)->$p, $ltagtype, $ltag, $opt, \"$p\") &&"
656 set dec "\t$inf(vprefix)${subName} *$p;"
660 lappend j "$dec /* OPT */"
664 if {[string compare $type ,]} break
667 if {[string length $tag] && !$implicit} {
668 lappend l "\t\todr_sequence_end (o) &&"
669 lappend l "\t\todr_constructed_end (o);"
671 lappend l "\t\todr_sequence_end (o);"
673 if {[string compare $type \}]} {
674 asnError "Missing \} got $type '$val'"
677 if {[info exists v]} {
680 return [list [join $l \n] [join $j \n]]
683 # asnOf: parses "SEQUENCE/SET OF type" and generates C code.
685 # $name is the type we are defining
690 proc asnOf {name tag implicit tagtype isset} {
696 set func odr_sequence_of
699 if {[info exists inf(unionmap,$inf(module),$name)]} {
700 set numName $inf(unionmap,$inf(module),$name)
702 set numName {num elements}
705 lappend j "struct $inf(vprefix)$name \{"
706 lappend j "\tint [lindex $numName 0];"
708 lappend l "\tif (!odr_initmember (o, p, sizeof(**p)))"
709 lappend l "\t\treturn odr_missing(o, opt, name);"
710 if {[string length $tag]} {
712 lappend l "\todr_implicit_settag (o, $tagtype, $tag);"
714 asnWarning "Constructed SEQUENCE/SET OF not handled"
717 set t [asnType $name]
721 lappend l "\tif ($func (o, (Odr_fun) [lindex $tname 0], &(*p)->[lindex $numName 1],"
722 lappend l "\t\t&(*p)->[lindex $numName 0], name))"
723 lappend j "\t[lindex $tname 1] **[lindex $numName 1];"
726 set subName [mapName ${name}_s]
727 lappend l "\tif ($func (o, (Odr_fun) $inf(fprefix)$subName, &(*p)->[lindex $numName 1],"
728 lappend l "\t\t&(*p)->[lindex $numName 0], name))"
729 lappend j "\t$inf(vprefix)$subName **[lindex $numName 1];"
730 asnSub $subName $t {} {} 0 {}
734 lappend l "\t\treturn 1;"
735 lappend l "\tif(o->direction == ODR_DECODE)"
736 lappend l "\t\t*p = 0;"
737 lappend l "\treturn odr_missing(o, opt, name);"
738 return [list [join $l \n] [join $j \n]]
741 # asnArm: parses c-list in choice
742 proc asnArm {name defname lx jx} {
748 set pq [asnName $name]
751 if {![string length $q]} {
755 asnMod ltag limplicit ltagtype
758 lappend enums "$inf(dprefix)$p"
759 if {![string compare $t Simple]} {
761 if {![string length $ltag]} {
762 lappend l "\t\t\{-1, -1, -1, $inf(dprefix)$p,"
763 lappend l "\t\t (Odr_fun) [lindex $tname 0], \"$q\"\},"
764 } elseif {$limplicit} {
765 lappend l "\t\t\{ODR_IMPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
766 lappend l "\t\t(Odr_fun) [lindex $tname 0], \"$q\"\},"
768 lappend l "\t\t\{ODR_EXPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
769 lappend l "\t\t(Odr_fun) [lindex $tname 0], \"$q\"\},"
771 lappend j "\t\t[lindex $tname 1] *$q;"
773 set subName [mapName ${name}_$q]
774 if {![string compare $inf(dprefix)${name}_$q \
775 $inf(vprefix)$subName]} {
776 set po [string toupper [string index $q 0]][string \
778 set subName [mapName ${name}${po}]
780 asnSub $subName $t $tname {} 0 {}
781 if {![string length $ltag]} {
782 lappend l "\t\t\{-1, -1, -1, $inf(dprefix)$p,"
783 lappend l "\t\t (Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
784 } elseif {$limplicit} {
785 lappend l "\t\t\{ODR_IMPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
786 lappend l "\t\t(Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
788 lappend l "\t\t\{ODR_EXPLICIT, $ltagtype, $ltag, $inf(dprefix)$p,"
789 lappend l "\t\t(Odr_fun) $inf(fprefix)$subName, \"$q\"\},"
791 lappend j "\t\t$inf(vprefix)$subName *$q;"
793 if {[string compare $type ,]} break
795 if {[string compare $type \}]} {
796 asnError "Missing \} got $type '$val'"
801 lappend j "#define $e $level"
804 lappend l "\t\t\{-1, -1, -1, -1, (Odr_fun) 0, 0\}"
807 # asnChoice: parses "CHOICE {c-list}" and generates C code.
809 # $name is the type we are defining
814 proc asnChoice {name tag implicit tagtype} {
817 if {[info exists inf(unionmap,$inf(module),$name)]} {
818 set uName $inf(unionmap,$inf(module),$name)
820 set uName [list which u $name]
823 lappend j "struct $inf(vprefix)$name \{"
824 lappend j "\tint [lindex $uName 0];"
825 lappend j "\tunion \{"
826 lappend l "\tstatic Odr_arm arm\[\] = \{"
827 asnArm $name [lindex $uName 2] l j
828 lappend j "\t\} [lindex $uName 1];"
831 if {![string length $tag]} {
832 lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
833 lappend l "\t\treturn odr_missing(o, opt, name);"
834 lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name))"
835 } elseif {$implicit} {
836 lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
837 lappend l "\t\treturn odr_missing(o, opt, name);"
838 lappend l "\todr_implicit_settag(o, $tagtype, $tag);"
839 lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name))"
841 lappend l "\tif (!odr_constructed_begin(o, p, $tagtype, $tag, 0))"
842 lappend l "\t\treturn odr_missing(o, opt, name);"
843 lappend l "\tif (!odr_initmember(o, p, sizeof(**p)))"
844 lappend l "\t\treturn odr_missing(o, opt, name);"
845 lappend l "\tif (odr_choice(o, arm, &(*p)->[lindex $uName 1], &(*p)->[lindex $uName 0], name) &&"
846 lappend l "\t\todr_constructed_end(o))"
848 lappend l "\t\treturn 1;"
850 lappend l "\tif(o->direction == ODR_DECODE)"
851 lappend l "\t\t*p = 0;"
853 lappend l "\treturn odr_missing(o, opt, name);"
854 return [list [join $l \n] [join $j \n]]
857 # asnImports: parses i-list in "IMPORTS {i-list}"
858 # On return inf(import,..)-array is updated.
859 # inf(import,"module") is a list of {C-handler, C-type} elements.
860 # The {C-handler, C-type} is compatible with the $tname as is used by the
861 # asnType procedure to solve external references.
863 global type val inf file
866 if {[string compare $type n]} {
867 asnError "Missing name in IMPORTS list"
871 if {![string compare $type n] && ![string compare $val FROM]} {
874 if {[info exists inf(filename,$val)]} {
875 set fname $inf(filename,$val)
879 puts $file(outh) "\#include <$inf(h-dir)${fname}.h>"
881 if {[info exists inf(prefix,$val)]} {
882 set prefix $inf(prefix,$val)
884 set prefix $inf(prefix)
887 if {[info exists inf(map,$val,$n)]} {
888 set v $inf(map,$val,$n)
892 set w [join [split $v -] _]
893 set inf(imports,$n) [list [lindex $prefix 0]$w \
894 [lindex $prefix 1]$w]
898 if {[string compare $type n]} break
899 } elseif {![string compare $type ,]} {
903 if {[string compare $type \;]} {
904 asnError "Missing ; after IMPORTS list - got $type '$val'"
909 # asnExports: parses e-list in "EXPORTS {e-list}"
910 # This function does nothing with elements in the list.
915 if {[string compare $type n]} {
916 asnError "Missing name in EXPORTS list"
918 set inf(exports,$val) 1
920 if {[string compare $type ,]} break
923 if {[string compare $type \;]} {
924 asnError "Missing ; after EXPORTS list - got $type ($val)"
929 # asnModuleBody: parses a module specification and generates C code.
930 # Exports lists, imports lists, and type definitions are handled;
931 # other things are silently ignored.
932 proc asnModuleBody {} {
933 global type val file inf
935 if {[info exists inf(prefix,$inf(module))]} {
936 set prefix $inf(prefix,$inf(module))
938 set prefix $inf(prefix)
940 set inf(fprefix) [lindex $prefix 0]
941 set inf(vprefix) [lindex $prefix 1]
942 set inf(dprefix) [lindex $prefix 2]
943 if {[llength $prefix] > 3} {
944 set inf(cprefix) [lindex $prefix 3]
946 set inf(cprefix) {YAZ_EXPORT }
950 puts "Module $inf(module), $inf(lineno)"
954 if {[info exists inf(init,$inf(module),c)]} {
955 puts $file(outc) $inf(init,$inf(module),c)
957 if {[info exists inf(init,$inf(module),h)]} {
958 puts $file(outh) "\#ifdef __cplusplus"
959 puts $file(outh) "extern \"C\" \{"
960 puts $file(outh) "\#endif"
962 puts $file(outh) $inf(init,$inf(module),h)
964 if {[info exists inf(init,$inf(module),p)]} {
965 puts $file(outp) $inf(init,$inf(module),p)
968 while {[string length $type]} {
969 if {[string compare $type n]} {
973 if {![string compare $val END]} {
975 } elseif {![string compare $val EXPORTS]} {
978 } elseif {![string compare $val IMPORTS]} {
980 puts $file(outh) "\#ifdef __cplusplus"
981 puts $file(outh) "\}"
982 puts $file(outh) "\#endif"
989 puts $file(outh) "\#ifdef __cplusplus"
990 puts $file(outh) "extern \"C\" \{"
991 puts $file(outh) "\#endif"
994 set inf(asndef) $inf(nodef)
997 if {![string compare $type :]} {
1001 } elseif {![string compare $type n]} {
1003 if {[string length $type]} {
1010 puts $file(outh) "\#ifdef __cplusplus"
1011 puts $file(outh) "\}"
1012 puts $file(outh) "\#endif"
1015 foreach x [array names inf imports,*] {
1020 # asnTagDefault: parses TagDefault section
1021 proc asnTagDefault {} {
1022 global type val inf file
1024 set inf(implicit-tags) 0
1025 while {[string length $type]} {
1026 if {[lex-name-move EXPLICIT]} {
1028 set inf(implicit-tags) 0
1029 } elseif {[lex-name-move IMPLICIT]} {
1031 set inf(implicit-tags) 1
1038 # asnModules: parses a collection of module specifications.
1039 # Depending on the module pattern, $inf(moduleP), a module is either
1040 # skipped or processed.
1041 proc asnModules {} {
1042 global type val inf file yc_version
1047 while {![string compare $type n]} {
1048 set inf(module) $val
1049 if {[info exists inf(moduleP)] && ![string match $inf(moduleP) $val]} {
1050 if {$inf(verbose)} {
1053 while {![lex-name-move END]} {
1060 while {![lex-name-move DEFINITIONS]} {
1062 if {![string length $type]} return
1064 if {[info exists inf(filename,$inf(module))]} {
1065 set fname $inf(filename,$inf(module))
1067 set fname $inf(module)
1069 set ppname [join [split $fname -] _]
1071 if {![info exists inf(c-file)]} {
1072 set inf(c-file) ${fname}.c
1074 set file(outc) [open $inf(c-file) w]
1076 if {![info exists inf(h-file)]} {
1077 set inf(h-file) ${fname}.h
1079 set file(outh) [open $inf(h-path)/$inf(h-dir)$inf(h-file) w]
1082 if {![info exists inf(p-file)]} {
1083 set inf(p-file) ${fname}-p.h
1085 set file(outp) [open $inf(h-path)/$inf(h-dir)$inf(p-file) w]
1088 set greeting {Generated automatically by YAZ ASN.1 Compiler}
1090 puts $file(outc) "/** \\file $inf(c-file)"
1091 puts $file(outc) " \\brief ASN.1 Module $inf(module)"
1093 puts $file(outc) " ${greeting} ${yc_version}"
1094 puts $file(outc) "*/"
1097 puts $file(outh) "/** \\file $inf(h-file)"
1098 puts $file(outh) " \\brief ASN.1 Module $inf(module)"
1100 puts $file(outh) " ${greeting} ${yc_version}"
1101 puts $file(outh) "*/"
1104 if {[info exists file(outp)]} {
1105 puts $file(outp) "/** \\file $inf(p-file)"
1106 puts $file(outp) " \\brief ASN.1 Module $inf(module)"
1108 puts $file(outp) " ${greeting} ${yc_version}"
1109 puts $file(outp) "*/"
1113 if {[info exists inf(p-file)]} {
1114 puts $file(outc) "\#include <$inf(h-dir)$inf(p-file)>"
1116 puts $file(outc) "\#include <$inf(h-dir)$inf(h-file)>"
1118 puts $file(outh) "\#ifndef ${ppname}_H"
1119 puts $file(outh) "\#define ${ppname}_H"
1121 puts $file(outh) "\#include <yaz/odr.h>"
1123 if {[info exists file(outp)]} {
1124 puts $file(outp) "\#ifndef ${ppname}_P_H"
1125 puts $file(outp) "\#define ${ppname}_P_H"
1127 puts $file(outp) "\#include <$inf(h-dir)$inf(h-file)>"
1132 if {[string compare $type :]} {
1133 asnError "::= expected got $type '$val'"
1136 if {![lex-name-move BEGIN]} {
1137 asnError "BEGIN expected"
1142 if {[info exists file(outp)]} {
1147 puts $f "\#ifdef __cplusplus"
1148 puts $f "extern \"C\" \{"
1150 for {set i 1} {$i < $inf(nodef)} {incr i} {
1151 puts $f $inf(var,$i)
1152 if {[info exists inf(asn,$i)]} {
1155 foreach comment $inf(asn,$i) {
1165 puts $f "\#ifdef __cplusplus"
1169 if {[info exists inf(body,$inf(module),h)]} {
1170 puts $file(outh) $inf(body,$inf(module),h)
1172 if {[info exists inf(body,$inf(module),c)]} {
1173 puts $file(outc) $inf(body,$inf(module),c)
1175 if {[info exists inf(body,$inf(module),p)]} {
1176 if {[info exists file(outp)]} {
1177 puts $file(outp) $inf(body,$inf(module),p)
1180 puts $file(outh) "\#endif"
1181 if {[info exists file(outp)]} {
1182 puts $file(outp) "\#endif"
1184 foreach f [array names file] {
1189 catch {unset inf(p-file)}
1194 # asnFile: parses an ASN.1 specification file as specified in $inf(iname).
1198 if {$inf(verbose) > 1} {
1199 puts "Reading ASN.1 file $inf(iname)"
1203 set inf(inf) [open $inf(iname) r]
1209 # The following procedures are invoked by the asnType function.
1210 # Each procedure takes the form: asnBasic<TYPE> and they must return
1211 # two elements: the C function handler and the C type.
1212 # On entry upvar $name is the type we are defining and global, $inf(module), is
1213 # the current module name.
1215 proc asnBasicEXTERNAL {} {
1216 return {odr_external {Odr_external}}
1219 proc asnBasicINTEGER {} {
1220 return {odr_integer {odr_int_t}}
1223 proc asnBasicENUMERATED {} {
1224 return {odr_enum {odr_int_t}}
1227 proc asnBasicNULL {} {
1228 return {odr_null {Odr_null}}
1231 proc asnBasicBOOLEAN {} {
1232 return {odr_bool {bool_t}}
1235 proc asnBasicOCTET {} {
1237 lex-name-move STRING
1238 return {odr_octetstring {Odr_oct}}
1241 proc asnBasicBIT {} {
1243 lex-name-move STRING
1244 return {odr_bitstring {Odr_bitmask}}
1247 proc asnBasicOBJECT {} {
1249 lex-name-move IDENTIFIER
1250 return {odr_oid {Odr_oid}}
1253 proc asnBasicGeneralString {} {
1254 return {odr_generalstring char}
1257 proc asnBasicVisibleString {} {
1258 return {odr_visiblestring char}
1261 proc asnBasicGeneralizedTime {} {
1262 return {odr_generalizedtime char}
1265 proc asnBasicANY {} {
1268 return [list $inf(fprefix)ANY_$name void]
1271 # userDef: reads user definitions file $name
1272 proc userDef {name} {
1275 if {$inf(verbose) > 1} {
1276 puts "Reading definitions file $name"
1280 if {[info exists default-prefix]} {
1281 set inf(prefix) ${default-prefix}
1283 if {[info exists h-path]} {
1284 set inf(h-path) ${h-path}
1286 foreach m [array names prefix] {
1287 set inf(prefix,$m) $prefix($m)
1289 foreach m [array names body] {
1290 set inf(body,$m) $body($m)
1292 foreach m [array names init] {
1293 set inf(init,$m) $init($m)
1295 foreach m [array names filename] {
1296 set inf(filename,$m) $filename($m)
1298 foreach m [array names map] {
1299 set inf(map,$m) $map($m)
1301 foreach m [array names membermap] {
1302 set inf(membermap,$m) $membermap($m)
1304 foreach m [array names unionmap] {
1305 set inf(unionmap,$m) $unionmap($m)
1310 set inf(prefix) {yc_ Yc_ YC_}
1314 # Parse command line
1315 set l [llength $argv]
1318 set arg [lindex $argv $i]
1319 switch -glob -- $arg {
1324 set p [string range $arg 2 end]
1325 if {![string length $p]} {
1326 set p [lindex $argv [incr i]]
1331 set p [string range $arg 2 end]
1332 if {![string length $p]} {
1333 set p [lindex $argv [incr i]]
1338 set p [string range $arg 2 end]
1339 if {![string length $p]} {
1340 set p [lindex $argv [incr i]]
1342 set inf(h-dir) [string trim $p \\/]/
1345 set p [string range $arg 2 end]
1346 if {![string length $p]} {
1347 set p [lindex $argv [incr i]]
1352 set p [string range $arg 2 end]
1353 if {![string length $p]} {
1354 set p [lindex $argv [incr i]]
1359 set p [string range $arg 2 end]
1360 if {![string length $p]} {
1361 set p [lindex $argv [incr i]]
1366 set p [string range $arg 2 end]
1367 if {![string length $p]} {
1368 set p [lindex $argv [incr i]]
1373 set p [string range $arg 2 end]
1374 if {![string length $p]} {
1375 set p [lindex $argv [incr i]]
1377 if {[llength $p] == 1} {
1378 set inf(prefix) [list [string tolower $p] \
1379 [string toupper $p] [string toupper $p]]
1380 } elseif {[llength $p] == 3} {
1394 if {![info exists inf(iname)]} {
1395 puts "YAZ ASN.1 Compiler ${yc_version}"
1397 puts -nonewline ${argv0}
1398 puts { [-v] [-c cfile] [-h hfile] [-p hfile] [-d dfile] [-I iout]}
1399 puts { [-i idir] [-m module] file}