gonzui 1.2-x86-mswin32-60

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 (120) hide show
  1. data/AUTHORS.txt +9 -0
  2. data/History.txt +5539 -0
  3. data/Manifest.txt +115 -0
  4. data/PostInstall.txt +17 -0
  5. data/README.rdoc +149 -0
  6. data/Rakefile +28 -0
  7. data/bin/gonzui-db +167 -0
  8. data/bin/gonzui-import +177 -0
  9. data/bin/gonzui-remove +58 -0
  10. data/bin/gonzui-search +68 -0
  11. data/bin/gonzui-server +176 -0
  12. data/bin/gonzui-update +53 -0
  13. data/data/gonzui/catalog/catalog.ja +80 -0
  14. data/data/gonzui/doc/favicon.ico +0 -0
  15. data/data/gonzui/doc/folder.png +0 -0
  16. data/data/gonzui/doc/gonzui.css +279 -0
  17. data/data/gonzui/doc/gonzui.js +111 -0
  18. data/data/gonzui/doc/text.png +0 -0
  19. data/data/gonzuirc.sample +29 -0
  20. data/ext/autopack/autopack.c +88 -0
  21. data/ext/autopack/extconf.rb +3 -0
  22. data/ext/delta/delta.c +147 -0
  23. data/ext/delta/extconf.rb +5 -0
  24. data/ext/texttokenizer/extconf.rb +5 -0
  25. data/ext/texttokenizer/texttokenizer.c +93 -0
  26. data/ext/xmlformatter/extconf.rb +5 -0
  27. data/ext/xmlformatter/xmlformatter.c +207 -0
  28. data/lib/gonzui.rb +59 -0
  29. data/lib/gonzui/apt.rb +193 -0
  30. data/lib/gonzui/autopack.so +0 -0
  31. data/lib/gonzui/bdbdbm.rb +118 -0
  32. data/lib/gonzui/cmdapp.rb +14 -0
  33. data/lib/gonzui/cmdapp/app.rb +175 -0
  34. data/lib/gonzui/cmdapp/search.rb +134 -0
  35. data/lib/gonzui/config.rb +117 -0
  36. data/lib/gonzui/content.rb +19 -0
  37. data/lib/gonzui/dbm.rb +673 -0
  38. data/lib/gonzui/deindexer.rb +162 -0
  39. data/lib/gonzui/delta.rb +49 -0
  40. data/lib/gonzui/delta.so +0 -0
  41. data/lib/gonzui/extractor.rb +347 -0
  42. data/lib/gonzui/fetcher.rb +309 -0
  43. data/lib/gonzui/gettext.rb +144 -0
  44. data/lib/gonzui/importer.rb +84 -0
  45. data/lib/gonzui/indexer.rb +316 -0
  46. data/lib/gonzui/info.rb +80 -0
  47. data/lib/gonzui/license.rb +100 -0
  48. data/lib/gonzui/logger.rb +48 -0
  49. data/lib/gonzui/monitor.rb +177 -0
  50. data/lib/gonzui/progressbar.rb +235 -0
  51. data/lib/gonzui/remover.rb +38 -0
  52. data/lib/gonzui/searcher.rb +330 -0
  53. data/lib/gonzui/searchquery.rb +235 -0
  54. data/lib/gonzui/searchresult.rb +111 -0
  55. data/lib/gonzui/texttokenizer.so +0 -0
  56. data/lib/gonzui/updater.rb +254 -0
  57. data/lib/gonzui/util.rb +415 -0
  58. data/lib/gonzui/vcs.rb +128 -0
  59. data/lib/gonzui/webapp.rb +25 -0
  60. data/lib/gonzui/webapp/advsearch.rb +123 -0
  61. data/lib/gonzui/webapp/filehandler.rb +24 -0
  62. data/lib/gonzui/webapp/jsfeed.rb +61 -0
  63. data/lib/gonzui/webapp/markup.rb +445 -0
  64. data/lib/gonzui/webapp/search.rb +269 -0
  65. data/lib/gonzui/webapp/servlet.rb +319 -0
  66. data/lib/gonzui/webapp/snippet.rb +155 -0
  67. data/lib/gonzui/webapp/source.rb +37 -0
  68. data/lib/gonzui/webapp/stat.rb +137 -0
  69. data/lib/gonzui/webapp/top.rb +63 -0
  70. data/lib/gonzui/webapp/uri.rb +140 -0
  71. data/lib/gonzui/webapp/webrick.rb +48 -0
  72. data/lib/gonzui/webapp/xmlformatter.so +0 -0
  73. data/script/console +10 -0
  74. data/script/destroy +14 -0
  75. data/script/generate +14 -0
  76. data/script/makemanifest.rb +21 -0
  77. data/tasks/extconf.rake +13 -0
  78. data/tasks/extconf/autopack.rake +43 -0
  79. data/tasks/extconf/delta.rake +43 -0
  80. data/tasks/extconf/texttokenizer.rake +43 -0
  81. data/tasks/extconf/xmlformatter.rake +43 -0
  82. data/test/_external_tools.rb +13 -0
  83. data/test/_test-util.rb +142 -0
  84. data/test/foo/Makefile.foo +66 -0
  85. data/test/foo/bar.c +5 -0
  86. data/test/foo/bar.h +6 -0
  87. data/test/foo/foo.c +25 -0
  88. data/test/foo/foo.spec +33 -0
  89. data/test/test_apt.rb +42 -0
  90. data/test/test_autopack_extn.rb +7 -0
  91. data/test/test_bdbdbm.rb +79 -0
  92. data/test/test_cmdapp-app.rb +35 -0
  93. data/test/test_cmdapp-search.rb +99 -0
  94. data/test/test_config.rb +28 -0
  95. data/test/test_content.rb +15 -0
  96. data/test/test_dbm.rb +171 -0
  97. data/test/test_deindexer.rb +50 -0
  98. data/test/test_delta.rb +66 -0
  99. data/test/test_extractor.rb +78 -0
  100. data/test/test_fetcher.rb +75 -0
  101. data/test/test_gettext.rb +50 -0
  102. data/test/test_gonzui.rb +11 -0
  103. data/test/test_helper.rb +10 -0
  104. data/test/test_importer.rb +56 -0
  105. data/test/test_indexer.rb +37 -0
  106. data/test/test_info.rb +82 -0
  107. data/test/test_license.rb +49 -0
  108. data/test/test_logger.rb +60 -0
  109. data/test/test_monitor.rb +23 -0
  110. data/test/test_searcher.rb +37 -0
  111. data/test/test_searchquery.rb +27 -0
  112. data/test/test_searchresult.rb +43 -0
  113. data/test/test_texttokenizer.rb +47 -0
  114. data/test/test_updater.rb +95 -0
  115. data/test/test_util.rb +149 -0
  116. data/test/test_vcs.rb +61 -0
  117. data/test/test_webapp-markup.rb +42 -0
  118. data/test/test_webapp-util.rb +19 -0
  119. data/test/test_webapp-xmlformatter.rb +19 -0
  120. metadata +292 -0
