nokogiri 1.10.7 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (224) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +42 -0
  3. data/LICENSE-DEPENDENCIES.md +1632 -1022
  4. data/LICENSE.md +1 -1
  5. data/README.md +188 -96
  6. data/bin/nokogiri +63 -50
  7. data/dependencies.yml +34 -66
  8. data/ext/nokogiri/depend +38 -358
  9. data/ext/nokogiri/extconf.rb +862 -421
  10. data/ext/nokogiri/gumbo.c +594 -0
  11. data/ext/nokogiri/html4_document.c +165 -0
  12. data/ext/nokogiri/html4_element_description.c +299 -0
  13. data/ext/nokogiri/html4_entity_lookup.c +37 -0
  14. data/ext/nokogiri/html4_sax_parser_context.c +108 -0
  15. data/ext/nokogiri/html4_sax_push_parser.c +95 -0
  16. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  17. data/ext/nokogiri/nokogiri.c +251 -105
  18. data/ext/nokogiri/nokogiri.h +222 -90
  19. data/ext/nokogiri/test_global_handlers.c +40 -0
  20. data/ext/nokogiri/xml_attr.c +17 -17
  21. data/ext/nokogiri/xml_attribute_decl.c +22 -22
  22. data/ext/nokogiri/xml_cdata.c +39 -31
  23. data/ext/nokogiri/xml_comment.c +20 -27
  24. data/ext/nokogiri/xml_document.c +408 -243
  25. data/ext/nokogiri/xml_document_fragment.c +13 -17
  26. data/ext/nokogiri/xml_dtd.c +64 -58
  27. data/ext/nokogiri/xml_element_content.c +63 -55
  28. data/ext/nokogiri/xml_element_decl.c +31 -31
  29. data/ext/nokogiri/xml_encoding_handler.c +54 -21
  30. data/ext/nokogiri/xml_entity_decl.c +37 -35
  31. data/ext/nokogiri/xml_entity_reference.c +17 -19
  32. data/ext/nokogiri/xml_namespace.c +131 -61
  33. data/ext/nokogiri/xml_node.c +1343 -674
  34. data/ext/nokogiri/xml_node_set.c +246 -216
  35. data/ext/nokogiri/xml_processing_instruction.c +18 -20
  36. data/ext/nokogiri/xml_reader.c +305 -213
  37. data/ext/nokogiri/xml_relax_ng.c +87 -78
  38. data/ext/nokogiri/xml_sax_parser.c +149 -124
  39. data/ext/nokogiri/xml_sax_parser_context.c +149 -103
  40. data/ext/nokogiri/xml_sax_push_parser.c +65 -37
  41. data/ext/nokogiri/xml_schema.c +138 -82
  42. data/ext/nokogiri/xml_syntax_error.c +42 -21
  43. data/ext/nokogiri/xml_text.c +35 -26
  44. data/ext/nokogiri/xml_xpath_context.c +363 -178
  45. data/ext/nokogiri/xslt_stylesheet.c +335 -189
  46. data/gumbo-parser/CHANGES.md +63 -0
  47. data/gumbo-parser/Makefile +126 -0
  48. data/gumbo-parser/THANKS +27 -0
  49. data/gumbo-parser/src/Makefile +34 -0
  50. data/gumbo-parser/src/README.md +41 -0
  51. data/gumbo-parser/src/ascii.c +75 -0
  52. data/gumbo-parser/src/ascii.h +115 -0
  53. data/gumbo-parser/src/attribute.c +42 -0
  54. data/gumbo-parser/src/attribute.h +17 -0
  55. data/gumbo-parser/src/char_ref.c +22225 -0
  56. data/gumbo-parser/src/char_ref.h +29 -0
  57. data/gumbo-parser/src/char_ref.rl +2154 -0
  58. data/gumbo-parser/src/error.c +630 -0
  59. data/gumbo-parser/src/error.h +148 -0
  60. data/gumbo-parser/src/foreign_attrs.c +103 -0
  61. data/gumbo-parser/src/foreign_attrs.gperf +27 -0
  62. data/gumbo-parser/src/insertion_mode.h +33 -0
  63. data/gumbo-parser/src/macros.h +91 -0
  64. data/gumbo-parser/src/nokogiri_gumbo.h +944 -0
  65. data/gumbo-parser/src/parser.c +4891 -0
  66. data/gumbo-parser/src/parser.h +41 -0
  67. data/gumbo-parser/src/replacement.h +33 -0
  68. data/gumbo-parser/src/string_buffer.c +103 -0
  69. data/gumbo-parser/src/string_buffer.h +68 -0
  70. data/gumbo-parser/src/string_piece.c +48 -0
  71. data/gumbo-parser/src/svg_attrs.c +174 -0
  72. data/gumbo-parser/src/svg_attrs.gperf +77 -0
  73. data/gumbo-parser/src/svg_tags.c +137 -0
  74. data/gumbo-parser/src/svg_tags.gperf +55 -0
  75. data/gumbo-parser/src/tag.c +223 -0
  76. data/gumbo-parser/src/tag_lookup.c +382 -0
  77. data/gumbo-parser/src/tag_lookup.gperf +170 -0
  78. data/gumbo-parser/src/tag_lookup.h +13 -0
  79. data/gumbo-parser/src/token_buffer.c +79 -0
  80. data/gumbo-parser/src/token_buffer.h +71 -0
  81. data/gumbo-parser/src/token_type.h +17 -0
  82. data/gumbo-parser/src/tokenizer.c +3464 -0
  83. data/gumbo-parser/src/tokenizer.h +112 -0
  84. data/gumbo-parser/src/tokenizer_states.h +339 -0
  85. data/gumbo-parser/src/utf8.c +245 -0
  86. data/gumbo-parser/src/utf8.h +164 -0
  87. data/gumbo-parser/src/util.c +66 -0
  88. data/gumbo-parser/src/util.h +34 -0
  89. data/gumbo-parser/src/vector.c +111 -0
  90. data/gumbo-parser/src/vector.h +45 -0
  91. data/lib/nokogiri/class_resolver.rb +67 -0
  92. data/lib/nokogiri/css/node.rb +10 -8
  93. data/lib/nokogiri/css/parser.rb +397 -377
  94. data/lib/nokogiri/css/parser.y +250 -245
  95. data/lib/nokogiri/css/parser_extras.rb +54 -49
  96. data/lib/nokogiri/css/syntax_error.rb +3 -1
  97. data/lib/nokogiri/css/tokenizer.rb +5 -3
  98. data/lib/nokogiri/css/tokenizer.rex +3 -2
  99. data/lib/nokogiri/css/xpath_visitor.rb +205 -96
  100. data/lib/nokogiri/css.rb +56 -17
  101. data/lib/nokogiri/decorators/slop.rb +9 -7
  102. data/lib/nokogiri/encoding_handler.rb +57 -0
  103. data/lib/nokogiri/extension.rb +32 -0
  104. data/lib/nokogiri/gumbo.rb +15 -0
  105. data/lib/nokogiri/html.rb +38 -27
  106. data/lib/nokogiri/{html → html4}/builder.rb +4 -2
  107. data/lib/nokogiri/html4/document.rb +214 -0
  108. data/lib/nokogiri/html4/document_fragment.rb +54 -0
  109. data/lib/nokogiri/{html → html4}/element_description.rb +3 -1
  110. data/lib/nokogiri/html4/element_description_defaults.rb +2040 -0
  111. data/lib/nokogiri/html4/encoding_reader.rb +121 -0
  112. data/lib/nokogiri/{html → html4}/entity_lookup.rb +4 -2
  113. data/lib/nokogiri/{html → html4}/sax/parser.rb +17 -16
  114. data/lib/nokogiri/html4/sax/parser_context.rb +20 -0
  115. data/lib/nokogiri/{html → html4}/sax/push_parser.rb +12 -11
  116. data/lib/nokogiri/html4.rb +47 -0
  117. data/lib/nokogiri/html5/document.rb +168 -0
  118. data/lib/nokogiri/html5/document_fragment.rb +90 -0
  119. data/lib/nokogiri/html5/node.rb +103 -0
  120. data/lib/nokogiri/html5.rb +326 -0
  121. data/lib/nokogiri/jruby/dependencies.rb +3 -0
  122. data/lib/nokogiri/jruby/nokogiri_jars.rb +43 -0
  123. data/lib/nokogiri/syntax_error.rb +2 -0
  124. data/lib/nokogiri/version/constant.rb +6 -0
  125. data/lib/nokogiri/version/info.rb +224 -0
  126. data/lib/nokogiri/version.rb +3 -108
  127. data/lib/nokogiri/xml/attr.rb +55 -3
  128. data/lib/nokogiri/xml/attribute_decl.rb +6 -2
  129. data/lib/nokogiri/xml/builder.rb +75 -34
  130. data/lib/nokogiri/xml/cdata.rb +3 -1
  131. data/lib/nokogiri/xml/character_data.rb +2 -0
  132. data/lib/nokogiri/xml/document.rb +312 -127
  133. data/lib/nokogiri/xml/document_fragment.rb +93 -48
  134. data/lib/nokogiri/xml/dtd.rb +4 -2
  135. data/lib/nokogiri/xml/element_content.rb +12 -2
  136. data/lib/nokogiri/xml/element_decl.rb +6 -2
  137. data/lib/nokogiri/xml/entity_decl.rb +7 -3
  138. data/lib/nokogiri/xml/entity_reference.rb +2 -0
  139. data/lib/nokogiri/xml/namespace.rb +44 -0
  140. data/lib/nokogiri/xml/node/save_options.rb +23 -8
  141. data/lib/nokogiri/xml/node.rb +1096 -419
  142. data/lib/nokogiri/xml/node_set.rb +137 -61
  143. data/lib/nokogiri/xml/notation.rb +13 -0
  144. data/lib/nokogiri/xml/parse_options.rb +145 -52
  145. data/lib/nokogiri/xml/pp/character_data.rb +9 -6
  146. data/lib/nokogiri/xml/pp/node.rb +42 -30
  147. data/lib/nokogiri/xml/pp.rb +4 -2
  148. data/lib/nokogiri/xml/processing_instruction.rb +4 -1
  149. data/lib/nokogiri/xml/reader.rb +21 -28
  150. data/lib/nokogiri/xml/relax_ng.rb +8 -2
  151. data/lib/nokogiri/xml/sax/document.rb +45 -49
  152. data/lib/nokogiri/xml/sax/parser.rb +39 -36
  153. data/lib/nokogiri/xml/sax/parser_context.rb +8 -3
  154. data/lib/nokogiri/xml/sax/push_parser.rb +6 -5
  155. data/lib/nokogiri/xml/sax.rb +6 -4
  156. data/lib/nokogiri/xml/schema.rb +19 -9
  157. data/lib/nokogiri/xml/searchable.rb +120 -72
  158. data/lib/nokogiri/xml/syntax_error.rb +7 -5
  159. data/lib/nokogiri/xml/text.rb +2 -0
  160. data/lib/nokogiri/xml/xpath/syntax_error.rb +4 -2
  161. data/lib/nokogiri/xml/xpath.rb +15 -4
  162. data/lib/nokogiri/xml/xpath_context.rb +3 -3
  163. data/lib/nokogiri/xml.rb +39 -38
  164. data/lib/nokogiri/xslt/stylesheet.rb +3 -1
  165. data/lib/nokogiri/xslt.rb +101 -22
  166. data/lib/nokogiri.rb +59 -75
  167. data/lib/xsd/xmlparser/nokogiri.rb +29 -25
  168. data/patches/libxml2/{0004-libxml2.la-is-in-top_builddir.patch → 0003-libxml2.la-is-in-top_builddir.patch} +1 -1
  169. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  170. data/patches/libxml2/0010-update-config.guess-and-config.sub-for-libxml2.patch +224 -0
  171. data/patches/libxml2/0011-rip-out-libxml2-s-libc_single_threaded-support.patch +30 -0
  172. data/patches/libxslt/0001-update-config.guess-and-config.sub-for-libxslt.patch +224 -0
  173. data/ports/archives/libxml2-2.12.3.tar.xz +0 -0
  174. data/ports/archives/libxslt-1.1.39.tar.xz +0 -0
  175. metadata +121 -291
  176. data/ext/nokogiri/html_document.c +0 -170
  177. data/ext/nokogiri/html_document.h +0 -10
  178. data/ext/nokogiri/html_element_description.c +0 -279
  179. data/ext/nokogiri/html_element_description.h +0 -10
  180. data/ext/nokogiri/html_entity_lookup.c +0 -32
  181. data/ext/nokogiri/html_entity_lookup.h +0 -8
  182. data/ext/nokogiri/html_sax_parser_context.c +0 -116
  183. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  184. data/ext/nokogiri/html_sax_push_parser.c +0 -87
  185. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  186. data/ext/nokogiri/xml_attr.h +0 -9
  187. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  188. data/ext/nokogiri/xml_cdata.h +0 -9
  189. data/ext/nokogiri/xml_comment.h +0 -9
  190. data/ext/nokogiri/xml_document.h +0 -23
  191. data/ext/nokogiri/xml_document_fragment.h +0 -10
  192. data/ext/nokogiri/xml_dtd.h +0 -10
  193. data/ext/nokogiri/xml_element_content.h +0 -10
  194. data/ext/nokogiri/xml_element_decl.h +0 -9
  195. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  196. data/ext/nokogiri/xml_entity_decl.h +0 -10
  197. data/ext/nokogiri/xml_entity_reference.h +0 -9
  198. data/ext/nokogiri/xml_io.c +0 -61
  199. data/ext/nokogiri/xml_io.h +0 -11
  200. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  201. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  202. data/ext/nokogiri/xml_namespace.h +0 -14
  203. data/ext/nokogiri/xml_node.h +0 -13
  204. data/ext/nokogiri/xml_node_set.h +0 -12
  205. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  206. data/ext/nokogiri/xml_reader.h +0 -10
  207. data/ext/nokogiri/xml_relax_ng.h +0 -9
  208. data/ext/nokogiri/xml_sax_parser.h +0 -39
  209. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  210. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  211. data/ext/nokogiri/xml_schema.h +0 -9
  212. data/ext/nokogiri/xml_syntax_error.h +0 -13
  213. data/ext/nokogiri/xml_text.h +0 -9
  214. data/ext/nokogiri/xml_xpath_context.h +0 -10
  215. data/ext/nokogiri/xslt_stylesheet.h +0 -14
  216. data/lib/nokogiri/html/document.rb +0 -335
  217. data/lib/nokogiri/html/document_fragment.rb +0 -49
  218. data/lib/nokogiri/html/element_description_defaults.rb +0 -671
  219. data/lib/nokogiri/html/sax/parser_context.rb +0 -16
  220. data/patches/libxml2/0001-Revert-Do-not-URI-escape-in-server-side-includes.patch +0 -78
  221. data/ports/archives/libxml2-2.9.10.tar.gz +0 -0
  222. data/ports/archives/libxslt-1.1.34.tar.gz +0 -0
  223. /data/patches/libxml2/{0002-Remove-script-macro-support.patch → 0001-Remove-script-macro-support.patch} +0 -0
  224. /data/patches/libxml2/{0003-Update-entities-to-remove-handling-of-ssi.patch → 0002-Update-entities-to-remove-handling-of-ssi.patch} +0 -0
