why-hpricot 0.6.201

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 (46) hide show
  1. data/CHANGELOG +62 -0
  2. data/COPYING +18 -0
  3. data/README +284 -0
  4. data/Rakefile +259 -0
  5. data/ext/fast_xs/FastXsService.java +1018 -0
  6. data/ext/fast_xs/extconf.rb +4 -0
  7. data/ext/fast_xs/fast_xs.c +200 -0
  8. data/ext/hpricot_scan/HpricotScanService.java +1305 -0
  9. data/ext/hpricot_scan/extconf.rb +6 -0
  10. data/ext/hpricot_scan/hpricot_common.rl +76 -0
  11. data/ext/hpricot_scan/hpricot_css.c +3506 -0
  12. data/ext/hpricot_scan/hpricot_scan.c +6679 -0
  13. data/ext/hpricot_scan/hpricot_scan.h +79 -0
  14. data/ext/hpricot_scan/hpricot_scan.java.rl +373 -0
  15. data/ext/hpricot_scan/hpricot_scan.rl +697 -0
  16. data/extras/mingw-rbconfig.rb +176 -0
  17. data/lib/hpricot.rb +26 -0
  18. data/lib/hpricot/blankslate.rb +63 -0
  19. data/lib/hpricot/builder.rb +215 -0
  20. data/lib/hpricot/elements.rb +510 -0
  21. data/lib/hpricot/htmlinfo.rb +691 -0
  22. data/lib/hpricot/inspect.rb +103 -0
  23. data/lib/hpricot/modules.rb +38 -0
  24. data/lib/hpricot/parse.rb +38 -0
  25. data/lib/hpricot/tag.rb +198 -0
  26. data/lib/hpricot/tags.rb +164 -0
  27. data/lib/hpricot/traverse.rb +838 -0
  28. data/lib/hpricot/xchar.rb +94 -0
  29. data/test/files/basic.xhtml +17 -0
  30. data/test/files/boingboing.html +2266 -0
  31. data/test/files/cy0.html +3653 -0
  32. data/test/files/immob.html +400 -0
  33. data/test/files/pace_application.html +1320 -0
  34. data/test/files/tenderlove.html +16 -0
  35. data/test/files/uswebgen.html +220 -0
  36. data/test/files/utf8.html +1054 -0
  37. data/test/files/week9.html +1723 -0
  38. data/test/files/why.xml +19 -0
  39. data/test/load_files.rb +7 -0
  40. data/test/test_alter.rb +77 -0
  41. data/test/test_builder.rb +37 -0
  42. data/test/test_parser.rb +400 -0
  43. data/test/test_paths.rb +25 -0
  44. data/test/test_preserved.rb +66 -0
  45. data/test/test_xml.rb +28 -0
  46. metadata +107 -0
