123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745 |
- #! /usr/bin/env python
- #
- # Copyright (C) 2015 Open Information Security Foundation
- #
- # You can copy, redistribute or modify this Program under the terms of
- # the GNU General Public License version 2 as published by the Free
- # Software Foundation.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # version 2 along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- # 02110-1301, USA.
- # This script generates DNP3 related source code based on definitions
- # of DNP3 objects (currently the object structs).
- from __future__ import print_function
- import sys
- import re
- import yaml
- import jinja2
- IN_PLACE_START = "/* START GENERATED CODE */"
- IN_PLACE_END = "/* END GENERATED CODE */"
- util_lua_dnp3_objects_c_template = """/* Copyright (C) 2015 Open Information Security Foundation
- *
- * You can copy, redistribute or modify this Program under the terms of
- * the GNU General Public License version 2 as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
- /**
- * DO NOT EDIT. THIS FILE IS AUTO-GENERATED.
- *
- * Generated by command:
- * {{command_line}}
- */
- #include "suricata-common.h"
- #include "app-layer-dnp3.h"
- #include "app-layer-dnp3-objects.h"
- #ifdef HAVE_LUA
- #include <lua.h>
- #include <lualib.h>
- #include <lauxlib.h>
- #include "util-lua.h"
- #include "util-lua-dnp3-objects.h"
- /**
- * \\brief Push an object point item onto the stack.
- */
- void DNP3PushPoint(lua_State *luastate, DNP3Object *object,
- DNP3Point *point)
- {
- switch (DNP3_OBJECT_CODE(object->group, object->variation)) {
- {% for object in objects %}
- case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): {
- DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data;
- {% for field in object.fields %}
- {% if is_integer_type(field.type) %}
- lua_pushliteral(luastate, "{{field.name}}");
- lua_pushinteger(luastate, data->{{field.name}});
- lua_settable(luastate, -3);
- {% elif field["type"] in ["flt32", "flt64"] %}
- lua_pushliteral(luastate, "{{field.name}}");
- lua_pushnumber(luastate, data->{{field.name}});
- lua_settable(luastate, -3);
- {% elif field["type"] == "chararray" %}
- lua_pushliteral(luastate, "{{field.name}}");
- LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}},
- strlen(data->{{field.name}}));
- lua_settable(luastate, -3);
- {% elif field["type"] == "vstr4" %}
- lua_pushliteral(luastate, "{{field.name}}");
- LuaPushStringBuffer(luastate, (uint8_t *)data->{{field.name}},
- strlen(data->{{field.name}}));
- lua_settable(luastate, -3);
- {% elif field.type == "bytearray" %}
- lua_pushliteral(luastate, "{{field.name}}");
- lua_pushlstring(luastate, (const char *)data->{{field.name}},
- data->{{field.len_field}});
- lua_settable(luastate, -3);
- {% elif field.type == "bstr8" %}
- {% for field in field.fields %}
- lua_pushliteral(luastate, "{{field.name}}");
- lua_pushinteger(luastate, data->{{field.name}});
- lua_settable(luastate, -3);
- {% endfor %}
- {% else %}
- {{ raise("Unhandled datatype: %s" % (field.type)) }}
- {% endif %}
- {% endfor %}
- break;
- }
- {% endfor %}
- default:
- break;
- }
- }
- #endif /* HAVE_LUA */
- """
- output_json_dnp3_objects_template = """/* Copyright (C) 2015 Open Information Security Foundation
- *
- * You can copy, redistribute or modify this Program under the terms of
- * the GNU General Public License version 2 as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
- /**
- * DO NOT EDIT. THIS FILE IS AUTO-GENERATED.
- *
- * Generated by command:
- * {{command_line}}
- */
- #include "suricata-common.h"
- #include "app-layer-dnp3.h"
- #include "app-layer-dnp3-objects.h"
- #include "output-json-dnp3-objects.h"
- #include "output-json.h"
- // clang-format off
- void OutputJsonDNP3SetItem(JsonBuilder *js, DNP3Object *object,
- DNP3Point *point)
- {
- switch (DNP3_OBJECT_CODE(object->group, object->variation)) {
- {% for object in objects %}
- case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): {
- DNP3ObjectG{{object.group}}V{{object.variation}} *data = point->data;
- {% for field in object.fields %}
- {% if is_integer_type(field.type) %}
- jb_set_uint(js, "{{field.name}}", data->{{field.name}});
- {% elif field.type in ["flt32", "flt64"] %}
- jb_set_float(js, "{{field.name}}", data->{{field.name}});
- {% elif field.type == "bytearray" %}
- jb_set_base64(js, "data->{{field.name}}", data->{{field.name}}, data->{{field.len_field}});
- {% elif field.type == "vstr4" %}
- jb_set_string(js, "data->{{field.name}}", data->{{field.name}});
- {% elif field.type == "chararray" %}
- if (data->{{field.len_field}} > 0) {
- jb_set_string_from_bytes(
- js, "{{field.name}}", (const uint8_t *)data->{{field.name}}, data->{{field.len_field}});
- } else {
- jb_set_string(js, "{{field.name}}", "");
- }
- {% elif field.type == "bstr8" %}
- {% for field in field.fields %}
- jb_set_uint(js, "{{field.name}}", data->{{field.name}});
- {% endfor %}
- {% else %}
- {{ raise("Unhandled datatype: %s" % (field.type)) }}
- {% endif %}
- {% endfor %}
- break;
- }
- {% endfor %}
- default:
- SCLogDebug("Unknown object: %d:%d", object->group,
- object->variation);
- break;
- }
- }
- // clang-format on
- """
- def has_freeable_types(fields):
- freeable_types = [
- "bytearray",
- ]
- for field in fields:
- if field["type"] in freeable_types:
- return True
- return False
- def is_integer_type(datatype):
- integer_types = [
- "uint64",
- "uint32",
- "uint24",
- "uint16",
- "uint8",
- "int64",
- "int32",
- "int16",
- "int8",
- "dnp3time",
- ]
- return datatype in integer_types
- def to_type(datatype):
- type_map = {
- "uint8": "uint8_t",
- }
- if datatype in type_map:
- return type_map[datatype]
- else:
- raise Exception("Unknown datatype: %s" % (datatype))
- def generate(template, filename, context):
- print("Generating %s." % (filename))
- try:
- env = jinja2.Environment(trim_blocks=True)
- output = env.from_string(template).render(context)
- with open(filename, "w") as fileobj:
- fileobj.write(output)
- except Exception as err:
- print("Failed to generate %s: %s" % (filename, err))
- sys.exit(1)
- def raise_helper(msg):
- raise Exception(msg)
- def gen_object_structs(context):
- """ Generate structs for all the define DNP3 objects. """
- template = """
- /* Code generated by:
- * {{command_line}}
- */
- {% for object in objects %}
- typedef struct DNP3ObjectG{{object.group}}V{{object.variation}}_ {
- {% for field in object.fields %}
- {% if field.type == "bstr8" %}
- {% for field in field.fields %}
- uint8_t {{field.name}}:{{field.width}};
- {% endfor %}
- {% else %}
- {% if field.type == "int16" %}
- int16_t {{field.name}};
- {% elif field.type == "int32" %}
- int32_t {{field.name}};
- {% elif field.type == "uint8" %}
- uint8_t {{field.name}};
- {% elif field.type == "uint16" %}
- uint16_t {{field.name}};
- {% elif field.type == "uint24" %}
- uint32_t {{field.name}};
- {% elif field.type == "uint32" %}
- uint32_t {{field.name}};
- {% elif field.type == "uint64" %}
- uint64_t {{field.name}};
- {% elif field.type == "flt32" %}
- float {{field.name}};
- {% elif field.type == "flt64" %}
- double {{field.name}};
- {% elif field.type == "dnp3time" %}
- uint64_t {{field.name}};
- {% elif field.type == "bytearray" %}
- uint8_t *{{field.name}};
- {% elif field.type == "vstr4" %}
- char {{field.name}}[5];
- {% elif field.type == "chararray" %}
- char {{field.name}}[{{field.size}}];
- {% else %}
- {{ raise("Unknown datatype type '%s' for object %d:%d" % (
- field.type, object.group, object.variation)) }}
- {% endif %}
- {% endif %}
- {% endfor %}
- {% if object.extra_fields %}
- {% for field in object.extra_fields %}
- {% if field.type == "uint8" %}
- uint8_t {{field.name}};
- {% elif field.type == "uint16" %}
- uint16_t {{field.name}};
- {% elif field.type == "uint32" %}
- uint32_t {{field.name}};
- {% else %}
- {{ raise("Unknown datatype: %s" % (field.type)) }}
- {% endif %}
- {% endfor %}
- {% endif %}
- } DNP3ObjectG{{object.group}}V{{object.variation}};
- {% endfor %}
- """
- filename = "src/app-layer-dnp3-objects.h"
- try:
- env = jinja2.Environment(trim_blocks=True)
- code = env.from_string(template).render(context)
- content = open(filename).read()
- content = re.sub(
- "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)),
- r"\1%s\2" % (code), content, 1, re.M | re.DOTALL)
- open(filename, "w").write(content)
- print("Updated %s." % (filename))
- except Exception as err:
- print("Failed to update %s: %s" % (filename, err), file=sys.stderr)
- sys.exit(1)
- def gen_object_decoders(context):
- """ Generate decoders for all defined DNP3 objects. """
- template = """
- /* Code generated by:
- * {{command_line}}
- */
- {% for object in objects %}
- {% if object.packed %}
- static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len,
- uint8_t prefix_code, uint32_t start, uint32_t count,
- DNP3PointList *points)
- {
- DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL;
- uint32_t bytes = (count / 8) + 1;
- uint32_t prefix = 0;
- uint32_t point_index = start;
- if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) {
- goto error;
- }
- for (uint32_t i = 0; i < bytes; i++) {
- uint8_t octet;
- if (!DNP3ReadUint8(buf, len, &octet)) {
- goto error;
- }
- for (int j = 0; j < 8 && count; j = j + {{object.fields[0].width}}) {
- object = SCCalloc(1, sizeof(*object));
- if (unlikely(object == NULL)) {
- goto error;
- }
- {% if object.fields[0].width == 1 %}
- object->{{object.fields[0].name}} = (octet >> j) & 0x1;
- {% elif object.fields[0].width == 2 %}
- object->{{object.fields[0].name}} = (octet >> j) & 0x3;
- {% else %}
- #error "Unhandled field width: {{object.fields[0].width}}"
- {% endif %}
- if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) {
- goto error;
- }
- object = NULL;
- count--;
- point_index++;
- }
- }
- return 1;
- error:
- if (object != NULL) {
- SCFree(object);
- }
- return 0;
- }
- {% else %}
- static int DNP3DecodeObjectG{{object.group}}V{{object.variation}}(const uint8_t **buf, uint32_t *len,
- uint8_t prefix_code, uint32_t start, uint32_t count,
- DNP3PointList *points)
- {
- DNP3ObjectG{{object.group}}V{{object.variation}} *object = NULL;
- uint32_t prefix = 0;
- uint32_t point_index = start;
- {% if object._track_offset %}
- uint32_t offset;
- {% endif %}
- {% if object.constraints %}
- {% for (key, val) in object.constraints.items() %}
- {% if key == "require_size_prefix" %}
- if (!DNP3PrefixIsSize(prefix_code)) {
- goto error;
- }
- {% elif key == "require_prefix_code" %}
- if (prefix_code != {{val}}) {
- goto error;
- }
- {% else %}
- {{ raise("Unhandled constraint: %s" % (key)) }}
- {% endif %}
- {% endfor %}
- {% endif %}
- if (*len < count/8) {
- goto error;
- }
- while (count--) {
- object = SCCalloc(1, sizeof(*object));
- if (unlikely(object == NULL)) {
- goto error;
- }
- if (!DNP3ReadPrefix(buf, len, prefix_code, &prefix)) {
- goto error;
- }
- {% if object._track_offset %}
- offset = *len;
- {% endif %}
- {% for field in object.fields %}
- {% if field.type == "int16" %}
- if (!DNP3ReadUint16(buf, len, (uint16_t *)&object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "int32" %}
- if (!DNP3ReadUint32(buf, len, (uint32_t *)&object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "uint8" %}
- if (!DNP3ReadUint8(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "uint16" %}
- if (!DNP3ReadUint16(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "uint24" %}
- if (!DNP3ReadUint24(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "uint32" %}
- if (!DNP3ReadUint32(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "uint64" %}
- if (!DNP3ReadUint64(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "flt32" %}
- if (!DNP3ReadFloat32(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "flt64" %}
- if (!DNP3ReadFloat64(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "dnp3time" %}
- if (!DNP3ReadUint48(buf, len, &object->{{field.name}})) {
- goto error;
- }
- {% elif field.type == "vstr4" %}
- if (*len < 4) {
- goto error;
- }
- memcpy(object->{{field.name}}, *buf, 4);
- object->{{field.name}}[4] = '\\\\0';
- *buf += 4;
- *len -= 4;
- {% elif field.type == "bytearray" %}
- {% if field.len_from_prefix %}
- if (prefix < (offset - *len)) {
- goto error;
- }
- object->{{field.len_field}} = (uint16_t) (prefix - (offset - *len));
- {% endif %}
- if (object->{{field.len_field}} > 0) {
- if (*len < object->{{field.len_field}}) {
- /* Not enough data. */
- goto error;
- }
- object->{{field.name}} = SCCalloc(1, object->{{field.len_field}});
- if (unlikely(object->{{field.name}} == NULL)) {
- goto error;
- }
- memcpy(object->{{field.name}}, *buf, object->{{field.len_field}});
- *buf += object->{{field.len_field}};
- *len -= object->{{field.len_field}};
- }
- {% elif field.type == "chararray" %}
- {% if field.len_from_prefix %}
- if (prefix - (offset - *len) >= {{field.size}} || prefix < (offset - *len)) {
- goto error;
- }
- {% if field.size == 255 %}
- object->{{field.len_field}} = (uint8_t) (prefix - (offset - *len));
- {% else %}
- object->{{field.len_field}} = (uint16_t) (prefix - (offset - *len));
- {% endif %}
- {% endif %}
- if (object->{{field.len_field}} > 0) {
- if (*len < object->{{field.len_field}}) {
- /* Not enough data. */
- goto error;
- }
- memcpy(object->{{field.name}}, *buf, object->{{field.len_field}});
- *buf += object->{{field.len_field}};
- *len -= object->{{field.len_field}};
- }
- object->{{field.name}}[object->{{field.len_field}}] = '\\\\0';
- {% elif field.type == "bstr8" %}
- {
- uint8_t octet;
- if (!DNP3ReadUint8(buf, len, &octet)) {
- goto error;
- }
- {% set ns = namespace(shift=0) %}
- {% for field in field.fields %}
- {% if field.width == 1 %}
- object->{{field.name}} = (octet >> {{ns.shift}}) & 0x1;
- {% elif field.width == 2 %}
- object->{{field.name}} = (octet >> {{ns.shift}}) & 0x3;
- {% elif field.width == 4 %}
- object->{{field.name}} = (octet >> {{ns.shift}}) & 0xf;
- {% elif field.width == 7 %}
- object->{{field.name}} = (octet >> {{ns.shift}}) & 0x7f;
- {% else %}
- {{ raise("Unhandled width of %d." % (field.width)) }}
- {% endif %}
- {% set ns.shift = ns.shift + field.width %}
- {% endfor %}
- }
- {% else %}
- {{ raise("Unhandled datatype '%s' for object %d:%d." % (field.type,
- object.group, object.variation)) }}
- {% endif %}
- {% endfor %}
- if (!DNP3AddPoint(points, object, point_index, prefix_code, prefix)) {
- goto error;
- }
- object = NULL;
- point_index++;
- }
- return 1;
- error:
- if (object != NULL) {
- {% for field in object.fields %}
- {% if field.type == "bytearray" %}
- if (object->{{field.name}} != NULL) {
- SCFree(object->{{field.name}});
- }
- {% endif %}
- {% endfor %}
- SCFree(object);
- }
- return 0;
- }
- {% endif %}
- {% endfor %}
- void DNP3FreeObjectPoint(int group, int variation, void *point)
- {
- switch(DNP3_OBJECT_CODE(group, variation)) {
- {% for object in objects %}
- {% if f_has_freeable_types(object.fields) %}
- case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}): {
- DNP3ObjectG{{object.group}}V{{object.variation}} *object = (DNP3ObjectG{{object.group}}V{{object.variation}} *) point;
- {% for field in object.fields %}
- {% if field.type == "bytearray" %}
- if (object->{{field.name}} != NULL) {
- SCFree(object->{{field.name}});
- }
- {% endif %}
- {% endfor %}
- break;
- }
- {% endif %}
- {% endfor %}
- default:
- break;
- }
- SCFree(point);
- }
- /**
- * \\\\brief Decode a DNP3 object.
- *
- * \\\\retval 0 on success. On failure a positive integer corresponding
- * to a DNP3 application layer event will be returned.
- */
- int DNP3DecodeObject(int group, int variation, const uint8_t **buf,
- uint32_t *len, uint8_t prefix_code, uint32_t start,
- uint32_t count, DNP3PointList *points)
- {
- int rc = 0;
- switch (DNP3_OBJECT_CODE(group, variation)) {
- {% for object in objects %}
- case DNP3_OBJECT_CODE({{object.group}}, {{object.variation}}):
- rc = DNP3DecodeObjectG{{object.group}}V{{object.variation}}(buf, len, prefix_code, start, count,
- points);
- break;
- {% endfor %}
- default:
- return DNP3_DECODER_EVENT_UNKNOWN_OBJECT;
- }
- return rc ? 0 : DNP3_DECODER_EVENT_MALFORMED;
- }
- """
- try:
- filename = "src/app-layer-dnp3-objects.c"
- env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True)
- code = env.from_string(template).render(context)
- content = open(filename).read()
- content = re.sub(
- "(%s).*(%s)" % (re.escape(IN_PLACE_START), re.escape(IN_PLACE_END)),
- r"\1%s\n\2" % (code), content, 1, re.M | re.DOTALL)
- open(filename, "w").write(content)
- print("Updated %s." % (filename))
- except Exception as err:
- print("Failed to update %s: %s" % (filename, err), file=sys.stderr)
- sys.exit(1)
- def preprocess_object(obj):
- valid_keys = [
- "group",
- "variation",
- "constraints",
- "extra_fields",
- "fields",
- "packed",
- ]
- valid_field_keys = [
- "type",
- "name",
- "width",
- "len_from_prefix",
- "len_field",
- "fields",
- "size",
- ]
- if "unimplemented" in obj:
- print("Object not implemented: %s:%s: %s" % (
- str(obj["group"]), str(obj["variation"]), obj["unimplemented"]))
- return None
- for key, val in obj.items():
- if key not in valid_keys:
- print("Invalid key '%s' in object %d:%d" % (
- key, obj["group"], obj["variation"]), file=sys.stderr)
- sys.exit(1)
- for field in obj["fields"]:
- for key in field.keys():
- if key not in valid_field_keys:
- print("Invalid key '%s' in object %d:%d" % (
- key, obj["group"], obj["variation"]), file=sys.stderr)
- sys.exit(1)
- if "len_from_prefix" in field and field["len_from_prefix"]:
- obj["_track_offset"] = True
- break
- if field["type"] == "bstr8":
- width = 0
- for subfield in field["fields"]:
- width += int(subfield["width"])
- assert(width == 8)
- return obj
- def main():
- # Require Jinja2 2.10 or greater.
- jv = jinja2.__version__.split(".")
- if int(jv[0]) < 2 or (int(jv[0]) == 2 and int(jv[1]) < 10):
- print("error: jinja2 v2.10 or great required")
- return 1
- definitions = yaml.load(open("scripts/dnp3-gen/dnp3-objects.yaml"))
- print("Loaded %s objects." % (len(definitions["objects"])))
- definitions["objects"] = map(preprocess_object, definitions["objects"])
- # Filter out unimplemented objects.
- definitions["objects"] = [
- obj for obj in definitions["objects"] if obj != None]
- context = {
- "raise": raise_helper,
- "objects": definitions["objects"],
- "is_integer_type": is_integer_type,
- "f_to_type": to_type,
- "f_has_freeable_types": has_freeable_types,
- "command_line": " ".join(sys.argv),
- }
- gen_object_structs(context)
- gen_object_decoders(context)
- generate(util_lua_dnp3_objects_c_template,
- "src/util-lua-dnp3-objects.c",
- context)
- generate(output_json_dnp3_objects_template,
- "src/output-json-dnp3-objects.c",
- context)
- if __name__ == "__main__":
- sys.exit(main())
|