@@ -1,298 +1,483 @@
1
- #include <xml_xpath_context.h>
1
+ #include <nokogiri.h>
2
2
 
3
- int vasprintf (char **strp, const char *fmt, va_list ap);
3
+ VALUE cNokogiriXmlXpathContext;
4
+
5
+ /*
6
+ * these constants have matching declarations in
7
+ * ext/java/nokogiri/internals/NokogiriNamespaceContext.java
8
+ */
9
+ static const xmlChar *NOKOGIRI_PREFIX = (const xmlChar *)"nokogiri";
10
+ static const xmlChar *NOKOGIRI_URI = (const xmlChar *)"http://www.nokogiri.org/default_ns/ruby/extensions_functions";
11
+ static const xmlChar *NOKOGIRI_BUILTIN_PREFIX = (const xmlChar *)"nokogiri-builtin";
12
+ static const xmlChar *NOKOGIRI_BUILTIN_URI = (const xmlChar *)"https://www.nokogiri.org/default_ns/ruby/builtins";
4
13
 
5
- static void deallocate(xmlXPathContextPtr ctx)
14
+ static void
15
+ xml_xpath_context_deallocate(void *data)
6
16
  {
7
- NOKOGIRI_DEBUG_START(ctx);
8
- xmlXPathFreeContext(ctx);
9
- NOKOGIRI_DEBUG_END(ctx);
17
+ xmlXPathContextPtr c_context = data;
18
+ xmlXPathFreeContext(c_context);
10
19
  }