Binary file
@@ -0,0 +1,29 @@
1
+ {
2
+ :access_log_file => "access.log",
3
+ :base_mount_point => "",
4
+ :cache_directory => "gonzui.db/cache",
5
+ # :catalog_directory => "catalog",
6
+ :daemon => false,
7
+ :db_cache_size => 5242880,
8
+ :db_directory => "gonzui.db",
9
+ :default_results_per_page => 10,
10
+ # :doc_directory => "doc",
11
+ :encoding_preference => ["iso-2022-jp", "euc-jp", "utf-8", "shift_jis", "cp932", "iso-8859-1", "ascii"],
12
+ :exclude_pattern => /~$|\.bak$|CVS|\.svn|\.git/,
13
+ :gonzui_log_file => "gonzui.log",
14
+ :group => "Administrators",
15
+ :http_port => 46984,
16
+ :max_packages_per_page => 100,
17
+ :max_pages => 20,
18
+ :max_results_per_page => 50,
19
+ :max_words => 10,
20
+ :noindex_formats => [],
21
+ :nresults_candidates => [10, 20, 30, 50],
22
+ :pid_file => "gonzui.pid",
23
+ :quiet => false,
24
+ :site_title => "gonzui",
25
+ # :temporary_directory => "/tmp",
26
+ :user => "Administrator",
27
+ :utf8 => true,
28
+ :verbose => false,
29
+ }
@@ -0,0 +1,88 @@
1
+ /* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2 c-style: "BSD" -*- */
2
+ /*
3
+ * autopack.c - C functions for AutoPack module.
4
+ *
5
+ * Copyright (C) 2005 Satoru Takabayashi <satoru@namazu.org>
6
+ * All rights reserved.
7
+ * This is free software with ABSOLUTELY NO WARRANTY.
8
+ *
9
+ * You can redistribute it and/or modify it under the terms of
10
+ * the GNU General Public License version 2.
11
+ */
12
+
13
+ #include <ruby.h>
14
+
15
+ #ifndef RSTRING_PTR
16
+ # define RSTRING_PTR(s) (RSTRING(s)->ptr)
17
+ #endif
18
+
19
+ static VALUE
20
+ rb_autopack_pack_fixnum(VALUE obj, VALUE value)
21
+ {
22
+ int n;
23
+ unsigned char str[4];
24
+ if (TYPE(value) != T_FIXNUM) {
25
+ rb_raise(rb_eTypeError, "Fixnum expected");
26
+ }
27
+ n = FIX2INT(value);
28
+ str[0] = (n >> 24) & 0xff;
29
+ str[1] = (n >> 16) & 0xff;
30
+ str[2] = (n >> 8) & 0xff;
31
+ str[3] = n & 0xff;
32
+ return rb_str_new(str, 4);
33
+ }
34
+
35
+ static VALUE
36
+ rb_autopack_pack_id2(VALUE obj, VALUE id1, VALUE id2)
37
+ {
38
+ int n1, n2;
39
+ unsigned char str[8];
40
+ if (!(TYPE(id1) == T_FIXNUM && TYPE(id2) == T_FIXNUM)) {
41
+ rb_raise(rb_eTypeError, "Fixnum expected");
42
+ }
43
+ n1 = FIX2INT(id1);
44
+ n2 = FIX2INT(id2);
45
+ str[0] = (n1 >> 24) & 0xff;
46
+ str[1] = (n1 >> 16) & 0xff;
47
+ str[2] = (n1 >> 8) & 0xff;
48
+ str[3] = n1 & 0xff;
49
+ str[4] = (n2 >> 24) & 0xff;
50
+ str[5] = (n2 >> 16) & 0xff;
51
+ str[6] = (n2 >> 8) & 0xff;
52
+ str[7] = n2 & 0xff;
53
+ return rb_str_new(str, 8);
54
+ }
55
+
56
+ static VALUE
57
+ rb_autopack_unpack_fixnum(VALUE obj, VALUE value)
58
+ {
59
+ int n;
60
+ unsigned char *str;
61
+ if (TYPE(value) != T_STRING) {
62
+ rb_raise(rb_eTypeError, "String expected");
63
+ }
64
+ str = RSTRING_PTR(value);
65
+ n = (str[0] << 24) + (str[1] << 16) + (str[2] << 8) + str[3];
66
+ return INT2FIX(n);
67
+ }
68
+
69
+ void Init_autopack()
70
+ {
71
+ VALUE mGonzui, mAutoPack;
72
+ mGonzui = rb_define_module("Gonzui");
73
+ mAutoPack = rb_define_module_under(mGonzui, "AutoPack");
74
+
75
+ rb_define_module_function(mAutoPack, "pack_id",
76
+ rb_autopack_pack_fixnum, 1);
77
+ rb_define_module_function(mAutoPack, "unpack_id",
78
+ rb_autopack_unpack_fixnum, 1);
79
+
80
+ rb_define_module_function(mAutoPack, "pack_fixnum",
81
+ rb_autopack_pack_fixnum, 1);
82
+ rb_define_module_function(mAutoPack, "unpack_fixnum",
83
+ rb_autopack_unpack_fixnum, 1);
84
+ rb_define_module_function(mAutoPack, "pack_id2",
85
+ rb_autopack_pack_id2, 2);
86
+ }
87
+
88
+
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('gonzui/autopack')
data/ext/delta/delta.c ADDED
@@ -0,0 +1,147 @@
1
+ /* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2 c-style: "BSD" -*- */
2
+ /*
3
+ * delta.c - byte-oriented delta compression implementation
4
+ *
5
+ * Copyright (C) 2005 Satoru Takabayashi <satoru@namazu.org>
6
+ * Copyright (C) 2005 Keisuke Nishida <knishida@open-cobol.org>
7
+ * All rights reserved.
8
+ * This is free software with ABSOLUTELY NO WARRANTY.
9
+ *
10
+ * You can redistribute it and/or modify it under the terms of
11
+ * the GNU General Public License version 2.
12
+ */
13
+
14
+ #include <ruby.h>
15
+ #include <assert.h>
16
+
17
+ #ifndef RARRAY_PTR
18
+ # define RARRAY_PTR(str) (RARRAY(str)->ptr)
19
+ #endif
20
+ #ifndef RARRAY_LEN
21
+ # define RARRAY_LEN(str) (RARRAY(str)->len)
22
+ #endif
23
+
24
+ typedef void (*CodeFunc)(VALUE *p, int i, int *prev);
25
+
26
+ static inline void
27
+ decode(VALUE *p, int i, int *prev)
28
+ {
29
+ int this;
30
+ if (TYPE(p[i]) != T_FIXNUM) {
31
+ rb_raise(rb_eTypeError, "wrong argument type (fixnum required)");
32
+ }
33
+ this = FIX2INT(p[i]);
34
+ p[i] = INT2FIX(this + *prev);
35
+ *prev = FIX2INT(p[i]);
36
+ }
37
+
38
+ static inline void
39
+ encode(VALUE *p, int i, int *prev)
40
+ {
41
+ int this;
42
+ if (TYPE(p[i]) != T_FIXNUM) {
43
+ rb_raise(rb_eTypeError, "wrong argument type (fixnum required)");
44
+ }
45
+
46
+ this = FIX2INT(p[i]);
47
+ p[i] = INT2FIX(this - *prev);
48
+ if (FIX2INT(p[i]) < 0) {
49
+ rb_raise(rb_eArgError, "Encode failed: value becomes minus");
50
+ }
51
+ *prev = this;
52
+ }
53
+
54
+ static VALUE
55
+ rb_delta_code_tuples(VALUE obj, VALUE list,
56
+ VALUE delta_size, VALUE unit_size, CodeFunc code)
57
+ {
58
+ enum { PREV_MAX = 128 };
59
+ int i, j;
60
+ int dsize;
61
+ int usize;
62
+ long len;
63
+ int prev[PREV_MAX];
64
+ VALUE *p;
65
+
66
+ if (!(TYPE(list) == T_ARRAY && TYPE(delta_size) == T_FIXNUM &&
67
+ TYPE(unit_size) == T_FIXNUM && FIX2INT(delta_size) < PREV_MAX ))
68
+ {
69
+ rb_raise(rb_eTypeError, "wrong argument type");
70
+ }
71
+
72
+ dsize = FIX2INT(delta_size);
73
+ usize = FIX2INT(unit_size);
74
+ len = RARRAY_LEN(list);
75
+ if (!(len % usize == 0 && dsize <= usize)) {
76
+ rb_raise(rb_eArgError, "wrong argument size");
77
+ }
78
+ p = RARRAY_PTR(list);
79
+ memset(prev, 0, sizeof(int) * dsize);
80
+ for (i = 0; i < len; i += usize) {
81
+ for (j = 0; j < dsize; j++) {
82
+ code(p, i + j, prev + j);
83
+ }
84
+ }
85
+ return list;
86
+ }
87
+
88
+ static VALUE
89
+ rb_delta_decode_tuples(VALUE obj, VALUE list,
90
+ VALUE delta_size, VALUE unit_size)
91
+ {
92
+ return rb_delta_code_tuples(obj, list, delta_size, unit_size, decode);
93
+ }
94
+
95
+ static VALUE
96
+ rb_delta_encode_tuples(VALUE obj, VALUE list,
97
+ VALUE delta_size, VALUE unit_size)
98
+ {
99
+ return rb_delta_code_tuples(obj, list, delta_size, unit_size, encode);
100
+ }
101
+
102
+ static VALUE
103
+ rb_delta_code_fixnums(VALUE obj, VALUE list, CodeFunc code)
104
+ {
105
+ int i;
106
+ long len;
107
+ VALUE *p;
108
+ int prev = 0;
109
+ if (TYPE(list) != T_ARRAY) {
110
+ rb_raise(rb_eTypeError, "wrong argument type");
111
+ }
112
+ p = RARRAY_PTR(list);
113
+ len = RARRAY_LEN(list);
114
+ for (i = 0; i < len; i++) {
115
+ code(p, i, &prev);
116
+ }
117
+ return list;
118
+ }
119
+
120
+ static VALUE
121
+ rb_delta_decode_fixnums(VALUE obj, VALUE list)
122
+ {
123
+ rb_delta_code_fixnums(obj, list, decode);
124
+ }
125
+
126
+ static VALUE
127
+ rb_delta_encode_fixnums(VALUE obj, VALUE list)
128
+ {
129
+ rb_delta_code_fixnums(obj, list, encode);
130
+ }
131
+
132
+ void Init_delta()
133
+ {
134
+ VALUE mGonzui, mDelta;
135
+ mGonzui = rb_define_module("Gonzui");
136
+ mDelta = rb_define_module_under(mGonzui, "DeltaDumper");
137
+ rb_define_module_function(mDelta, "encode_tuples",
138
+ rb_delta_encode_tuples, 3);
139
+ rb_define_module_function(mDelta, "decode_tuples",
140
+ rb_delta_decode_tuples, 3);
141
+ rb_define_module_function(mDelta, "encode_fixnums",
142
+ rb_delta_encode_fixnums, 1);
143
+ rb_define_module_function(mDelta, "decode_fixnums",
144
+ rb_delta_decode_fixnums, 1);
145
+ }
146
+
147
+
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("delta")
4
+
5
+ create_makefile("gonzui/delta")
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("texttokenizer")
4
+
5
+ create_makefile("gonzui/texttokenizer")
@@ -0,0 +1,93 @@
1
+ /* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2 c-style: "BSD" -*- */
2
+ /*
3
+ * texttokenizer.c - a simple text tokenizer
4
+ *
5
+ * Copyright (C) 2005 Satoru Takabayashi <satoru@namazu.org>
6
+ * Copyright (C) 2005 Keisuke Nishida <knishida@open-cobol.org>
7
+ * All rights reserved.
8
+ * This is free software with ABSOLUTELY NO WARRANTY.
9
+ *
10
+ * You can redistribute it and/or modify it under the terms of
11
+ * the GNU General Public License version 2.
12
+ *
13
+ *
14
+ */
15
+
16
+ #include <assert.h>
17
+ #include <ruby.h>
18
+
19
+ #ifndef RSTRING_PTR
20
+ # define RSTRING_PTR(s) (RSTRING(s)->ptr)
21
+ #endif
22
+ #ifndef RSTRING_LEN
23
+ # define RSTRING_LEN(s) (RSTRING(s)->len)
24
+ #endif
25
+
26
+ static inline int utf8len(const unsigned char *s, const unsigned char *eot)
27
+ {
28
+ int len = 0;
29
+ if (*s < 0x80) {
30
+ len = 1;
31
+ } else if ((s + 1 < eot) && (*s & 0xe0) == 0xc0) {
32
+ len = 2;
33
+ } else if ((s + 2 < eot) && (*s & 0xf0) == 0xe0) {
34
+ len = 3;
35
+ } else if ((s + 3 < eot) && (*s & 0xf8) == 0xf0) {
36
+ len = 4;
37
+ } else if ((s + 4 < eot) && (*s & 0xfc) == 0xf8) {
38
+ len = 5;
39
+ } else if ((s + 5 < eot) && (*s & 0xfe) == 0xfc) {
40
+ len = 6;
41
+ } else {
42
+ rb_raise(rb_eArgError, "invalid UTF-8 character");
43
+ }
44
+ return len;
45
+ }
46
+
47
+ static inline unsigned char *
48
+ skip(unsigned char *s, unsigned char *eot)
49
+ {
50
+ for (; s < eot; s++)
51
+ if (isalnum(*s) || *s >= 0x80)
52
+ break;
53
+ return s;
54
+ }
55
+
56
+ /*
57
+ * Iterate over each word.
58
+ * word: [a-zA-Z0-9]+ or single multi-byte UTF-8 character
59
+ */
60
+ static VALUE texttokenizer_each_word(VALUE obj, VALUE text)
61
+ {
62
+ VALUE str;
63
+ unsigned char *s, *beg, *eot;
64
+
65
+ str = rb_obj_as_string(text);
66
+ beg = RSTRING_PTR(str);
67
+ eot = beg + RSTRING_LEN(str);
68
+ s = skip(beg, eot);
69
+
70
+ while (s < eot) {
71
+ unsigned char *b = s;
72
+ if (*s >= 0x80) {
73
+ s += utf8len(s, eot);
74
+ } else {
75
+ for (; s < eot; s++)
76
+ if (!((isalnum(*s) || *s == '_')))
77
+ break;
78
+ }
79
+ rb_yield_values(2, rb_str_new(b, s - b), INT2FIX(b - beg));
80
+ s = skip(s, eot);
81
+ }
82
+ return Qnil;
83
+ }
84
+
85
+ void Init_texttokenizer()
86
+ {
87
+ VALUE mGonzui, mTextTokenizer;
88
+ mGonzui = rb_define_module("Gonzui");
89
+ mTextTokenizer = rb_define_module_under(mGonzui, "TextTokenizer");
90
+
91
+ rb_define_module_function(mTextTokenizer, "each_word",
92
+ texttokenizer_each_word, 1);
93
+ }
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("xmlformatter")
4
+
5
+ create_makefile("gonzui/webapp/xmlformatter")
@@ -0,0 +1,207 @@
1
+ /* -*- mode: C; indent-tabs-mode: nil; c-basic-offset: 2 c-style: "BSD" -*- */
2
+ /*
3
+ * xmlformatter.c - a simple class for generating XML texts
4
+ *
5
+ * Copyright (C) 2004-2005 Keisuke Nishida <knishida@open-cobol.org>
6
+ * All rights reserved.
7
+ * This is free software with ABSOLUTELY NO WARRANTY.
8
+ *
9
+ * You can redistribute it and/or modify it under the terms of
10
+ * the GNU General Public License version 2.
11
+ */
12
+
13
+ #include <ruby.h>
14
+ #include <st.h>
15
+
16
+ #define BLOCK_SIZE (128 * 1024) /* 128 KB */
17
+
18
+ #ifndef RARRAY_PTR
19
+ # define RARRAY_PTR(str) (RARRAY(str)->ptr)
20
+ #endif
21
+ #ifndef RARRAY_LEN
22
+ # define RARRAY_LEN(str) (RARRAY(str)->len)
23
+ #endif
24
+
25
+ #ifndef RSTRING_PTR
26
+ # define RSTRING_PTR(s) (RSTRING(s)->ptr)
27
+ #endif
28
+ #ifndef RSTRING_LEN
29
+ # define RSTRING_LEN(s) (RSTRING(s)->len)
30
+ #endif
31
+
32
+ typedef struct gonzui_xmlformatter {
33
+ char *data;
34
+ size_t size;
35
+ size_t max_size;
36
+ } gonzui_xmlformatter_t;
37
+
38
+ static gonzui_xmlformatter_t *xmlformatter_new(void)
39
+ {
40
+ gonzui_xmlformatter_t *xf = malloc(sizeof(gonzui_xmlformatter_t));
41
+ memset(xf, 0, sizeof(gonzui_xmlformatter_t));
42
+ xf->max_size = BLOCK_SIZE;
43
+ xf->size = 0;
44
+ xf->data = malloc(xf->max_size);
45
+ return xf;
46
+ }
47
+
48
+ static void xmlformatter_write(gonzui_xmlformatter_t *xf, char *data)
49
+ {
50
+ long size = strlen(data);
51
+ if (xf->size + size > xf->max_size) {
52
+ xf->max_size += BLOCK_SIZE;
53
+ xf->data = realloc(xf->data, xf->max_size);
54
+ }
55
+ memcpy(xf->data + xf->size, data, size);
56
+ xf->size += size;
57
+ }
58
+
59
+ static void xmlformatter_write_obj(gonzui_xmlformatter_t *xf, VALUE obj)
60
+ {
61
+ char *p;
62
+ char *data;
63
+ size_t size;
64
+ if (SYMBOL_P(obj)) {
65
+ data = rb_id2name(SYM2ID(obj));
66
+ size = strlen(data);
67
+ } else {
68
+ VALUE s = rb_obj_as_string(obj);
69
+ data = RSTRING_PTR(s);
70
+ size = RSTRING_LEN(s);
71
+ }
72
+ if (xf->size + size * 6 > xf->max_size) {
73
+ xf->max_size += BLOCK_SIZE;
74
+ xf->data = realloc(xf->data, xf->max_size);
75
+ }
76
+ for (p = data; *p; p++) {
77
+ int c = *p;
78
+ if (c == '<') {
79
+ memcpy(xf->data + xf->size, "&lt;", 4);
80
+ xf->size += 4;
81
+ } else if (c == '>') {
82
+ memcpy(xf->data + xf->size, "&gt;", 4);
83
+ xf->size += 4;
84
+ } else if (c == '&') {
85
+ memcpy(xf->data + xf->size, "&amp;", 5);
86
+ xf->size += 5;
87
+ } else if (c == '"') {
88
+ memcpy(xf->data + xf->size, "&quot;", 6);
89
+ xf->size += 6;
90
+ } else {
91
+ xf->data[xf->size++] = c;
92
+ }
93
+ }
94
+ }
95
+
96
+ static void xmlformatter_free(gonzui_xmlformatter_t *xf)
97
+ {
98
+ if (xf == NULL)
99
+ return;
100
+ free(xf->data);
101
+ free(xf);
102
+ }
103
+
104
+ static VALUE xmlformatter_s_allocate(VALUE klass)
105
+ {
106
+ return Data_Wrap_Struct(klass, NULL, xmlformatter_free, NULL);
107
+ }
108
+
109
+ static VALUE xmlformatter_initialize(VALUE self)
110
+ {
111
+ gonzui_xmlformatter_t *xf;
112
+ Data_Get_Struct(self, gonzui_xmlformatter_t, xf);
113
+ if (xf)
114
+ rb_raise(rb_eArgError, "called twice");
115
+
116
+ DATA_PTR(self) = xmlformatter_new();
117
+ return self;
118
+ }
119
+
120
+ static VALUE xmlformatter_add_xml_declaration(VALUE self)
121
+ {
122
+ gonzui_xmlformatter_t *xf;
123
+ Data_Get_Struct(self, gonzui_xmlformatter_t, xf);
124
+ if (xf)
125
+ xmlformatter_write(xf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
126
+ return Qnil;
127
+ }
128
+
129
+ static VALUE xmlformatter_add_doctype(VALUE self)
130
+ {
131
+ gonzui_xmlformatter_t *xf;
132
+ Data_Get_Struct(self, gonzui_xmlformatter_t, xf);
133
+ if (xf)
134
+ xmlformatter_write(xf, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
135
+ " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
136
+ return Qnil;
137
+ }
138
+
139
+ static int format_hash(VALUE key, VALUE val, gonzui_xmlformatter_t *xf)
140
+ {
141
+ xmlformatter_write(xf, " ");
142
+ xmlformatter_write_obj(xf, key);
143
+ xmlformatter_write(xf, "=\"");
144
+ xmlformatter_write_obj(xf, val);
145
+ xmlformatter_write(xf, "\"");
146
+ return ST_CONTINUE;
147
+ }
148
+
149
+ static void format(gonzui_xmlformatter_t *xf, VALUE xml)
150
+ {
151
+ if (rb_type(xml) == T_ARRAY) {
152
+ /* array */
153
+ long i = 0;
154
+ long len = RARRAY_LEN(xml);
155
+ VALUE *a = RARRAY_PTR(xml);
156
+ VALUE tag;
157
+
158
+ if (len == 0)
159
+ rb_raise(rb_eArgError, "too short");
160
+
161
+ /* start tag */
162
+ tag = a[i++];
163
+ xmlformatter_write(xf, "<");
164
+ xmlformatter_write_obj(xf, tag);
165
+
166
+ /* attributes */
167
+ if (i < len && rb_type(a[i]) == T_HASH)
168
+ st_foreach(RHASH(a[i++])->tbl, format_hash, (st_data_t)xf);
169
+
170
+ /* body, end tag */
171
+ if (i >= len) {
172
+ xmlformatter_write(xf, "\n/>");
173
+ } else {
174
+ xmlformatter_write(xf, "\n>");
175
+ for (; i < len; i++)
176
+ format(xf, a[i]);
177
+ xmlformatter_write(xf, "</");
178
+ xmlformatter_write_obj(xf, tag);
179
+ xmlformatter_write(xf, "\n>");
180
+ }
181
+ } else {
182
+ /* other nobject */
183
+ xmlformatter_write_obj(xf, xml);
184
+ }
185
+ }
186
+
187
+ static VALUE xmlformatter_format(VALUE self, VALUE xml)
188
+ {
189
+ gonzui_xmlformatter_t *xf;
190
+ Data_Get_Struct(self, gonzui_xmlformatter_t, xf);
191
+ if (xf == NULL)
192
+ return Qnil;
193
+ Check_Type(xml, T_ARRAY);
194
+ format(xf, xml);
195
+ return rb_str_new(xf->data, xf->size);
196
+ }
197
+
198
+ void Init_xmlformatter()
199
+ {
200
+ VALUE Gonzui = rb_define_module("Gonzui");
201
+ VALUE XMLFormatter = rb_define_class_under(Gonzui, "XMLFormatter", rb_cData);
202
+ rb_define_alloc_func(XMLFormatter, xmlformatter_s_allocate);
203
+ rb_define_method(XMLFormatter, "initialize", xmlformatter_initialize, 0);
204
+ rb_define_method(XMLFormatter, "add_xml_declaration", xmlformatter_add_xml_declaration, 0);
205
+ rb_define_method(XMLFormatter, "add_doctype", xmlformatter_add_doctype, 0);
206
+ rb_define_method(XMLFormatter, "format", xmlformatter_format, 1);
207
+ }