cauterize 0.0.1.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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 */
|