11
20
 
21
+ static const rb_data_type_t xml_xpath_context_type = {
22
+ .wrap_struct_name = "Nokogiri::XML::XPathContext",
23
+ .function = {
24
+ .dfree = xml_xpath_context_deallocate,
25
+ },
26
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
27
+ };
28
+
29
+ /* find a CSS class in an HTML element's `class` attribute */
30
+ static const xmlChar *
31
+ builtin_css_class(const xmlChar *str, const xmlChar *val)
32
+ {
33
+ int val_len;
34
+
35
+ if (str == NULL) { return (NULL); }
36
+ if (val == NULL) { return (NULL); }
37
+
38
+ val_len = xmlStrlen(val);
39
+ if (val_len == 0) { return (str); }
40
+
41
+ while (*str != 0) {
42
+ if ((*str == *val) && !xmlStrncmp(str, val, val_len)) {
43
+ const xmlChar *next_byte = str + val_len;
44
+
45
+ /* only match if the next byte is whitespace or end of string */
46
+ if ((*next_byte == 0) || (IS_BLANK_CH(*next_byte))) {
47
+ return ((const xmlChar *)str);
48
+ }
49
+ }
50
+
51
+ /* advance str to whitespace */
52
+ while ((*str != 0) && !IS_BLANK_CH(*str)) {
53
+ str++;
54
+ }
55
+
56
+ /* advance str to start of next word or end of string */
57
+ while ((*str != 0) && IS_BLANK_CH(*str)) {
58
+ str++;
59
+ }
60
+ }
61
+
62
+ return (NULL);
63
+ }
64
+
65
+ /* xmlXPathFunction to wrap builtin_css_class() */
66
+ static void
67
+ xpath_builtin_css_class(xmlXPathParserContextPtr ctxt, int nargs)
68
+ {
69
+ xmlXPathObjectPtr hay, needle;
70
+
71
+ CHECK_ARITY(2);
72
+
73
+ CAST_TO_STRING;
74
+ needle = valuePop(ctxt);
75
+ if ((needle == NULL) || (needle->type != XPATH_STRING)) {
76
+ xmlXPathFreeObject(needle);
77
+ XP_ERROR(XPATH_INVALID_TYPE);
78
+ }
79
+
80
+ CAST_TO_STRING;
81
+ hay = valuePop(ctxt);
82
+ if ((hay == NULL) || (hay->type != XPATH_STRING)) {
83
+ xmlXPathFreeObject(hay);
84
+ xmlXPathFreeObject(needle);
85
+ XP_ERROR(XPATH_INVALID_TYPE);
86
+ }
87
+
88
+ if (builtin_css_class(hay->stringval, needle->stringval)) {
89
+ valuePush(ctxt, xmlXPathNewBoolean(1));
90
+ } else {
91
+ valuePush(ctxt, xmlXPathNewBoolean(0));
92
+ }
93
+
94
+ xmlXPathFreeObject(hay);
95
+ xmlXPathFreeObject(needle);
96
+ }
97
+
98
+
99
+ /* xmlXPathFunction to select nodes whose local name matches, for HTML5 CSS queries that should
100
+ * ignore namespaces */
101
+ static void
102
+ xpath_builtin_local_name_is(xmlXPathParserContextPtr ctxt, int nargs)
103
+ {
104
+ xmlXPathObjectPtr element_name;
105
+
106
+ assert(ctxt->context->node);
107
+
108
+ CHECK_ARITY(1);
109
+ CAST_TO_STRING;
110
+ CHECK_TYPE(XPATH_STRING);
111
+ element_name = valuePop(ctxt);
112
+
113
+ valuePush(
114
+ ctxt,
115
+ xmlXPathNewBoolean(xmlStrEqual(ctxt->context->node->name, element_name->stringval))
116
+ );
117
+
118
+ xmlXPathFreeObject(element_name);
119
+ }
120
+
121
+
12
122
  /*
13
123
  * call-seq:
14
- * register_ns(prefix, uri)
124
+ * register_ns(prefix, uri) → Nokogiri::XML::XPathContext
15
125
  *
16
- * Register the namespace with +prefix+ and +uri+.
126
+ * Register the namespace with +prefix+ and +uri+ for use in future queries.
127
+ *
128
+ * [Returns] +self+
17
129
  */
