cauterize 0.0.1.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +24 -0
  2. data/.rspec +1 -0
  3. data/.travisci.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +152 -0
  7. data/Rakefile +38 -0
  8. data/bin/cauterize +53 -0
  9. data/c/src/cauterize.c +74 -0
  10. data/c/src/cauterize.h +46 -0
  11. data/c/src/cauterize_debug.h +29 -0
  12. data/c/src/cauterize_util.h +7 -0
  13. data/c/test/greatest.h +536 -0
  14. data/c/test/test.c +166 -0
  15. data/cauterize.gemspec +26 -0
  16. data/example/Cauterize +44 -0
  17. data/example/build.sh +4 -0
  18. data/lib/cauterize/base_type.rb +96 -0
  19. data/lib/cauterize/builders.rb +27 -0
  20. data/lib/cauterize/builders/c/buildable.rb +59 -0
  21. data/lib/cauterize/builders/c/composite.rb +55 -0
  22. data/lib/cauterize/builders/c/enumeration.rb +41 -0
  23. data/lib/cauterize/builders/c/fixed_array.rb +62 -0
  24. data/lib/cauterize/builders/c/group.rb +95 -0
  25. data/lib/cauterize/builders/c/scalar.rb +31 -0
  26. data/lib/cauterize/builders/c/variable_array.rb +90 -0
  27. data/lib/cauterize/c_builder.rb +63 -0
  28. data/lib/cauterize/cauterize.rb +33 -0
  29. data/lib/cauterize/composite.rb +50 -0
  30. data/lib/cauterize/enumeration.rb +77 -0
  31. data/lib/cauterize/fixed_array.rb +43 -0
  32. data/lib/cauterize/formatter.rb +59 -0
  33. data/lib/cauterize/group.rb +56 -0
  34. data/lib/cauterize/scalar.rb +38 -0
  35. data/lib/cauterize/snake_case.rb +21 -0
  36. data/lib/cauterize/variable_array.rb +56 -0
  37. data/lib/cauterize/version.rb +3 -0
  38. data/spec/base_type_spec.rb +167 -0
  39. data/spec/builders/c/buildable_spec.rb +25 -0
  40. data/spec/builders/c/composite_spec.rb +46 -0
  41. data/spec/builders/c/enumeration_spec.rb +32 -0
  42. data/spec/builders/c/fixed_array_spec.rb +36 -0
  43. data/spec/builders/c/group_spec.rb +112 -0
  44. data/spec/builders/c/scalar_spec.rb +8 -0
  45. data/spec/builders/c/variable_array_spec.rb +50 -0
  46. data/spec/builders_spec.rb +51 -0
  47. data/spec/c_builder_spec.rb +133 -0
  48. data/spec/cauterize_spec.rb +8 -0
  49. data/spec/composite_spec.rb +62 -0
  50. data/spec/enumeration_spec.rb +104 -0
  51. data/spec/fixed_array_spec.rb +62 -0
  52. data/spec/group_spec.rb +104 -0
  53. data/spec/scalar_spec.rb +36 -0
  54. data/spec/spec_helper.rb +115 -0
  55. data/spec/support/shared_examples_for_array_buildables.rb +22 -0
  56. data/spec/support/shared_examples_for_c_buildables.rb +91 -0
  57. data/spec/support/shared_examples_for_sane_c_buildables.rb +22 -0
  58. data/spec/support/shared_examples_for_stubbed_functions.rb +18 -0
  59. data/spec/test_main.c +13 -0
  60. data/spec/variable_array_spec.rb +92 -0
  61. 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
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ script: bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cauterize.gemspec
4
+ gemspec
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 */