From patchwork Sat Jan 28 19:52:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [esnacc-dev,1/2] python: Introduce Python library X-Patchwork-Submitter: Aaron Conole X-Patchwork-Id: 8 Message-Id: <1485633123-4103-2-git-send-email-aconole@bytheb.org> To: dev@lists.esnacc.org Date: Sat, 28 Jan 2017 14:52:02 -0500 From: Aaron Conole List-Id: eSNACC Development discussion This commit introduces ASN.1 primitive types for ASN.1 Integer, Enumerated, Octet-String, RelativeOID, OID, Bit-String, and the various collected string types. Additionally, a tiny buffer system is added. Signed-off-by: Aaron Conole --- NEWS | 1 + py-lib/.gitignore | 1 + py-lib/esnacc/__init__.py | 7 + py-lib/esnacc/asn_base.py | 189 +++++++++++++++++++ py-lib/esnacc/asn_bool.py | 53 ++++++ py-lib/esnacc/asn_buffer.py | 124 +++++++++++++ py-lib/esnacc/asn_ints.py | 356 ++++++++++++++++++++++++++++++++++++ py-lib/esnacc/asn_list.py | 98 ++++++++++ py-lib/esnacc/asn_octs.py | 112 ++++++++++++ py-lib/esnacc/asn_useful.py | 35 ++++ py-lib/esnacctests/__init__.py | 7 + py-lib/esnacctests/asn_ints_test.py | 192 +++++++++++++++++++ 12 files changed, 1175 insertions(+) create mode 100644 py-lib/.gitignore create mode 100644 py-lib/esnacc/__init__.py create mode 100644 py-lib/esnacc/asn_base.py create mode 100644 py-lib/esnacc/asn_bool.py create mode 100644 py-lib/esnacc/asn_buffer.py create mode 100644 py-lib/esnacc/asn_ints.py create mode 100644 py-lib/esnacc/asn_list.py create mode 100644 py-lib/esnacc/asn_octs.py create mode 100644 py-lib/esnacc/asn_useful.py create mode 100644 py-lib/esnacctests/__init__.py create mode 100755 py-lib/esnacctests/asn_ints_test.py diff --git a/NEWS b/NEWS index 4f4ad5d..5e1c2dd 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ Future * c++-lib: IOManipulator based encoding/decoding * documentation: Developer's guides * esnacc-logo: A mascot (and CC-BY license) was added for esnacc +* py-lib: Introduce a first cut at a python back-end 1.80 diff --git a/py-lib/.gitignore b/py-lib/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/py-lib/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/py-lib/esnacc/__init__.py b/py-lib/esnacc/__init__.py new file mode 100644 index 0000000..c274353 --- /dev/null +++ b/py-lib/esnacc/__init__.py @@ -0,0 +1,7 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# This file intentionally blank... diff --git a/py-lib/esnacc/asn_base.py b/py-lib/esnacc/asn_base.py new file mode 100644 index 0000000..5e88247 --- /dev/null +++ b/py-lib/esnacc/asn_base.py @@ -0,0 +1,189 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 Base type for eSNACC + +from asn_buffer import AsnBuf +from asn_buffer import BDecDefLen +from asn_buffer import BEncDefLen + +class Constraint(object): + def __init__(self): + pass + + def withinConstraint(self, value): + raise NotImplementedError + + +class BERConsts(object): + BER_ANY_CLASS = -2 + BER_NULL_CLASS = -1 + BER_UNIVERSAL_CLASS = 0 + BER_APPLICATION_CLASS = 1 << 6 + BER_CONTEXTUAL_CLASS = 2 << 6 + BER_PRIVATE_CLASS = 3 << 6 + + UNIV = BER_UNIVERSAL_CLASS + APPL = BER_APPLICATION_CLASS + CNTX = BER_CONTEXTUAL_CLASS + PRIV = BER_PRIVATE_CLASS + + BER_ANY_FORM = -2 + BER_NULL_FORM = -1 + BER_PRIMITIVE_FORM = 0 + BER_CONSTRUCTED_FORM = 1 << 5 + + PRIM = BER_PRIMITIVE_FORM + CONS = BER_CONSTRUCTED_FORM + + @staticmethod + def MakeTag(cls, frm, tag): + fnl = cls & 0xff + fnl |= (frm & 0xff) + + def intcnv(f): + return chr(int(f)) + + if tag < 31: + fnl |= tag & 0xff + fnl = chr(fnl) + else: + tg = intcnv(tag & 0x7f) + tag >>= 7 + while tag: + tg = intcnv(0x80|(tag & 0x7f)) + tg + tag >>= 7 + fnl = intcnv(fnl|0x1f) + tg + + return int(fnl.encode('hex'), 16) + + NO_TAG_CODE = 0 + BOOLEAN_TAG_CODE = 1 + INTEGER_TAG_CODE = 2 + BITSTRING_TAG_CODE = 3 + OCTETSTRING_TAG_CODE = 4 + NULLTYPE_TAG_CODE = 5 + OID_TAG_CODE = 6 + OD_TAG_CODE = 7 + EXTERNAL_TAG_CODE = 8 + REAL_TAG_CODE = 9 + ENUM_TAG_CODE = 10 + UTF8STRING_TAG_CODE = 12 + RELATIVE_OID_TAG_CODE = 13 + SEQ_TAG_CODE = 16 + SET_TAG_CODE = 17 + NUMERICSTRING_TAG_CODE = 18 + PRINTABLESTRING_TAG_CODE = 19 + TELETEXSTRING_TAG_CODE = 20 + VIDEOTEXSTRING_TAG_CODE = 21 + IA5STRING_TAG_CODE = 22 + UTCTIME_TAG_CODE = 23 + GENERALIZEDTIME_TAG_CODE = 24 + GRAPHICSTRING_TAG_CODE = 25 + VISIBLESTRING_TAG_CODE = 26 + GENERALSTRING_TAG_CODE = 27 + UNIVERSALSTRING_TAG_CODE = 28 + BMPSTRING_TAG_CODE = 30 + + +class AsnBase(object): + + BER_CLASS = BERConsts.BER_UNIVERSAL_CLASS + BER_FORM = BERConsts.BER_PRIMITIVE_FORM + + def __init__(self): + pass + + def typename(self): + raise NotImplementedError + + def passesAllConstraints(self, constraints): + return True + + def addConstraint(self, constraint): + try: + self.constraints.append(constraint) + except AttributeError: + self.constraints = [] + self.constraints.append(constraint) + + def BEncContent(self, asnbuf): + raise NotImplementedError + + def BDecContent(self, asnbuf, contentlen): + raise NotImplementedError + + def BEnc(self, asnbuf): + try: + if len(self.constraints) > 0 and \ + not self.passesAllConstraints(self.constraints): + raise ValueError("Not all constraints passed") + except AttributeError: + pass + except TypeError: + pass + + newbuf = AsnBuf() + asnlen = self.BEncContent(newbuf) + asnlen += BEncDefLen(newbuf, asnlen) + TAG_CODE = BERConsts.MakeTag(self.BER_CLASS & 0xff, + self.BER_FORM & 0xff, + self.BER_TAG & 0xff) + asnlen += newbuf.PutBufReverse(TAG_CODE) + asnbuf.PutBuf(newbuf.buf) + return asnlen + + def BDecTag(self, asnbuf, asnlen): + al = 1 + bufTag = ord(asnbuf.Buffer()[0]) + lastTag = bufTag + + if (lastTag & 0x1f) != 0x1f: + return bufTag, al + + lastTag = ord(asnbuf.Buffer()[al]) + while lastTag & 0x80: + lastTag = ord(asnbuf.Buffer()[al]) + bufTag <<= 8 + bufTag |= lastTag + al += 1 + return bufTag, al + + def BDec(self, asnbuf, asnlen): + bufTag, al = self.BDecTag(asnbuf, asnlen) + + PRIM_TAG = BERConsts.MakeTag(self.BER_CLASS & 0xff, + BERConsts.BER_PRIMITIVE_FORM & 0xff, + self.BER_TAG & 0xff) + CONS_TAG = BERConsts.MakeTag(self.BER_CLASS & 0xff, + BERConsts.BER_CONSTRUCTED_FORM & 0xff, + self.BER_TAG & 0xff) + + if bufTag != PRIM_TAG and bufTag != CONS_TAG: + raise IOError("Invalid bytes 0x%x expected [0x%x|0x%x]" % + (bufTag, PRIM_TAG, CONS_TAG)) + + asnbuf.swallow(al) + asnlen += al + tag_total_len, totalBytesLength = BDecDefLen(asnbuf) + asnlen += tag_total_len + asnlen += totalBytesLength + self.BDecContent(asnbuf, totalBytesLength) + return asnlen + + def BEncPdu(self, asnbuf, asnlen): + try: + asnlen = self.BEnc(asnbuf) + except Exception: + return False + return True, asnlen + + def BDecPdu(self, asnbuf, asnlen): + try: + asnlen = self.BDec(asnbuf, asnlen) + except Exception: + return False + return True, asnlen diff --git a/py-lib/esnacc/asn_bool.py b/py-lib/esnacc/asn_bool.py new file mode 100644 index 0000000..5646e5a --- /dev/null +++ b/py-lib/esnacc/asn_bool.py @@ -0,0 +1,53 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 Boolean for eSNACC + +from asn_base import BERConsts +from asn_ints import AsnInt + +def convert_to_bool(value): + if value is None: + return False + + if isinstance(value, int) or isinstance(value, float): + if value == 0: + return False + return True + + if isinstance(value, basestring): + if value.lower() != "true": + return False + return True + + return False + +class AsnBool(AsnInt): + + BER_TAG = BERConsts.BOOLEAN_TAG_CODE + + def __init__(self, value=None): + self.value(value) + + def value(self, newval=None): + if convert_to_bool(newval): + self.intVal = 0xff + else: + self.intVal = 0 + return convert_to_bool(newval) + + def typename(self): + return "AsnBool" + + def __int__(self): + if convert_to_bool(self.value()): + return 0xff + return 0 + + def __str__(self): + if convert_to_bool(self.value()): + return 'True' + return 'False' diff --git a/py-lib/esnacc/asn_buffer.py b/py-lib/esnacc/asn_buffer.py new file mode 100644 index 0000000..553968a --- /dev/null +++ b/py-lib/esnacc/asn_buffer.py @@ -0,0 +1,124 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 Buffer library for eSNACC + + +def ints2octs(listOfInts): + return [chr(int(x)) for x in listOfInts] + + +def BEncDefLen(asnbuf, length): + if length < 128: + asnbuf.PutBufReverse(chr(length & 0xff)) + return 1 + elif length < 256: + asnbuf.PutBufReverse(chr(length & 0xff)) + asnbuf.PutBufReverse(chr(0x81)) + return 2 + elif length < 65536: + asnbuf.PutBufReverse(chr(length & 0xff)) + asnbuf.PutBufReverse(chr((length & 0xff00) >> 8)) + asnbuf.PutBufReverse(chr(0x82)) + return 3 + elif length < 16777126: + asnbuf.PutBufReverse(chr(length & 0xff)) + asnbuf.PutBufReverse(chr((length & 0xff00) >> 8)) + asnbuf.PutBufReverse(chr((length & 0xff0000) >> 16)) + asnbuf.PutBufReverse(chr(0x83)) + return 4 + else: + asnbuf.PutBufReverse(chr(length & 0xff)) + asnbuf.PutBufReverse(chr((length & 0xff00) >> 8)) + asnbuf.PutBufReverse(chr((length & 0xff0000) >> 16)) + asnbuf.PutBufReverse(chr((length & 0xff000000) >> 24)) + asnbuf.PutBufReverse(chr(0x84)) + return 5 + + +def BDecDefLen(asnbuf): + lenByte = ord(asnbuf.GetByte()) + if lenByte < 128: + return 1, lenByte + elif lenByte == 0x80: + raise IOError("INDEFINITE length not supported") + + bytesTotal = lenByte & 0x7f + lenByte = 0 + for b in range(bytesTotal): + lenByte = lenByte << 8 + lenByte += ord(asnbuf.GetByte()) + return bytesTotal, lenByte + + +class AsnBuf(object): + + def __init__(self, bufbytes=None): + if bufbytes is None: + self.buf = [] + else: + if isinstance(bufbytes, basestring): + self.buf = list(bufbytes) + elif isinstance(bufbytes, file): + self.buf = list(bufbytes.read()) + else: + self.buf = bufbytes + + def __len__(self): + return len(self.buf) + + def PutBufReverse(self, listOf): + length = 0 + if isinstance(listOf, list): + for x in reversed(listOf): + length += self.PutBufReverse(x) + else: + self.buf.insert(0, listOf) + length = 1 + return length + + def PutBufIntsReverse(self, listOfInts): + return self.PutBufReverse(ints2octs(listOfInts)) + + def PutBuf(self, listOf): + length = 0 + if isinstance(listOf, list): + for x in listOf: + length += self.PutBuf(x) + else: + self.buf.append(listOf) + length = 1 + return length + + def PutBufInts(self, listOfInts): + return self.PutBuf(ints2octs(listOfInts)) + + def Buffer(self): + return self.buf + + def swallow(self, num): + if len(self.buf) < num: + raise ValueError("Too many bytes to swallow") + + for x in range(num): + del self.buf[0] + + def GetByte(self): + ret = self.buf[0] + self.swallow(1) + return ret + + def GetSeg(self, length): + ret = [] + + if len(self.buf) < length: + raise ValueError("Too many bytes specified") + + for x in range(length): + ret.append(self.buf[0]) + del self.buf[0] + + return ret diff --git a/py-lib/esnacc/asn_ints.py b/py-lib/esnacc/asn_ints.py new file mode 100644 index 0000000..db1b77e --- /dev/null +++ b/py-lib/esnacc/asn_ints.py @@ -0,0 +1,356 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 Integer Types for eSNACC + +from asn_base import AsnBase +from asn_base import Constraint +from asn_base import BERConsts +from asn_buffer import AsnBuf +import math + + +class IntegerConstraint(Constraint): + def __init__(self, lowerBound=None, upperBound=None): + self.lower = lowerBound + self.upper = upperBound + + def withinConstraint(self, value): + if self.lower is not None and value is not None and value < self.lower: + return False + if self.upper is not None and value is not None and value > self.upper: + return False + return True + + +def isfundamental_int_type(value): + if isinstance(value, int) or isinstance(value, float) or \ + isinstance(value, basestring): + return True + return False + + +class AsnInt(AsnBase): + + BER_TAG = BERConsts.INTEGER_TAG_CODE + + def __init__(self, value=None): + self.constraints = None + if value is None: + self.intVal = 0 + elif isfundamental_int_type(value): + self.intVal = int(value) + elif isinstance(value, AsnInt): + self.intVal = value.intVal + else: + raise ValueError("AsnInt - bad value") + + def __bool__(self): + if self.intVal == 0: + return False + return True + + __nonzero__=__bool__ + + def __cmp__(self, obj): + cmpValA = self.intVal + if isinstance(obj, int): + cmpValB = obj + elif isinstance(obj, AsnInt): + cmpValB = obj.intVal + elif isinstance(obj, basestring) or isinstance(obj, float): + cmpValB = int(obj) + else: + raise TypeError("Compare with int, or AsnInt") + return cmp(cmpValA, cmpValB) + + def value(self, newval=None): + if newval is not None: + if isinstance(newval, int) or isinstance(newval, float) or \ + isinstance(newval, basestring): + self.intVal = int(newval) + elif isinstance(newval, AsnInt): + self.intVal = newval.intVal + return self.intVal + + def __int__(self): + return self.value() + + def __float__(self): + return float(self.intVal) + + def __add__(self, obj): + if isinstance(obj, AsnInt): + return self.intVal + obj.intVal + return self.intVal + int(obj) + + def __iadd__(self, obj): + if isinstance(obj, AsnInt): + self.intVal += obj.intVal + else: + self.intVal += int(obj) + return self + + def __sub__(self, obj): + if isinstance(obj, AsnInt): + return self.intVal - obj.intVal + return self.intVal - int(obj) + + def __isub__(self, obj): + if isinstance(obj, AsnInt): + self.intVal -= obj.intVal + else: + self.intVal -= int(obj) + return self + + def __mul__(self, obj): + if isinstance(obj, AsnInt): + return self.intVal * obj.intVal + return self.intVal * obj + + def __imul__(self, obj): + if isinstance(obj, AsnInt): + self.intVal *= obj.intVal + else: + self.intVal *= obj + return self + + def __str__(self): + return str(self.value()) + + def typename(self): + return "AsnInt" + + def passesAllConstraints(self, constraints): + if constraints is None: + return True + if isinstance(constraints, IntegerConstraint): + return constraints.withinConstraint(self.intVal) + elif isinstance(constraints, list): + for x in constraints: + if not self.passesAllConstraints(x): + return False + return True + + def BEncContent(self, asnbuf): + if not isinstance(asnbuf, AsnBuf): + raise ValueError("Buffer must be esnacc.asn_buf.AsnBuf") + + octets = [] + value = int(self) + while 1: + octets.insert(0, value & 0xff) + if value == 0 or value == -1: + break + value = value >> 8 + if value == 0 and octets[0] & 0x80: + octets.insert(0, 0) + while len(octets) > 1 and \ + (octets[0] == 0 and octets[1] & 0x80 == 0 or + octets[0] == 0xff and octets[1] & 0x80 != 0): + del octets[0] + + asnbuf.PutBufIntsReverse(octets) + return len(octets) + + def BDecContent(self, asnbuf, intlen): + buf = ord(asnbuf.Buffer()[0]) + result = 0 + if buf & 0x80: + result = -1 + + for x in range(intlen): + result <<= 8 + result |= ord(asnbuf.GetByte()) + self.intVal = result + return intlen + + +class EnumeratedConstraint(Constraint): + def __init__(self, listOfEnumerations): + self.enums = listOfEnumerations + + def withinConstraint(self, value): + if value not in self.enums: + return False + return True + + +class AsnEnum(AsnInt): + BER_TAG = BERConsts.ENUM_TAG_CODE + + def __init__(self, value=None): + self.constraints = None + if value is not None: + self.intVal = value + + def typename(self): + return "AsnEnum" + + def passesAllConstraints(self, constraints): + if constraints is None: + return True + if isinstance(constraints, IntegerConstraint) \ + or isinstance(constraints, EnumeratedConstraint): + return constraints.withinConstraint(self.intVal) + elif isinstance(constraints, list): + for x in constraints: + if not self.passesAllConstraints(x): + return False + return True + + +class AsnReal(AsnBase): + + BER_TAG = BERConsts.REAL_TAG_CODE + + def __bool__(self): + if self.floatVal == 0: + return False + return True + + def __int__(self): + return int(self.value()) + + def __float__(self): + return self.value() + + def __add__(self, obj): + if isinstance(obj, AsnReal): + return self.floatVal + obj.floatVal + return self.floatVal + float(obj) + + def __iadd__(self, obj): + if isinstance(obj, AsnReal): + self.floatVal += obj.floatVal + else: + self.floatVal += float(obj) + return self + + def __sub__(self, obj): + if isinstance(obj, AsnReal): + return self.floatVal - obj.floatVal + return self.floatVal - float(obj) + + def __isub__(self, obj): + if isinstance(obj, AsnReal): + self.floatVal -= obj.floatVal + else: + self.floatVal -= float(obj) + return self + + def __mul__(self, obj): + if isinstance(obj, AsnReal): + return self.floatVal * obj.floatVal + return self.floatVal * obj + + def __imul__(self, obj): + if isinstance(obj, AsnReal): + self.floatVal *= obj.floatVal + else: + self.floatVal *= obj + return self + + def __str__(self): + return str(self.value()) + + __nonzero__=__bool__ + + def __cmp__(self, obj): + cmpValA = self.floatVal + if isinstance(obj, int): + cmpValB = obj + elif isinstance(obj, AsnReal): + cmpValB = obj.floatVal + elif isinstance(obj, basestring) or isinstance(obj, int): + cmpValB = int(obj) + else: + raise TypeError("Compare with float, or AsnReal") + return cmp(cmpValA, cmpValB) + + def typename(self): + return "AsnReal" + + def value(self, newval=None): + if newval is not None: + if isinstance(newval, int) or isinstance(newval, float) or \ + isinstance(newval, basestring): + self.floatVal = float(newval) + elif isinstance(newval, AsnReal): + self.floatVal = newval.floatVal + return self.floatVal + + PLUS_INF = float('+inf') + MINUS_INF = float('-inf') + NOT_A_NUM = float('nan') + + def BEncContent(self, asnbuf): + if not isinstance(asnbuf, AsnBuf): + raise ValueError("Buffer must be esnacc.asn_buf.AsnBuf") + + if self.floatVal is 0.0: + return 0 + + if self.floatVal is AsnReal.PLUS_INF: + asnbuf.PutBuf(chr(0x40)) + return 1 + elif self.floatVal is AsnReal.MINUS_INF: + asnbuf.PutBuf(chr(0x41)) + return 1 + + def intcnv(f): + return chr(int(f)) + + m, e = math.frexp(self.floatVal) + # Time to normalize for base2 encoding + + encF = 0x80 + if m < 0: + encF |= 0x40 + + while m & 0x1 == 0: + m >>= 1 + e += 1 + + scaleF = 0 + while m & 0x1 == 0: + m >>= 1 + scaleF += 1 + + if scaleF > 3: + raise ValueError('Scale Factor overflow') + + encE = intcnv(0 & 0xff) + encF |= scaleF << 2 + if e in (0, -1): + encE = intcnv(e & 0xff) + else: + while e not in (0, -1): + encE = intcnv(e&0xff) + encE + e >>= 8 + if e == 0 and encE[0] != 0 and int(encE[0]) & 0x80: + encE = intcnv(0) + encE + if e == -1 and encE[0] != 0 and int(encE[0]) & 0x80: + encE = intcnv(0xff) + encE + ln = len(encE) + if ln > 0xff: + raise ValueError('Overflow of real value') + if ln > 1: + encF |= ln - 1 + if ln > 3: + encE = intcnv(ln & 0xff) + encE + + encV = intcnv(0) + while m: + encV = intcnv(m & 0xff) + encV + m >>= 8 + + octs = intcnv(encF) + encE + encV + asnbuf.PutBufReverse(octs) + return len(octs) + + def BDecContent(self, asnbuf, length): + raise NotImplementedError('Not ready yet') diff --git a/py-lib/esnacc/asn_list.py b/py-lib/esnacc/asn_list.py new file mode 100644 index 0000000..a77012b --- /dev/null +++ b/py-lib/esnacc/asn_list.py @@ -0,0 +1,98 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 Integer Types for eSNACC + +from asn_base import AsnBase +from asn_base import BERConsts + + +class AsnSetOf(AsnBase): + + BER_TAG = BERConsts.SET_TAG_CODE + BER_FORM = BERConsts.BER_CONSTRUCTED_FORM + + def __init__(self, elemts=None, expected=None): + self.constraints = None + self.elemts = [] + self.expected = expected + if expected is None: + raise ValueError("Cannot decode a bare typed list: specify a type") + if elemts is not None: + self.elemts = elemts + + def __getitem__(self, idx): + if self.elemts is None or idx > len(self.elemts): + raise IndexError("Octet value out of range") + return self.elemts[idx] + + def __contains__(self, a): + if self.elemts is not None: + return a in self.elemts + return None + + def __len__(self): + if self.elemts is not None: + return len(self.elemts) + return 0 + + def __delitem__(self, idx): + if self.elemts is not None: + del self.elemts[idx] + raise IndexError("Out of range") + + def append(self, item): + if isinstance(item, self.expected): + self.elemts.append(item) + else: + raise TypeError("Invalid type, expected: %s" % (self.expected)) + + def __str__(self): + s = "%s" % self.typename() + s += " {" + s += ','.join(str(x) for x in self.elemts) + s += "}" + return s + + def typename(self): + return "AsnSetOf" + + def BEncContent(self, asnbuf): + enclength = 0 + for x in reversed(self.elemts): + enclength += x.BEnc(asnbuf) + + return enclength + + def BDecContent(self, asnbuf, contentlen): + while contentlen > 0: + t = self.expected() + contentlen -= t.BDec(asnbuf, contentlen) + + +class AsnSequenceOf(AsnSetOf): + + BER_TAG = BERConsts.SEQ_TAG_CODE + + def __init__(self, elemts=None, expected=None): + AsnSetOf.__init__(self, elemts, expected) + + def typename(self): + return "AsnSequenceOf" + + def BEncContent(self, asnbuf): + self.elemts.sort() + return AsnSetOf.BEncContent(self, asnbuf) + + def BDecContent(self, asnbuf, contentlen): + ret = AsnSetOf.BDecContent(self, asnbuf, contentlen) + # Generally, an ASN list is unsorted, but a SEQ implies sorted + # - however -, if a remote end decides to give us an unsorted + # list, we'll just do the sort here. + self.elemts.sort() + if ret is None: + ret = 0 + return ret diff --git a/py-lib/esnacc/asn_octs.py b/py-lib/esnacc/asn_octs.py new file mode 100644 index 0000000..f4fec16 --- /dev/null +++ b/py-lib/esnacc/asn_octs.py @@ -0,0 +1,112 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 Integer Types for eSNACC + +from asn_base import AsnBase +from asn_base import BERConsts +from asn_base import Constraint + + +class CharacterValueConstraint(Constraint): + def __init__(self, lowerBound=None, upperBound=None, charList=None): + self.lower = lowerBound + self.upper = upperBound + self.chars = charList + + def withinConstraint(self, value): + if isinstance(value, list) or isinstance(value, basestring): + for x in value: + if self.withinConstraint(x): + return False + if self.lower is not None and value is not None and \ + value < self.lower: + return False + if self.upper is not None and value is not None and \ + value > self.upper: + return False + if self.chars is not None and value is not None and \ + value not in self.chars: + return False + return True + + +class OctetLengthConstraint(Constraint): + def __init__(self, length=None): + self.length = length + + def withinConstraint(self, value): + if isinstance(value, list) or isinstance(value, basestring): + if len(value) <= self.length: + return True + return False + + +class AsnOcts(AsnBase): + BER_TAG = BERConsts.OCTETSTRING_TAG_CODE + + def __init__(self, value=None): + self.constraints = None + self.octs = None + if value is not None: + self.setData(value) + + def __getitem__(self, idx): + if self.octs is None or idx > len(self.octs): + raise IndexError("Octet value out of range") + return self.octs[idx] + + def __contains__(self, a): + if self.octs is not None: + return a in self.octs + return None + + def __len__(self): + if self.octs is not None: + return len(self.octs) + return 0 + + def __delitem__(self, idx): + if self.octs is not None: + del self.octs[idx] + raise IndexError("Out of range") + + def __str__(self): + s = "[" + if self.octs is not None: + s += ' '.join(["%02X" % ord(x) for x in self.octs]) + s += "]" + return s + + def typename(self): + return "AsnOcts" + + def octs(self): + return self.octs + + def setData(self, octets): + if isinstance(octets, list): + self.octs = octets + elif isinstance(octets, basestring): + self.octs = [] + for x in octets: + self.octs.append(chr(ord(x))) + + def BEncContent(self, asnbuf): + asnbuf.PutBufReverse(self.octs) + return len(self.octs) + + def BDecContent(self, asnbuf, contentlen): + self.octs = asnbuf.GetSeg(contentlen) + return len(self.octs) + + +class AsnString(AsnOcts): + def __init__(self, value=None): + self.contains = None + if value is None: + value = "" + self.setData(value) diff --git a/py-lib/esnacc/asn_useful.py b/py-lib/esnacc/asn_useful.py new file mode 100644 index 0000000..b818d4c --- /dev/null +++ b/py-lib/esnacc/asn_useful.py @@ -0,0 +1,35 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ASN.1 'Useful' Types for eSNACC +# Normally, this should be auto-generated. For now, we'll handcode it +# (because insanity) + +from asn_base import BERConsts +from asn_octs import AsnOcts +from asn_octs import CharacterValueConstraint + + +NumericStrConstraint = \ + CharacterValueConstraint(charList=['0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', ' ']) + + +class NumericString(AsnOcts): + + BER_TAG = BERConsts.NUMERICSTRING_TAG_CODE + + def __init__(self, value=None): + self.constraints = [NumericStrConstraint] + self.octs = value + if self.octs is not None: + self.setData(value) + +class IA5String(AsnOcts): + BER_TAG = BERConsts.IA5STRING_TAG_CODE + + def __init__(self, value=None): + AsnOcts.__init__(self, value) diff --git a/py-lib/esnacctests/__init__.py b/py-lib/esnacctests/__init__.py new file mode 100644 index 0000000..c274353 --- /dev/null +++ b/py-lib/esnacctests/__init__.py @@ -0,0 +1,7 @@ +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# This file intentionally blank... diff --git a/py-lib/esnacctests/asn_ints_test.py b/py-lib/esnacctests/asn_ints_test.py new file mode 100755 index 0000000..ea4193f --- /dev/null +++ b/py-lib/esnacctests/asn_ints_test.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python +# Copyright (C) 2016, Aaron Conole +# +# Licensed under the terms of the GNU General Public License +# agreement (version 2 or greater). Alternately, may be licensed +# under the terms of the ESNACC Public License. +# +# ESNACC ASN.1 integer tests + +import unittest +if __package__ is None: + import sys + from os import path + sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) ) + from esnacc import asn_ints + from esnacc import asn_buffer +else: + from ..esnacc import asn_ints + from ..esnacc import asn_buffer + +class TestAsnInts(unittest.TestCase): + def test_operations_default(self): + asninteger = asn_ints.AsnInt(1) + + self.assertTrue(asninteger == 1) + self.assertTrue(asninteger > 0) + self.assertTrue(asninteger < 2) + + asninteger += 1 + + self.assertTrue(asninteger == 2) + self.assertTrue((asninteger * 1) == 2) + self.assertTrue((asninteger - 1) == 1) + + def test_ber_encoder_simple(self): + class testVec(unittest.TestCase): + def __init__(self, number, length, byteCodes): + self.nm = number + self.ln = length + self.bc = byteCodes + + def run(self): + asninteger = asn_ints.AsnInt(self.nm) + asnbuf = asn_buffer.AsnBuf() + + self.assertTrue(asninteger.BEnc(asnbuf) == self.ln) + byteCodes = asnbuf.Buffer() + self.assertTrue(len(byteCodes) == len(self.bc)) + for x in range(len(byteCodes)): + self.assertTrue(self.bc[x] == byteCodes[x]) + return True + + tests = [] + tvn65535codes = [chr(0x2), chr(0x3), chr(0xff), chr(0x0), chr(0x1)] + tests.append(testVec(-65535, 5, tvn65535codes)) + + tvn10codes = [chr(0x2), chr(0x1), chr(0xf6)] + tests.append(testVec(-10, 3, tvn10codes)) + + tv0codes = [chr(0x2), chr(0x1), chr(0x0)] + tests.append(testVec(0, 3, tv0codes)) + + tv1codes = [chr(0x2), chr(0x1), chr(0x1)] + tests.append(testVec(1, 3, tv1codes)) + + tv2codes = [chr(0x2), chr(0x2), chr(0x3f), chr(0xc3)] + tests.append(testVec(16323, 4, tv2codes)) + + tv3codes = [chr(0x2), chr(02), chr(0x7f), chr(0xff)] + tests.append(testVec(32767, 4, tv3codes)) + + tv4codes = [chr(0x2), chr(0x3), chr(0x00), chr(0x80), chr(0x00)] + tests.append(testVec(32768, 5, tv4codes)) + + tv5codes = [chr(0x2), chr(0x3), chr(0x20), chr(0x00), chr(0x00)] + tests.append(testVec(2097152, 5, tv5codes)) + + tv6codes = [chr(0x2), chr(0x4), chr(0x1), chr(0x0), chr(0x0), chr(0x0)] + tests.append(testVec(16777216, 6, tv6codes)) + + for x in tests: + self.assertTrue(x.run()) + + def test_ber_decoder_simple(self): + class testVec(unittest.TestCase): + def __init__(self, number, length, byteCodes): + self.nm = number + self.ln = length + self.bc = byteCodes + + def run(self): + asnbuf = asn_buffer.AsnBuf(self.bc) + asninteger = asn_ints.AsnInt() + self.assertTrue(asninteger.BDec(asnbuf, 0) == self.ln) + self.assertTrue(self.nm == int(asninteger)) + return True + + tests = [] + tvn65535codes = [chr(0x2), chr(0x3), chr(0xff), chr(0x0), chr(0x1)] + tests.append(testVec(-65535, 5, tvn65535codes)) + + tvn10codes = [chr(0x2), chr(0x1), chr(0xf6)] + tests.append(testVec(-10, 3, tvn10codes)) + + tv0codes = [chr(0x2), chr(0x1), chr(0x0)] + tests.append(testVec(0, 3, tv0codes)) + + tv1codes = [chr(0x2), chr(0x1), chr(0x1)] + tests.append(testVec(1, 3, tv1codes)) + + tv2codes = [chr(0x2), chr(0x2), chr(0x3f), chr(0xc3)] + tests.append(testVec(16323, 4, tv2codes)) + + tv3codes = [chr(0x2), chr(02), chr(0x7f), chr(0xff)] + tests.append(testVec(32767, 4, tv3codes)) + + tv4codes = [chr(0x2), chr(0x3), chr(0x00), chr(0x80), chr(0x00)] + tests.append(testVec(32768, 5, tv4codes)) + + tv5codes = [chr(0x2), chr(0x3), chr(0x20), chr(0x00), chr(0x00)] + tests.append(testVec(2097152, 5, tv5codes)) + + tv6codes = [chr(0x2), chr(0x4), chr(0x1), chr(0x0), chr(0x0), chr(0x0)] + tests.append(testVec(16777216, 6, tv6codes)) + + for x in tests: + self.assertTrue(x.run()) + + + def test_constraints(self): + class testVec(unittest.TestCase): + def __init__(self, number): + self.nm = number + + def run(self): + cnstraint_good = asn_ints.IntegerConstraint(self.nm-1, self.nm+1) + asninteger = asn_ints.AsnInt(self.nm) + asninteger.addConstraint(cnstraint_good) + + buf = asn_buffer.AsnBuf() + self.assertTrue(asninteger.BEnc(buf) != 0) + + cnstraint_bad = asn_ints.IntegerConstraint(self.nm+1, self.nm+2) + asninteger.addConstraint(cnstraint_bad) + with self.assertRaises(ValueError): + asninteger.BEnc(buf) + return True + + tests = [] + tests.append(testVec(-65535)) + tests.append(testVec(-10)) + tests.append(testVec(0)) + tests.append(testVec(1)) + tests.append(testVec(16323)) + tests.append(testVec(32767)) + tests.append(testVec(32768)) + tests.append(testVec(2097152)) + tests.append(testVec(16777216)) + + for x in tests: + self.assertTrue(x.run()) + +class TestAsnEnums(unittest.TestCase): + def test_enumeration_encoding(self): + class testVec(unittest.TestCase): + def __init__(self, number, length, byteCodes): + self.nm = number + self.ln = length + self.bc = byteCodes + + def run(self): + asnenum = asn_ints.AsnEnum(self.nm) + asnbuf = asn_buffer.AsnBuf() + + self.assertTrue(asnenum.BEnc(asnbuf) == self.ln) + byteCodes = asnbuf.Buffer() + self.assertTrue(len(byteCodes) == len(self.bc)) + for x in range(len(byteCodes)): + self.assertTrue(self.bc[x] == byteCodes[x]) + return True + + tests = [] + tv0codes = [chr(0xa), chr(0x1), chr(0x0)] + tests.append(testVec(0, 3, tv0codes)) + + for x in tests: + self.assertTrue(x.run()) + + +if __name__ == '__main__': + + unittest.main() From patchwork Sat Jan 28 19:52:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [esnacc-dev,2/2] compiler/python: Initial handling of Python code X-Patchwork-Submitter: Aaron Conole X-Patchwork-Id: 9 Message-Id: <1485633123-4103-3-git-send-email-aconole@bytheb.org> To: dev@lists.esnacc.org Date: Sat, 28 Jan 2017 14:52:03 -0500 From: Aaron Conole List-Id: eSNACC Development discussion This is a simple python backend for generating code. It currently doesn't handle constraints, implicit tagging, or non-BER forms of serialization. Signed-off-by: Aaron Conole --- NEWS | 2 + compiler/automake.mk | 5 + compiler/back-ends/py-gen/gen-any.c | 265 ++++++++++ compiler/back-ends/py-gen/gen-code.c | 929 +++++++++++++++++++++++++++++++++++ compiler/back-ends/py-gen/rules.c | 569 +++++++++++++++++++++ compiler/back-ends/py-gen/rules.h | 36 ++ compiler/back-ends/py-gen/types.c | 529 ++++++++++++++++++++ compiler/back-ends/str-util.c | 48 +- compiler/back-ends/str-util.h | 1 + compiler/core/define.c | 3 +- compiler/core/snacc.c | 171 +++++-- 11 files changed, 2515 insertions(+), 43 deletions(-) create mode 100644 compiler/back-ends/py-gen/gen-any.c create mode 100644 compiler/back-ends/py-gen/gen-code.c create mode 100644 compiler/back-ends/py-gen/rules.c create mode 100644 compiler/back-ends/py-gen/rules.h create mode 100644 compiler/back-ends/py-gen/types.c diff --git a/NEWS b/NEWS index 5e1c2dd..a18b389 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ Future * documentation: Developer's guides * esnacc-logo: A mascot (and CC-BY license) was added for esnacc * py-lib: Introduce a first cut at a python back-end +* py-gen: Add python backend, which supports only basic explicit tagging, no + extensions, and BER only. 1.80 diff --git a/compiler/automake.mk b/compiler/automake.mk index 7a1f910..b46372f 100644 --- a/compiler/automake.mk +++ b/compiler/automake.mk @@ -70,6 +70,11 @@ compiler_esnacc_SOURCES = \ compiler/back-ends/idl-gen/gen-code.c \ compiler/back-ends/idl-gen/types.c \ compiler/back-ends/idl-gen/gen-vals.c \ + compiler/back-ends/py-gen/gen-any.c \ + compiler/back-ends/py-gen/gen-code.c \ + compiler/back-ends/py-gen/rules.c \ + compiler/back-ends/py-gen/rules.h \ + compiler/back-ends/py-gen/types.c \ policy.h \ version.h diff --git a/compiler/back-ends/py-gen/gen-any.c b/compiler/back-ends/py-gen/gen-any.c new file mode 100644 index 0000000..76bb86b --- /dev/null +++ b/compiler/back-ends/py-gen/gen-any.c @@ -0,0 +1,265 @@ +/* + * compiler/back-ends/py-gen/gen-any.c - routines for printing python + * anytype code + * + * assumes that the type tree has already been run through the + * python type generator (py-gen/types.c). + * + * Copyright (C) 2016 Aaron Conole + * + * 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 of the License, or + * (at your option) any later version. + * + */ + +#include +#include "asn-incl.h" +#include "asn1module.h" +#include "str-util.h" +#include "rules.h" +#include "snacc-util.h" + +#ifdef WIN32 +#pragma warning( disable : 4100 ) /* IGNORE unreferenced formal parameter */ +#endif + + +void PrintPyAnyEnum PROTO ((FILE *hdr, Module *m)); +void PrintPyAnyHashInitRoutine PROTO ((FILE *src, FILE *hdr, + Module *m, PyRules *r)); +void PrintPyOidValue PROTO ((FILE *f, PyRules *r, AsnOid *oid, int parenOrQuote)); + +static TypeDef* GetTypeDef PROTO ((Type *t)); + + +extern int anyEnumValG; + + +void +PrintPyAnyCode PARAMS ((src, hdr, r, mods, m), + FILE *src _AND_ + FILE *hdr _AND_ + PyRules *r _AND_ + ModuleList *mods _AND_ + Module *m) +{ + + if (!m->hasAnys) + return; + + PrintPyAnyEnum(hdr, m); + PrintPyAnyHashInitRoutine(src, hdr, m, r); + +} /* PrintAnyCode */ + + + +void +PrintPyAnyEnum PARAMS ((hdr, m), + FILE *hdr _AND_ + Module *m) +{ + int firstPrinted = TRUE; + char *modName; + ValueDef *vd; + Type *t; + char anyId[512]; + + modName = Asn1TypeName2CTypeName (m->modId->name); + + fprintf (hdr,"typedef enum %sAnyId\n", modName); + fprintf (hdr,"{\n"); + + FOR_EACH_LIST_ELMT (vd, m->valueDefs) { + if (vd->value != NULL) { + t = vd->value->type; + if ((GetBuiltinType(t) == BASICTYPE_MACROTYPE) && + (t->basicType->a.macroType->choiceId == + MACROTYPE_SNMPOBJECTTYPE)) { + strcpy(anyId, vd->definedName); + Dash2Underscore(anyId, strlen (anyId)); + strcat(anyId, "_ANY_ID"); + + if (!firstPrinted) + fprintf (hdr,",\n"); + fprintf (hdr," %s = %d", anyId, anyEnumValG); + anyEnumValG++; + firstPrinted = FALSE; + } + } + } + + if (firstPrinted) + fprintf (hdr,"/* NO INTEGER or OBJECT IDENTIFIER to ANY type relationships were defined (via MACROs or other mechanism) */\n ??? \n"); + + fprintf (hdr,"\n} %sAnyId;\n\n\n", modName); + Free (modName); + +} /* PrintAnyEnum */ + + +void +PrintPyAnyHashInitRoutine PARAMS ((src, hdr, m, r), + FILE *src _AND_ + FILE *hdr _AND_ + Module *m _AND_ + PyRules *r) +{ + + TypeDef *td; + int i; + int installedSomeHashes=0; + struct CxxTDI *cxxtdi; + char *modName; + enum BasicTypeChoiceId typeId; + ValueDef *vd; + Type *t; + BasicValue *bv; + char anyId[512]; + char *typeName = NULL; + + modName = Asn1TypeName2CTypeName (m->modId->name); + + /* print Any class src file */ + fprintf (src,"// this class will automatically intialize the any hash tbl\n"); + fprintf (src,"class InitAny%s\n", modName); + fprintf (src,"{\n"); + fprintf (src," public:\n"); + fprintf (src," InitAny%s();\n", modName); + fprintf (src," /* Do not add a destructor to this class! It could\n"); + fprintf (src," * cause pre-mature destruction of the ANY tables.\n"); + fprintf (src," * The ANY tables will be destroyed by the runtime library.\n"); + fprintf (src," */\n"); + fprintf (src,"};\n\n"); + + fprintf (src,"static InitAny%s anyInitalizer;\n", modName); + + /* print constructor method that build hash tbl to src file*/ + fprintf (src,"InitAny%s::InitAny%s()\n", modName, modName); + fprintf (src,"{\n"); + + /* first print value for OID's */ + i = 0; + + FOR_EACH_LIST_ELMT (vd, m->valueDefs) { + if (vd->value != NULL) { + t = vd->value->type; + if ((GetBuiltinType(t) == BASICTYPE_MACROTYPE) && + (t->basicType->a.macroType->choiceId == + MACROTYPE_SNMPOBJECTTYPE)) { + bv = vd->value->basicValue; + if (bv != NULL) { + installedSomeHashes = TRUE; + if (bv->choiceId == BASICVALUE_OID) { + fprintf(src," %s oid%d", + r->typeConvTbl[BASICTYPE_OID].className, i++); +#if 0 + PrintPyOidValue(src, r, bv->a.oid, 1); +#endif + fprintf(src,";\n"); + } + } + } + } + } + fprintf (src,"\n\n"); + + /* now print hash init calls */ + i = 0; + + FOR_EACH_LIST_ELMT (vd, m->valueDefs) { + if (vd->value != NULL) { + t = vd->value->type; + if ((GetBuiltinType(t) == BASICTYPE_MACROTYPE) && + (t->basicType->a.macroType->choiceId == + MACROTYPE_SNMPOBJECTTYPE)) { + bv = vd->value->basicValue; + if (bv != NULL) { + strcpy (anyId, vd->definedName); + Dash2Underscore (anyId, strlen (anyId)); + strcat (anyId, "_ANY_ID"); + + installedSomeHashes = TRUE; + t = t->basicType->a.macroType->a.snmpObjectType->syntax; + + /* If the syntax of this any is a basic type, get the + class name from the rules table. */ + typeId = t->basicType->choiceId; + if (((typeId >= BASICTYPE_BOOLEAN) && + (typeId <= BASICTYPE_SETOF)) || + ((typeId >= BASICTYPE_NUMERIC_STR) && + (typeId <= BASICTYPE_T61_STR))) { + typeName = r->typeConvTbl[typeId].className; + } else { + /* Else if the syntax of this any is either a locally + defined type or an imported type, get the name from + the this type's ref info. */ + td = GetTypeDef(t); + if (td != NULL) { + cxxtdi = td->cxxTypeDefInfo; + typeName = cxxtdi->className; + } else + typeName = NULL; + } + + if (typeName == NULL) { + fprintf(src, "*** ERROR *** Unknown ANY\n\n"); + } else { + if (bv->choiceId == BASICVALUE_OID) { + fprintf(src, + " AsnAny::InstallAnyByOid (oid%d, %s, new %s);\n", + i++, anyId, typeName); + } else if (bv->choiceId == BASICVALUE_INTEGER) { + fprintf(src, + " AsnAny::InstallAnyByInt (%d, %s, new %s);\n", + bv->a.integer, anyId, typeName); + } + } + } + } + } + } + + if (!installedSomeHashes) { + fprintf(src," /* Since no INTEGER/OID to ANY type relations were defined\n"); + fprintf(src," * (usually done via MACROs) you must manually do the code\n"); + fprintf(src," * to fill the hash tbl.\n"); + fprintf(src," * if the ids are INTEGER use the following:\n"); + fprintf(src," * AsnAny::InstallAnyByInt (3, ??_ANY_ID, new );\n"); + fprintf(src," * if the ids are OBJECT IDENTIFIERs use the following:\n"); + fprintf(src," * AsnAny::InstallAnyByOid (OidValue, ??_ANY_ID, new );\n"); + fprintf(src," * put the ??_ANY_IDs in the AnyId enum.\n\n"); + fprintf(src," * For example if you have some thing like\n"); + fprintf(src," * T1 ::= SEQUENCE { id INTEGER, ANY DEFINED BY id }\n"); + fprintf(src," * and the id 1 maps to the type BOOLEAN use the following:\n"); + fprintf(src," * AsnAny::InstallAnyByInt (1, SOMEBOOL_ANY_ID, new AsnBool);\n"); + fprintf(src," */\n ???????\n"); /* generate compile error */ + } + + + fprintf (src,"} /* InitAny::InitAny */\n\n\n"); +} /* PrintAnyHashInitRoutine */ + + +static TypeDef* +GetTypeDef PARAMS ((t), + Type *t) +{ + if (t == NULL) + return NULL; + + switch (t->basicType->choiceId) + { + case BASICTYPE_LOCALTYPEREF: + case BASICTYPE_IMPORTTYPEREF: + return t->basicType->a.localTypeRef->link; + break; + + default: + return NULL; + } + return NULL;*/ + +} /* GetTypeDef */ diff --git a/compiler/back-ends/py-gen/gen-code.c b/compiler/back-ends/py-gen/gen-code.c new file mode 100644 index 0000000..77a5301 --- /dev/null +++ b/compiler/back-ends/py-gen/gen-code.c @@ -0,0 +1,929 @@ +/* + * compiler/back-ends/py-gen/gen-code.c - routines for printing python + * code from type trees + * + * assumes that the type tree has already been run through the + * python type generator (py-gen/types.c). + * + * Copyright (C) 2016 Aaron Conole + * + * 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 of the License, or + * (at your option) any later version. + * + */ + +#include "snacc.h" + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include + +#include "asn-incl.h" +#include "asn1module.h" +#include "rules.h" +#include "snacc-util.h" +#include "print.h" +#include "tag-util.h" /* get GetTags/FreeTags/CountTags/TagByteLen */ + +#if META +#include "meta.h" +#endif + + +enum BasicTypeChoiceId ParanoidGetBuiltinType PARAMS ((t),Type *t); +void PrintPyAnyCode PROTO ((FILE *src, FILE *hdr, PyRules *r, + ModuleList *mods, Module *m)); +void PrintPyValueDef PROTO ((FILE *src, PyRules *r, ValueDef *v)); +void PrintPyValueExtern PROTO ((FILE *hdr, PyRules *r, ValueDef *v)); +static char * +LookupNamespace PROTO ((Type *t, ModuleList *mods)); + +/* flag to see if constraints were present */ +static int constraints_flag; +static long lconstraintvar=0; + +extern char *bVDAGlobalDLLExport; +extern int gNO_NAMESPACE; +extern const char *gAlternateNamespaceString; +extern int genPERCode; +//extern short ImportedFilesG; + +static const char bufTypeNameG[] = "asn_buffer.AsnBuf"; +static const char lenTypeNameG[] = "AsnLen"; +static const char tagTypeNameG[] = "AsnTag"; +static const char baseClassesG[] = "(asn_base.AsnBase)"; + +static int printTypesG; +static int printEncodersG; +static int printDecodersG; +static int printPrintersG; +static int printFreeG; + +static char *GetImportFileName (char *Impname, ModuleList *mods) +{ + Module *currMod; + char *fileName = NULL; + FOR_EACH_LIST_ELMT (currMod, mods) { + /* Find the import Module in the Modules and + * return the header file name + */ + if ((strcmp(Impname, currMod->modId->name) == 0)) { + /* Set the file name and break */ + fileName = currMod->cxxHdrFileName; + break; + } + } + return fileName; +} + +static Module *GetImportModuleRef (char *Impname, ModuleList *mods) +{ + Module *currMod=NULL; + FOR_EACH_LIST_ELMT (currMod, mods) { + /* Find the import Module in the Modules and + * return the header file name + */ + if ((strcmp(Impname, currMod->modId->name) == 0)) { + break; + } + } + return currMod; +} + +/* Prints the default instantiation for a typedefined object */ +static void PrintPyTypeDefDefault PARAMS((src, td), + FILE* src _AND_ + TypeDef* td) +{ + fprintf(src, + "%s=%s\n\n", + + td->cxxTypeDefInfo->className ? + td->cxxTypeDefInfo->className : + "ERROR__", + + td->type->cxxTypeRefInfo->className ? + td->type->cxxTypeRefInfo->className : + "BAD__"); +} + + +static void +PrintSrcComment PARAMS ((src, m), + FILE *src _AND_ + Module *m) +{ + time_t now = time (NULL); + + fprintf (src, "# %s - class definitions for ASN.1 module %s\n", + m->cxxSrcFileName, m->modId->name); + fprintf (src, "#\n"); + fprintf (src, "# This file was generated by esnacc on %s\n", + ctime(&now)); + fprintf (src, "# NOTE: this is a machine generated file-" + "-editing not recommended\n"); + fprintf (src, "\n"); + +} /* PrintSrcComment */ + + +static void +PrintSrcIncludes PARAMS ((src), FILE *src) +{ + fprintf(src, "from esnacc import asn_base\n"); + fprintf(src, "from esnacc import asn_bool\n"); + fprintf(src, "from esnacc import asn_buffer\n"); + fprintf(src, "from esnacc import asn_ints\n"); + fprintf(src, "from esnacc import asn_list\n"); + fprintf(src, "from esnacc import asn_octs\n"); + fprintf(src, "from esnacc import asn_useful\n"); + /* TODO: import modules */ + fprintf(src, "\n"); +} /* PrintSrcIncludes */ + +/* + * prints inline definition of constructors if this class is + * derived from a library class. + * assumes FILE *f is positioned in the derived class definition (.h) + * + * 12/92 MS - added overloaded "=" ops for string types. + */ +static void +PrintDerivedConstructors PARAMS ((f, td), + FILE *f _AND_ + TypeDef *td) +{ + char *baseClassName = td->type->cxxTypeRefInfo->className; + fprintf(f, + " def __init__(self, value=None):\n" + " %s.__init__(self,value)\n\n", baseClassName); +} + +/* + * prints length encoding code. Primitives always use + * definite length and constructors get "ConsLen" + * which can be configured at compile to to be indefinite + * or definite. Primitives can also be "short" (isShort is true) + * in which case a fast macro is used to write the length. + * Types for which isShort apply are: boolean, null and + * (almost always) integer and reals + */ +static void +PrintPyLenEncodingCode PARAMS ((f, lenVarName, bufVarName, classStr, + formStr), + FILE *f _AND_ + char *lenVarName _AND_ + char *bufVarName _AND_ + char *classStr _AND_ + char *formStr) +{ + fprintf(f, " %s += asn_buffer.BEncDefLen(%s, %s)\n", + lenVarName, bufVarName, lenVarName); + fprintf(f, " TAG_CODE = asn_base.BERConsts.MakeTag(asn_base.BERConsts.%s,\n" + " self.%s,\n" + " self.BER_TAG)\n", + classStr, formStr); +} + +/* prints last tag's encoding code first */ +static void +PrintPyTagAndLenList PARAMS ((src, tagList, lenVarName, bufVarName), + FILE *src _AND_ + TagList *tagList _AND_ + char *lenVarName _AND_ + char *bufVarName) +{ + char *classStr; + char *formStr; + Tag *tg; + int tagLen; + + if ((tagList == NULL) || LIST_EMPTY (tagList)) + return; + + /* + * since encoding backward encode tags backwards + */ + FOR_EACH_LIST_ELMT_RVS (tg, tagList) { + classStr = Class2ClassStr (tg->tclass); + + if (tg->form == CONS) { + formStr = Form2FormStr (CONS); + } else { + formStr = Form2FormStr (PRIM); + } + PrintPyLenEncodingCode (src, lenVarName, bufVarName, + classStr, formStr); + fprintf (src, "\n"); + + if (tg->tclass == UNIV) { + const char* ptr = DetermineCode(tg, &tagLen, 0); + fprintf (src, " %s += BEncTag%d (%s, %s, %s, %s);\n", lenVarName, tagLen, bufVarName, classStr, formStr, ptr); + } else { + const char* ptr = DetermineCode(tg, &tagLen, 1); + fprintf(src, " %s += BEncTag%d(%s, %s, %s, %s);\n", lenVarName, tagLen, bufVarName, classStr, formStr, ptr); + } //RWC;tg->code); + } +} /* PrintPyTagAndLenList */ + +/* + * Recursively walks through tags, printing lower lvl tags + * first (since encoding is done backwards). + * + */ +static void +PrintPyTagAndLenEncodingCode PARAMS ((src, t, lenVarName, bufVarName), + FILE *src _AND_ + Type *t _AND_ + char *lenVarName _AND_ + char *bufVarName) +{ + TagList *tl; + int stoleChoiceTags; + + /* + * get all the tags on this type + */ + tl = (TagList*) GetTags(t, &stoleChoiceTags); + + /* + * leave choice elmt tag enc to encoding routine + */ + if (!stoleChoiceTags) + PrintPyTagAndLenList(src, tl, lenVarName, bufVarName); + + FreeTags(tl); +} /* PrintPyTagAndLenEncodingCode */ + + +/* + * returns true if elmts curr following + * onward are all optional ow. false + */ +static int +RestAreTailOptional PARAMS ((e), + NamedTypeList *e) +{ + NamedType *elmt; + void *tmp; + int retVal; + + if (e == NULL) + return TRUE; + + tmp = (void*)CURR_LIST_NODE (e); + retVal = TRUE; + AsnListNext (e); + FOR_REST_LIST_ELMT (elmt, e) + { + if ((!elmt->type->optional) && (elmt->type->defaultVal == NULL)&&(!elmt->type->extensionAddition)) + { + retVal = FALSE; + break; + } + } + SET_CURR_LIST_NODE (e, tmp); /* reset list to orig loc */ + return retVal; +} + + +/* + * prints typedef or new class given an ASN.1 type def of a primitive type + * or typeref. Uses inheritance to cover re-tagging and named elmts. + */ +static void +PrintPySimpleDef PARAMS ((src, td), + FILE *src _AND_ + TypeDef *td) +{ + Tag *tag; + TagList *tags; + char *formStr; + char *classStr; + CNamedElmt *n; + int stoleChoiceTags; + + if (IsNewType (td->type)) { + int hasNamedElmts; + + fprintf(src, "class %s(%s):\n", + td->cxxTypeDefInfo->className, + td->type->cxxTypeRefInfo->className); + + if ((hasNamedElmts = HasNamedElmts (td->type)) != 0) { + int count = 0; + fprintf(src, " # ENUMERATIONS\n"); + FOR_EACH_LIST_ELMT (n, td->type->cxxTypeRefInfo->namedElmts) { + fprintf(src, " %s = %d\n", n->name, n->value); + count++; + } + fprintf(src, "\n"); + } + + /* + * must explicitly call constructors for base class + */ + PrintDerivedConstructors (src, td); + + fprintf(src, " def typename(self):\n"); + fprintf(src, " return \"%s\"\n\n", + td->cxxTypeDefInfo->className); + /* + * Re-do BerEncode, BerDeocode, BerDecodePdu and BerDecodePdu + * if this type has been re-tagged + */ + if ((IsDefinedByLibraryType(td->type) && !HasDefaultTag(td->type)) + || (IsTypeRef (td->type) && ((td->type->tags != NULL) + && !LIST_EMPTY(td->type->tags)))) { + + int tagLen = 0; + tags = GetTags (td->type, &stoleChoiceTags); + if (tags->count > 1) { + fprintf(src, " # WARNING: only one tag added...\n"); + } + tag = tags->first->data; + classStr = Class2ClassStr (tag->tclass); + formStr = Form2FormStr((tag->form == ANY_FORM) ? PRIM : tag->form); + fprintf(src, " BER_FORM = asn_base.BERConsts.%s\n", formStr); + fprintf(src, " BER_CLASS = asn_base.BERConsts.%s\n", classStr); + fflush(src); + if (!stoleChoiceTags) { + const char *ptr = DetermineCode(tag, &tagLen, (tag->tclass == UNIV) ? 0 : 1); + fprintf(src, " BER_TAG = %s\n", ptr); + } + FreeTags(tags); + fprintf(src, "\n\n"); + } + } else { + /* For now, we don't handle constrained values in primitive types */ + PrintPyTypeDefDefault(src, td); + } +} + +static void +PrintPyChoiceDefCode(FILE *src, FILE *hdr, ModuleList *mods, Module *m, + PyRules *r, TypeDef *td,Type *parent, Type *choice, + int novolatilefuncs) +{ + fprintf(src, "# WARNING : Choice code not implemented.\n"); + fprintf(src, "# This ASN.1 file will not load properly.\n"); +} + +static char * +PyDetermineCode(Tag *tag, int *ptagLen, int bJustIntegerFlag) +{ + static char retstring[256]; + char *codeStr=NULL; + int iValue=500; + memset(retstring, 0, sizeof(retstring)); + if (tag->valueRef == NULL) { + if (!bJustIntegerFlag) { + char *univstr = Code2UnivCodeStr(tag->code); + sprintf(retstring, "asn_base.BERConsts.%s", univstr); + } else { + sprintf(retstring, "%d", tag->code); + } + codeStr = retstring; + if (ptagLen) { + *ptagLen = TagByteLen(tag->code); + } + } else { + if (tag->valueRef && tag->valueRef->basicValue && + tag->valueRef->basicValue->choiceId == BASICVALUE_LOCALVALUEREF && + tag->valueRef->basicValue->a.localValueRef && + tag->valueRef->basicValue->a.localValueRef->link && + tag->valueRef->basicValue->a.localValueRef->link->value && + tag->valueRef->basicValue->a.localValueRef->link->value->basicValue) { + if (tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->choiceId == + BASICVALUE_INTEGER) { + iValue = tag->valueRef->basicValue->a.localValueRef->link-> + value->basicValue->a.integer; + } else if (tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->choiceId == + BASICVALUE_LOCALVALUEREF) { + ValueRef *pvalueRef = NULL; + if (tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->choiceId == BASICVALUE_LOCALVALUEREF) { + pvalueRef = tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->a.localValueRef; + if (pvalueRef->link->value && pvalueRef->link->value->basicValue && + pvalueRef->link->value->basicValue->choiceId == BASICVALUE_INTEGER) + iValue = pvalueRef->link->value->basicValue->a.integer; + } + } else { + printf("Tag value type NOT RECOGNIZED; COULD NOT RESOLVE tag integer!\n"); + } + } else if (tag->valueRef->basicValue->choiceId == + BASICVALUE_IMPORTVALUEREF && + tag->valueRef->basicValue->a.importValueRef && + tag->valueRef->basicValue->a.importValueRef->link && + tag->valueRef->basicValue->a.importValueRef->link->value && + tag->valueRef->basicValue->a.importValueRef->link->value-> + basicValue && + tag->valueRef->basicValue->a.importValueRef->link->value-> + basicValue->choiceId == BASICVALUE_INTEGER) { + iValue = tag->valueRef->basicValue->a.importValueRef->link-> + value->basicValue->a.integer; + } + sprintf(retstring, "%d", iValue); + codeStr = retstring; + if (ptagLen) { + *ptagLen = TagByteLen(iValue); + } + } + return(codeStr); +} + +static void +PrintPySeqOrSetDefCode(FILE *src, + FILE *hdr ESNACC_UNUSED, + ModuleList *mods ESNACC_UNUSED, + Module *m ESNACC_UNUSED, + PyRules *r ESNACC_UNUSED, + TypeDef *td, + Type *parent ESNACC_UNUSED, + Type *seq, int novolatilefuncs ESNACC_UNUSED, + int isSequence) +{ + NamedType *e; + char *classStr; + char *codeStr; + Tag *tag; + + fprintf(src, "class %s%s:\n\n", td->cxxTypeDefInfo->className, + baseClassesG); + + tag = seq->tags->first->data; + classStr = Class2ClassStr (tag->tclass); + codeStr = PyDetermineCode(tag, NULL, (tag->tclass == UNIV) ? 0 : 1); + fprintf(src, " BER_CLASS=asn_base.BERConsts.%s\n", classStr); + fprintf(src, " BER_FORM=asn_base.BERConsts.BER_CONSTRUCTED_FORM\n\n"); + fprintf(src, " BER_TAG=%s\n", codeStr); + /* write out the sequence elmts */ + + if (!seq->basicType->a.sequence || !seq->basicType->a.sequence->count) { + fprintf(stderr, "WARNING: Sequence unknown?\n"); + } + + fprintf(src, " def typename(self):\n"); + fprintf(src, " return \"%s\"\n\n", td->cxxTypeDefInfo->className); + /* constructor */ + fprintf(src, " def __init__(self"); + FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) { + if (e->type->extensionAddition) + continue; + + fprintf(src, ", %s", e->type->cxxTypeRefInfo->fieldName); + + if (e->type->defaultVal) { + Value *defVal = GetValue(e->type->defaultVal->value); + switch (ParanoidGetBuiltinType(e->type)) { + case BASICTYPE_INTEGER: + case BASICTYPE_ENUMERATED: + fprintf(src, " = %s(%d)", + e->type->cxxTypeRefInfo->className, + defVal->basicValue->a.integer); + break; + case BASICTYPE_BOOLEAN: + fprintf(src, " = asn_bool.AsnBool(%s)", + defVal->basicValue->a.boolean == 0 ? + "\"False\"" : "\"True\""); + break; + case BASICTYPE_BITSTRING: + fprintf(stderr, + "WARNING: unsupported default BIT STRING\n"); + break; + default: + fprintf(src, " = %s()\n", + e->type->cxxTypeRefInfo->className); + break; + } /* end switch */ + } else { + fprintf(src, " = None"); + } + } + fprintf(src, "):\n"); + + FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) { + if (e->type->extensionAddition) + continue; + + fprintf(src, " if "); + fprintf(src, "%s is not None and ", + e->type->cxxTypeRefInfo->fieldName); + fprintf(src, "not isinstance(%s, %s):\n", + e->type->cxxTypeRefInfo->fieldName, + e->type->cxxTypeRefInfo->className); + fprintf(src, " raise TypeError(\"Expected %s for %s\")\n", + e->type->cxxTypeRefInfo->className, + e->type->cxxTypeRefInfo->fieldName); + fprintf(src, " else:\n"); + fprintf(src, " self.%s = %s\n", + e->type->cxxTypeRefInfo->fieldName, + e->type->cxxTypeRefInfo->fieldName); + } + + fprintf(src, "\n\n"); + + /* benccontent */ + fprintf(src, " def BEncContent(self, asnbuf):\n"); + fprintf(src, " asnlen = 0\n"); + FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) { + if (e->type->extensionAddition) + continue; + + fprintf(src, " "); + char *indent = " "; + if (e->type->cxxTypeRefInfo->isPtr) { + fprintf(src, "if self.%s is not None:\n", + e->type->cxxTypeRefInfo->fieldName); + indent = " "; + } else { + fprintf(src, "if self.%s is None:\n " + "raise UnboundLocalError('Populate %s before encoding')\n", + e->type->cxxTypeRefInfo->fieldName, + e->type->cxxTypeRefInfo->fieldName); + } + if (e->type->tags->count) { + fprintf(src, "%s# %d tags to encode\n", indent, + e->type->tags->count); + fprintf(src, "%ssafe_buf = asnbuf\n", indent); + fprintf(src, "%ssafe_len = asnlen\n", indent); + fprintf(src, "%sasnlen = 0\n", indent); + fprintf(src, "%sasnbuf = %s()\n", indent, bufTypeNameG); + } + fprintf(src, "%sasnlen += self.%s.BEnc(asnbuf)\n", indent, + e->type->cxxTypeRefInfo->fieldName); + /* this will only be entered if the above check for count is true */ + FOR_EACH_LIST_ELMT(tag, e->type->tags) { + fprintf(src, "%snewbuf = %s()\n", indent, bufTypeNameG); + fprintf(src, "%stagCode = asn_base.BERConsts.MakeTag(asn_base.BERConsts.%s, asn_base.BERConsts.%s, %d)\n", + indent, Class2ClassStr(tag->tclass), + Form2FormStr(tag->form), tag->code); + fprintf(src, "%sasnlen += asn_buffer.BEncDefLen(asnbuf, asnlen)\n", + indent); + fprintf(src, "%sasnlen += asnbuf.PutBufReverse(tagCode)\n", + indent); + fprintf(src, "%snewbuf.PutBuf(asnbuf.buf)\n", indent); + fprintf(src, "%sasnbuf = newbuf\n", indent); + } + if (e->type->tags->count) { + fprintf(src, "%ssafe_buf.PutBuf(asnbuf.buf)\n", indent); + fprintf(src, "%sasnbuf = safe_buf\n", indent); + fprintf(src, "%sasnlen = asnlen + safe_len\n", indent); + } + } + fprintf(src, " return asnlen\n\n"); + + /* bdeccontent */ + fprintf(src, " def BDecContent(self, asnbuf, length):\n"); + fprintf(src, " asnlen = 0\n"); + FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) { + if (e->type->extensionAddition) + continue; + + int i = 0; + Tag *lastTag = NULL; + fprintf(src, " # tags: %d\n", e->type->tags->count); + FOR_EACH_LIST_ELMT(tag, e->type->tags) { + char *formStr = Form2FormStr(tag->form); + lastTag = tag; + if (i) { + fprintf(src, " bufTag, al = self.BDecTag(asnbuf, asnlen)\n"); + fprintf(src, " if bufTag != TAG_CODE_EXPECTED:\n"); + fprintf(src, " raise Exception('ahh: %%x vs %%x' %% (bufTag, TAG_CODE_EXPECTED))\n"); + fprintf(src, " asnlen += al\n" + " asnbuf.swallow(al)\n"); + fprintf(src, " tagTotalLen, totalBytesLen = asn_buffer.BDecDefLen(asnbuf)\n"); + fprintf(src, " asnlen += tagTotalLen\n"); + } else { + i = 1; + } + if (tag->tclass == CNTX) + formStr = Form2FormStr(CONS); + fprintf(src, + " TAG_CODE_EXPECTED = asn_base.BERConsts.MakeTag(asn_base.BERConsts.%s, asn_base.BERConsts.%s, %d)\n", + Class2ClassStr(tag->tclass), formStr, tag->code); + } + if (!e->type->tags->count) { + fprintf(src, + " TAG_CODE_EXPECTED = asn_base.BERConsts.MakeTag(%s.BER_CLASS,\n" + " %s.BER_FORM,\n" + " %s.BER_TAG)\n", + e->type->cxxTypeRefInfo->className, + e->type->cxxTypeRefInfo->className, + e->type->cxxTypeRefInfo->className); + } + fprintf(src, " bufTag, al = self.BDecTag(asnbuf, asnlen)\n"); + fprintf(src, " if bufTag != TAG_CODE_EXPECTED:\n"); + if (!e->type->cxxTypeRefInfo->isPtr) + fprintf(src, " raise Exception('Unexpected: %%x; expected: %%x' %% (bufTag, TAG_CODE_EXPECTED))\n"); + else + fprintf(src, " pass\n"); + fprintf(src, " else:\n"); + if (e->type->tags->count == 1 && lastTag && lastTag->tclass == CNTX) { + fprintf(src, " asnbuf.swallow(al)\n"); + fprintf(src, " tagTotalLen, totalBytesLen = asn_buffer.BDecDefLen(asnbuf)\n"); + fprintf(src, " asnlen += tagTotalLen\n"); + } + fprintf(src, " self.%s = %s()\n", + e->type->cxxTypeRefInfo->fieldName, + e->type->cxxTypeRefInfo->className); + fprintf(src, " asnlen += self.%s.BDec(asnbuf, length)\n", + e->type->cxxTypeRefInfo->fieldName); + } + fprintf(src, " return asnlen\n\n"); + + fprintf(src, " def __str__(self):\n"); + fprintf(src, " s = \"%%s = {\" %% self.typename()\n"); + FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) { + fprintf(src, " s += \"%s = \"\n", + e->type->cxxTypeRefInfo->fieldName); + fprintf(src, " if self.%s is not None:\n", + e->type->cxxTypeRefInfo->fieldName); + fprintf(src, " s += str(self.%s)\n", + e->type->cxxTypeRefInfo->fieldName); + fprintf(src, " else:\n"); + fprintf(src, " s += \"None\"\n"); + fprintf(src, " s += \"\\n\"\n"); + } + fprintf(src, " s += \"}\"\n"); + fprintf(src, " return s;\n"); +} + + +static void +PrintPySeqDefCode (FILE *src, FILE *hdr, ModuleList *mods, Module *m, + PyRules *r ,TypeDef *td, Type *parent ESNACC_UNUSED, + Type *seq, int novolatilefuncs ESNACC_UNUSED) +{ + + PrintPySeqOrSetDefCode (src, hdr, mods, m, r, td, parent, seq, + novolatilefuncs, 1); + +} /* PrintPySeqDefCode */ + + +static void +PrintPySetDefCode (FILE *src, FILE *hdr, ModuleList *mods, Module *m, + PyRules *r, TypeDef *td, Type *parent ESNACC_UNUSED, + Type *set, int novolatilefuncs ESNACC_UNUSED) +{ + PrintPySeqOrSetDefCode (src, hdr, mods, m, r, td, parent, set, + novolatilefuncs, 0); + +} /* PrintPySetDefCode */ + + +static void +PrintPyListClass(FILE *src, TypeDef *td, Type *lst, Module* m) +{ + struct NamedType p_etemp; + NamedType* p_e; + char *lcn; /* list class name */ + char *ecn; /* (list) elmt class name */ + + p_e = &p_etemp; + p_e->type = lst->basicType->a.setOf; + + ecn = lst->basicType->a.setOf->cxxTypeRefInfo->className; + lcn = td->cxxTypeDefInfo->className; + + fprintf(src, "class %s(asn_list.", lcn); + + switch (lst->basicType->choiceId) { + case BASICTYPE_SEQUENCEOF: + fprintf(src, "AsnSequenceOf"); + break; + case BASICTYPE_SETOF: + fprintf(src, "AsnSetOf"); + break; + + default: + break; + } + + fprintf(src, "):\n"); + fprintf(src, " def __init__(self, elemts=None, expected=None):\n"); + fprintf(src, " if expected is None:\n"); + fprintf(src, " expected = %s\n", ecn); + fprintf(src, " asn_list.%s.__init__(self, elemts, expected)\n\n", + (lst->basicType->choiceId == BASICTYPE_SEQUENCEOF) ? + "AsnSequenceOf" : "AsnSetOf"); + + fprintf(src, " def typename(self):\n"); + fprintf(src, " return \"%s\"\n\n", lcn); + + if (td->type->subtypes != NULL) { + if ((td->type->subtypes->choiceId == SUBTYPE_SINGLE) && + (td->type->subtypes->a.single->choiceId == + SUBTYPEVALUE_SIZECONSTRAINT) && + (td->type->subtypes->a.single->a.sizeConstraint->choiceId == + SUBTYPE_SINGLE)) { +#if 0 + PrintPySetOfSizeConstraint(src, + td->type->subtypes->a.single->a.sizeConstraint->a.single, + m, td->type); +#endif + } else { + PrintErrLoc(m->asn1SrcFileName, (long)td->type->lineNo); + fprintf(errFileG, "ERROR - unsupported constraint\n"); + } + } +} + +static void +PrintPySetOfDefCode PARAMS ((src, m, td, setOf), + FILE *src _AND_ + Module *m _AND_ + TypeDef *td _AND_ + Type *setOf) +{ + /* do class */ + PrintPyListClass(src, td, setOf, m); + +} /* PrintPySetOfDefCode */ + + +static void +PrintPyTypeDefCode PARAMS ((src, hdr, mods, m, r, td, novolatilefuncs), + FILE *src _AND_ + FILE *hdr _AND_ + ModuleList *mods _AND_ + Module *m _AND_ + PyRules *r _AND_ + TypeDef *td _AND_ + int novolatilefuncs) +{ + switch (td->type->basicType->choiceId) { + case BASICTYPE_BOOLEAN: /* library type */ + case BASICTYPE_REAL: /* library type */ + case BASICTYPE_OCTETSTRING: /* library type */ + case BASICTYPE_NULL: /* library type */ + case BASICTYPE_EXTERNAL: /* library type */ + case BASICTYPE_OID: /* library type */ + case BASICTYPE_RELATIVE_OID: + case BASICTYPE_INTEGER: /* library type */ + case BASICTYPE_BITSTRING: /* library type */ + case BASICTYPE_ENUMERATED: /* library type */ + case BASICTYPE_NUMERIC_STR: /* 22 */ + case BASICTYPE_PRINTABLE_STR: /* 23 */ + case BASICTYPE_UNIVERSAL_STR: /* 24 */ + case BASICTYPE_IA5_STR: /* 25 */ + case BASICTYPE_BMP_STR: /* 26 */ + case BASICTYPE_UTF8_STR: /* 27 */ + case BASICTYPE_UTCTIME: /* 28 tag 23 */ + case BASICTYPE_GENERALIZEDTIME: /* 29 tag 24 */ + case BASICTYPE_GRAPHIC_STR: /* 30 tag 25 */ + case BASICTYPE_VISIBLE_STR: /* 31 tag 26 aka ISO646String */ + case BASICTYPE_GENERAL_STR: /* 32 tag 27 */ + case BASICTYPE_OBJECTDESCRIPTOR: /* 33 tag 7 */ + case BASICTYPE_VIDEOTEX_STR: /* 34 tag 21 */ + case BASICTYPE_T61_STR: /* 35 tag 20 */ + PrintPySimpleDef(src, td); + break; + case BASICTYPE_SEQUENCEOF: /* list types */ + case BASICTYPE_SETOF: + PrintPySetOfDefCode(src, m, td, td->type); + break; + case BASICTYPE_IMPORTTYPEREF: /* type references */ + case BASICTYPE_LOCALTYPEREF: + /* if this type has been re-tagged then must create new class + * instead of using a typedef */ + PrintPySimpleDef(src, td); + break; + case BASICTYPE_CHOICE: + PrintPyChoiceDefCode(src, hdr, mods, m, r, td, NULL, td->type, novolatilefuncs); + break; + case BASICTYPE_SET: + PrintPySetDefCode(src, hdr, mods, m, r, td, NULL, td->type, novolatilefuncs); + break; + case BASICTYPE_SEQUENCE: + PrintPySeqDefCode(src, hdr, mods, m, r, td, NULL, td->type, novolatilefuncs); + break; + case BASICTYPE_COMPONENTSOF: + case BASICTYPE_SELECTION: + case BASICTYPE_UNKNOWN: + case BASICTYPE_MACRODEF: + case BASICTYPE_MACROTYPE: + case BASICTYPE_ANYDEFINEDBY: /* ANY types */ + case BASICTYPE_ANY: + /* do nothing */ + break; + default: + /* TBD: print error? */ + break; + } +} /* PrintPyTypeDefCode */ + +void +PrintPyCode PARAMS ((src, hdr, if_META (printMeta COMMA meta COMMA meta_pdus COMMA) + mods, m, r, longJmpVal, printTypes, printValues, + printEncoders, printDecoders, printPrinters, printFree + if_TCL (COMMA printTcl), novolatilefuncs), + FILE *src _AND_ + FILE *hdr _AND_ + if_META (MetaNameStyle printMeta _AND_) + if_META (const Meta *meta _AND_) + if_META (MetaPDU *meta_pdus _AND_) + ModuleList *mods _AND_ + Module *m _AND_ + PyRules *r _AND_ + long longJmpVal ESNACC_UNUSED _AND_ + int printTypes _AND_ + int printValues _AND_ + int printEncoders _AND_ + int printDecoders _AND_ + int printPrinters _AND_ + int printFree + if_TCL (_AND_ int printTcl) _AND_ + int novolatilefuncs) +{ + Module *currMod; + AsnListNode *currModTmp; + TypeDef *td; + ValueDef *vd; + + + printTypesG = printTypes; + printEncodersG = printEncoders; + printDecodersG = printDecoders; + printPrintersG = printPrinters; + printFreeG = printFree; + + PrintSrcComment(src, m); + PrintSrcIncludes(src); + + FOR_EACH_LIST_ELMT (currMod, mods) { + if (!strcmp(m->cxxHdrFileName, currMod->cxxHdrFileName)) { + ImportModuleList *ModLists; + ImportModule *impMod; + char *ImpFile = NULL; + ModLists = currMod->imports; + currModTmp = mods->curr; + FOR_EACH_LIST_ELMT(impMod, ModLists) { + ImpFile = GetImportFileName(impMod->modId->name, mods); + if (ImpFile != NULL) + fprintf(src, "import %s\n", ImpFile); + if (impMod->moduleRef == NULL) + impMod->moduleRef = GetImportModuleRef(impMod->modId->name, mods); + } + mods->curr = currModTmp; + } + } + fprintf(src, "\n"); + + if (printValues) { + fprintf(src, "# value defs\n\n"); + FOR_EACH_LIST_ELMT (vd, m->valueDefs) { + /* PrintPyValueDef(src, r, vd); */ + } + fprintf(src, "\n"); + } + + fprintf(src, "# class member definitions:\n\n"); + PrintPyAnyCode (src, hdr, r, mods, m); + + FOR_EACH_LIST_ELMT (td, m->typeDefs) { + PrintPyTypeDefCode(src, hdr, mods, m, r, td, novolatilefuncs); + } + +} /* PrintPyCode */ + +static char * +LookupNamespace PARAMS ((t, mods), + Type *t _AND_ + ModuleList *mods) +{ + char *pszNamespace = NULL; + Module *mTmp = NULL; + TypeDef *ptTmp = NULL; + BasicType *pbtTmp2 = NULL; + + pbtTmp2 = t->basicType; + if (pbtTmp2->choiceId == BASICTYPE_SEQUENCEOF || + pbtTmp2->choiceId == BASICTYPE_SETOF) + pbtTmp2 = pbtTmp2->a.sequenceOf->basicType; // Burrow 1 more layer down for SequenceOf/SetOf + if (pbtTmp2->choiceId == BASICTYPE_IMPORTTYPEREF) { + FOR_EACH_LIST_ELMT (mTmp, mods) { + ptTmp = LookupType(mTmp->typeDefs, + pbtTmp2->a.importTypeRef->typeName); //WHAT we are looking for... + if (ptTmp != NULL) + break; //FOUND the MODULE that contains our defninition... + } + + if (ptTmp != NULL && mTmp != NULL && mTmp->namespaceToUse) { + pszNamespace = mTmp->namespaceToUse; + } + } + + return(pszNamespace); +} diff --git a/compiler/back-ends/py-gen/rules.c b/compiler/back-ends/py-gen/rules.c new file mode 100644 index 0000000..2d2ba11 --- /dev/null +++ b/compiler/back-ends/py-gen/rules.c @@ -0,0 +1,569 @@ +/* + * compiler/back-ends/py-gen/rules.c - initialized rule structure + * inits a table that contains info about + * converting each ASN.1 type to a python class + * + * Copyright (C) 2016 Aaron Conole + * + * 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 of the License, or + * (at your option) any later version. + * + */ + +#include "asn-incl.h" +#include "asn1module.h" +#include "rules.h" + +PyRules pyRulesG = +{ + 4, + "choiceId", + "ChoiceIdEnum", + "a", + "ChoiceUnion", + FALSE, + "Enc", + "Dec", + "EncContent", + "DecContent", + "EncPdu", + "DecPdu", + { + { /* 0 */ + BASICTYPE_UNKNOWN, + "???", + FALSE, + FALSE, + FALSE, + TRUE, + TRUE, + TRUE, + TRUE, + "None", + "unknown" + }, + { /* 1 */ + BASICTYPE_BOOLEAN, + "asn_bool.AsnBool", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "bool" + }, + { /* 2 */ + BASICTYPE_INTEGER, /* 2 */ + "asn_ints.AsnInt", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "integer" + }, + { /* 3 */ + BASICTYPE_BITSTRING, + "asn_octs.AsnBits", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "bits" + }, + {/* 4 */ + BASICTYPE_OCTETSTRING, + "asn_octs.AsnOcts", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "octs" + }, + {/* 5 */ + BASICTYPE_NULL, + "asn_base.AsnNull", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "null" + }, + { /* 6 */ + BASICTYPE_OID, + "asn_oid.AsnOid", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "oid" + }, + { /* 7 */ + BASICTYPE_REAL, + "asn_ints.AsnReal", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "real" + }, + {/* 8 */ + BASICTYPE_ENUMERATED, + "asn_ints.AsnEnum", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "enumeration" + }, + {/* 9 */ + BASICTYPE_SEQUENCE, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "seq" + }, + {/* 10 */ + BASICTYPE_SEQUENCEOF, + "asn_list.AsnSequenceOf", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "seqOf" + }, + {/* 11 */ + BASICTYPE_SET, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + FALSE, + "None", + "set" + }, + {/* 12 */ + BASICTYPE_SETOF, + "asn_list.AsnSetOf", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "setOf" + }, + {/* 13 */ + BASICTYPE_CHOICE, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + FALSE, + "None", + "choice" + }, + {/* 14 */ + BASICTYPE_SELECTION, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "foo" + }, + {/* 15 */ + BASICTYPE_COMPONENTSOF, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "bar" + }, + {/* 16 */ + BASICTYPE_ANY, + "asn_base.AsnAny", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "any" + }, + {/* 17 */ + BASICTYPE_ANYDEFINEDBY, + "AsnAnyDefinedBy", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "anyDefBy" + }, + {/* 18 */ + BASICTYPE_LOCALTYPEREF, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "foo" + }, + {/* 19 */ + BASICTYPE_IMPORTTYPEREF, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "bar" + }, + {/* 20 */ + BASICTYPE_MACROTYPE, + NULL, + FALSE, + FALSE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "foo" + }, + {/* 21 */ + BASICTYPE_MACRODEF, + NULL, + FALSE, + FALSE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "foo" + }, + {/* 22 */ + BASICTYPE_NUMERIC_STR, + "asn_useful.NumericString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "numericString" + }, + {/* 23 */ + BASICTYPE_PRINTABLE_STR, + "asn_useful.PrintableString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "printableString" + }, + {/* 24 */ + BASICTYPE_UNIVERSAL_STR, + "asn_useful.UniversalString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "universalString" + }, + {/* 25 */ + BASICTYPE_IA5_STR, + "asn_useful.IA5String", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "ia5String" + }, + {/* 26 */ + BASICTYPE_BMP_STR, + "asn_useful.BMPString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "bmpString" + }, + {/* 27 */ + BASICTYPE_UTF8_STR, + "asn_useful.UTF8String", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "utf8String" + }, + {/* 28 */ + BASICTYPE_UTCTIME, /* 23 */ + "asn_useful.UTCTime", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "utcTime" + }, + {/* 29 */ + BASICTYPE_GENERALIZEDTIME, /* 24 */ + "asn_useful.GeneralizedTime", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "generalizedTime" + }, + {/* 30 */ + BASICTYPE_GRAPHIC_STR, /* 25 */ + "asn_useful.GraphicString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "graphicString" + }, + {/* 31 */ + BASICTYPE_VISIBLE_STR, /* 26 */ + "asn_useful.VisibleString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "visibleString" + }, + {/* 32 */ + BASICTYPE_GENERAL_STR, /* 27 */ + "asn_useful.GeneralString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "generalString" + }, + {/* 33 */ + BASICTYPE_OBJECTDESCRIPTOR, + "asn_useful.ObjectDescriptor", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "objectDescriptor" + } , + {/* 34 */ + BASICTYPE_VIDEOTEX_STR, + "asn_useful.VideotexString", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "videotexString" + }, + {/* 35 */ + BASICTYPE_T61_STR, + "asn_useful.T61String", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "t61String" + }, + {/* 36 */ + BASICTYPE_EXTERNAL, + "asn_useful.EXTERNAL", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + TRUE, + TRUE, + "None", + "external" + }, + {/* 37 */ + BASICTYPE_OCTETCONTAINING, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "octetContainer" + }, + {/* 38 */ + BASICTYPE_BITCONTAINING, + NULL, + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "bitContainer" + }, + { /* 39 */ + BASICTYPE_RELATIVE_OID, + "AsnRelativeOid", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "relativeOid" + }, + { /* 40 */ + BASICTYPE_EXTENSION, + "asn_base.AsnExtension", + FALSE, + TRUE, + FALSE, + TRUE, + TRUE, + FALSE, + TRUE, + "None", + "extension" + } + + } +}; diff --git a/compiler/back-ends/py-gen/rules.h b/compiler/back-ends/py-gen/rules.h new file mode 100644 index 0000000..e5d61bf --- /dev/null +++ b/compiler/back-ends/py-gen/rules.h @@ -0,0 +1,36 @@ +/* + * compiler/back-ends/py-gen/rules.h + * + * Copyright (C) 2016 Aaron Conole + * + * 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 of the License, or + * (at your option) any later version. + * + */ + +#ifndef PY_RulesInclude +#define PY_RulesInclude +/* see asn1module.h for CxxTDI (C++ type def info) */ + +typedef struct PyRules +{ + int maxDigitsToAppend; + char *choiceIdFieldName; /* name of choiceId field */ + char *choiceIdEnumName; /* name (tag) for choiceId enum def name */ + char *choiceUnionFieldName; /* what the name of the choice's union is */ + char *choiceUnionName; /* name (tag) for choice union def name */ + int capitalizeNamedElmts; + char *encodeBaseName; + char *decodeBaseName; + char *encodeContentBaseName; + char *decodeContentBaseName; + char *encodePduBaseName; + char *decodePduBaseName; + CxxTDI typeConvTbl[BASICTYPE_EXTENSION + 1]; +} PyRules; + +extern PyRules pyRulesG; + +#endif diff --git a/compiler/back-ends/py-gen/types.c b/compiler/back-ends/py-gen/types.c new file mode 100644 index 0000000..a6a7f3b --- /dev/null +++ b/compiler/back-ends/py-gen/types.c @@ -0,0 +1,529 @@ +/* + * compiler/back-ends/py-gen/types.c - fills in python type information + * + * Copyright (C) 2016 Aaron Conole + * + * 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 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include "asn-incl.h" +#include "asn1module.h" +#include "snacc-util.h" +#include "str-util.h" +#include "rules.h" + +static DefinedObj *definedNamesG; + +/* unexported prototypes */ + +void FillPyTypeDefInfo PROTO ((PyRules *r, Module *m, TypeDef *td)); +static void FillPyFieldNames PROTO ((PyRules *r, + NamedTypeList *firstSibling)); +static void FillPyTypeRefInfo PROTO ((PyRules *r, Module *m, + TypeDef *head, Type *parent, Type *t)); +static void FillPyStructElmts PROTO ((PyRules *r, Module *m, + TypeDef *head, Type *parent, + NamedTypeList *t)); +static void FillPyChoiceElmts PROTO ((PyRules *r, Module *m, TypeDef *head, + Type *parent, NamedTypeList *first)); +static int IsPyNone PROTO ((PyRules *r, TypeDef *td, Type *parent, Type *t)); +void FillPyTDIDefaults PROTO ((PyRules *r, CxxTDI *ctdi, TypeDef *td)); + + +static char *pykwds[] = { + "False", "class", "finally", "is", "return", + "None", "continue", "for", "lambda", "try", + "True", "def", "from", "nonlocal", "while", + "and", "del", "global", "not", "with", + "as", "elif", "if", "or", "yield", + "assert", "else", "import", "pass", + "break", "except", "in", "raise", NULL +}; + + +/* + * returns non-zero if the given str is a C++ key word + */ +int +IsPyKeyWord PARAMS ((str), + char *str) +{ + size_t i; + + for (i=0; pykwds[i] != NULL && strcmp(pykwds[i], str); i++); + + return pykwds[i] != NULL; +} + + +/* + * allocates and fills all the cxxTypeInfos + * in the type trees for every module in the list + */ +void +FillPyTypeInfo PARAMS ((r, modList), + PyRules *r _AND_ + ModuleList *modList) +{ + TypeDef *td; + Module *m; + + /* + * go through each module's type defs and fill + * in the C type and enc/dec routines etc + */ + definedNamesG = NULL; + + FOR_EACH_LIST_ELMT (m, modList) { + FOR_EACH_LIST_ELMT (td, m->typeDefs) + FillPyTypeDefInfo (r, m, td); + } + + /* + * now that type def info is filled in + * set up set/seq/list/choice elements that ref + * those definitions + */ + FOR_EACH_LIST_ELMT (m, modList) { + FOR_EACH_LIST_ELMT (td, m->typeDefs) + FillPyTypeRefInfo (r, m, td, NULL, td->type); + } + + /* done with checking for name conflicts */ + FreeDefinedObjs (&definedNamesG); + definedNamesG = NULL; + +} + + +/* + * allocates and fills structure holding C type definition information + * fo the given ASN.1 type definition. Does not fill CTRI for contained + * types etc. + */ +void +FillPyTypeDefInfo PARAMS ((r, m, td), + PyRules *r _AND_ + Module *m _AND_ + TypeDef *td) +{ + char *tmpName; + CxxTDI *cxxtdi; + + /* + * if CxxTDI is present this type def has already been 'filled' + */ + if (td->cxxTypeDefInfo != NULL) + return; + + + cxxtdi = MT (CxxTDI); + td->cxxTypeDefInfo = cxxtdi; + + /* get default type def attributes from table for type on rhs of ::= */ + + FillPyTDIDefaults (r, cxxtdi, td); + + + /* + * if defined by a ref to another type definition fill in that type + * def's CxxTDI so can inherit (actully completly replace default + * attributes) from it + */ + if ((td->type->basicType->choiceId == BASICTYPE_LOCALTYPEREF) || + (td->type->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) + { + /* + * Fill in CxxTDI for defining type if nec. + * this works for importTypeRef as well since both a.localTypeRef + * and a.importTypeRef are of type TypeRef + */ + FillPyTypeDefInfo(r, td->type->basicType->a.localTypeRef->module, + td->type->basicType->a.localTypeRef->link); + + tmpName = cxxtdi->className; /* save className */ + /* copy all type def info and restore name related stuff - hack*/ + *cxxtdi = *td->type->basicType->a.localTypeRef->link->cxxTypeDefInfo; + cxxtdi->className = tmpName; /* restore className */ + } +} /* FillCxxTypeDefInfo */ + + +static void +FillPyTypeRefInfo PARAMS ((r, m, head, parent, t), + PyRules *r _AND_ + Module *m _AND_ + TypeDef *head _AND_ + Type *parent _AND_ + Type *t) +{ + CxxTRI *cxxtri; + CxxTDI *tmpCxxtdi; + ValueDef *namedElmt; + CNamedElmt *cne; + CNamedElmt **cneHndl; + char *elmtName; + int len; + enum BasicTypeChoiceId basicTypeId; + + /* + * you must check for cycles yourself before calling this + */ + if (t->cxxTypeRefInfo == NULL) { + cxxtri = MT (CxxTRI); + t->cxxTypeRefInfo = cxxtri; + } else + cxxtri = t->cxxTypeRefInfo; + + basicTypeId = t->basicType->choiceId; + + tmpCxxtdi = &r->typeConvTbl[basicTypeId]; + + /* get base type def info from the conversion table in the rules */ + cxxtri->isEnc = tmpCxxtdi->isEnc; + if ((basicTypeId == BASICTYPE_OCTETCONTAINING) || + (basicTypeId == BASICTYPE_BITCONTAINING)) { + cxxtri->className = + r->typeConvTbl[t->basicType->a.stringContaining->basicType-> + choiceId].className; + } else + cxxtri->className = tmpCxxtdi->className; + + cxxtri->optTestRoutineName = tmpCxxtdi->optTestRoutineName; + + + /* + * convert named elmts to C++ names. + * check for name conflict with other defined Types/Names/Values + */ + if (((basicTypeId == BASICTYPE_INTEGER) || + (basicTypeId == BASICTYPE_ENUMERATED) || + (basicTypeId == BASICTYPE_BITSTRING)) && + (!(LIST_EMPTY (t->basicType->a.integer)))) { + cxxtri->namedElmts = AsnListNew (sizeof (void*)); + + FOR_EACH_LIST_ELMT (namedElmt, t->basicType->a.integer) { + cneHndl = (CNamedElmt**)AsnListAppend (cxxtri->namedElmts); + cne = *cneHndl = MT(CNamedElmt); + elmtName = Asn1ValueName2CValueName(namedElmt->definedName); + cne->name = elmtName; /* not very efficient */ + + if (namedElmt->value->basicValue->choiceId == BASICVALUE_INTEGER) + cne->value = namedElmt->value->basicValue->a.integer; + else { + fprintf (errFileG, "Warning: unlinked defined value. Using -9999999\n"); + cne->value = -9999999; + } + + if (r->capitalizeNamedElmts) + Str2UCase(cne->name, len); + + /* + * append digits if enum value name is a keyword + */ + MakePyStrUnique(definedNamesG, cne->name, r->maxDigitsToAppend, 1); + } + } + + /* fill in rest of type info depending on the type */ + switch (basicTypeId) + { + default: + case BASICTYPE_UNKNOWN: + case BASICTYPE_MACRODEF: + case BASICTYPE_MACROTYPE: + /* do nothing */ + case BASICTYPE_BOOLEAN: /* library types */ + case BASICTYPE_INTEGER: + case BASICTYPE_BITSTRING: + case BASICTYPE_OCTETSTRING: + case BASICTYPE_NULL: + case BASICTYPE_OID: + case BASICTYPE_RELATIVE_OID: + case BASICTYPE_REAL: + case BASICTYPE_ENUMERATED: + case BASICTYPE_ANY: + case BASICTYPE_ANYDEFINEDBY: /* ANY types */ + /* don't need to do anything else */ + break; + + case BASICTYPE_SEQUENCEOF: /* list types */ + case BASICTYPE_SETOF: + /* fill in component type */ + FillPyTypeRefInfo (r, m, head, t, t->basicType->a.setOf); + break; + + case BASICTYPE_IMPORTTYPEREF: /* type references */ + case BASICTYPE_LOCALTYPEREF: + /* + * grab class name from link (link is the def of the + * the ref'd type) + */ + if (t->basicType->a.localTypeRef->link != NULL) { + /* inherit attributes from referenced type */ + tmpCxxtdi= t->basicType->a.localTypeRef->link->cxxTypeDefInfo; + cxxtri->className = tmpCxxtdi->className; + cxxtri->isEnc = tmpCxxtdi->isEnc; + cxxtri->optTestRoutineName = tmpCxxtdi->optTestRoutineName; + } + break; /* these are handled now */ + + case BASICTYPE_CHOICE: + /* + * must fill field names BEFORE filling choice elmts + * (allows better naming for choice ids) + */ + FillPyFieldNames(r, t->basicType->a.choice); + FillPyChoiceElmts(r, m, head, t, t->basicType->a.choice); + break; + + case BASICTYPE_SET: + case BASICTYPE_SEQUENCE: + FillPyStructElmts (r, m, head, t, t->basicType->a.set); + FillPyFieldNames (r, t->basicType->a.set); + break; + + case BASICTYPE_COMPONENTSOF: + case BASICTYPE_SELECTION: + fprintf(errFileG, + "Compiler error - COMPONENTS OF or SELECTION type slipped through normalizing phase.\n"); + exit(-1); + break; + } + + /* + * figure out whether this is a ptr based on the enclosing + * type (if any) and optionality/default + */ + cxxtri->isPtr = (unsigned char)IsPyNone(r, head, parent, t); +} /* FillCxxTypeRefInfo */ + + + +static void +FillPyStructElmts PARAMS ((r, m, head, parent, elmts), + PyRules *r _AND_ + Module *m _AND_ + TypeDef *head _AND_ + Type *parent _AND_ + NamedTypeList *elmts) +{ + NamedType *et; + + FOR_EACH_LIST_ELMT (et, elmts) { + FillPyTypeRefInfo(r, m, head, parent, et->type); + } +} + +/* + * Figures out non-conflicting enum names for the + * choice id's + */ +static void +FillPyChoiceElmts PARAMS ((r, m, head, parent, elmts), + PyRules *r _AND_ + Module *m _AND_ + TypeDef *head _AND_ + Type *parent _AND_ + NamedTypeList *elmts) +{ + NamedType *et; + int idCount = 0; + CxxTRI *cxxtri; + int len; + + /* + * fill in type info for elmt types first + */ + FOR_EACH_LIST_ELMT (et, elmts) + FillPyTypeRefInfo (r, m, head, parent, et->type); + + FOR_EACH_LIST_ELMT (et, elmts) { + cxxtri = et->type->cxxTypeRefInfo; + + if (cxxtri == NULL) + continue; /* wierd type */ + + cxxtri->choiceIdValue = idCount++; + + len = strlen (cxxtri->fieldName); + cxxtri->choiceIdSymbol = Malloc (len + 4); + strcpy (cxxtri->choiceIdSymbol, cxxtri->fieldName); + strcat (cxxtri->choiceIdSymbol, "Cid"); + + if (r->capitalizeNamedElmts) + Str2UCase (cxxtri->choiceIdSymbol, len); + } +} + +/* + * takes a list of "sibling" (eg same level in a structure) + * ElmtTypes and fills sets up the c field names in + * the CxxTRI struct + */ +static void +FillPyFieldNames PARAMS ((r, elmts), + PyRules *r _AND_ + NamedTypeList *elmts) +{ + NamedType *et; + CxxTRI *cxxtri; + DefinedObj *fieldNames; + int len; + char *tmpName; + char *asn1FieldName; + char *cFieldName = NULL; + + /* + * Initialize fieldname data + * allocate (if nec) and fill in CTRI fieldname if poss + * from asn1 field name. leave blank otherwise + */ + fieldNames = NewObjList(); + FOR_EACH_LIST_ELMT (et, elmts) { + cxxtri = et->type->cxxTypeRefInfo; + if (cxxtri == NULL) { + cxxtri = MT(CxxTRI); + et->type->cxxTypeRefInfo = cxxtri; + } + + if (et->fieldName != NULL) { + /* + * can assume that the field names are + * distinct because they have passed the + * error checking step. + * However, still call MakeStrUnique + * to change any field names that + * conflict with C++ keywords + */ + asn1FieldName = et->fieldName; + cxxtri->fieldName = Asn1FieldName2CFieldName(asn1FieldName); + MakePyStrUnique(fieldNames, cxxtri->fieldName, + r->maxDigitsToAppend, 1); + DefineObj(&fieldNames, cxxtri->fieldName); + } + + /* + * generate field names for those without them + */ + cFieldName = cxxtri->fieldName; + if (cxxtri->fieldName == NULL) { + if ((et->type->basicType->choiceId == BASICTYPE_LOCALTYPEREF) || + (et->type->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) { + /* + * take ref'd type name as field name + * convert first let to lower case + */ + tmpName = et->type->basicType->a.localTypeRef->link-> + cxxTypeDefInfo->className; + tmpName = Asn1TypeName2CTypeName(tmpName); + } else { + /* + * get default field name for this type + */ + tmpName = Strdup(r->typeConvTbl[et->type->basicType->choiceId]. + defaultFieldName); + } + cFieldName = tmpName; + if (isupper(cFieldName[0])) + cFieldName[0] = (char)tolower(cFieldName[0]); + + len = strlen(cFieldName); + + /* + * try to use just the type name (with lower case first char). + * if that is already used in this type or a C++ keyword, + * append ascii digits to field name until unique + * in this type + */ + MakePyStrUnique(fieldNames, cFieldName, r->maxDigitsToAppend, 1); + DefineObj(&fieldNames, cFieldName); + cxxtri->fieldName = cFieldName; + } + } + FreeDefinedObjs (&fieldNames); +} + +/* + * returns true if this c type for this type should be + * be ref'd as a ptr + */ +static int +IsPyNone PARAMS ((r, td, parent, t), + PyRules *r _AND_ + TypeDef *td _AND_ + Type *parent _AND_ + Type *t) +{ + CxxTDI *cxxtdi; + int retVal = FALSE; + + /* + * inherit ptr attriubutes from ref'd type if any + * otherwise grab lib c type def from the PyRules + */ + if ((t->basicType->choiceId == BASICTYPE_LOCALTYPEREF) || + (t->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) { + cxxtdi = t->basicType->a.localTypeRef->link->cxxTypeDefInfo; + } else + cxxtdi = &r->typeConvTbl[GetBuiltinType (t)]; + + /* no parent means t is the root of a typedef */ + if ((parent == NULL) && (cxxtdi->isPtrForTypeDef)) + retVal = TRUE; + else if ((parent != NULL) && + ((parent->basicType->choiceId == BASICTYPE_SET) || + (parent->basicType->choiceId == BASICTYPE_SEQUENCE)) && + (cxxtdi->isPtrInSetAndSeq)) + retVal = TRUE; + else if ((parent != NULL) && + ((parent->basicType->choiceId == BASICTYPE_SETOF) || + (parent->basicType->choiceId == BASICTYPE_SEQUENCEOF)) && + (cxxtdi->isPtrInList)) + retVal = TRUE; + else if ((parent != NULL) && + (parent->basicType->choiceId == BASICTYPE_CHOICE) && + (cxxtdi->isPtrInChoice)) + retVal = TRUE; + else if (((t->optional) || (t->defaultVal != NULL)) && (cxxtdi->isPtrForOpt)) + retVal = TRUE; + + return retVal; +} + +/* fill given cxxtdi with defaults from table for given typedef */ +void +FillPyTDIDefaults PARAMS ((r, cxxtdi, td), + PyRules *r _AND_ + CxxTDI *cxxtdi _AND_ + TypeDef *td) +{ + CxxTDI *tblCxxtdi; + int typeIndex; + char *tmpName; + + typeIndex = GetBuiltinType (td->type); + + if (typeIndex < 0) + return; + + tblCxxtdi = &r->typeConvTbl[typeIndex]; + + memcpy (cxxtdi, tblCxxtdi, sizeof (CxxTDI)); + + /* make sure class name is unique wrt to previously defined classes */ + tmpName = Asn1TypeName2CTypeName (td->definedName); + cxxtdi->className = Malloc (strlen (tmpName) + r->maxDigitsToAppend +1); + strcpy (cxxtdi->className, tmpName); + Free (tmpName); + + MakePyStrUnique (definedNamesG, cxxtdi->className, r->maxDigitsToAppend, 1); + DefineObj (&definedNamesG, cxxtdi->className); + +} diff --git a/compiler/back-ends/str-util.c b/compiler/back-ends/str-util.c index 073a4f1..b8c6dfb 100644 --- a/compiler/back-ends/str-util.c +++ b/compiler/back-ends/str-util.c @@ -90,6 +90,7 @@ int IsCKeyWord PROTO ((char *str)); int IsCxxKeyWord PROTO ((char *str)); +int IsPyKeyWord PROTO ((char *str)); int keepbaseG = TRUE; @@ -127,9 +128,8 @@ Asn1FieldName2CFieldName PARAMS ((aName), if (aName == NULL) return NULL; - retVal = Malloc (strlen (aName) + 1); - strcpy (retVal, aName); - Dash2Underscore (retVal, strlen (retVal)); + retVal = Strdup(aName); + Dash2Underscore(retVal, strlen(retVal)); return retVal; } /* Asn1FieldName2CFieldName */ @@ -262,8 +262,7 @@ Dash2Underscore PARAMS ((str, len), int len) { int i; - for (i=0; i < len; i++) - { + for (i=0; i < len; i++) { if (str[i] == '-') str[i] = '_'; } @@ -377,6 +376,34 @@ MakeCxxStrUnique PARAMS ((nameList, str, maxDigits, startingDigit), } } /* MakeCxxStrUnique */ + +/* + * same as MakeCStrUnique except checks against C++ keywords + */ +void +MakePyStrUnique PARAMS ((nameList, str, maxDigits, startingDigit), + DefinedObj *nameList _AND_ + char *str _AND_ + int maxDigits _AND_ + int startingDigit) +{ + int digit, len, maxDigitVal; + + if (ObjIsDefined(nameList, str, StrObjCmp) || IsPyKeyWord (str)) { + for (maxDigitVal = 1; maxDigits > 0; maxDigits--) + maxDigitVal *= 10; + + len = strlen(str); + digit = startingDigit; + do + { + str[len] = '\0'; + AppendDigit (str, digit++); + } while (ObjIsDefined (nameList, str, StrObjCmp) && + (digit < maxDigitVal)); + } +} /* MakeCxxStrUnique */ + static char *OutputDirectoryName; void StoreOutputDirectory PARAMS ((directory), @@ -596,6 +623,17 @@ MakeCxxSrcFileName PARAMS ((refName), return MakeFileName (refName, ".cpp"); } +char * +MakePySrcFileName PARAMS ((refName), + const char *refName) +{ + char *name = Strdup(refName); + Dash2Underscore(name, strlen(refName)); + char *ret = MakeFileName(name, ".py"); + Free(name); + return ret; +} + #if IDL char * MakeIDLFileName PARAMS ((refName), diff --git a/compiler/back-ends/str-util.h b/compiler/back-ends/str-util.h index d3a0b54..b758c44 100644 --- a/compiler/back-ends/str-util.h +++ b/compiler/back-ends/str-util.h @@ -72,6 +72,7 @@ char *MakeCHdrFileName PROTO ((const char *moduleName)); char *MakeCSrcFileName PROTO ((const char *moduleName)); char *MakeCxxHdrFileName PROTO ((const char *moduleName)); char *MakeCxxSrcFileName PROTO ((const char *moduleName)); +char *MakePySrcFileName PROTO ((const char *moduleName)); #if IDL char *MakeIDLFileName PROTO ((const char *moduleName)); #endif diff --git a/compiler/core/define.c b/compiler/core/define.c index 5d4d92d..3583a19 100644 --- a/compiler/core/define.c +++ b/compiler/core/define.c @@ -176,8 +176,7 @@ UndefineObj PARAMS ((objListHndl, obj, cmpRoutine), int ObjIsDefined (DefinedObj *objListPtr, void *obj, CmpObjsRoutine cmpRoutine) { - for ( ; objListPtr != NULL; objListPtr = objListPtr->next) - { + for ( ; objListPtr != NULL; objListPtr = objListPtr->next) { if (cmpRoutine (objListPtr->obj, obj)) return TRUE; } diff --git a/compiler/core/snacc.c b/compiler/core/snacc.c index cb0cba8..407394b 100644 --- a/compiler/core/snacc.c +++ b/compiler/core/snacc.c @@ -81,6 +81,8 @@ char *bVDAGlobalDLLExport=(char *)0; #include "c++-gen/rules.h" /* for c++ file generation */ +#include "py-gen/rules.h" + #if IDL #include "idl-gen/rules.h" /* for idl file generation */ #endif @@ -126,6 +128,12 @@ void PrintCxxCode (FILE *src, FILE *hdr, if_META (MetaNameStyle genMeta COMMA int printTypes, int printValues, int printEncoders, int printDecoders, int printPrinters, int printFree, if_TCL (int printTcl COMMA) int novolatilefuncs); +void PrintPyCode (FILE *src, FILE *hdr, if_META (MetaNameStyle genMeta COMMA + const Meta *meta COMMA MetaPDU *metapdus COMMA) + ModuleList *mods, Module *m, CxxRules *r, long longJmpVal, + int printTypes, int printValues, int printEncoders, + int printDecoders, int printPrinters, int printFree, + if_TCL (int printTcl COMMA) int novolatilefuncs); void PrintIDLCode PROTO ((FILE *idl, ModuleList *mods, Module *m, IDLRules *r, long int longJmpVal, int printValues)); void ProcessMacros PROTO ((Module *m)); @@ -143,6 +151,11 @@ static void GenCxxCode PROTO ((ModuleList *allMods, long longJmpVal, int genPrinters, int genValues, int genFree, if_META (MetaNameStyle genMeta COMMA MetaPDU *meta_pdus COMMA) if_TCL (int genTcl COMMA) int novolatilefuncs)); +static void GenPyCode PROTO ((ModuleList *allMods, long longJmpVal, + int genTypes, int genEncoders, int genDecoders, + int genPrinters, int genValues, int genFree, + if_META (MetaNameStyle genMeta COMMA MetaPDU *meta_pdus COMMA) + if_TCL (int genTcl COMMA) int novolatilefuncs)); static void GenIDLCode PROTO ((ModuleList *allMods, long longJmpVal, int genTypes, int genPrinters, int genValues, int genFree)); static int ModNamesUnique PROTO ((ModuleList *m)); @@ -317,6 +330,7 @@ int main PARAMS ((argc, argv), int genCCode = FALSE; /* defaults to C if neither specified */ int genCxxCode = FALSE; int genIDLCode = FALSE; + int genPyCode = FALSE; long longJmpVal = -100; int novolatilefuncs = FALSE; char* dirName; /* REN -- 6/2/03 -- added */ @@ -432,7 +446,11 @@ int main PARAMS ((argc, argv), break; case 'p': - genPrintCode = TRUE; + if (argv[currArg][2] == 'y') { + genPyCode = TRUE; + } else { + genPrintCode = TRUE; + } currArg++; break; @@ -693,15 +711,15 @@ error: genFreeCode = TRUE; genPrintCode = TRUE; } - else if (genCCode + genCxxCode + genTypeTbls + genIDLCode > 1) + else if (genCCode + genPyCode + genCxxCode + genTypeTbls + genIDLCode > 1) { - fprintf (stderr, "%s: ERROR---Choose only one of the -c -C or -T options\n", + fprintf (stderr, "%s: ERROR---Choose only one of the -py, -p py, -c, -C or -T options\n", argv[0]); Usage (argv[0], stderr); return 1; } - if (!genCCode && !genCxxCode && !genTypeTbls && !genIDLCode) + if (!genCCode && !genCxxCode && !genPyCode && !genTypeTbls && !genIDLCode) genCCode = TRUE; /* default to C if neither specified */ /* Set the encoding rules to BER if not set */ @@ -714,11 +732,9 @@ error: allMods = (ModuleList *)AsnListNew (sizeof (void*)); tmpLst = srcList; - while (tmpLst != NULL) - { + while (tmpLst != NULL) { // Only do if not NULL - if (tmpLst->fileName) - { + if (tmpLst->fileName) { currMod = ParseAsn1File (tmpLst->fileName, tmpLst->ImportFileFlag); @@ -738,8 +754,7 @@ error: /* * Check that the module names/oids are unique */ - if (!ModNamesUnique (allMods)) - { + if (!ModNamesUnique (allMods)) { fprintf (errFileG, "\nConflicting module names, cannot proceed.\n"); return 1; } @@ -750,8 +765,7 @@ error: * Now that all files have been parsed, * link local and locatable import type refs */ - if (LinkTypeRefs (allMods) < 0) - { + if (LinkTypeRefs (allMods) < 0) { fprintf (errFileG, "\nType linking errors---cannot proceed\n"); return 2; } @@ -763,8 +777,7 @@ error: * and have been linked. Need type info to be able to * parse values easily (elimitate ambiguity). */ - FOR_EACH_LIST_ELMT (currMod, allMods) - { + FOR_EACH_LIST_ELMT (currMod, allMods) { if (ParseValues (allMods, currMod) != 0) fprintf (errFileG, "WARNING: Value parsing error (s), attempting to continue\n"); } @@ -775,8 +788,7 @@ error: * Value parsing may have defined some new values * so can link local and locatable import value refs now. */ - if (LinkValueRefs (allMods) < 0) - { + if (LinkValueRefs (allMods) < 0) { fprintf (errFileG, "\nValue linking errors---cannot proceed\n"); return 4; } @@ -790,8 +802,8 @@ error: * so they are put in the id to ANY type hash tbl. */ semErr = 0; - FOR_EACH_LIST_ELMT (currMod, allMods) - { // For Macors, New TypeDefs are added here, if required + FOR_EACH_LIST_ELMT (currMod, allMods) { + // For Macros, New TypeDefs are added here, if required ProcessMacros (currMod); if (currMod->status == MOD_ERROR) semErr = 1; @@ -808,8 +820,8 @@ error: * boil down values into simplest rep. (eg OID -> ENC_OID) */ semErr = 0; - FOR_EACH_LIST_ELMT (currMod, allMods) - { // New TypeDefs are added here, if required + FOR_EACH_LIST_ELMT (currMod, allMods) { + // New TypeDefs are added here, if required NormalizeModule (currMod); if (currMod->status == MOD_ERROR) semErr = 1; @@ -823,8 +835,7 @@ error: * Mark recusive types. Currently the recursive information is * not used elsewhere. */ - FOR_EACH_LIST_ELMT (currMod, allMods) - { + FOR_EACH_LIST_ELMT (currMod, allMods) { MarkRecursiveTypes (currMod); } @@ -835,8 +846,7 @@ error: * Check all modules and exit if errors were found */ semErr = 0; - FOR_EACH_LIST_ELMT (currMod, allMods) - { + FOR_EACH_LIST_ELMT (currMod, allMods) { ErrChkModule (currMod); if (currMod->status == MOD_ERROR) semErr = 1; @@ -851,23 +861,20 @@ error: * production but should not affect the other processing/error * checking steps. This allows full display of errors. */ - if (smallErrG) - { + if (smallErrG) { /* * for debugging show "parsed" version of ASN.1 module if * the print flag is set. * Dumps each module to stdout. Printed from Module data struct * print here before exiting otherwise print after sorting */ - if (printModuleFlag) - { - FOR_EACH_LIST_ELMT (currMod, allMods) - { + if (printModuleFlag) { + FOR_EACH_LIST_ELMT (currMod, allMods) { printf ("\n\n"); PrintModule (stdout, currMod); } } - + return 8; } @@ -893,6 +900,8 @@ error: FillIDLTypeInfo (&idlRulesG, allMods); #endif + else if (genPyCode) + FillPyTypeInfo(&pyRulesG, allMods); /* * STEP 10 @@ -911,10 +920,8 @@ error: * dumps each module to stdout. Printed from Module data struct * Shows the results of normalization and sorting. */ - if (printModuleFlag) - { - FOR_EACH_LIST_ELMT (currMod, allMods) - { + if (printModuleFlag) { + FOR_EACH_LIST_ELMT (currMod, allMods) { printf ("\n\n"); PrintModule (stdout, currMod); } @@ -944,6 +951,12 @@ error: genPrintCode, genFreeCode); #endif + else if (genPyCode) + GenPyCode(allMods, longJmpVal, genTypeCode, genValueCode, + genEncodeCode, genDecodeCode, genPrintCode, genFreeCode, + if_META (genMetaCode COMMA meta_pdus COMMA) + if_TCL (genTclCode COMMA) novolatilefuncs); + tmpLst = srcList; while(tmpLst) { SRC_FILE *tmp; @@ -1159,6 +1172,92 @@ GenCCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDeco } /* GenCCode */ +void +GenPyCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDecoders, genPrinters, genFree, if_META (genMeta COMMA meta_pdus COMMA) if_TCL (genTcl COMMA) novolatilefuncs), + ModuleList *allMods _AND_ + long longJmpVal _AND_ + int genTypes _AND_ + int genValues _AND_ + int genEncoders _AND_ + int genDecoders _AND_ + int genPrinters _AND_ + int genFree _AND_ + if_META (MetaNameStyle genMeta _AND_) + if_META (MetaPDU *meta_pdus _AND_) + if_TCL (int genTcl _AND_) + int novolatilefuncs) +{ + Module *currMod; + AsnListNode *saveMods; + char *modBaseFileName; + FILE *hdrFilePtr; + FILE *srcFilePtr; + DefinedObj *fNames; + int fNameConflict = FALSE; + + /* + * Make names for each module's encoder/decoder src and hdr files + * so import references can be made via include files + * check for truncation --> name conflicts & exit if nec + */ + fNames = NewObjList(); + + FOR_EACH_LIST_ELMT (currMod, allMods) { + modBaseFileName = MakeBaseFileName (keepbaseG + ? currMod->asn1SrcFileName + : currMod->modId->name); + currMod->cxxHdrFileName = ""; + currMod->cxxSrcFileName = MakePySrcFileName(modBaseFileName); + if (ObjIsDefined (fNames, currMod->cxxHdrFileName, StrObjCmp) || + ObjIsDefined (fNames, currMod->cxxSrcFileName, StrObjCmp)) { + fprintf(errFileG, + "ERROR: file name conflict for generated source files with names `%s' and `%s'.\n\n", + currMod->cxxHdrFileName, currMod->cxxSrcFileName); + fprintf(errFileG, + "This usually means the max file name length is truncating the file names.\n"); + fprintf(errFileG, + "Try re-naming the modules with shorter names or increasing the argument to -mf option (if you are using it).\n"); + fprintf(errFileG, + "This error can also be caused by 2 modules have the same names but different OBJECT IDENTIFIERs."); + fprintf(errFileG, + " Try renaming the modules to correct this.\n"); + fNameConflict = TRUE; + } else { + DefineObj (&fNames, currMod->cxxHdrFileName); + DefineObj (&fNames, currMod->cxxSrcFileName); + } + Free (modBaseFileName); + + if (fNameConflict) + return; + + FreeDefinedObjs (&fNames); + } + + FOR_EACH_LIST_ELMT (currMod, allMods) { + if (currMod->ImportedFlag == FALSE) { + /* + * create and fill .h file for module's data structs + */ + srcFilePtr = fopen (currMod->cxxSrcFileName, "wt"); + + if (srcFilePtr == NULL) { + perror ("fopen"); + } else { + saveMods = allMods->curr; + PrintPyCode (srcFilePtr, hdrFilePtr, + if_META (genMeta COMMA &meta COMMA meta_pdus COMMA) + allMods, currMod, &cxxRulesG, longJmpVal, + genTypes, genValues, genEncoders, genDecoders, + genPrinters, genFree, + if_TCL (genTcl COMMA) novolatilefuncs); + allMods->curr = saveMods; + fclose (srcFilePtr); + } + } + } +} + /* * Given the list of parsed, linked, normalized, error-checked and sorted * modules, and some code generation flags, generates C++ code and @@ -1345,7 +1444,7 @@ GenCxxCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDe fclose (meta.srcfp); #endif - } + } } } /* GenCxxCode */