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.
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 */