cauterize 0.0.1.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +24 -0
- data/.rspec +1 -0
- data/.travisci.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +38 -0
- data/bin/cauterize +53 -0
- data/c/src/cauterize.c +74 -0
- data/c/src/cauterize.h +46 -0
- data/c/src/cauterize_debug.h +29 -0
- data/c/src/cauterize_util.h +7 -0
- data/c/test/greatest.h +536 -0
- data/c/test/test.c +166 -0
- data/cauterize.gemspec +26 -0
- data/example/Cauterize +44 -0
- data/example/build.sh +4 -0
- data/lib/cauterize/base_type.rb +96 -0
- data/lib/cauterize/builders.rb +27 -0
- data/lib/cauterize/builders/c/buildable.rb +59 -0
- data/lib/cauterize/builders/c/composite.rb +55 -0
- data/lib/cauterize/builders/c/enumeration.rb +41 -0
- data/lib/cauterize/builders/c/fixed_array.rb +62 -0
- data/lib/cauterize/builders/c/group.rb +95 -0
- data/lib/cauterize/builders/c/scalar.rb +31 -0
- data/lib/cauterize/builders/c/variable_array.rb +90 -0
- data/lib/cauterize/c_builder.rb +63 -0
- data/lib/cauterize/cauterize.rb +33 -0
- data/lib/cauterize/composite.rb +50 -0
- data/lib/cauterize/enumeration.rb +77 -0
- data/lib/cauterize/fixed_array.rb +43 -0
- data/lib/cauterize/formatter.rb +59 -0
- data/lib/cauterize/group.rb +56 -0
- data/lib/cauterize/scalar.rb +38 -0
- data/lib/cauterize/snake_case.rb +21 -0
- data/lib/cauterize/variable_array.rb +56 -0
- data/lib/cauterize/version.rb +3 -0
- data/spec/base_type_spec.rb +167 -0
- data/spec/builders/c/buildable_spec.rb +25 -0
- data/spec/builders/c/composite_spec.rb +46 -0
- data/spec/builders/c/enumeration_spec.rb +32 -0
- data/spec/builders/c/fixed_array_spec.rb +36 -0
- data/spec/builders/c/group_spec.rb +112 -0
- data/spec/builders/c/scalar_spec.rb +8 -0
- data/spec/builders/c/variable_array_spec.rb +50 -0
- data/spec/builders_spec.rb +51 -0
- data/spec/c_builder_spec.rb +133 -0
- data/spec/cauterize_spec.rb +8 -0
- data/spec/composite_spec.rb +62 -0
- data/spec/enumeration_spec.rb +104 -0
- data/spec/fixed_array_spec.rb +62 -0
- data/spec/group_spec.rb +104 -0
- data/spec/scalar_spec.rb +36 -0
- data/spec/spec_helper.rb +115 -0
- data/spec/support/shared_examples_for_array_buildables.rb +22 -0
- data/spec/support/shared_examples_for_c_buildables.rb +91 -0
- data/spec/support/shared_examples_for_sane_c_buildables.rb +22 -0
- data/spec/support/shared_examples_for_stubbed_functions.rb +18 -0
- data/spec/test_main.c +13 -0
- data/spec/variable_array_spec.rb +92 -0
- metadata +212 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module Builders
|
3
|
+
module C
|
4
|
+
class Enumeration < Buildable
|
5
|
+
def render
|
6
|
+
"enum #{@blueprint.name.to_s}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def declare(formatter, sym)
|
10
|
+
formatter << "#{render} #{sym};"
|
11
|
+
end
|
12
|
+
|
13
|
+
def packer_defn(formatter)
|
14
|
+
formatter << packer_sig
|
15
|
+
formatter.braces do
|
16
|
+
formatter << "return CauterizeAppend(dst, (uint8_t*)src, sizeof(*src));"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def unpacker_defn(formatter)
|
21
|
+
formatter << unpacker_sig
|
22
|
+
formatter.braces do
|
23
|
+
formatter << "return CauterizeRead(src, (uint8_t*)dst, sizeof(*dst));"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def enum_defn(formatter)
|
28
|
+
formatter << render
|
29
|
+
formatter.braces do
|
30
|
+
@blueprint.values.values.each do |v|
|
31
|
+
formatter << "#{v.name.to_s.up_snake} = #{v.value},"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
formatter.append(";")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Cauterize::Builders.register(:c, Cauterize::Enumeration, Cauterize::Builders::C::Enumeration)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module Builders
|
3
|
+
module C
|
4
|
+
class FixedArray < Buildable
|
5
|
+
def render
|
6
|
+
# HEY! PAY ATTENTION!
|
7
|
+
# Keep in mind that there's no sane way to "render" an array in C
|
8
|
+
# that doesn't involve an identifier.
|
9
|
+
ty_bldr.render
|
10
|
+
end
|
11
|
+
|
12
|
+
def declare(formatter, sym)
|
13
|
+
formatter << "#{ty_bldr.render} #{sym}[#{@blueprint.array_size}]; /* #{@blueprint.name} */"
|
14
|
+
end
|
15
|
+
|
16
|
+
def packer_defn(formatter)
|
17
|
+
formatter << packer_sig
|
18
|
+
formatter.braces do
|
19
|
+
formatter << "CAUTERIZE_STATUS_T err;"
|
20
|
+
formatter << "size_t i;"
|
21
|
+
formatter.blank_line
|
22
|
+
|
23
|
+
# store each used item in the array
|
24
|
+
formatter << "for (i = 0; i < #{@blueprint.array_size}; i++)"
|
25
|
+
formatter.braces do
|
26
|
+
formatter << "if (CA_OK != (err = #{ty_bldr.packer_sym}(dst, &src[i]))) { return err; }"
|
27
|
+
end
|
28
|
+
formatter.blank_line
|
29
|
+
|
30
|
+
formatter << "return CA_OK;"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def unpacker_defn(formatter)
|
35
|
+
formatter << unpacker_sig
|
36
|
+
formatter.braces do
|
37
|
+
formatter << "CAUTERIZE_STATUS_T err;"
|
38
|
+
formatter << "size_t i;"
|
39
|
+
formatter.blank_line
|
40
|
+
|
41
|
+
# store each used item in the array
|
42
|
+
formatter << "for (i = 0; i < #{@blueprint.array_size}; i++)"
|
43
|
+
formatter.braces do
|
44
|
+
formatter << "if (CA_OK != (err = #{ty_bldr.unpacker_sym}(src, &dst[i]))) { return err; }"
|
45
|
+
end
|
46
|
+
formatter.blank_line
|
47
|
+
|
48
|
+
formatter << "return CA_OK;"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def ty_bldr
|
55
|
+
@ty_bldr ||= Builders.get(:c, @blueprint.array_type)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Cauterize::Builders.register(:c, Cauterize::FixedArray, Cauterize::Builders::C::FixedArray)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module Builders
|
3
|
+
module C
|
4
|
+
class Group < Buildable
|
5
|
+
def initialize(blueprint)
|
6
|
+
super(blueprint)
|
7
|
+
@tag_enum = blueprint.tag_enum
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
"struct #{@blueprint.name.to_s}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def declare(formatter, sym)
|
15
|
+
formatter << "#{render} #{sym};"
|
16
|
+
end
|
17
|
+
|
18
|
+
def packer_defn(formatter)
|
19
|
+
enum_builder = Builders.get(:c, @tag_enum)
|
20
|
+
formatter << packer_sig
|
21
|
+
formatter.braces do
|
22
|
+
formatter << "CAUTERIZE_STATUS_T err;"
|
23
|
+
|
24
|
+
# pack the tag
|
25
|
+
formatter << "if (CA_OK != (err = #{enum_builder.packer_sym}(dst, &src->tag))) { return err; }"
|
26
|
+
|
27
|
+
# pack the fields
|
28
|
+
formatter << "switch (src->tag)"
|
29
|
+
formatter.braces do
|
30
|
+
@blueprint.fields.values.each do |field|
|
31
|
+
bldr = Builders.get(:c, field.type)
|
32
|
+
formatter.backdent "case #{@blueprint.enum_sym(field.name)}:"
|
33
|
+
formatter << "if (CA_OK != (err = #{bldr.packer_sym}(dst, &src->data.#{field.name}))) { return err; }"
|
34
|
+
formatter << "break;"
|
35
|
+
end
|
36
|
+
|
37
|
+
formatter.backdent "default:"
|
38
|
+
formatter << "return CA_ERR_INVALUD_TYPE_TAG;"
|
39
|
+
formatter << "break;"
|
40
|
+
end
|
41
|
+
formatter << "return CA_OK;"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def unpacker_defn(formatter)
|
46
|
+
enum_builder = Builders.get(:c, @tag_enum)
|
47
|
+
formatter << unpacker_sig
|
48
|
+
formatter.braces do
|
49
|
+
formatter << "CAUTERIZE_STATUS_T err;"
|
50
|
+
|
51
|
+
# unpack the tag
|
52
|
+
formatter << "if (CA_OK != (err = #{enum_builder.unpacker_sym}(src, &dst->tag))) { return err; }"
|
53
|
+
|
54
|
+
# pack the fields
|
55
|
+
formatter << "switch (dst->tag)"
|
56
|
+
formatter.braces do
|
57
|
+
@blueprint.fields.values.each do |field|
|
58
|
+
bldr = Builders.get(:c, field.type)
|
59
|
+
formatter.backdent "case #{@blueprint.enum_sym(field.name)}:"
|
60
|
+
formatter << "if (CA_OK != (err = #{bldr.unpacker_sym}(src, &dst->data.#{field.name}))) { return err; }"
|
61
|
+
formatter << "break;"
|
62
|
+
end
|
63
|
+
|
64
|
+
formatter.backdent "default:"
|
65
|
+
formatter << "return CA_ERR_INVALUD_TYPE_TAG;"
|
66
|
+
formatter << "break;"
|
67
|
+
end
|
68
|
+
formatter << "return CA_OK;"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def struct_proto(formatter)
|
73
|
+
formatter << (render + ";")
|
74
|
+
end
|
75
|
+
|
76
|
+
def struct_defn(formatter)
|
77
|
+
formatter << render
|
78
|
+
formatter.braces do
|
79
|
+
Builders.get(:c, @tag_enum).declare(formatter, "tag")
|
80
|
+
formatter << "union"
|
81
|
+
formatter.braces do
|
82
|
+
@blueprint.fields.values.each do |field|
|
83
|
+
Builders.get(:c, field.type).declare(formatter, field.name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
formatter.append(" data;")
|
87
|
+
end
|
88
|
+
formatter.append(";")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Cauterize::Builders.register(:c, Cauterize::Group, Cauterize::Builders::C::Group)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module Builders
|
3
|
+
module C
|
4
|
+
class Scalar < Buildable
|
5
|
+
def render
|
6
|
+
@blueprint.name.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def declare(formatter, sym)
|
10
|
+
formatter << "#{render} #{sym};"
|
11
|
+
end
|
12
|
+
|
13
|
+
def packer_defn(formatter)
|
14
|
+
formatter << packer_sig
|
15
|
+
formatter.braces do
|
16
|
+
formatter << "return CauterizeAppend(dst, (uint8_t*)src, sizeof(*src));"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def unpacker_defn(formatter)
|
21
|
+
formatter << unpacker_sig
|
22
|
+
formatter.braces do
|
23
|
+
formatter << "return CauterizeRead(src, (uint8_t*)dst, sizeof(*dst));"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Cauterize::Builders.register(:c, Cauterize::Scalar, Cauterize::Builders::C::Scalar)
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Cauterize
|
2
|
+
module Builders
|
3
|
+
module C
|
4
|
+
class VariableArray < Buildable
|
5
|
+
def render
|
6
|
+
"struct #{@blueprint.name}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def declare(formatter, sym)
|
10
|
+
formatter << "struct #{@blueprint.name} #{sym};"
|
11
|
+
end
|
12
|
+
|
13
|
+
def packer_defn(formatter)
|
14
|
+
size_type_builder = Builders.get(:c, @blueprint.size_type)
|
15
|
+
array_type_builder = Builders.get(:c, @blueprint.array_type)
|
16
|
+
|
17
|
+
formatter << packer_sig
|
18
|
+
formatter.braces do
|
19
|
+
formatter << "CAUTERIZE_STATUS_T err;"
|
20
|
+
formatter << "size_t i;"
|
21
|
+
formatter.blank_line
|
22
|
+
# check the length
|
23
|
+
formatter << "if (src->length > ARRAY_SIZE(src->data)) { return CA_ERR_INVALID_LENGTH; }"
|
24
|
+
|
25
|
+
# store the length
|
26
|
+
formatter << "if (CA_OK != (err = #{size_type_builder.packer_sym}(dst, &src->length))) { return err; }"
|
27
|
+
formatter.blank_line
|
28
|
+
|
29
|
+
# store each used item in the array
|
30
|
+
formatter << "for (i = 0; i < src->length; i++)"
|
31
|
+
formatter.braces do
|
32
|
+
formatter << "if (CA_OK != (err = #{array_type_builder.packer_sym}(dst, &src->data[i]))) { return err; }"
|
33
|
+
end
|
34
|
+
formatter.blank_line
|
35
|
+
|
36
|
+
formatter << "return CA_OK;"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def unpacker_defn(formatter)
|
41
|
+
size_type_builder = Builders.get(:c, @blueprint.size_type)
|
42
|
+
array_type_builder = Builders.get(:c, @blueprint.array_type)
|
43
|
+
|
44
|
+
formatter << unpacker_sig
|
45
|
+
formatter.braces do
|
46
|
+
formatter << "CAUTERIZE_STATUS_T err;"
|
47
|
+
formatter << "size_t i;"
|
48
|
+
formatter.blank_line
|
49
|
+
|
50
|
+
# read the length
|
51
|
+
formatter << "if (CA_OK != (err = #{size_type_builder.unpacker_sym}(src, &dst->length))) { return err; }"
|
52
|
+
formatter.blank_line
|
53
|
+
|
54
|
+
# check the length
|
55
|
+
formatter << "if (dst->length > ARRAY_SIZE(dst->data)) { return CA_ERR_INVALID_LENGTH; }"
|
56
|
+
formatter.blank_line
|
57
|
+
|
58
|
+
|
59
|
+
# store each used item in the array
|
60
|
+
formatter << "for (i = 0; i < dst->length; i++)"
|
61
|
+
formatter.braces do
|
62
|
+
formatter << "if (CA_OK != (err = #{array_type_builder.unpacker_sym}(src, &dst->data[i]))) { return err; }"
|
63
|
+
end
|
64
|
+
formatter.blank_line
|
65
|
+
|
66
|
+
formatter << "return CA_OK;"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def struct_proto(formatter)
|
71
|
+
formatter << (render + ";")
|
72
|
+
end
|
73
|
+
|
74
|
+
def struct_defn(formatter)
|
75
|
+
formatter << render
|
76
|
+
formatter.braces do
|
77
|
+
at_builder = Builders.get(:c, @blueprint.array_type)
|
78
|
+
st_builder = Builders.get(:c, @blueprint.size_type)
|
79
|
+
|
80
|
+
st_builder.declare(formatter, "length")
|
81
|
+
formatter << "#{at_builder.render} data[#{@blueprint.array_size}];"
|
82
|
+
end
|
83
|
+
formatter.append(";")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Cauterize::Builders.register(:c, Cauterize::VariableArray, Cauterize::Builders::C::VariableArray)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Cauterize
|
2
|
+
class CBuilder
|
3
|
+
attr_reader :h, :c
|
4
|
+
|
5
|
+
def initialize(h_file, c_file, name="cauterize")
|
6
|
+
@h = h_file
|
7
|
+
@c = c_file
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
build_h
|
13
|
+
build_c
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def build_h
|
19
|
+
f = default_formatter
|
20
|
+
|
21
|
+
excluder = @name.up_snake + "_H_#{Time.now.to_i}"
|
22
|
+
f << "#ifndef #{excluder}"
|
23
|
+
f << "#define #{excluder}"
|
24
|
+
f.blank_line
|
25
|
+
f << %Q{#include <cauterize.h>}
|
26
|
+
f << %Q{#include <stdint.h>}
|
27
|
+
f.blank_line
|
28
|
+
|
29
|
+
instances = BaseType.all_instances
|
30
|
+
builders = instances.map {|i| Builders.get(:c, i)}
|
31
|
+
|
32
|
+
builders.each { |b| b.enum_defn(f) }
|
33
|
+
builders.each { |b| b.struct_proto(f) }
|
34
|
+
builders.each { |b| b.struct_defn(f) }
|
35
|
+
builders.each { |b| b.packer_proto(f) }
|
36
|
+
builders.each { |b| b.unpacker_proto(f) }
|
37
|
+
|
38
|
+
f.blank_line
|
39
|
+
f << "#endif /* #{excluder} */"
|
40
|
+
|
41
|
+
File.open(@h, "wb") do |fh|
|
42
|
+
fh.write(f.to_s)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_c
|
47
|
+
f = default_formatter
|
48
|
+
|
49
|
+
f << %Q{#include <cauterize_util.h>}
|
50
|
+
f << %Q{#include "#{@name}.h"}
|
51
|
+
|
52
|
+
instances = BaseType.all_instances
|
53
|
+
builders = instances.map {|i| Builders.get(:c, i)}
|
54
|
+
|
55
|
+
builders.each { |b| b.packer_defn(f) }
|
56
|
+
builders.each { |b| b.unpacker_defn(f) }
|
57
|
+
|
58
|
+
File.open(@c, "wb") do |fh|
|
59
|
+
fh.write(f.to_s)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "require_all"
|
2
|
+
|
3
|
+
lib_path = File.dirname(__FILE__) + "/.."
|
4
|
+
require_all Dir[lib_path + "/**/*.rb"]
|
5
|
+
|
6
|
+
module Cauterize
|
7
|
+
# Genearte the C code corresponding to the generated configuration
|
8
|
+
def self.generate_c(target_dir, desc_file)
|
9
|
+
Object.new.extend(Cauterize).instance_exec do
|
10
|
+
# this magic allows us to emit useful exception messages when evaling the
|
11
|
+
# file. if your description file has errors, you'll be able to find them
|
12
|
+
# because of this magic.
|
13
|
+
p = Proc.new {}
|
14
|
+
eval(File.read(desc_file), p.binding, desc_file)
|
15
|
+
end
|
16
|
+
output_prefix = get_name || "generated_interface"
|
17
|
+
|
18
|
+
FileUtils.mkdir_p(target_dir)
|
19
|
+
h_file = File.join(target_dir, "#{output_prefix}.h")
|
20
|
+
c_file = File.join(target_dir, "#{output_prefix}.c")
|
21
|
+
|
22
|
+
builder = Cauterize::CBuilder.new(h_file, c_file, output_prefix)
|
23
|
+
builder.build
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.get_name
|
27
|
+
@@description_name
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_name(desc_name)
|
31
|
+
@@description_name = desc_name
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# composite.rb
|
2
|
+
#
|
3
|
+
# Composites correspond to C structs.
|
4
|
+
|
5
|
+
module Cauterize
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def composite(name)
|
9
|
+
c = composites[name] || composites[name] = Composite.new(name)
|
10
|
+
yield c if block_given?
|
11
|
+
return c
|
12
|
+
end
|
13
|
+
|
14
|
+
def composite!(name, &blk)
|
15
|
+
if composites[name]
|
16
|
+
raise Exception.new("Composite with name #{name} already exists.")
|
17
|
+
else
|
18
|
+
composite(name, &blk)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def composites
|
23
|
+
@composites ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
class CompositeField
|
27
|
+
attr_reader :name, :type
|
28
|
+
def initialize(field_name, type_name)
|
29
|
+
@name = field_name
|
30
|
+
@type = BaseType.find_type!(type_name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Composite < BaseType
|
35
|
+
attr_reader :fields
|
36
|
+
|
37
|
+
def initialize(name)
|
38
|
+
super
|
39
|
+
@fields = {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def field(name, type)
|
43
|
+
if @fields[name]
|
44
|
+
raise Exception.new("Field name #{name} already used.")
|
45
|
+
else
|
46
|
+
@fields[name] = CompositeField.new(name, type)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|