fast-xml 1.0.1 → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +145 -37
- data/ext/fastxml/ccan/build_assert/build_assert.h +40 -0
- data/ext/fastxml/ccan/check_type/check_type.h +63 -0
- data/ext/fastxml/ccan/container_of/container_of.h +142 -0
- data/ext/fastxml/ccan/list/list.h +773 -0
- data/ext/fastxml/ccan/str/str.h +16 -0
- data/ext/fastxml/fastxml.c +35 -2
- data/ext/fastxml/xh.c +19 -8
- data/ext/fastxml/xh.h +2 -1
- data/ext/fastxml/xh_config.h +3 -0
- data/ext/fastxml/xh_core.h +1 -5
- data/ext/fastxml/xh_log.h +37 -27
- data/ext/fastxml/xh_param.c +3 -11
- data/ext/fastxml/xh_param.h +1 -1
- data/ext/fastxml/xh_reader.c +528 -0
- data/ext/fastxml/xh_reader.h +43 -0
- data/ext/fastxml/xh_ruby_hash.h +384 -0
- data/ext/fastxml/xh_x2h.c +1002 -0
- data/ext/fastxml/xh_x2h.h +133 -0
- data/lib/fastxml/version.rb +1 -1
- metadata +13 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bfc552fd27d382d26a930254300930396aed5da
|
4
|
+
data.tar.gz: f960e2a0cd0b2c38ad983ca497a1ef0664422929
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 958ee82a61a7d887f72dc89db46cc928a322012406ed816b368a03a0f35106ca6b6104e482d4deaa214ce66f7c471d4b15d267d03957b2da083693056309ac5a
|
7
|
+
data.tar.gz: 3629dd0432f31eb23ef46fed569a942cf0f01749c33a2684109aa677d56442110d46264aac0bfa0250fdc63113eea3f95c6bd626a5cefd3c5b66b5afa734176f
|
data/README.md
CHANGED
@@ -26,10 +26,11 @@ See [CHANGELOG.md](CHANGELOG.md)
|
|
26
26
|
|
27
27
|
## Usage
|
28
28
|
|
29
|
+
### Convert hash toXML
|
30
|
+
|
29
31
|
```ruby
|
30
32
|
require 'fastxml'
|
31
33
|
|
32
|
-
# convert hash to XML
|
33
34
|
FastXML.hash2xml({ tag1: { tag2: 'content' } }, indent: 2)
|
34
35
|
# =>
|
35
36
|
# <?xml version="1.0" encoding="utf-8"?>
|
@@ -60,83 +61,191 @@ fh.string
|
|
60
61
|
# <enumerator>1</enumerator>
|
61
62
|
# <enumerator>2</enumerator>
|
62
63
|
# </root>
|
64
|
+
```
|
63
65
|
|
66
|
+
### Convert XML to hash
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b attr="bbb">bbb2</b></root>')
|
70
|
+
# => {"a"=>["aaa", "aaa2"], "b"=>{"attr"=>"bbb", "content"=>"bbb2"}}
|
71
|
+
|
72
|
+
# use filter
|
73
|
+
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: '/root/a') do |node|
|
74
|
+
p node
|
75
|
+
end
|
76
|
+
# =>
|
77
|
+
# {"a"=>"aaa"}
|
78
|
+
# {"a"=>"aaa2"}
|
64
79
|
```
|
65
80
|
|
66
81
|
## Options
|
67
82
|
|
68
83
|
The following options are available to pass to FastXML.hash2xml(hash, options = {}).
|
69
84
|
|
70
|
-
* **:root
|
85
|
+
* **:root => 'root' # hash2xml**
|
71
86
|
* Root node name.
|
72
87
|
|
73
|
-
* **:version
|
88
|
+
* **:version => '1.0' # hash2xml**
|
74
89
|
* XML document version
|
75
90
|
|
76
|
-
* **:encoding
|
91
|
+
* **:encoding => 'utf-8' # hash2xml + xml2hash**
|
77
92
|
* XML input/output encoding
|
78
93
|
|
79
|
-
* **:indent
|
80
|
-
* if indent great than
|
94
|
+
* **:indent => 0 # hash2xml**
|
95
|
+
* if indent great than **0**, XML output should be indented according to
|
81
96
|
its hierarchic structure. This value determines the number of
|
82
97
|
spaces.
|
83
98
|
|
84
|
-
* if indent is
|
99
|
+
* if indent is **0**, XML output will all be on one line.
|
85
100
|
|
86
|
-
* **:output
|
101
|
+
* **:output => nil # hash2xml**
|
87
102
|
* XML output method
|
88
103
|
|
89
|
-
* if output is nil
|
104
|
+
* if output is **nil**, XML document dumped into string.
|
90
105
|
|
91
106
|
* if output is filehandle, XML document writes directly to a filehandle or a
|
92
107
|
stream.
|
93
108
|
|
94
|
-
* **:canonical
|
95
|
-
* if canonical is
|
109
|
+
* **:canonical => false # hash2xml**
|
110
|
+
* if canonical is **true**, the converter will be write hashes sorted by key.
|
111
|
+
|
112
|
+
* if canonical is **false**, the order of the element will be pseudo-randomly.
|
113
|
+
|
114
|
+
* **:use_attr => false # hash2xml**
|
115
|
+
* if use_attr is **true**, the converter will be use the attributes.
|
116
|
+
|
117
|
+
* if use_attr is **fale**, the converter will be use tags only.
|
118
|
+
|
119
|
+
* **:content => 'content' # hash2xml + xml2hash**
|
120
|
+
* The key name for the text content.
|
121
|
+
|
122
|
+
* **:force_array => nil # xml2hash**
|
123
|
+
* When this option is **true**, the converter will be to force nested elements
|
124
|
+
to be represented as arrays even when there is only one.
|
125
|
+
|
126
|
+
```FastXML.xml2hash('<root><a>aaa</a></root>', force_array: true)```
|
127
|
+
|
128
|
+
will be converted to:
|
129
|
+
|
130
|
+
```{ "a" => ["aaa"] }```
|
131
|
+
|
132
|
+
instead of:
|
133
|
+
|
134
|
+
```{ "a" => "aaa" }```
|
135
|
+
|
136
|
+
* When this option is an array, this allows to specify a list of element
|
137
|
+
names which should always be forced into an array representation,
|
138
|
+
rather than the 'all or nothing' approach above.
|
139
|
+
|
140
|
+
```FastXML.xml2hash('<root><a>aaa</a><b>bbb</b></root>', force_array: ['a'])```
|
141
|
+
|
142
|
+
will be converted to:
|
143
|
+
|
144
|
+
```{ "a" => ["aaa"], "b" => "bbb" }```
|
145
|
+
|
146
|
+
```FastXML.xml2hash('<root><a>aaa</a><a2>aaa</a2><b>bbb</b></root>', force_array: [/^a/])```
|
147
|
+
|
148
|
+
will be converted to:
|
149
|
+
|
150
|
+
```{ "a" => ["aaa"], "a2" => ["aaa"], "b" => "bbb" }```
|
151
|
+
|
152
|
+
* **:force_content => false # xml2hash**
|
153
|
+
* When this options is **true**, this allows you to force text content to always
|
154
|
+
convert to a hash value.
|
155
|
+
|
156
|
+
```FastXML.xml2hash('<root><a>value</a></root>', force_content: true)```
|
96
157
|
|
97
|
-
|
158
|
+
will be converted to:
|
98
159
|
|
99
|
-
|
100
|
-
* if use_attr is "true", converter will be use the attributes.
|
160
|
+
```{ "a" => { "content" => "value" } }```
|
101
161
|
|
102
|
-
|
162
|
+
instead of:
|
103
163
|
|
104
|
-
|
105
|
-
* if defined that the key name for the text content(used only if
|
106
|
-
use_attr = true).
|
164
|
+
```{ "a" => "value" }```
|
107
165
|
|
108
|
-
* **:
|
109
|
-
*
|
110
|
-
(https://metacpan.org/pod/XML::Simple#ForceArray-1-in---important).
|
166
|
+
* **:merge_text => false # xml2hash**
|
167
|
+
* Setting this option to **true** will cause merge adjacent text nodes.
|
111
168
|
|
112
|
-
|
113
|
-
* This option is similar to "ForceContent" from [XMl::Simple module]:
|
114
|
-
(https://metacpan.org/pod/XML::Simple#ForceContent-1-in---seldom-used).
|
169
|
+
```FastXML.xml2hash('<root>value1<!-- comment -->value2</root>', merge_text: true)```
|
115
170
|
|
116
|
-
|
117
|
-
* Setting this option to "true" will cause merge adjacent text nodes.
|
171
|
+
will be converted to:
|
118
172
|
|
119
|
-
|
120
|
-
* if xml_decl is "true", output will start with the XML declaration
|
121
|
-
'<?xml version="1.0" encoding="utf-8"?>'.
|
173
|
+
```"value1value2"```
|
122
174
|
|
123
|
-
|
175
|
+
instead of:
|
124
176
|
|
125
|
-
|
177
|
+
```["value1", "value2"]```
|
178
|
+
|
179
|
+
* **:xml_decl => true # hash2xml**
|
180
|
+
* if xml_decl is **true**, output will start with the XML declaration
|
181
|
+
```<?xml version="1.0" encoding="utf-8"?>```
|
182
|
+
|
183
|
+
* if xml_decl is **false**, XML declaration will not be output.
|
184
|
+
|
185
|
+
* **:trim => false # hash2xml + xml2hash**
|
126
186
|
* Trim leading and trailing whitespace from text nodes.
|
127
187
|
|
128
|
-
* **:utf8
|
129
|
-
* Turn on utf8 flag for strings if
|
188
|
+
* **:utf8 => true # hash2xml + xml2hash**
|
189
|
+
* Turn on utf8 flag for strings if is **true**.
|
130
190
|
|
131
|
-
* **:max_depth
|
191
|
+
* **:max_depth => 1024 # xml2hash**
|
132
192
|
* Maximum recursion depth.
|
133
193
|
|
134
|
-
* **:buf_size
|
194
|
+
* **:buf_size => 4096 # hash2xml + xml2hash**
|
135
195
|
* Buffer size for reading end encoding data.
|
136
196
|
|
137
|
-
* **:keep_root
|
197
|
+
* **:keep_root => false # xml2hash**
|
138
198
|
* Keep root element.
|
139
199
|
|
200
|
+
```FastXML.xml2hash('<root>value1</root>', keep_root: true)```
|
201
|
+
|
202
|
+
will be converted to:
|
203
|
+
|
204
|
+
```{ "root" => "value1" }```
|
205
|
+
|
206
|
+
instead of:
|
207
|
+
|
208
|
+
```"value1"```
|
209
|
+
|
210
|
+
* **:filter => nil # xml2hash**
|
211
|
+
* Filter nodes matched by pattern and return an array of nodes.
|
212
|
+
|
213
|
+
```FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: '/root/a')```
|
214
|
+
|
215
|
+
will be converted to:
|
216
|
+
|
217
|
+
```[{ "a" => "aaa" }, { "a" => "aaa2" }]```
|
218
|
+
|
219
|
+
```FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: /a|b/)```
|
220
|
+
|
221
|
+
will be converted to:
|
222
|
+
|
223
|
+
```[{ "a" => "aaa" }, { "a" => "aaa2" }, { "b" => "bbb" }]```
|
224
|
+
|
225
|
+
```FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: ['/root/a', '/root/b'])```
|
226
|
+
|
227
|
+
will be converted to:
|
228
|
+
|
229
|
+
```[{ "a" => "aaa" }, { "a" => "aaa2" }, { "b" => "bbb" }]```
|
230
|
+
|
231
|
+
* You can pass a block as parameter.
|
232
|
+
|
233
|
+
```
|
234
|
+
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: '/root/a') do |node|
|
235
|
+
p node
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
will be printed:
|
240
|
+
|
241
|
+
```
|
242
|
+
{"a"=>"aaa"}
|
243
|
+
{"a"=>"aaa2"}
|
244
|
+
```
|
245
|
+
|
246
|
+
It may be used to parse large XML because does not require a lot of
|
247
|
+
memory.
|
248
|
+
|
140
249
|
## Configuration
|
141
250
|
```
|
142
251
|
FastXML.configure do |config|
|
@@ -161,4 +270,3 @@ fastxml 0.010000 0.000000 0.010000 ( 0.018434)
|
|
161
270
|
## License
|
162
271
|
|
163
272
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
164
|
-
|
@@ -0,0 +1,40 @@
|
|
1
|
+
/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
|
2
|
+
#ifndef CCAN_BUILD_ASSERT_H
|
3
|
+
#define CCAN_BUILD_ASSERT_H
|
4
|
+
|
5
|
+
/**
|
6
|
+
* BUILD_ASSERT - assert a build-time dependency.
|
7
|
+
* @cond: the compile-time condition which must be true.
|
8
|
+
*
|
9
|
+
* Your compile will fail if the condition isn't true, or can't be evaluated
|
10
|
+
* by the compiler. This can only be used within a function.
|
11
|
+
*
|
12
|
+
* Example:
|
13
|
+
* #include <stddef.h>
|
14
|
+
* ...
|
15
|
+
* static char *foo_to_char(struct foo *foo)
|
16
|
+
* {
|
17
|
+
* // This code needs string to be at start of foo.
|
18
|
+
* BUILD_ASSERT(offsetof(struct foo, string) == 0);
|
19
|
+
* return (char *)foo;
|
20
|
+
* }
|
21
|
+
*/
|
22
|
+
#define BUILD_ASSERT(cond) \
|
23
|
+
do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
|
24
|
+
|
25
|
+
/**
|
26
|
+
* BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
|
27
|
+
* @cond: the compile-time condition which must be true.
|
28
|
+
*
|
29
|
+
* Your compile will fail if the condition isn't true, or can't be evaluated
|
30
|
+
* by the compiler. This can be used in an expression: its value is "0".
|
31
|
+
*
|
32
|
+
* Example:
|
33
|
+
* #define foo_to_char(foo) \
|
34
|
+
* ((char *)(foo) \
|
35
|
+
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
|
36
|
+
*/
|
37
|
+
#define BUILD_ASSERT_OR_ZERO(cond) \
|
38
|
+
(sizeof(char [1 - 2*!(cond)]) - 1)
|
39
|
+
|
40
|
+
#endif /* CCAN_BUILD_ASSERT_H */
|
@@ -0,0 +1,63 @@
|
|
1
|
+
/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
|
2
|
+
#ifndef CCAN_CHECK_TYPE_H
|
3
|
+
#define CCAN_CHECK_TYPE_H
|
4
|
+
|
5
|
+
/**
|
6
|
+
* check_type - issue a warning or build failure if type is not correct.
|
7
|
+
* @expr: the expression whose type we should check (not evaluated).
|
8
|
+
* @type: the exact type we expect the expression to be.
|
9
|
+
*
|
10
|
+
* This macro is usually used within other macros to try to ensure that a macro
|
11
|
+
* argument is of the expected type. No type promotion of the expression is
|
12
|
+
* done: an unsigned int is not the same as an int!
|
13
|
+
*
|
14
|
+
* check_type() always evaluates to 0.
|
15
|
+
*
|
16
|
+
* If your compiler does not support typeof, then the best we can do is fail
|
17
|
+
* to compile if the sizes of the types are unequal (a less complete check).
|
18
|
+
*
|
19
|
+
* Example:
|
20
|
+
* // They should always pass a 64-bit value to _set_some_value!
|
21
|
+
* #define set_some_value(expr) \
|
22
|
+
* _set_some_value((check_type((expr), uint64_t), (expr)))
|
23
|
+
*/
|
24
|
+
|
25
|
+
/**
|
26
|
+
* check_types_match - issue a warning or build failure if types are not same.
|
27
|
+
* @expr1: the first expression (not evaluated).
|
28
|
+
* @expr2: the second expression (not evaluated).
|
29
|
+
*
|
30
|
+
* This macro is usually used within other macros to try to ensure that
|
31
|
+
* arguments are of identical types. No type promotion of the expressions is
|
32
|
+
* done: an unsigned int is not the same as an int!
|
33
|
+
*
|
34
|
+
* check_types_match() always evaluates to 0.
|
35
|
+
*
|
36
|
+
* If your compiler does not support typeof, then the best we can do is fail
|
37
|
+
* to compile if the sizes of the types are unequal (a less complete check).
|
38
|
+
*
|
39
|
+
* Example:
|
40
|
+
* // Do subtraction to get to enclosing type, but make sure that
|
41
|
+
* // pointer is of correct type for that member.
|
42
|
+
* #define container_of(mbr_ptr, encl_type, mbr) \
|
43
|
+
* (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
|
44
|
+
* ((encl_type *) \
|
45
|
+
* ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
|
46
|
+
*/
|
47
|
+
#if HAVE_TYPEOF
|
48
|
+
#define check_type(expr, type) \
|
49
|
+
((typeof(expr) *)0 != (type *)0)
|
50
|
+
|
51
|
+
#define check_types_match(expr1, expr2) \
|
52
|
+
((typeof(expr1) *)0 != (typeof(expr2) *)0)
|
53
|
+
#else
|
54
|
+
#include "ccan/build_assert/build_assert.h"
|
55
|
+
/* Without typeof, we can only test the sizes. */
|
56
|
+
#define check_type(expr, type) \
|
57
|
+
BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
|
58
|
+
|
59
|
+
#define check_types_match(expr1, expr2) \
|
60
|
+
BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
|
61
|
+
#endif /* HAVE_TYPEOF */
|
62
|
+
|
63
|
+
#endif /* CCAN_CHECK_TYPE_H */
|
@@ -0,0 +1,142 @@
|
|
1
|
+
/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
|
2
|
+
#ifndef CCAN_CONTAINER_OF_H
|
3
|
+
#define CCAN_CONTAINER_OF_H
|
4
|
+
#include "ccan/check_type/check_type.h"
|
5
|
+
|
6
|
+
/**
|
7
|
+
* container_of - get pointer to enclosing structure
|
8
|
+
* @member_ptr: pointer to the structure member
|
9
|
+
* @containing_type: the type this member is within
|
10
|
+
* @member: the name of this member within the structure.
|
11
|
+
*
|
12
|
+
* Given a pointer to a member of a structure, this macro does pointer
|
13
|
+
* subtraction to return the pointer to the enclosing type.
|
14
|
+
*
|
15
|
+
* Example:
|
16
|
+
* struct foo {
|
17
|
+
* int fielda, fieldb;
|
18
|
+
* // ...
|
19
|
+
* };
|
20
|
+
* struct info {
|
21
|
+
* int some_other_field;
|
22
|
+
* struct foo my_foo;
|
23
|
+
* };
|
24
|
+
*
|
25
|
+
* static struct info *foo_to_info(struct foo *foo)
|
26
|
+
* {
|
27
|
+
* return container_of(foo, struct info, my_foo);
|
28
|
+
* }
|
29
|
+
*/
|
30
|
+
#define container_of(member_ptr, containing_type, member) \
|
31
|
+
((containing_type *) \
|
32
|
+
((char *)(member_ptr) \
|
33
|
+
- container_off(containing_type, member)) \
|
34
|
+
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
35
|
+
|
36
|
+
|
37
|
+
/**
|
38
|
+
* container_of_or_null - get pointer to enclosing structure, or NULL
|
39
|
+
* @member_ptr: pointer to the structure member
|
40
|
+
* @containing_type: the type this member is within
|
41
|
+
* @member: the name of this member within the structure.
|
42
|
+
*
|
43
|
+
* Given a pointer to a member of a structure, this macro does pointer
|
44
|
+
* subtraction to return the pointer to the enclosing type, unless it
|
45
|
+
* is given NULL, in which case it also returns NULL.
|
46
|
+
*
|
47
|
+
* Example:
|
48
|
+
* struct foo {
|
49
|
+
* int fielda, fieldb;
|
50
|
+
* // ...
|
51
|
+
* };
|
52
|
+
* struct info {
|
53
|
+
* int some_other_field;
|
54
|
+
* struct foo my_foo;
|
55
|
+
* };
|
56
|
+
*
|
57
|
+
* static struct info *foo_to_info_allowing_null(struct foo *foo)
|
58
|
+
* {
|
59
|
+
* return container_of_or_null(foo, struct info, my_foo);
|
60
|
+
* }
|
61
|
+
*/
|
62
|
+
static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
63
|
+
{
|
64
|
+
return member_ptr ? (char *)member_ptr - offset : NULL;
|
65
|
+
}
|
66
|
+
#define container_of_or_null(member_ptr, containing_type, member) \
|
67
|
+
((containing_type *) \
|
68
|
+
container_of_or_null_(member_ptr, \
|
69
|
+
container_off(containing_type, member)) \
|
70
|
+
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
71
|
+
|
72
|
+
/**
|
73
|
+
* container_off - get offset to enclosing structure
|
74
|
+
* @containing_type: the type this member is within
|
75
|
+
* @member: the name of this member within the structure.
|
76
|
+
*
|
77
|
+
* Given a pointer to a member of a structure, this macro does
|
78
|
+
* typechecking and figures out the offset to the enclosing type.
|
79
|
+
*
|
80
|
+
* Example:
|
81
|
+
* struct foo {
|
82
|
+
* int fielda, fieldb;
|
83
|
+
* // ...
|
84
|
+
* };
|
85
|
+
* struct info {
|
86
|
+
* int some_other_field;
|
87
|
+
* struct foo my_foo;
|
88
|
+
* };
|
89
|
+
*
|
90
|
+
* static struct info *foo_to_info(struct foo *foo)
|
91
|
+
* {
|
92
|
+
* size_t off = container_off(struct info, my_foo);
|
93
|
+
* return (void *)((char *)foo - off);
|
94
|
+
* }
|
95
|
+
*/
|
96
|
+
#define container_off(containing_type, member) \
|
97
|
+
offsetof(containing_type, member)
|
98
|
+
|
99
|
+
/**
|
100
|
+
* container_of_var - get pointer to enclosing structure using a variable
|
101
|
+
* @member_ptr: pointer to the structure member
|
102
|
+
* @container_var: a pointer of same type as this member's container
|
103
|
+
* @member: the name of this member within the structure.
|
104
|
+
*
|
105
|
+
* Given a pointer to a member of a structure, this macro does pointer
|
106
|
+
* subtraction to return the pointer to the enclosing type.
|
107
|
+
*
|
108
|
+
* Example:
|
109
|
+
* static struct info *foo_to_i(struct foo *foo)
|
110
|
+
* {
|
111
|
+
* struct info *i = container_of_var(foo, i, my_foo);
|
112
|
+
* return i;
|
113
|
+
* }
|
114
|
+
*/
|
115
|
+
#if HAVE_TYPEOF
|
116
|
+
#define container_of_var(member_ptr, container_var, member) \
|
117
|
+
container_of(member_ptr, typeof(*container_var), member)
|
118
|
+
#else
|
119
|
+
#define container_of_var(member_ptr, container_var, member) \
|
120
|
+
((void *)((char *)(member_ptr) - \
|
121
|
+
container_off_var(container_var, member)))
|
122
|
+
#endif
|
123
|
+
|
124
|
+
/**
|
125
|
+
* container_off_var - get offset of a field in enclosing structure
|
126
|
+
* @container_var: a pointer to a container structure
|
127
|
+
* @member: the name of a member within the structure.
|
128
|
+
*
|
129
|
+
* Given (any) pointer to a structure and a its member name, this
|
130
|
+
* macro does pointer subtraction to return offset of member in a
|
131
|
+
* structure memory layout.
|
132
|
+
*
|
133
|
+
*/
|
134
|
+
#if HAVE_TYPEOF
|
135
|
+
#define container_off_var(var, member) \
|
136
|
+
container_off(typeof(*var), member)
|
137
|
+
#else
|
138
|
+
#define container_off_var(var, member) \
|
139
|
+
((const char *)&(var)->member - (const char *)(var))
|
140
|
+
#endif
|
141
|
+
|
142
|
+
#endif /* CCAN_CONTAINER_OF_H */
|