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
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Object files
|
2
|
+
*.o
|
3
|
+
|
4
|
+
# Libraries
|
5
|
+
*.lib
|
6
|
+
*.a
|
7
|
+
|
8
|
+
# Shared objects (inc. Windows DLLs)
|
9
|
+
*.dll
|
10
|
+
*.so
|
11
|
+
*.so.*
|
12
|
+
*.dylib
|
13
|
+
|
14
|
+
# Executables
|
15
|
+
*.exe
|
16
|
+
*.out
|
17
|
+
*.app
|
18
|
+
|
19
|
+
# Bundler
|
20
|
+
Gemfile.lock
|
21
|
+
pkg
|
22
|
+
|
23
|
+
# Examples
|
24
|
+
example/cauterize_output
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-r spec_helper --color
|
data/.travisci.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 John Van Enk
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# *THIS PROJECT IS EXPERIMENTAL. IT MAY BREAK AND RUIN EVERYTHING YOU KNOW AND LOVE.*
|
2
|
+
|
3
|
+
# cauterize
|
4
|
+
|
5
|
+
A Ruby DSL for generating marshalable structured data easily compatable with
|
6
|
+
statically allocated C systems. Currently, it prefers simplicity and
|
7
|
+
predictability over speed.
|
8
|
+
|
9
|
+
# Why?
|
10
|
+
|
11
|
+
Basically, `malloc` is a huge pain when you only have 16K of RAM.
|
12
|
+
|
13
|
+
# Examples
|
14
|
+
|
15
|
+
There's currently a (single) example in this project. To run it, do this:
|
16
|
+
|
17
|
+
```
|
18
|
+
git clone git://github.com/sw17ch/cauterize.git
|
19
|
+
cd cauterize
|
20
|
+
bundle install
|
21
|
+
cd example
|
22
|
+
sh build.sh
|
23
|
+
```
|
24
|
+
|
25
|
+
If this completes without error, then you should find a bunch of generated code
|
26
|
+
in cauterize_output. Look at the structures and enumerations defined in the
|
27
|
+
`example_project.h` file. Also look at how the `Pack_*` and `Unpack_*`
|
28
|
+
functions are organized and named.
|
29
|
+
|
30
|
+
Once you've looked at this, take a look at `example_project.c`. This will show
|
31
|
+
you the exact mechanism used to package and unpackage different structures.
|
32
|
+
|
33
|
+
`cauterize.h` and `cauterize.c` are used as iterators over C buffers. They are
|
34
|
+
used to abstract the process of packaging and unpackaging different elements.
|
35
|
+
|
36
|
+
# Different Types
|
37
|
+
|
38
|
+
There are 6 fundamental classes of types in Cauterize. These types have several characteristics:
|
39
|
+
|
40
|
+
* They can be copied with `memcpy`.
|
41
|
+
* They do not attempt to cover the concept of indirection or pointers.
|
42
|
+
* They are simple.
|
43
|
+
* They cannot be defined recursively.
|
44
|
+
|
45
|
+
## Scalars
|
46
|
+
|
47
|
+
Scalars are any type that corresponds to a C scalar value. That is, something
|
48
|
+
that can be defined with the native types (`int`, `long`, `short`, etc). It is
|
49
|
+
highly recommended that these ONLY ever use values from `stdint.h`. This
|
50
|
+
ensures that the sizes of these scalars will be consistent across platforms.
|
51
|
+
|
52
|
+
Scalars can be defined simply by giving them a name that corresponds to a type
|
53
|
+
from `stdint.h`.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
scalar(:uint8_t)
|
57
|
+
scalar(:uint32_t)
|
58
|
+
```
|
59
|
+
|
60
|
+
## Enumerations
|
61
|
+
|
62
|
+
Enumerations correspond almost exactly to C enumerations. They are a list of
|
63
|
+
names. When appropriate, a specific scalar value may also be specified. If no
|
64
|
+
scalar is specified, enumerations will be represented in order from 0.
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
enumeration(:color) do |e|
|
68
|
+
e.value :red
|
69
|
+
e.value :blue
|
70
|
+
e.value :green
|
71
|
+
end
|
72
|
+
|
73
|
+
enumeration(:days_of_week) do |e|
|
74
|
+
e.value :sunday, 100
|
75
|
+
e.value :monday, 101
|
76
|
+
e.value :tuesday, 102
|
77
|
+
e.value :wednesday, 103
|
78
|
+
e.value :thursday, 104
|
79
|
+
e.value :friday, 105
|
80
|
+
e.value :saturday, 106
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
## Fixed Arrays
|
85
|
+
|
86
|
+
Fixed arrays are arrays that only ever make sense when they are full. An
|
87
|
+
example of an array with this property is a MAC Address. MAC addresses are
|
88
|
+
always 6 bytes. Never more. Never less.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
fixed_array(:mac_address) do |a|
|
92
|
+
a.array_type :uint8_t # the type held by the array
|
93
|
+
a.array_size 6 # the number of elements in the array
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
## Variable Arrays
|
98
|
+
|
99
|
+
Variable Arrays are arrays that have a maximum length, but may not be entirely
|
100
|
+
utilized.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
# a way to represent some number of dates/times as 32-bit values
|
104
|
+
variable_array(:datetimes) do |a|
|
105
|
+
a.size_type :uint8_t # WILL BE DEPRECATED
|
106
|
+
a.array_type :int32_t
|
107
|
+
a.array_size 128
|
108
|
+
end
|
109
|
+
|
110
|
+
# a string, represented as `int_8`'s, with a maximum length of 32 bytes
|
111
|
+
variable_array(:string_32) do |a|
|
112
|
+
a.size_type :uint8_t # WILL BE DEPRECATED
|
113
|
+
a.array_type :int8_t
|
114
|
+
a.array_size 32
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
## Composites
|
119
|
+
|
120
|
+
Composites are very similar to C structures. They are collections of other
|
121
|
+
types. Each field has a name and may correspond to any other defined type.
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
composite(:person) do |c|
|
125
|
+
c.field :name, :string_32
|
126
|
+
c.field :age, :uint8_t
|
127
|
+
c.field :date_of_birth, :uint32_t
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
## Groups
|
132
|
+
|
133
|
+
Groups are similar to C unions with one major difference. Each group is
|
134
|
+
comprised of a type tag and a union of the types the union is capable of
|
135
|
+
representing. This is known as a tagged union.
|
136
|
+
|
137
|
+
The tag is used to inform the user application what type the union is currently
|
138
|
+
representing. The tag is a special enumeration that is automatically defined.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
group(:requests) do |g|
|
142
|
+
c.field :add_user, :add_user_request
|
143
|
+
c.field :get_user, :get_user_request
|
144
|
+
c.field :delete_user, :delete_user_request
|
145
|
+
end
|
146
|
+
|
147
|
+
group(:responses) do |g|
|
148
|
+
c.field :add_user, :add_user_response
|
149
|
+
c.field :get_user, :get_user_response
|
150
|
+
c.field :delete_user, :delete_user_response
|
151
|
+
end
|
152
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
task :default => :greatest
|
9
|
+
|
10
|
+
desc "Run C tests"
|
11
|
+
task :greatest do
|
12
|
+
Dir.mktmpdir do |d|
|
13
|
+
test_suite_path = File.join(d, "test_suite.c")
|
14
|
+
mk_test_suite_file(test_suite_path)
|
15
|
+
|
16
|
+
args = "-Wall -Wextra -Werror -Ic/test -Ic/src -I#{d}"
|
17
|
+
srcs = "c/src/cauterize.c c/test/test.c"
|
18
|
+
bin = File.join(d, "test.bin")
|
19
|
+
sh "gcc #{args} #{srcs} -o #{bin}"
|
20
|
+
sh bin
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Support Methods
|
25
|
+
|
26
|
+
SUITE_ENTRY_TEMPLATE = " RUN_TEST(%s);"
|
27
|
+
|
28
|
+
def mk_test_suite_file(path)
|
29
|
+
test_files = Dir["c/test/*.c"]
|
30
|
+
suite_text = test_files.map do |test_file|
|
31
|
+
File.read(test_file).lines.map do |l|
|
32
|
+
m = l.match(/^TEST (?<sym>[^\(]+)\(\)/)
|
33
|
+
m ? m[:sym] : nil
|
34
|
+
end.compact
|
35
|
+
end.flatten.map {|t| SUITE_ENTRY_TEMPLATE % t}.join("\n") + "\n"
|
36
|
+
|
37
|
+
File.open(path, "wb") {|fh| fh.write(suite_text)}
|
38
|
+
end
|
data/bin/cauterize
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
LIB_PATH = File.dirname(__FILE__) + "/../lib"
|
4
|
+
C_PATH = File.dirname(__FILE__) + "/../c/src"
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift LIB_PATH
|
7
|
+
|
8
|
+
require 'thor'
|
9
|
+
require 'cauterize/cauterize'
|
10
|
+
|
11
|
+
class CmdLineException < Exception; end
|
12
|
+
|
13
|
+
class CauterizeCmdline < Thor
|
14
|
+
desc "generate [language] [target_dir] [[description file]]",
|
15
|
+
"Generate sources for [language] in [target_dir]."
|
16
|
+
method_option :omit_support, :type => :boolean,
|
17
|
+
:desc => "Omit the support files needed by Cauterize",
|
18
|
+
:default => false
|
19
|
+
method_option :force, :type => :boolean,
|
20
|
+
:desc => "Bravely overwrite files in non-empty directories",
|
21
|
+
:default => false
|
22
|
+
def generate(language, target_dir, desc_file = nil)
|
23
|
+
raise CmdLineException.new("Language '#{language}' is not supported.") unless language == 'c'
|
24
|
+
|
25
|
+
if not options[:force] and Dir.exist?(target_dir) and Dir[target_dir + "/*"].size > 0
|
26
|
+
raise CmdLineException.new("Directory '#{target_dir}' isn't empty. Cowardly quitting.")
|
27
|
+
end
|
28
|
+
|
29
|
+
desc_file ||= "Cauterize"
|
30
|
+
|
31
|
+
if not File.exist? desc_file
|
32
|
+
raise CmdLineException.new("The description file #{desc_file} does not exist.")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Generate the C files.
|
36
|
+
Cauterize.generate_c(target_dir, desc_file)
|
37
|
+
|
38
|
+
# Copy the cauterize support files.
|
39
|
+
unless options[:omit_support]
|
40
|
+
Dir[C_PATH + "/*"].each do |path|
|
41
|
+
FileUtils.cp(path, target_dir)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
begin
|
48
|
+
CauterizeCmdline.start
|
49
|
+
rescue CmdLineException => ex
|
50
|
+
puts ex.message
|
51
|
+
end
|
52
|
+
|
53
|
+
# vim: set syntax=ruby ts=2 sw=2 et ai
|
data/c/src/cauterize.c
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#define CAUTERIZE_C
|
2
|
+
|
3
|
+
#include "cauterize.h"
|
4
|
+
#include "cauterize_debug.h"
|
5
|
+
|
6
|
+
#include <string.h>
|
7
|
+
|
8
|
+
#define S CAUTERIZE_STATUS_T
|
9
|
+
#define T struct Cauterize
|
10
|
+
|
11
|
+
S CauterizeInitAppend( struct Cauterize * m, uint8_t * buffer, size_t length)
|
12
|
+
{
|
13
|
+
CA_ASSERT(NULL != m);
|
14
|
+
CA_ASSERT(NULL != buffer);
|
15
|
+
|
16
|
+
m->size = length;
|
17
|
+
m->used = 0;
|
18
|
+
m->pos = 0;
|
19
|
+
m->buffer = buffer;
|
20
|
+
|
21
|
+
return CA_OK;
|
22
|
+
}
|
23
|
+
|
24
|
+
S CauterizeInitRead( struct Cauterize * m, uint8_t * buffer, size_t used)
|
25
|
+
{
|
26
|
+
CA_ASSERT(NULL != m);
|
27
|
+
CA_ASSERT(NULL != buffer);
|
28
|
+
|
29
|
+
m->size = used;
|
30
|
+
m->used = used;
|
31
|
+
m->pos = 0;
|
32
|
+
m->buffer = buffer;
|
33
|
+
|
34
|
+
return CA_OK;
|
35
|
+
}
|
36
|
+
|
37
|
+
S CauterizeAppend(T * m, uint8_t * src, size_t length)
|
38
|
+
{
|
39
|
+
CA_ASSERT(NULL != m);
|
40
|
+
CA_ASSERT(NULL != src);
|
41
|
+
|
42
|
+
size_t needed = m->used + length;
|
43
|
+
|
44
|
+
if (needed > m->size)
|
45
|
+
return CA_ERR_NOT_ENOUGH_SPACE;
|
46
|
+
|
47
|
+
uint8_t * dest = &m->buffer[m->used];
|
48
|
+
memcpy(dest, src, length);
|
49
|
+
m->used += length;
|
50
|
+
|
51
|
+
return CA_OK;
|
52
|
+
}
|
53
|
+
|
54
|
+
S CauterizeRead(T * m, uint8_t * dst, size_t length)
|
55
|
+
{
|
56
|
+
CA_ASSERT(NULL != m);
|
57
|
+
CA_ASSERT(NULL != dst);
|
58
|
+
CA_ASSERT(m->used >= m->pos);
|
59
|
+
|
60
|
+
size_t available = m->used - m->pos;
|
61
|
+
|
62
|
+
if (length > available)
|
63
|
+
return CA_ERR_NOT_ENOUGH_DATA;
|
64
|
+
|
65
|
+
uint8_t * src = &m->buffer[m->pos];
|
66
|
+
memcpy(dst, src, length);
|
67
|
+
m->pos += length;
|
68
|
+
|
69
|
+
return CA_OK;
|
70
|
+
}
|
71
|
+
|
72
|
+
#undef S
|
73
|
+
#undef T
|
74
|
+
#undef CAUTERIZE_C
|
data/c/src/cauterize.h
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#ifndef CAUTERIZE_H
|
2
|
+
#define CAUTERIZE_H
|
3
|
+
|
4
|
+
#include <stdint.h>
|
5
|
+
#include <stddef.h>
|
6
|
+
|
7
|
+
typedef uint32_t CAUTERIZE_STATUS_T;
|
8
|
+
|
9
|
+
#define CA_OK (0)
|
10
|
+
#define CA_ERR_ASSERT (1)
|
11
|
+
#define CA_ERR_NOT_ENOUGH_SPACE (2)
|
12
|
+
#define CA_ERR_NOT_ENOUGH_DATA (3)
|
13
|
+
#define CA_ERR_INVALID_LENGTH (4)
|
14
|
+
#define CA_ERR_INVALUD_TYPE_TAG (5)
|
15
|
+
#define CA_ERR_GENERAL (UINT32_MAX)
|
16
|
+
|
17
|
+
struct Cauterize {
|
18
|
+
size_t size; // Size of the buffer in bytes
|
19
|
+
size_t used; // Number of used bytes in the buffer
|
20
|
+
size_t pos; // The next byte to be read
|
21
|
+
uint8_t * buffer; // Buffer to hold data
|
22
|
+
};
|
23
|
+
|
24
|
+
CAUTERIZE_STATUS_T CauterizeInitAppend(
|
25
|
+
struct Cauterize * m,
|
26
|
+
uint8_t * buffer,
|
27
|
+
size_t length);
|
28
|
+
|
29
|
+
CAUTERIZE_STATUS_T CauterizeInitRead(
|
30
|
+
struct Cauterize * m,
|
31
|
+
uint8_t * buffer,
|
32
|
+
size_t used);
|
33
|
+
|
34
|
+
CAUTERIZE_STATUS_T CauterizeAppend(
|
35
|
+
struct Cauterize * m,
|
36
|
+
uint8_t * src,
|
37
|
+
size_t length);
|
38
|
+
|
39
|
+
CAUTERIZE_STATUS_T CauterizeRead(
|
40
|
+
struct Cauterize * m,
|
41
|
+
uint8_t * dst,
|
42
|
+
size_t length);
|
43
|
+
|
44
|
+
#define CA_MAX(a,b) ((a) > (b) ? (a) : (b))
|
45
|
+
|
46
|
+
#endif /* CAUTERIZE_H */
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#ifndef CAUTERIZE_DEBUG_H
|
2
|
+
#define CAUTERIZE_DEBUG_H
|
3
|
+
|
4
|
+
#ifndef CAUTERIZE_C
|
5
|
+
#error "You should not include cauterize_debug.h."
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#ifndef NDEBUG
|
9
|
+
|
10
|
+
#include <stdio.h>
|
11
|
+
#define CA_ASSERT_PRINT(msg) \
|
12
|
+
fprintf(stderr, "ASSERT: %s (%s:%d)\n", msg, __FILE__, __LINE__);
|
13
|
+
|
14
|
+
#define CA_ASSERT(cond) CA_ASSERTm(#cond, cond)
|
15
|
+
#define CA_ASSERTm(msg, cond) \
|
16
|
+
do { \
|
17
|
+
if(!(cond)) { \
|
18
|
+
CA_ASSERT_PRINT(msg); \
|
19
|
+
return CA_ERR_ASSERT; \
|
20
|
+
} \
|
21
|
+
} while(0)
|
22
|
+
|
23
|
+
#else
|
24
|
+
|
25
|
+
#define CA_ASSERT(cond)
|
26
|
+
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#endif /* CAUTERIZE_DEBUG_H */
|