@@ -0,0 +1,697 @@
1
+ /*
2
+ * hpricot_scan.rl
3
+ *
4
+ * $Author: why $
5
+ * $Date: 2006-05-08 22:03:50 -0600 (Mon, 08 May 2006) $
6
+ *
7
+ * Copyright (C) 2006 why the lucky stiff
8
+ */
9
+ #include <ruby.h>
10
+
11
+ #ifndef RARRAY_LEN
12
+ #define RARRAY_LEN(arr) RARRAY(arr)->len
13
+ #define RSTRING_LEN(str) RSTRING(str)->len
14
+ #define RSTRING_PTR(str) RSTRING(str)->ptr
15
+ #endif
16
+
17
+ VALUE hpricot_css(VALUE, VALUE, VALUE, VALUE, VALUE);
18
+
19
+ #define NO_WAY_SERIOUSLY "*** This should not happen, please send a bug report with the HTML you're parsing to why@whytheluckystiff.net. So sorry!"
20
+
21
+ static VALUE sym_xmldecl, sym_doctype, sym_procins, sym_stag, sym_etag, sym_emptytag, sym_comment,
22
+ sym_cdata, sym_text, sym_EMPTY, sym_CDATA;
23
+ static VALUE mHpricot, rb_eHpricotParseError;
24
+ static VALUE cBaseEle, cBogusETag, cCData, cComment, cDoc, cDocType, cElem, cETag, cText,
25
+ cXMLDecl, cProcIns, symAllow, symDeny;
26
+ static ID s_ElementContent;
27
+ static ID s_downcase, s_new, s_parent, s_read, s_to_str;
28
+ static ID iv_parent;
29
+ static VALUE reProcInsParse;
30
+
31
+ typedef struct {
32
+ int name;
33
+ VALUE tag, attr, etag, raw, EC;
34
+ VALUE parent, children;
35
+ } hpricot_ele;
36
+
37
+ #define OPT(opts, key) (!NIL_P(opts) && RTEST(rb_hash_aref(opts, ID2SYM(rb_intern("" # key)))))
38
+
39
+ #define ELE(N) \
40
+ if (te > ts || text == 1) { \
41
+ char *raw = NULL; \
42
+ int rawlen = 0; \
43
+ ele_open = 0; text = 0; \
44
+ if (ts != 0 && sym_##N != sym_cdata && sym_##N != sym_text && sym_##N != sym_procins && sym_##N != sym_comment) { \
45
+ raw = ts; rawlen = te - ts; \
46
+ } \
47
+ if (rb_block_given_p()) { \
48
+ VALUE raw_string = Qnil; \
49
+ if (raw != NULL) raw_string = rb_str_new(raw, rawlen); \
50
+ rb_yield_tokens(sym_##N, tag, attr, Qnil, taint); \
51
+ } else \
52
+ rb_hpricot_token(S, sym_##N, tag, attr, raw, rawlen, taint); \
53
+ }
54
+
55
+ #define SET(N, E) \
56
+ if (mark_##N == NULL || E == mark_##N) \
57
+ N = rb_str_new2(""); \
58
+ else if (E > mark_##N) \
59
+ N = rb_str_new(mark_##N, E - mark_##N);
60
+
61
+ #define CAT(N, E) if (NIL_P(N)) { SET(N, E); } else { rb_str_cat(N, mark_##N, E - mark_##N); }
62
+
63
+ #define SLIDE(N) if ( mark_##N > ts ) mark_##N = buf + (mark_##N - ts);
64
+
65
+ #define ATTR(K, V) \
66
+ if (!NIL_P(K)) { \
67
+ if (NIL_P(attr)) attr = rb_hash_new(); \
68
+ rb_hash_aset(attr, K, V); \
69
+ }
70
+
71
+ #define TEXT_PASS() \
72
+ if (text == 0) \
73
+ { \
74
+ if (ele_open == 1) { \
75
+ ele_open = 0; \
76
+ if (ts > 0) { \
77
+ mark_tag = ts; \
78
+ } \
79
+ } else { \
80
+ mark_tag = p; \
81
+ } \
82
+ attr = Qnil; \
83
+ tag = Qnil; \
84
+ text = 1; \
85
+ }
86
+
87
+ #define EBLK(N, T) CAT(tag, p - T + 1); ELE(N);
88
+
89
+ %%{
90
+ machine hpricot_scan;
91
+
92
+ action newEle {
93
+ if (text == 1) {
94
+ CAT(tag, p);
95
+ ELE(text);
96
+ text = 0;
97
+ }
98
+ attr = Qnil;
99
+ tag = Qnil;
100
+ mark_tag = NULL;
101
+ ele_open = 1;
102
+ }
103
+
104
+ action _tag { mark_tag = p; }
105
+ action _aval { mark_aval = p; }
106
+ action _akey { mark_akey = p; }
107
+ action tag { SET(tag, p); }
108
+ action tagc { SET(tag, p-1); }
109
+ action aval { SET(aval, p); }
110
+ action aunq {
111
+ if (*(p-1) == '"' || *(p-1) == '\'') { SET(aval, p-1); }
112
+ else { SET(aval, p); }
113
+ }
114
+ action akey { SET(akey, p); }
115
+ action xmlver { SET(aval, p); ATTR(ID2SYM(rb_intern("version")), aval); }
116
+ action xmlenc { SET(aval, p); ATTR(ID2SYM(rb_intern("encoding")), aval); }
117
+ action xmlsd { SET(aval, p); ATTR(ID2SYM(rb_intern("standalone")), aval); }
118
+ action pubid { SET(aval, p); ATTR(ID2SYM(rb_intern("public_id")), aval); }
119
+ action sysid { SET(aval, p); ATTR(ID2SYM(rb_intern("system_id")), aval); }
120
+
121
+ action new_attr {
122
+ akey = Qnil;
123
+ aval = Qnil;
124
+ mark_akey = NULL;
125
+ mark_aval = NULL;
126
+ }
127
+
128
+ action save_attr {
129
+ ATTR(akey, aval);
130
+ }
131
+
132
+ include hpricot_common "hpricot_common.rl";
133
+
134
+ }%%
135
+
136
+ %% write data nofinal;
137
+
138
+ #define BUFSIZE 16384
139
+
140
+ void rb_yield_tokens(VALUE sym, VALUE tag, VALUE attr, VALUE raw, int taint)
141
+ {
142
+ VALUE ary;
143
+ if (sym == sym_text) {
144
+ raw = tag;
145
+ }
146
+ ary = rb_ary_new3(4, sym, tag, attr, raw);
147
+ if (taint) {
148
+ OBJ_TAINT(ary);
149
+ OBJ_TAINT(tag);
150
+ OBJ_TAINT(attr);
151
+ OBJ_TAINT(raw);
152
+ }
153
+ rb_yield(ary);
154
+ }
155
+
156
+ static void
157
+ rb_hpricot_add(VALUE focus, VALUE ele)
158
+ {
159
+ hpricot_ele *he, *he2;
160
+ Data_Get_Struct(focus, hpricot_ele, he);
161
+ Data_Get_Struct(ele, hpricot_ele, he2);
162
+ if (NIL_P(he->children))
163
+ he->children = rb_ary_new();
164
+ rb_ary_push(he->children, ele);
165
+ he2->parent = focus;
166
+ }
167
+
168
+ typedef struct {
169
+ VALUE doc;
170
+ VALUE focus;
171
+ VALUE last;
172
+ VALUE EC;
173
+ unsigned char xml, strict, fixup;
174
+ } hpricot_state;
175
+
176
+ static void
177
+ hpricot_ele_mark(hpricot_ele *he)
178
+ {
179
+ rb_gc_mark(he->tag);
180
+ rb_gc_mark(he->attr);
181
+ rb_gc_mark(he->etag);
182
+ rb_gc_mark(he->raw);
183
+ rb_gc_mark(he->parent);
184
+ rb_gc_mark(he->children);
185
+ }
186
+
187
+ static void
188
+ hpricot_ele_free(hpricot_ele *he)
189
+ {
190
+ free(he);
191
+ }
192
+
193
+ #define H_PROP(prop) \
194
+ static VALUE hpricot_ele_set_##prop(VALUE self, VALUE x) { \
195
+ hpricot_ele *he; \
196
+ Data_Get_Struct(self, hpricot_ele, he); \
197
+ he->prop = x; \
198
+ return self; \
199
+ } \
200
+ static VALUE hpricot_ele_get_##prop(VALUE self) { \
201
+ hpricot_ele *he; \
202
+ Data_Get_Struct(self, hpricot_ele, he); \
203
+ return he->prop; \
204
+ }
205
+
206
+ #define H_ATTR(prop) \
207
+ static VALUE hpricot_ele_set_##prop(VALUE self, VALUE x) { \
208
+ hpricot_ele *he; \
209
+ Data_Get_Struct(self, hpricot_ele, he); \
210
+ rb_hash_aset(he->attr, ID2SYM(rb_intern("" # prop)), x); \
211
+ return self; \
212
+ } \
213
+ static VALUE hpricot_ele_get_##prop(VALUE self) { \
214
+ hpricot_ele *he; \
215
+ Data_Get_Struct(self, hpricot_ele, he); \
216
+ return rb_hash_aref(he->attr, ID2SYM(rb_intern("" # prop))); \
217
+ }
218
+
219
+ H_PROP(tag);
220
+ H_PROP(attr);
221
+ H_PROP(etag);
222
+ H_PROP(parent);
223
+ H_PROP(children);
224
+ H_ATTR(encoding);
225
+ H_ATTR(version);
226
+ H_ATTR(standalone);
227
+ H_ATTR(system_id);
228
+ H_ATTR(public_id);
229
+
230
+ static VALUE
231
+ hpricot_ele_get_raw(VALUE self, VALUE x) {
232
+ hpricot_ele *he;
233
+ Data_Get_Struct(self, hpricot_ele, he);
234
+ return he->raw;
235
+ }
236
+
237
+ static VALUE
238
+ hpricot_ele_clear_raw(VALUE self)
239
+ {
240
+ hpricot_ele *he;
241
+ Data_Get_Struct(self, hpricot_ele, he);
242
+ he->raw = Qnil;
243
+ return Qtrue;
244
+ }
245
+
246
+ #define H_ELE(klass) \
247
+ hpricot_ele *he = ALLOC(hpricot_ele); \
248
+ he->name = 0; \
249
+ he->tag = tag; \
250
+ he->attr = attr; \
251
+ he->raw = Qnil; \
252
+ he->EC = ec; \
253
+ he->etag = he->parent = he->children = Qnil; \
254
+ if (raw != NULL && (sym == sym_emptytag || sym == sym_stag || sym == sym_etag || sym == sym_doctype)) { \
255
+ he->raw = rb_str_new(raw, rawlen); \
256
+ } \
257
+ ele = Data_Wrap_Struct(klass, hpricot_ele_mark, hpricot_ele_free, he); \
258
+ S->last = ele
259
+
260
+ VALUE
261
+ hpricot_ele_alloc(VALUE klass)
262
+ {
263
+ VALUE ele;
264
+ hpricot_ele *he = ALLOC(hpricot_ele);
265
+ he->name = 0;
266
+ he->tag = he->attr = he->raw = he->EC = Qnil;
267
+ he->etag = he->parent = he->children = Qnil;
268
+ ele = Data_Wrap_Struct(klass, hpricot_ele_mark, hpricot_ele_free, he);
269
+ return ele;
270
+ }
271
+
272
+ //
273
+ // the swift, compact parser logic. most of the complicated stuff is done
274
+ // in the lexer. this step just pairs up the start and end tags.
275
+ //
276
+ VALUE
277
+ rb_hpricot_token(hpricot_state *S, VALUE sym, VALUE tag, VALUE attr, char *raw, int rawlen, int taint)
278
+ {
279
+ VALUE ele, ec = Qnil;
280
+
281
+ //
282
+ // in html mode, fix up start tags incorrectly formed as empty tags
283
+ //
284
+ if (!S->xml) {
285
+ hpricot_ele *last;
286
+ Data_Get_Struct(S->focus, hpricot_ele, last);
287
+ if (last->EC == sym_CDATA &&
288
+ (sym != sym_procins && sym != sym_comment && sym != sym_cdata && sym != sym_text) &&
289
+ !(sym == sym_etag && rb_str_hash(tag) == last->name))
290
+ {
291
+ sym = sym_text;
292
+ tag = rb_str_new(raw, rawlen);
293
+ }
294
+
295
+ if (sym == sym_emptytag || sym == sym_stag || sym == sym_etag) {
296
+ ec = rb_hash_aref(S->EC, tag);
297
+ if (NIL_P(ec)) {
298
+ tag = rb_funcall(tag, s_downcase, 0);
299
+ ec = rb_hash_aref(S->EC, tag);
300
+ }
301
+ if (sym == sym_emptytag) {
302
+ if (ec != sym_EMPTY)
303
+ sym = sym_stag;
304
+ } else if (sym == sym_stag) {
305
+ if (ec == sym_EMPTY)
306
+ sym = sym_emptytag;
307
+ }
308
+ }
309
+ }
310
+
311
+ if (sym == sym_emptytag || sym == sym_stag) {
312
+ H_ELE(cElem);
313
+ he->name = rb_str_hash(tag);
314
+
315
+ if (!S->xml) {
316
+ VALUE match = Qnil, e = S->focus;
317
+ while (e != S->doc)
318
+ {
319
+ hpricot_ele *hee;
320
+ Data_Get_Struct(e, hpricot_ele, hee);
321
+
322
+ if (TYPE(hee->EC) == T_HASH)
323
+ {
324
+ VALUE has = rb_hash_lookup(hee->EC, INT2NUM(he->name));
325
+ if (has != Qnil) {
326
+ if (has == Qtrue) {
327
+ if (match == Qnil)
328
+ match = e;
329
+ } else if (has == symAllow) {
330
+ match = S->focus;
331
+ } else if (has == symDeny) {
332
+ match = Qnil;
333
+ }
334
+ }
335
+ }
336
+
337
+ e = hee->parent;
338
+ }
339
+
340
+ if (match == Qnil)
341
+ match = S->focus;
342
+ S->focus = match;
343
+ }
344
+
345
+ rb_hpricot_add(S->focus, ele);
346
+
347
+ //
348
+ // in the case of a start tag that should be empty, just
349
+ // skip the step that focuses the element. focusing moves
350
+ // us deeper into the document.
351
+ //
352
+ if (sym == sym_stag) {
353
+ if (S->xml || ec != sym_EMPTY) {
354
+ S->focus = ele;
355
+ S->last = Qnil;
356
+ }
357
+ }
358
+ } else if (sym == sym_etag) {
359
+ int name;
360
+ VALUE match = Qnil, e = S->focus;
361
+ if (S->strict) {
362
+ if (NIL_P(rb_hash_aref(S->EC, tag))) {
363
+ tag = rb_str_new2("div");
364
+ }
365
+ }
366
+
367
+ //
368
+ // another optimization will be to improve this very simple
369
+ // O(n) tag search, where n is the depth of the focused tag.
370
+ //
371
+ // (see also: the search above for fixups)
372
+ //
373
+ name = rb_str_hash(tag);
374
+ while (e != S->doc)
375
+ {
376
+ hpricot_ele *he;
377
+ Data_Get_Struct(e, hpricot_ele, he);
378
+
379
+ if (he->name == name)
380
+ {
381
+ match = e;
382
+ break;
383
+ }
384
+
385
+ e = he->parent;
386
+ }
387
+
388
+ if (NIL_P(match))
389
+ {
390
+ H_ELE(cBogusETag);
391
+ rb_hpricot_add(S->focus, ele);
392
+ }
393
+ else
394
+ {
395
+ H_ELE(cETag);
396
+ Data_Get_Struct(match, hpricot_ele, he);
397
+ he->etag = ele;
398
+ S->focus = he->parent;
399
+ S->last = Qnil;
400
+ }
401
+ } else if (sym == sym_cdata) {
402
+ H_ELE(cCData);
403
+ rb_hpricot_add(S->focus, ele);
404
+ } else if (sym == sym_comment) {
405
+ H_ELE(cComment);
406
+ rb_hpricot_add(S->focus, ele);
407
+ } else if (sym == sym_doctype) {
408
+ H_ELE(cDocType);
409
+ if (S->strict) {
410
+ rb_hash_aset(attr, ID2SYM(rb_intern("system_id")), rb_str_new2("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"));
411
+ rb_hash_aset(attr, ID2SYM(rb_intern("public_id")), rb_str_new2("-//W3C//DTD XHTML 1.0 Strict//EN"));
412
+ }
413
+ rb_hpricot_add(S->focus, ele);
414
+ } else if (sym == sym_procins) {
415
+ VALUE match = rb_funcall(tag, rb_intern("match"), 1, reProcInsParse);
416
+ tag = rb_reg_nth_match(1, match);
417
+ attr = rb_reg_nth_match(2, match);
418
+ H_ELE(cProcIns);
419
+ rb_hpricot_add(S->focus, ele);
420
+ } else if (sym == sym_text) {
421
+ // TODO: add raw_string as well?
422
+ if (!NIL_P(S->last) && RBASIC(S->last)->klass == cText) {
423
+ hpricot_ele *he;
424
+ Data_Get_Struct(S->last, hpricot_ele, he);
425
+ rb_str_append(he->tag, tag);
426
+ } else {
427
+ H_ELE(cText);
428
+ rb_hpricot_add(S->focus, ele);
429
+ }
430
+ } else if (sym == sym_xmldecl) {
431
+ H_ELE(cXMLDecl);
432
+ rb_hpricot_add(S->focus, ele);
433
+ }
434
+ }
435
+
436
+ VALUE hpricot_scan(int argc, VALUE *argv, VALUE self)
437
+ {
438
+ int cs, act, have = 0, nread = 0, curline = 1, text = 0;
439
+ char *ts = 0, *te = 0, *buf = NULL, *eof = NULL;
440
+
441
+ hpricot_state *S = NULL;
442
+ VALUE port, opts;
443
+ VALUE attr = Qnil, tag = Qnil, akey = Qnil, aval = Qnil, bufsize = Qnil;
444
+ char *mark_tag = 0, *mark_akey = 0, *mark_aval = 0;
445
+ int done = 0, ele_open = 0, buffer_size = 0, taint = 0;
446
+
447
+ rb_scan_args(argc, argv, "11", &port, &opts);
448
+ taint = OBJ_TAINTED( port );
449
+ if ( !rb_respond_to( port, s_read ) )
450
+ {
451
+ if ( rb_respond_to( port, s_to_str ) )
452
+ {
453
+ port = rb_funcall( port, s_to_str, 0 );
454
+ StringValue(port);
455
+ }
456
+ else
457
+ {
458
+ rb_raise(rb_eArgError, "an Hpricot document must be built from an input source (a String or IO object.)");
459
+ }
460
+ }
461
+
462
+ if (TYPE(opts) != T_HASH)
463
+ opts = Qnil;
464
+
465
+ if (!rb_block_given_p())
466
+ {
467
+ S = ALLOC(hpricot_state);
468
+ hpricot_ele *he = ALLOC(hpricot_ele);
469
+ MEMZERO(he, hpricot_ele, 1);
470
+ he->tag = he->attr = he->etag = he->parent = he->children = Qnil;
471
+ S->doc = Data_Wrap_Struct(cDoc, hpricot_ele_mark, hpricot_ele_free, he);
472
+ rb_gc_register_address(&S->doc);
473
+ S->focus = S->doc;
474
+ S->last = Qnil;
475
+ S->xml = OPT(opts, xml);
476
+ S->strict = OPT(opts, xhtml_strict);
477
+ S->fixup = OPT(opts, fixup_tags);
478
+ if (S->strict) S->fixup = 1;
479
+ rb_ivar_set(S->doc, rb_intern("@options"), opts);
480
+
481
+ S->EC = rb_const_get(mHpricot, s_ElementContent);
482
+ }
483
+
484
+ buffer_size = BUFSIZE;
485
+ if (rb_ivar_defined(self, rb_intern("@buffer_size")) == Qtrue) {
486
+ bufsize = rb_ivar_get(self, rb_intern("@buffer_size"));
487
+ if (!NIL_P(bufsize)) {
488
+ buffer_size = NUM2INT(bufsize);
489
+ }
490
+ }
491
+ buf = ALLOC_N(char, buffer_size);
492
+
493
+ %% write init;
494
+
495
+ while ( !done ) {
496
+ VALUE str;
497
+ char *p, *pe;
498
+ int len, space = buffer_size - have, tokstart_diff, tokend_diff, mark_tag_diff, mark_akey_diff, mark_aval_diff;
499
+
500
+ if ( space == 0 ) {
501
+ /* We've used up the entire buffer storing an already-parsed token
502
+ * prefix that must be preserved. Likely caused by super-long attributes.
503
+ * Increase buffer size and continue */
504
+ tokstart_diff = ts - buf;
505
+ tokend_diff = te - buf;
506
+ mark_tag_diff = mark_tag - buf;
507
+ mark_akey_diff = mark_akey - buf;
508
+ mark_aval_diff = mark_aval - buf;
509
+
510
+ buffer_size += BUFSIZE;
511
+ buf = REALLOC_N(buf, char, buffer_size);
512
+
513
+ space = buffer_size - have;
514
+
515
+ ts= buf + tokstart_diff;
516
+ te = buf + tokend_diff;
517
+ mark_tag = buf + mark_tag_diff;
518
+ mark_akey = buf + mark_akey_diff;
519
+ mark_aval = buf + mark_aval_diff;
520
+ }
521
+ p = buf + have;
522
+
523
+ if ( rb_respond_to( port, s_read ) )
524
+ {
525
+ str = rb_funcall( port, s_read, 1, INT2FIX(space) );
526
+ }
527
+ else
528
+ {
529
+ str = rb_str_substr( port, nread, space );
530
+ }
531
+
532
+ StringValue(str);
533
+ memcpy( p, RSTRING_PTR(str), RSTRING_LEN(str) );
534
+ len = RSTRING_LEN(str);
535
+ nread += len;
536
+
537
+ /* If this is the last buffer, tack on an EOF. */
538
+ if ( len < space ) {
539
+ p[len++] = 0;
540
+ done = 1;
541
+ }
542
+
543
+ pe = p + len;
544
+ %% write exec;
545
+
546
+ if ( cs == hpricot_scan_error ) {
547
+ free(buf);
548
+ if ( !NIL_P(tag) )
549
+ {
550
+ rb_raise(rb_eHpricotParseError, "parse error on element <%s>, starting on line %d.\n" NO_WAY_SERIOUSLY, RSTRING_PTR(tag), curline);
551
+ }
552
+ else
553
+ {
554
+ rb_raise(rb_eHpricotParseError, "parse error on line %d.\n" NO_WAY_SERIOUSLY, curline);
555
+ }
556
+ }
557
+
558
+ if ( done && ele_open )
559
+ {
560
+ ele_open = 0;
561
+ if (ts > 0) {
562
+ mark_tag = ts;
563
+ ts = 0;
564
+ text = 1;
565
+ }
566
+ }
567
+
568
+ if ( ts == 0 )
569
+ {
570
+ have = 0;
571
+ /* text nodes have no ts because each byte is parsed alone */
572
+ if ( mark_tag != NULL && text == 1 )
573
+ {
574
+ if (done)
575
+ {
576
+ if (mark_tag < p-1)
577
+ {
578
+ CAT(tag, p-1);
579
+ ELE(text);
580
+ }
581
+ }
582
+ else
583
+ {
584
+ CAT(tag, p);
585
+ }
586
+ }
587
+ mark_tag = buf;
588
+ }
589
+ else
590
+ {
591
+ have = pe - ts;
592
+ memmove( buf, ts, have );
593
+ SLIDE(tag);
594
+ SLIDE(akey);
595
+ SLIDE(aval);
596
+ te = buf + (te - ts);
597
+ ts = buf;
598
+ }
599
+ }
600
+ free(buf);
601
+
602
+ if (S != NULL)
603
+ {
604
+ VALUE doc = S->doc;
605
+ rb_gc_unregister_address(&S->doc);
606
+ free(S);
607
+ return doc;
608
+ }
609
+
610
+ return Qnil;
611
+ }
612
+
613
+ void Init_hpricot_scan()
614
+ {
615
+ mHpricot = rb_define_module("Hpricot");
616
+ rb_define_attr(rb_singleton_class(mHpricot), "buffer_size", 1, 1);
617
+ rb_define_singleton_method(mHpricot, "scan", hpricot_scan, -1);
618
+ rb_define_singleton_method(mHpricot, "css", hpricot_css, 3);
619
+ rb_eHpricotParseError = rb_define_class_under(mHpricot, "ParseError", rb_eStandardError);
620
+
621
+ cDoc = rb_define_class_under(mHpricot, "Doc", rb_cObject);
622
+ rb_define_alloc_func(cDoc, hpricot_ele_alloc);
623
+ rb_define_method(cDoc, "children", hpricot_ele_get_children, 0);
624
+ rb_define_method(cDoc, "children=", hpricot_ele_set_children, 1);
625
+
626
+ cBaseEle = rb_define_class_under(mHpricot, "BaseEle", rb_cObject);
627
+ rb_define_alloc_func(cBaseEle, hpricot_ele_alloc);
628
+ rb_define_method(cBaseEle, "raw_string", hpricot_ele_get_raw, 0);
629
+ rb_define_method(cBaseEle, "clear_raw", hpricot_ele_clear_raw, 0);
630
+ rb_define_method(cBaseEle, "parent", hpricot_ele_get_parent, 0);
631
+ rb_define_method(cBaseEle, "parent=", hpricot_ele_set_parent, 1);
632
+ cCData = rb_define_class_under(mHpricot, "CData", cBaseEle);
633
+ rb_define_method(cCData, "content", hpricot_ele_get_tag, 0);
634
+ rb_define_method(cCData, "content=", hpricot_ele_set_tag, 1);
635
+ cComment = rb_define_class_under(mHpricot, "Comment", cBaseEle);
636
+ rb_define_method(cComment, "content", hpricot_ele_get_tag, 0);
637
+ rb_define_method(cComment, "content=", hpricot_ele_set_tag, 1);
638
+ cDocType = rb_define_class_under(mHpricot, "DocType", cBaseEle);
639
+ rb_define_method(cDocType, "target", hpricot_ele_get_tag, 0);
640
+ rb_define_method(cDocType, "target=", hpricot_ele_set_tag, 1);
641
+ rb_define_method(cDocType, "public_id", hpricot_ele_get_public_id, 0);
642
+ rb_define_method(cDocType, "public_id=", hpricot_ele_set_public_id, 1);
643
+ rb_define_method(cDocType, "system_id", hpricot_ele_get_system_id, 0);
644
+ rb_define_method(cDocType, "system_id=", hpricot_ele_set_system_id, 1);
645
+ cElem = rb_define_class_under(mHpricot, "Elem", cBaseEle);
646
+ rb_define_method(cElem, "raw_attributes", hpricot_ele_get_attr, 0);
647
+ rb_define_method(cElem, "raw_attributes=", hpricot_ele_set_attr, 1);
648
+ rb_define_method(cElem, "children", hpricot_ele_get_children, 0);
649
+ rb_define_method(cElem, "children=", hpricot_ele_set_children, 1);
650
+ rb_define_method(cElem, "etag", hpricot_ele_get_etag, 0);
651
+ rb_define_method(cElem, "etag=", hpricot_ele_set_etag, 1);
652
+ rb_define_method(cElem, "name", hpricot_ele_get_tag, 0);
653
+ rb_define_method(cElem, "name=", hpricot_ele_set_tag, 1);
654
+ cETag = rb_define_class_under(mHpricot, "ETag", cBaseEle);
655
+ rb_define_method(cETag, "name", hpricot_ele_get_tag, 0);
656
+ rb_define_method(cETag, "name=", hpricot_ele_set_tag, 1);
657
+ cBogusETag = rb_define_class_under(mHpricot, "BogusETag", cETag);
658
+ cText = rb_define_class_under(mHpricot, "Text", cBaseEle);
659
+ rb_define_method(cText, "content", hpricot_ele_get_tag, 0);
660
+ rb_define_method(cText, "content=", hpricot_ele_set_tag, 1);
661
+ cXMLDecl = rb_define_class_under(mHpricot, "XMLDecl", cBaseEle);
662
+ rb_define_method(cXMLDecl, "encoding", hpricot_ele_get_encoding, 0);
663
+ rb_define_method(cXMLDecl, "encoding=", hpricot_ele_set_encoding, 1);
664
+ rb_define_method(cXMLDecl, "standalone", hpricot_ele_get_standalone, 0);
665
+ rb_define_method(cXMLDecl, "standalone=", hpricot_ele_set_standalone, 1);
666
+ rb_define_method(cXMLDecl, "version", hpricot_ele_get_version, 0);
667
+ rb_define_method(cXMLDecl, "version=", hpricot_ele_set_version, 1);
668
+ cProcIns = rb_define_class_under(mHpricot, "ProcIns", cBaseEle);
669
+ rb_define_method(cProcIns, "target", hpricot_ele_get_tag, 0);
670
+ rb_define_method(cProcIns, "target=", hpricot_ele_set_tag, 1);
671
+ rb_define_method(cProcIns, "content", hpricot_ele_get_attr, 0);
672
+ rb_define_method(cProcIns, "content=", hpricot_ele_set_attr, 1);
673
+
674
+ s_ElementContent = rb_intern("ElementContent");
675
+ symAllow = ID2SYM(rb_intern("allow"));
676
+ symDeny = ID2SYM(rb_intern("deny"));
677
+ s_downcase = rb_intern("downcase");
678
+ s_new = rb_intern("new");
679
+ s_parent = rb_intern("parent");
680
+ s_read = rb_intern("read");
681
+ s_to_str = rb_intern("to_str");
682
+ iv_parent = rb_intern("parent");
683
+ sym_xmldecl = ID2SYM(rb_intern("xmldecl"));
684
+ sym_doctype = ID2SYM(rb_intern("doctype"));
685
+ sym_procins = ID2SYM(rb_intern("procins"));
686
+ sym_stag = ID2SYM(rb_intern("stag"));
687
+ sym_etag = ID2SYM(rb_intern("etag"));
688
+ sym_emptytag = ID2SYM(rb_intern("emptytag"));
689
+ sym_comment = ID2SYM(rb_intern("comment"));
690
+ sym_cdata = ID2SYM(rb_intern("cdata"));
691
+ sym_text = ID2SYM(rb_intern("text"));
692
+ sym_EMPTY = ID2SYM(rb_intern("EMPTY"));
693
+ sym_CDATA = ID2SYM(rb_intern("CDATA"));
694
+
695
+ rb_const_set(mHpricot, rb_intern("ProcInsParse"),
696
+ reProcInsParse = rb_eval_string("/\\A<\\?(\\S+)\\s+(.+)/m"));
697
+ }