nokogiri 1.13.6 → 1.16.7

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