18
- static VALUE register_ns(VALUE self, VALUE prefix, VALUE uri)
130
+ static VALUE
131
+ rb_xml_xpath_context_register_ns(VALUE rb_context, VALUE prefix, VALUE uri)
19
132
  {
20
- xmlXPathContextPtr ctx;
21
- Data_Get_Struct(self, xmlXPathContext, ctx);
133
+ xmlXPathContextPtr c_context;
22
134
 
23
- xmlXPathRegisterNs( ctx,
24
- (const xmlChar *)StringValueCStr(prefix),
25
- (const xmlChar *)StringValueCStr(uri)
135
+ TypedData_Get_Struct(
136
+ rb_context,
137
+ xmlXPathContext,
138
+ &xml_xpath_context_type,
139
+ c_context
26
140
  );
27
- return self;
141
+
142
+ xmlXPathRegisterNs(c_context,
143
+ (const xmlChar *)StringValueCStr(prefix),
144
+ (const xmlChar *)StringValueCStr(uri)
145
+ );
146
+ return rb_context;
28
147
  }
29
148
 
30
149
  /*
31
150
  * call-seq:
32
- * register_variable(name, value)
151
+ * register_variable(name, value) → Nokogiri::XML::XPathContext
152
+ *
153
+ * Register the variable +name+ with +value+ for use in future queries.
33
154
  *
34
- * Register the variable +name+ with +value+.
155
+ * [Returns] +self+
35
156
  */
36
- static VALUE register_variable(VALUE self, VALUE name, VALUE value)
157
+ static VALUE
158
+ rb_xml_xpath_context_register_variable(VALUE rb_context, VALUE name, VALUE value)
37
159
  {
38
- xmlXPathContextPtr ctx;
39
- xmlXPathObjectPtr xmlValue;
40
- Data_Get_Struct(self, xmlXPathContext, ctx);
160
+ xmlXPathContextPtr c_context;
161
+ xmlXPathObjectPtr xmlValue;
162
+
163
+ TypedData_Get_Struct(
164
+ rb_context,
165
+ xmlXPathContext,
166
+ &xml_xpath_context_type,
167
+ c_context
168
+ );
41
169
 
42
- xmlValue = xmlXPathNewCString(StringValueCStr(value));
170
+ xmlValue = xmlXPathNewCString(StringValueCStr(value));
43
171
 
44
- xmlXPathRegisterVariable( ctx,
45
- (const xmlChar *)StringValueCStr(name),
46
- xmlValue
47
- );
172
+ xmlXPathRegisterVariable(
173
+ c_context,
174
+ (const xmlChar *)StringValueCStr(name),
175
+ xmlValue
176
+ );
48
177
 
49
- return self;
178
+ return rb_context;
50
179
  }
51
180
 
52
- void Nokogiri_marshal_xpath_funcall_and_return_values(xmlXPathParserContextPtr ctx, int nargs, VALUE handler, const char* function_name)
181
+
182
+ /*
183
+ * convert an XPath object into a Ruby object of the appropriate type.
184
+ * returns Qundef if no conversion was possible.
185
+ */
186
+ static VALUE
187
+ xpath2ruby(xmlXPathObjectPtr c_xpath_object, xmlXPathContextPtr c_context)
53
188
  {
54
- int i;
55
- VALUE result, doc;
189
+ VALUE rb_retval;
190
+
191
+ assert(c_context->doc);
192
+ assert(DOC_RUBY_OBJECT_TEST(c_context->doc));
193
+
194
+ switch (c_xpath_object->type) {
195
+ case XPATH_STRING:
196
+ rb_retval = NOKOGIRI_STR_NEW2(c_xpath_object->stringval);
197
+ xmlFree(c_xpath_object->stringval);
198
+ return rb_retval;
199
+
200
+ case XPATH_NODESET:
201
+ return noko_xml_node_set_wrap(
202
+ c_xpath_object->nodesetval,
203
+ DOC_RUBY_OBJECT(c_context->doc)
204
+ );
205
+
206
+ case XPATH_NUMBER:
207
+ return rb_float_new(c_xpath_object->floatval);
208
+
209
+ case XPATH_BOOLEAN:
210
+ return (c_xpath_object->boolval == 1) ? Qtrue : Qfalse;
211
+
212
+ default:
213
+ return Qundef;
214
+ }
215
+ }
216
+
217
+ void
218
+ Nokogiri_marshal_xpath_funcall_and_return_values(
219
+ xmlXPathParserContextPtr ctxt,
220
+ int argc,
221
+ VALUE rb_xpath_handler,
222
+ const char *method_name
223
+ )
224
+ {
225
+ VALUE rb_retval;
56
226
  VALUE *argv;
57
- VALUE node_set = Qnil;
58
- xmlNodeSetPtr xml_node_set = NULL;
59
- xmlXPathObjectPtr obj;
227
+ VALUE rb_node_set = Qnil;
228
+ xmlNodeSetPtr c_node_set = NULL;
229
+ xmlXPathObjectPtr c_xpath_object;
60
230
 
61
- assert(ctx->context->doc);
62
- assert(DOC_RUBY_OBJECT_TEST(ctx->context->doc));
231
+ assert(ctxt->context->doc);
232
+ assert(DOC_RUBY_OBJECT_TEST(ctxt->context->doc));
63
233
 
64
- argv = (VALUE *)calloc((size_t)nargs, sizeof(VALUE));
65
- for (i = 0 ; i < nargs ; ++i) {
66
- rb_gc_register_address(&argv[i]);
234
+ argv = (VALUE *)ruby_xcalloc((size_t)argc, sizeof(VALUE));
235
+ for (int j = 0 ; j < argc ; ++j) {
236
+ rb_gc_register_address(&argv[j]);
67
237
  }
68
238
 
69
- doc = DOC_RUBY_OBJECT(ctx->context->doc);
70
-
71
- if (nargs > 0) {
72
- i = nargs - 1;
73
- do {
74
- obj = valuePop(ctx);
75
- switch(obj->type) {
76
- case XPATH_STRING:
77
- argv[i] = NOKOGIRI_STR_NEW2(obj->stringval);
78
- break;
79
- case XPATH_BOOLEAN:
80
- argv[i] = obj->boolval == 1 ? Qtrue : Qfalse;
81
- break;
82
- case XPATH_NUMBER:
83
- argv[i] = rb_float_new(obj->floatval);
84
- break;
85
- case XPATH_NODESET:
86
- argv[i] = Nokogiri_wrap_xml_node_set(obj->nodesetval, doc);
87
- break;
88
- default:
89
- argv[i] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(obj));
90
- }
91
- xmlXPathFreeNodeSetList(obj);
92
- } while(i-- > 0);
239
+ for (int j = argc - 1 ; j >= 0 ; --j) {
240
+ c_xpath_object = valuePop(ctxt);
241
+ argv[j] = xpath2ruby(c_xpath_object, ctxt->context);
242
+ if (argv[j] == Qundef) {
243
+ argv[j] = NOKOGIRI_STR_NEW2(xmlXPathCastToString(c_xpath_object));
244
+ }
245
+ xmlXPathFreeNodeSetList(c_xpath_object);
93
246
  }
94
247
 
95
- result = rb_funcall2(handler, rb_intern((const char*)function_name), nargs, argv);
248
+ rb_retval = rb_funcall2(
249
+ rb_xpath_handler,
250
+ rb_intern((const char *)method_name),
251
+ argc,
252
+ argv
253
+ );
96
254
 
97
- for (i = 0 ; i < nargs ; ++i) {
98
- rb_gc_unregister_address(&argv[i]);
255
+ for (int j = 0 ; j < argc ; ++j) {
256
+ rb_gc_unregister_address(&argv[j]);
99
257
  }
100
- free(argv);
258
+ ruby_xfree(argv);
101
259
 
102
- switch(TYPE(result)) {
260
+ switch (TYPE(rb_retval)) {
103
261
  case T_FLOAT:
104
262
  case T_BIGNUM:
105
263
  case T_FIXNUM:
106
- xmlXPathReturnNumber(ctx, NUM2DBL(result));
264
+ xmlXPathReturnNumber(ctxt, NUM2DBL(rb_retval));
107
265
  break;
108
266
  case T_STRING:
109
- xmlXPathReturnString(
110
- ctx,
111
- xmlCharStrdup(StringValueCStr(result))
112
- );
267
+ xmlXPathReturnString(ctxt, xmlCharStrdup(StringValueCStr(rb_retval)));
113
268
  break;
114
269
  case T_TRUE:
115
- xmlXPathReturnTrue(ctx);
270
+ xmlXPathReturnTrue(ctxt);
116
271
  break;
117
272
  case T_FALSE:
118
- xmlXPathReturnFalse(ctx);
273
+ xmlXPathReturnFalse(ctxt);
119
274
  break;
120
275
  case T_NIL:
121
276
  break;
122
- case T_ARRAY:
123
- {
124
- VALUE args[2];
125
- args[0] = doc;
126
- args[1] = result;
127
- node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet);
128
- Data_Get_Struct(node_set, xmlNodeSet, xml_node_set);
129
- xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
130
- }
277
+ case T_ARRAY: {
278
+ VALUE construct_args[2] = { DOC_RUBY_OBJECT(ctxt->context->doc), rb_retval };
279
+ rb_node_set = rb_class_new_instance(2, construct_args, cNokogiriXmlNodeSet);
280
+ c_node_set = noko_xml_node_set_unwrap(rb_node_set);
281
+ xmlXPathReturnNodeSet(ctxt, xmlXPathNodeSetMerge(NULL, c_node_set));
282
+ }
131
283
  break;
132
284
  case T_DATA:
133
- if(rb_obj_is_kind_of(result, cNokogiriXmlNodeSet)) {
134
- Data_Get_Struct(result, xmlNodeSet, xml_node_set);
285
+ if (rb_obj_is_kind_of(rb_retval, cNokogiriXmlNodeSet)) {
286
+ c_node_set = noko_xml_node_set_unwrap(rb_retval);
135
287
  /* Copy the node set, otherwise it will get GC'd. */
136
- xmlXPathReturnNodeSet(ctx, xmlXPathNodeSetMerge(NULL, xml_node_set));
288
+ xmlXPathReturnNodeSet(ctxt, xmlXPathNodeSetMerge(NULL, c_node_set));
137
289
  break;
138
290
  }
139
291
  default:
140
292
  rb_raise(rb_eRuntimeError, "Invalid return type");
141
- }
293
+ }
142
294
  }
143
295
 
144
- static void ruby_funcall(xmlXPathParserContextPtr ctx, int nargs)
296
+ static void
297
+ method_caller(xmlXPathParserContextPtr ctxt, int argc)
145
298
  {
146
- VALUE handler = Qnil;
147
- const char *function = NULL ;
148
-
149
- assert(ctx);
150
- assert(ctx->context);
151
- assert(ctx->context->userData);
152
- assert(ctx->context->function);
153
-
154
- handler = (VALUE)(ctx->context->userData);
155
- function = (const char*)(ctx->context->function);
156
-
157
- Nokogiri_marshal_xpath_funcall_and_return_values(ctx, nargs, handler, function);
299
+ VALUE rb_xpath_handler = Qnil;
300
+ const char *method_name = NULL ;
301
+
302
+ assert(ctxt);
303
+ assert(ctxt->context);
304
+ assert(ctxt->context->userData);
305
+ assert(ctxt->context->function);
306
+
307
+ rb_xpath_handler = (VALUE)(ctxt->context->userData);
308
+ method_name = (const char *)(ctxt->context->function);
309
+
310
+ Nokogiri_marshal_xpath_funcall_and_return_values(
311
+ ctxt,
312
+ argc,
313
+ rb_xpath_handler,
314
+ method_name
315
+ );
158
316
  }
159
317
 
160
- static xmlXPathFunction lookup( void *ctx,
161
- const xmlChar * name,
162
- const xmlChar* ns_uri )
318
+ static xmlXPathFunction
319
+ handler_lookup(void *data, const xmlChar *c_name, const xmlChar *c_ns_uri)
163
320
  {
164
- VALUE xpath_handler = (VALUE)ctx;
165
- if(rb_respond_to(xpath_handler, rb_intern((const char *)name)))
166
- return ruby_funcall;
321
+ VALUE rb_handler = (VALUE)data;
322
+ if (rb_respond_to(rb_handler, rb_intern((const char *)c_name))) {
323
+ if (c_ns_uri == NULL) {
324
+ NOKO_WARN_DEPRECATION("A custom XPath or CSS handler function named '%s' is being invoked without a namespace. Please update your query to reference this function as 'nokogiri:%s'. Invoking custom handler functions without a namespace is deprecated and will become an error in Nokogiri v1.17.0.",
325
+ c_name, c_name); // deprecated in v1.15.0, remove in v1.17.0
326
+ }
327
+ return method_caller;
328
+ }
167
329
 
168
330
  return NULL;
169
331
  }
170
332
 
171
- NORETURN(static void xpath_generic_exception_handler(void * ctx, const char *msg, ...));
172
- static void xpath_generic_exception_handler(void * ctx, const char *msg, ...)
333
+ PRINTFLIKE_DECL(2, 3)
334
+ static void
335
+ generic_exception_pusher(void *data, const char *msg, ...)
173
336
  {
174
- char * message;
337
+ VALUE rb_errors = (VALUE)data;
338
+ VALUE rb_message;
339
+ VALUE rb_exception;
340
+
341
+ Check_Type(rb_errors, T_ARRAY);
175
342
 
343
+ #ifdef TRUFFLERUBY_NOKOGIRI_SYSTEM_LIBRARIES
344
+ /* It is not currently possible to pass var args from native
345
+ functions to sulong, so we work around the issue here. */
346
+ rb_message = rb_sprintf("generic_exception_pusher: %s", msg);
347
+ #else
176
348
  va_list args;
177
349
  va_start(args, msg);
178
- vasprintf(&message, msg, args);
350
+ rb_message = rb_vsprintf(msg, args);
179
351
  va_end(args);
352
+ #endif
180
353
 
181
- rb_raise(rb_eRuntimeError, "%s", message);
354
+ rb_exception = rb_exc_new_str(cNokogiriXmlXpathSyntaxError, rb_message);
355
+ rb_ary_push(rb_errors, rb_exception);
182
356
  }
183
357
 
184
358
  /*
185
359
  * call-seq:
186
- * evaluate(search_path, handler = nil)
360
+ * evaluate(search_path, handler = nil) → Object
187
361
  *
188
- * Evaluate the +search_path+ returning an XML::XPath object.
362
+ * Evaluate the +search_path+ query.
363
+ *
364
+ * [Returns] an object of the appropriate type for the query, which could be +NodeSet+, a +String+,
365
+ * a +Float+, or a boolean.
189
366
  */
190
- static VALUE evaluate(int argc, VALUE *argv, VALUE self)
367
+ static VALUE
368
+ rb_xml_xpath_context_evaluate(int argc, VALUE *argv, VALUE rb_context)
191
369
  {
192
370
  VALUE search_path, xpath_handler;
193
- VALUE thing = Qnil;
194
- xmlXPathContextPtr ctx;
371
+ VALUE retval = Qnil;
372
+ xmlXPathContextPtr c_context;
195
373
  xmlXPathObjectPtr xpath;
196
374
  xmlChar *query;
375
+ VALUE errors = rb_ary_new();
197
376
 
198
- Data_Get_Struct(self, xmlXPathContext, ctx);
377
+ TypedData_Get_Struct(
378
+ rb_context,
379
+ xmlXPathContext,
380
+ &xml_xpath_context_type,
381
+ c_context
382
+ );
199
383
 
200
- if(rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1)
384
+ if (rb_scan_args(argc, argv, "11", &search_path, &xpath_handler) == 1) {
201
385
  xpath_handler = Qnil;
386
+ }
202
387
 
203
388
  query = (xmlChar *)StringValueCStr(search_path);
204
389
 
205
- if(Qnil != xpath_handler) {
390
+ if (Qnil != xpath_handler) {
206
391
  /* FIXME: not sure if this is the correct place to shove private data. */
207
- ctx->userData = (void *)xpath_handler;
208
- xmlXPathRegisterFuncLookup(ctx, lookup, (void *)xpath_handler);
392
+ c_context->userData = (void *)xpath_handler;
393
+ xmlXPathRegisterFuncLookup(
394
+ c_context,
395
+ handler_lookup,
396
+ (void *)xpath_handler
397
+ );
209
398
  }
210
399
 
211
- xmlResetLastError();
212
- xmlSetStructuredErrorFunc(NULL, Nokogiri_error_raise);
400
+ xmlSetStructuredErrorFunc((void *)errors, Nokogiri_error_array_pusher);
401
+ xmlSetGenericErrorFunc((void *)errors, generic_exception_pusher);
213
402
 
214
- /* For some reason, xmlXPathEvalExpression will blow up with a generic error */
215
- /* when there is a non existent function. */
216
- xmlSetGenericErrorFunc(NULL, xpath_generic_exception_handler);
403
+ xpath = xmlXPathEvalExpression(query, c_context);
217
404
 
218
- xpath = xmlXPathEvalExpression(query, ctx);
219
405
  xmlSetStructuredErrorFunc(NULL, NULL);
220
406
  xmlSetGenericErrorFunc(NULL, NULL);
221
407
 
222
- if(xpath == NULL) {
223
- xmlErrorPtr error = xmlGetLastError();
224
- rb_exc_raise(Nokogiri_wrap_xml_syntax_error(error));
408
+ if (xpath == NULL) {
409
+ rb_exc_raise(rb_ary_entry(errors, 0));
225
410
  }
226
411
 
227
- assert(ctx->doc);
228
- assert(DOC_RUBY_OBJECT_TEST(ctx->doc));
229
-
230
- switch(xpath->type) {
231
- case XPATH_STRING:
232
- thing = NOKOGIRI_STR_NEW2(xpath->stringval);
233
- xmlFree(xpath->stringval);
234
- break;
235
- case XPATH_NODESET:
236
- thing = Nokogiri_wrap_xml_node_set(xpath->nodesetval,
237
- DOC_RUBY_OBJECT(ctx->doc));
238
- break;
239
- case XPATH_NUMBER:
240
- thing = rb_float_new(xpath->floatval);
241
- break;
242
- case XPATH_BOOLEAN:
243
- thing = xpath->boolval == 1 ? Qtrue : Qfalse;
244
- break;
245
- default:
246
- thing = Nokogiri_wrap_xml_node_set(NULL, DOC_RUBY_OBJECT(ctx->doc));
412
+ retval = xpath2ruby(xpath, c_context);
413
+ if (retval == Qundef) {
414
+ retval = noko_xml_node_set_wrap(NULL, DOC_RUBY_OBJECT(c_context->doc));
247
415
  }
248
416
 
249
417
  xmlXPathFreeNodeSetList(xpath);
250
418
 
251
- return thing;
419
+ return retval;
252
420
  }
253
421
 
254
422
  /*
255
423
  * call-seq:
256
- * new(node)
424
+ * new(node)
257
425
  *
258
- * Create a new XPathContext with +node+ as the reference point.
426
+ * Create a new XPathContext with +node+ as the context node.
259
427
  */
260
- static VALUE new(VALUE klass, VALUE nodeobj)
428
+ static VALUE
429
+ rb_xml_xpath_context_new(VALUE klass, VALUE rb_node)
261
430
  {
262
431
  xmlNodePtr node;
263
- xmlXPathContextPtr ctx;
264
- VALUE self;
432
+ xmlXPathContextPtr c_context;
433
+ VALUE rb_context;
265
434
 
266
- xmlXPathInit();
435
+ Noko_Node_Get_Struct(rb_node, xmlNode, node);
267
436
 
268
- Data_Get_Struct(nodeobj, xmlNode, node);
437
+ #if LIBXML_VERSION < 21000
438
+ /* deprecated in 40483d0 */
439
+ xmlXPathInit();
440
+ #endif
441
+
442
+ c_context = xmlXPathNewContext(node->doc);
443
+ c_context->node = node;
444
+
445
+ xmlXPathRegisterNs(c_context, NOKOGIRI_PREFIX, NOKOGIRI_URI);
446
+ xmlXPathRegisterNs(c_context, NOKOGIRI_BUILTIN_PREFIX, NOKOGIRI_BUILTIN_URI);
447
+ xmlXPathRegisterFuncNS(
448
+ c_context,
449
+ (const xmlChar *)"css-class",
450
+ NOKOGIRI_BUILTIN_URI,
451
+ xpath_builtin_css_class
452
+ );
453
+ xmlXPathRegisterFuncNS(
454
+ c_context,
455
+ (const xmlChar *)"local-name-is",
456
+ NOKOGIRI_BUILTIN_URI,
457
+ xpath_builtin_local_name_is
458
+ );
269
459
 
270
- ctx = xmlXPathNewContext(node->doc);
271
- ctx->node = node;
272
- self = Data_Wrap_Struct(klass, 0, deallocate, ctx);
273
- /*rb_iv_set(self, "@xpath_handler", Qnil); */
274
- return self;
460
+ rb_context = TypedData_Wrap_Struct(
461
+ klass,
462
+ &xml_xpath_context_type,
463
+ c_context
464
+ );
465
+ return rb_context;
275
466
  }
276
467
 
277
- VALUE cNokogiriXmlXpathContext;
278
- void init_xml_xpath_context(void)
468
+ void
469
+ noko_init_xml_xpath_context(void)
279
470
  {
280
- VALUE module = rb_define_module("Nokogiri");
281
-
282
471
  /*
283
- * Nokogiri::XML
472
+ * XPathContext is the entry point for searching a +Document+ by using XPath.
284
473
  */
285
- VALUE xml = rb_define_module_under(module, "XML");
474
+ cNokogiriXmlXpathContext = rb_define_class_under(mNokogiriXml, "XPathContext", rb_cObject);
286
475
 
287
- /*
288
- * XPathContext is the entry point for searching a Document by using XPath.
289
- */
290
- VALUE klass = rb_define_class_under(xml, "XPathContext", rb_cObject);
476
+ rb_undef_alloc_func(cNokogiriXmlXpathContext);
291
477
 
292
- cNokogiriXmlXpathContext = klass;
478
+ rb_define_singleton_method(cNokogiriXmlXpathContext, "new", rb_xml_xpath_context_new, 1);
293
479
 
294
- rb_define_singleton_method(klass, "new", new, 1);
295
- rb_define_method(klass, "evaluate", evaluate, -1);
296
- rb_define_method(klass, "register_variable", register_variable, 2);
297
- rb_define_method(klass, "register_ns", register_ns, 2);
480
+ rb_define_method(cNokogiriXmlXpathContext, "evaluate", rb_xml_xpath_context_evaluate, -1);
481
+ rb_define_method(cNokogiriXmlXpathContext, "register_variable", rb_xml_xpath_context_register_variable, 2);
482
+ rb_define_method(cNokogiriXmlXpathContext, "register_ns", rb_xml_xpath_context_register_ns, 2);
298
483
  }