summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--error.c9
-rw-r--r--eval.c23
-rw-r--r--ext/dbm/dbm.c10
-rw-r--r--ext/tcltklib/extconf.rb2
-rw-r--r--ext/tk/lib/tkfont.rb15
-rw-r--r--intern.h6
-rw-r--r--io.c6
-rw-r--r--lib/cgi.rb1949
-rw-r--r--lib/jcode.rb111
-rw-r--r--re.c16
-rw-r--r--re.h3
-rw-r--r--regex.c3
-rw-r--r--string.c17
-rw-r--r--win32/Makefile5
-rw-r--r--win32/ruby.def3
16 files changed, 2121 insertions, 75 deletions
diff --git a/ChangeLog b/ChangeLog
index f656705..49c15a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Wed Nov 3 08:52:57 1999 Masaki Fukushima <fukusima@goto.info.waseda.ac.jp>
+
+ * io.c (Init_IO): forgot to use INT2FIX() around SEEK_SET, etc.
+
+Wed Nov 3 00:25:20 1999 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (rb_str_split_method): use mbclen2() to handle kcode
+ option of regexp objects.
+
+Mon Nov 1 14:22:15 1999 EGUCHI Osamu <eguchi@shizuokanet.ne.jp>
+
+ * eval.c (rb_eval): reduce recursive calls to rb_eval()
+ case of ||= and &&= .
+
+Sun Oct 31 13:12:42 1999 WATANABE Hirofumi <eban@os.rim.or.jp>
+
+ * regex.c (re_compile_pattern): wrong [\W] match.
+
Fri Oct 29 16:57:30 1999 Yukihiro Matsumoto <matz@netlab.co.jp>
* ext/nkf/lib/kconv.rb: new String methods (kconv, tojis, toeuc,
diff --git a/error.c b/error.c
index 1e53b9a..feb3778 100644
--- a/error.c
+++ b/error.c
@@ -26,8 +26,11 @@
int sys_nerr = 256;
#endif
-#if defined __CYGWIN__ && defined _sys_nerr
-#define sys_nerr _sys_nerr
+#if defined __CYGWIN__
+# include <cygwin/version.h>
+# if (CYGWIN_VERSION_API_MAJOR > 0) || (CYGWIN_VERSION_API_MINOR >= 8)
+# define sys_nerr _sys_nerr
+# endif
#endif
int ruby_nerrs;
@@ -442,7 +445,7 @@ static const syserr_index_entry syserr_index[]= {
static VALUE *syserr_list;
#endif
-#ifndef NT
+#if !defined NT && !defined sys_nerr
extern int sys_nerr;
#endif
diff --git a/eval.c b/eval.c
index 7a85801..6e9ad5e 100644
--- a/eval.c
+++ b/eval.c
@@ -1771,7 +1771,7 @@ rb_eval(self, node)
/* nodes for speed-up(literal match) */
case NODE_MATCH2:
result = rb_reg_match(rb_eval(self,node->nd_recv),
- rb_eval(self,node->nd_value));
+ rb_eval(self,node->nd_value));
break;
/* nodes for speed-up(literal match) */
@@ -1841,7 +1841,12 @@ rb_eval(self, node)
{
VALUE val;
- val = rb_eval(self, node->nd_head);
+ if (node->nd_head) {
+ val = rb_eval(self, node->nd_head);
+ }
+ else {
+ val = Qtrue;
+ }
node = node->nd_body;
while (node) {
NODE *tag;
@@ -2334,17 +2339,15 @@ rb_eval(self, node)
case NODE_OP_ASGN_AND:
result = rb_eval(self, node->nd_head);
- if (RTEST(result)) {
- result = rb_eval(self, node->nd_value);
- }
- break;
+ if (!RTEST(result)) break;
+ node = node->nd_value;
+ goto again;
case NODE_OP_ASGN_OR:
result = rb_eval(self, node->nd_head);
- if (!RTEST(result)) {
- result = rb_eval(self, node->nd_value);
- }
- break;
+ if (RTEST(result)) break;
+ node = node->nd_value;
+ goto again;
case NODE_MASGN:
result = massign(self, node, rb_eval(self, node->nd_value),0);
diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c
index 4d83cec..1240f4b 100644
--- a/ext/dbm/dbm.c
+++ b/ext/dbm/dbm.c
@@ -72,12 +72,16 @@ fdbm_s_open(argc, argv, klass)
Check_SafeStr(file);
dbm = 0;
- if (mode >= 0)
+ if (mode >= 0) {
dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode);
- if (!dbm)
+ }
+ if (!dbm) {
+ mode = 0666;
dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, mode);
- if (!dbm)
+ }
+ if (!dbm) {
dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, mode);
+ }
if (!dbm) {
if (mode == -1) return Qnil;
diff --git a/ext/tcltklib/extconf.rb b/ext/tcltklib/extconf.rb
index e108685..713cc81 100644
--- a/ext/tcltklib/extconf.rb
+++ b/ext/tcltklib/extconf.rb
@@ -21,6 +21,7 @@ def find_tcl(tcllib)
find_library(tcllib, func, *paths)
else
find_library("tcl", func, *paths) or
+ find_library("tcl8.2", func, *paths) or
find_library("tcl8.0", func, *paths) or
find_library("tcl7.6", func, *paths)
end
@@ -33,6 +34,7 @@ def find_tk(tklib)
find_library(tklib, func, *paths)
else
find_library("tk", func, *paths) or
+ find_library("tk8.2", func, *paths) or
find_library("tk8.0", func, *paths) or
find_library("tk4.2", func, *paths)
end
diff --git a/ext/tk/lib/tkfont.rb b/ext/tk/lib/tkfont.rb
index c680d16..2683260 100644
--- a/ext/tk/lib/tkfont.rb
+++ b/ext/tk/lib/tkfont.rb
@@ -667,7 +667,20 @@ class TkFont
alias measure_core measure_core_tk8x
alias metrics_core metrics_core_tk8x
- when /^8\.1/
+ when /^8\.[12]/
+ alias create_latinfont create_latinfont_tk8x
+ alias create_kanjifont create_kanjifont_tk81
+ alias create_compoundfont create_compoundfont_tk81
+ alias actual_core actual_core_tk8x
+ alias configure_core configure_core_tk8x
+ alias configinfo_core configinfo_core_tk8x
+ alias delete_core delete_core_tk8x
+ alias latin_replace_core latin_replace_core_tk8x
+ alias kanji_replace_core kanji_replace_core_tk81
+ alias measure_core measure_core_tk8x
+ alias metrics_core metrics_core_tk8x
+
+ when /^8\.*/
alias create_latinfont create_latinfont_tk8x
alias create_kanjifont create_kanjifont_tk81
alias create_compoundfont create_compoundfont_tk81
diff --git a/intern.h b/intern.h
index 40b8040..8c303e9 100644
--- a/intern.h
+++ b/intern.h
@@ -210,6 +210,12 @@ VALUE rb_Array _((VALUE));
/* parse.y */
extern int ruby_sourceline;
extern char *ruby_sourcefile;
+#define yyparse rb_yyparse
+#define yylex rb_yylex
+#define yyerror rb_yyerror
+#define yylval rb_yylval
+#define yychar rb_yychar
+#define yydebug rb_yydebug
int yyparse _((void));
ID rb_id_attrset _((ID));
void rb_parser_append_print _((void));
diff --git a/io.c b/io.c
index 8ee1683..61052b3 100644
--- a/io.c
+++ b/io.c
@@ -3254,9 +3254,9 @@ Init_IO()
rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
rb_define_method(rb_cIO, "seek", rb_io_seek, 2);
- rb_define_const(rb_cIO, "SEEK_SET", SEEK_SET);
- rb_define_const(rb_cIO, "SEEK_CUR", SEEK_CUR);
- rb_define_const(rb_cIO, "SEEK_END", SEEK_END);
+ rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
+ rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
+ rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
diff --git a/lib/cgi.rb b/lib/cgi.rb
new file mode 100644
index 0000000..fa98fec
--- /dev/null
+++ b/lib/cgi.rb
@@ -0,0 +1,1949 @@
+=begin
+$Date$
+
+== CGI SUPPORT LIBRARY
+
+CGI.rb
+
+Version 1.00
+
+Copyright (C) 1999 Network Applied Communication Laboratory, Inc.
+
+Wakou Aoyama <wakou@fsinet.or.jp>
+
+
+== EXAMPLE
+
+=== GET FORM VALUES
+
+ require "cgi"
+ cgi = CGI.new
+ values = cgi['field_name'] # <== array of 'field_name'
+ # if not 'field_name' included, then return [].
+ fields = cgi.keys # <== array of field names
+
+ # returns true if form has 'field_name'
+ cgi.has_key?('field_name')
+ cgi.key?('field_name')
+ cgi.include?('field_name')
+
+
+=== GET FORM VALUES AS HASH
+
+ require "cgi"
+ cgi = CGI.new
+ params = cgi.params
+
+cgi.params is a hash.
+
+ cgi.params['new_field_name'] = ["value"] # add new param
+ cgi.params['field_name'] = ["new_value"] # change value
+ cgi.params.delete('field_name') # delete param
+ cgi.params.clear # delete all params
+
+
+=== SAVE FORM VALUES TO FILE
+
+ require "pstore"
+ db = PStore.new("query.db")
+ db.transaction do
+ db["params"] = cgi.params
+ end
+
+
+=== RESTORE FORM VALUES FROM FILE
+
+ require "pstore"
+ db = PStore.new("query.db")
+ db.transaction do
+ cgi.params = db["params"]
+ end
+
+
+=== GET MULTIPART FORM VALUES
+
+ require "cgi"
+ cgi = CGI.new
+ values = cgi['field_name'] # <== array of 'field_name'
+ values[0].read # <== body of values[0]
+ values[0].local_path # <== path to local file of values[0]
+ values[0].original_filename # <== original filename of values[0]
+ values[0].content_type # <== content_type of values[0]
+
+and values[0] has Tempfile class methods.
+
+(Tempfile class object has File class methods)
+
+
+=== GET COOKIE VALUES
+
+ require "cgi"
+ cgi = CGI.new
+ values = cgi.cookies['name'] # <== array of 'name'
+ # if not 'name' included, then return [].
+ names = cgi.cookies.keys # <== array of cookie names
+
+and cgi.cookies is a hash.
+
+
+=== GET COOKIE OBJECTS
+
+ require "cgi"
+ cgi = CGI.new
+ for name, cookie in cgi.cookies
+ cookie.expires = Time.now + 30
+ end
+ cgi.out({ "cookie" => cgi.cookies }){}
+
+ cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
+
+ require "cgi"
+ cgi = CGI.new
+ cgi.cookies['name'].expires = Time.now + 30
+ cgi.out({ "cookie" => cgi.cookies['name'] }){}
+
+and see MAKE COOKIE OBJECT.
+
+
+=== GET ENVIRONMENT VALUE
+
+ require "CGI"
+ cgi = CGI.new
+ value = cgi.auth_type
+ # ENV["AUTH_TYPE"]
+
+http://www.w3.org/CGI/
+
+AUTH_TYPE CONTENT_LENGTH CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
+PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_IDENT
+REMOTE_USER REQUEST_METHOD SCRIPT_NAME SERVER_NAME SERVER_PORT
+SERVER_PROTOCOL SERVER_SOFTWARE
+
+content_length and server_port return Integer. and the others return String.
+
+and HTTP_COOKIE, HTTP_COOKIE2
+
+ value = cgi.raw_cookie
+ # ENV["HTTP_COOKIE"]
+ value = cgi.raw_cookie2
+ # ENV["HTTP_COOKIE2"]
+
+and other HTTP_*
+
+ value = cgi.accept
+ # ENV["HTTP_ACCEPT"]
+ value = cgi.accept_charset
+ # ENV["HTTP_ACCEPT_CHARSET"]
+
+HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
+HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST HTTP_NEGOTIATE HTTP_PRAGMA
+HTTP_REFERER HTTP_USER_AGENT
+
+
+=== PRINT HTTP HEADER AND HTML STRING TO $>
+
+ require "cgi"
+ cgi = CGI.new("html3") # add HTML generation methods
+ cgi.out{
+ cgi.html{
+ cgi.head{ cgi.title{"TITLE"} } +
+ cgi.body{
+ cgi.form{
+ cgi.textarea("get_text") +
+ cgi.br +
+ cgi.submit
+ } +
+ cgi.pre{
+ CGI::escapeHTML(
+ "params: " + cgi.params.inspect + "\n" +
+ "cookies: " + cgi.cookies.inspect + "\n" +
+ ENV.collect{|key, value|
+ key + " --> " + value + "\n"
+ }.to_s
+ )
+ }
+ }
+ }
+ }
+
+ # add HTML generation methods
+ CGI.new("html3") # html3.2
+ CGI.new("html4") # html4.0 (Strict)
+ CGI.new("html4Tr") # html4.0 Transitional
+ CGI.new("html4Fr") # html4.0 Frameset
+
+=end
+
+
+class CGI
+
+ CR = "\015"
+ LF = "\012"
+ EOL = CR + LF
+v = $-v
+$-v = false
+ VERSION = "1.00"
+ RELEASE_DATE = "$Date$"
+$-v = v
+
+ NEEDS_BINMODE = true if /WIN/ni === PLATFORM
+ PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
+
+ HTTP_STATUS = {
+ "OK" => "200 OK",
+ "PARTIAL_CONTENT" => "206 Partial Content",
+ "MULTIPLE_CHOICES" => "300 Multiple Choices",
+ "MOVED" => "301 Moved Permanently",
+ "REDIRECT" => "302 Found",
+ "NOT_MODIFIED" => "304 Not Modified",
+ "BAD_REQUEST" => "400 Bad Request",
+ "AUTH_REQUIRED" => "401 Authorization Required",
+ "FORBIDDEN" => "403 Forbidden",
+ "NOT_FOUND" => "404 Not Found",
+ "METHOD_NOT_ALLOWED" => "405 Method Not Allowed",
+ "NOT_ACCEPTABLE" => "406 Not Acceptable",
+ "LENGTH_REQUIRED" => "411 Length Required",
+ "PRECONDITION_FAILED" => "412 Rrecondition Failed",
+ "SERVER_ERROR" => "500 Internal Server Error",
+ "NOT_IMPLEMENTED" => "501 Method Not Implemented",
+ "BAD_GATEWAY" => "502 Bad Gateway",
+ "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
+ }
+
+ RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
+ RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
+
+ def env_table
+ ENV
+ end
+
+ def stdinput
+ $stdin
+ end
+
+ def stdoutput
+ $>
+ end
+
+ private :env_table, :stdinput, :stdoutput
+
+=begin
+== METHODS
+=end
+
+=begin
+=== ESCAPE URL ENCODE
+ url_encoded_string = CGI::escape("string")
+=end
+ def CGI::escape(string)
+ str = string.dup
+ str.gsub!(/[^a-zA-Z0-9_.-]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
+ str
+ end
+
+
+=begin
+=== UNESCAPE URL ENCODED
+ string = CGI::unescape("url encoded string")
+=end
+ def CGI::unescape(string)
+ str = string.dup
+ str.gsub!(/\+/n, ' ')
+ str.gsub!(/%([0-9a-fA-F]{2})/n){ [$1.hex].pack("c") }
+ str
+ end
+
+
+=begin
+=== ESCAPE HTML &"<>
+ CGI::escapeHTML("string")
+=end
+ def CGI::escapeHTML(string)
+ str = string.dup
+ str.gsub!(/&/n, '&amp;')
+ str.gsub!(/\"/n, '&quot;')
+ str.gsub!(/>/n, '&gt;')
+ str.gsub!(/</n, '&lt;')
+ str
+ end
+
+
+=begin
+=== UNESCAPE HTML
+ CGI::unescapeHTML("HTML escaped string")
+=end
+ def CGI::unescapeHTML(string)
+ str = string.dup
+ str.gsub!(/&(.*?);/n){
+ match = $1.dup
+ case match
+ when /\Aamp\z/ni then '&'
+ when /\Aquot\z/ni then '"'
+ when /\Agt\z/ni then '>'
+ when /\Alt\z/ni then '<'
+ when /\A#(\d+)\z/n then Integer($1).chr
+ when /\A#x([0-9a-f]+)\z/ni then $1.hex.chr
+ end
+ }
+ str
+ end
+
+
+=begin
+=== ESCAPE ELEMENT
+ print CGI::escapeElement("<BR><A HREF="url"></A>", "A", "IMG")
+ # "<BR>&lt;A HREF="url"&gt;&lt;/A&gt"
+
+ print CGI::escapeElement("<BR><A HREF="url"></A>", ["A", "IMG"])
+ # "<BR>&lt;A HREF="url"&gt;&lt;/A&gt"
+=end
+ def CGI::escapeElement(string, *element)
+ str = string.dup
+ str.gsub!(/<\/?(?:#{element.join("|")})(?!\w)(?:.|\n)*?>/ni){
+ CGI::escapeHTML($&)
+ }
+ str
+ end
+
+
+=begin
+=== UNESCAPE ELEMENT
+ print CGI::unescapeElement(
+ CGI::escapeHTML("<BR><A HREF="url"></A>"), "A", "IMG")
+ # "&lt;BR&gt;<A HREF="url"></A>"
+
+ print CGI::unescapeElement(
+ CGI::escapeHTML("<BR><A HREF="url"></A>"), ["A", "IMG"])
+ # "&lt;BR&gt;<A HREF="url"></A>"
+=end
+ def CGI::unescapeElement(string, *element)
+ str = string.dup
+ str.gsub!(/&lt;\/?(?:#{element.join("|")})(?!\w)(?:.|\n)*?&gt;/ni){
+ CGI::unescapeHTML($&)
+ }
+ str
+ end
+
+
+=begin
+=== MAKE RFC1123 DATE STRING
+ CGI::rfc1123_date(Time.now)
+ # Sut, 1 Jan 2000 00:00:00 GMT
+=end
+ def CGI::rfc1123_date(time)
+ t = time.clone.gmtime
+ return format("%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
+ RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
+ t.hour, t.min, t.sec)
+ end
+
+
+=begin
+=== MAKE HTTP HEADER STRING
+ header
+ # Content-Type: text/html
+
+ header("text/plain")
+ # Content-Type: text/plain
+
+ header({"nph" => true,
+ "status" => "OK", # == "200 OK"
+ # "status" => "200 GOOD",
+ "server" => ENV['SERVER_SOFTWARE'],
+ "connection" => "close",
+ "type" => "text/html",
+ "charset" => "iso-2022-jp",
+ # Content-Type: text/html; charset=iso-2022-jp
+ "language" => "ja",
+ "expires" => Time.now + 30,
+ "cookie" => [cookie1, cookie2],
+ "my_header1" => "my_value"
+ "my_header2" => "my_value"})
+
+header will not convert charset.
+
+status:
+ "OK" --> "200 OK"
+ "PARTIAL_CONTENT" --> "206 Partial Content"
+ "MULTIPLE_CHOICES" --> "300 Multiple Choices"
+ "MOVED" --> "301 Moved Permanently"
+ "REDIRECT" --> "302 Found"
+ "NOT_MODIFIED" --> "304 Not Modified"
+ "BAD_REQUEST" --> "400 Bad Request"
+ "AUTH_REQUIRED" --> "401 Authorization Required"
+ "FORBIDDEN" --> "403 Forbidden"
+ "NOT_FOUND" --> "404 Not Found"
+ "METHOD_NOT_ALLOWED" --> "405 Method Not Allowed"
+ "NOT_ACCEPTABLE" --> "406 Not Acceptable"
+ "LENGTH_REQUIRED" --> "411 Length Required"
+ "PRECONDITION_FAILED" --> "412 Rrecondition Failed"
+ "SERVER_ERROR" --> "500 Internal Server Error"
+ "NOT_IMPLEMENTED" --> "501 Method Not Implemented"
+ "BAD_GATEWAY" --> "502 Bad Gateway"
+ "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
+
+=end
+ def header(options = "text/html")
+
+ buf = ""
+
+ if options.kind_of?(String)
+ options = { "type" => options }
+ end
+
+ unless options.key?("type")
+ options["type"] = "text/html"
+ end
+
+ if options.key?("charset")
+ options["type"].concat( "; charset=" )
+ options["type"].concat( options.delete("charset") )
+ end
+
+ if options.delete("nph") or (/IIS/n === env_table['SERVER_SOFTWARE'])
+ buf.concat( (env_table["SERVER_PROTOCOL"] or "HTTP/1.0") + " " )
+ buf.concat( (HTTP_STATUS[options["status"]] or
+ options["status"] or
+ "200 OK"
+ ) + EOL
+ )
+ buf.concat(
+ "Date: " + CGI::rfc1123_date(Time.now) + EOL
+ )
+
+ unless options.key?("server")
+ options["server"] = (env_table['SERVER_SOFTWARE'] or "")
+ end
+
+ unless options.key?("connection")
+ options["connection"] = "close"
+ end
+
+ end
+ options.delete("status")
+
+ if options.key?("server")
+ buf.concat("Server: " + options.delete("server") + EOL)
+ end
+
+ if options.key?("connection")
+ buf.concat("Connection: " + options.delete("connection") + EOL)
+ end
+
+ buf.concat("Content-Type: " + options.delete("type") + EOL)
+
+ if options.key?("length")
+ buf.concat("Content-Length: " + options.delete("length").to_s + EOL)
+ end
+
+ if options.key?("language")
+ buf.concat("Content-Language: " + options.delete("language") + EOL)
+ end
+
+ if options.key?("expires")
+ buf.concat("Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL)
+ end
+
+ if options.key?("cookie")
+ if options["cookie"].kind_of?(String) or
+ options["cookie"].kind_of?(Cookie)
+ buf.concat("Set-Cookie: " + options.delete("cookie").to_s + EOL)
+ elsif options["cookie"].kind_of?(Array)
+ options.delete("cookie").each{|cookie|
+ buf.concat("Set-Cookie: " + cookie.to_s + EOL)
+ }
+ elsif options["cookie"].kind_of?(Hash)
+ options.delete("cookie").each_value{|cookie|
+ buf.concat("Set-Cookie: " + cookie.to_s + EOL)
+ }
+ end
+ end
+ if @output_cookies
+ for cookie in @output_cookies
+ buf.concat("Set-Cookie: " + cookie.to_s + EOL)
+ end
+ end
+
+ options.each{|key, value|
+ buf.concat(key + ": " + value + EOL)
+ }
+
+ if env_table['MOD_RUBY']
+ buf.scan(/([^:]+): (.+)#{EOL}/n){
+ Apache::request[$1] = $2
+ }
+ Apache::request.send_http_header
+ ''
+ else
+ buf + EOL
+ end
+
+ end # header()
+
+
+=begin
+=== PRINT HTTP HEADER AND STRING TO $>
+ cgi = CGI.new
+ cgi.out{ "string" }
+ # Content-Type: text/html
+ # Content-Length: 6
+ #
+ # string
+
+ cgi.out("text/plain"){ "string" }
+ # Content-Type: text/plain
+ # Content-Length: 6
+ #
+ # string
+
+ cgi.out({"nph" => true,
+ "status" => "OK", # == "200 OK"
+ "server" => ENV['SERVER_SOFTWARE'],
+ "connection" => "close",
+ "type" => "text/html",
+ "charset" => "iso-2022-jp",
+ # Content-Type: text/html; charset=iso-2022-jp
+ "language" => "ja",
+ "expires" => Time.now + (3600 * 24 * 30),
+ "cookie" => [cookie1, cookie2],
+ "my_header1" => "my_value",
+ "my_header2" => "my_value"}){ "string" }
+
+if charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
+convert string charset, and set language to "ja".
+
+=end
+ def out(options = "text/html")
+
+ options = { "type" => options } if options.kind_of?(String)
+ content = yield
+
+ if options.key?("charset")
+ require "nkf"
+ case options["charset"]
+ when /iso-2022-jp/ni
+ content = NKF::nkf('-j', content)
+ options["language"] = "ja" unless options.key?("language")
+ when /euc-jp/ni
+ content = NKF::nkf('-e', content)
+ options["language"] = "ja" unless options.key?("language")
+ when /shift_jis/ni
+ content = NKF::nkf('-s', content)
+ options["language"] = "ja" unless options.key?("language")
+ end
+ end
+
+ options["length"] = content.length.to_s
+ output = stdoutput
+ output.binmode if defined? output.binmode
+ output.print header(options)
+ output.print content
+ end
+
+
+=begin
+=== PRINT
+ cgi = CGI.new
+ cgi.print # default: cgi.print == $>.print
+=end
+ def print(*options)
+ stdoutput.print(*options)
+ end
+
+
+=begin
+=== MAKE COOKIE OBJECT
+ cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
+ cookie1 = CGI::Cookie::new({"name" => "name", "value" => "value"})
+ cookie1 = CGI::Cookie::new({'name' => 'name',
+ 'value' => ['value1', 'value2', ...],
+ 'path' => 'path', # optional
+ 'domain' => 'domain', # optional
+ 'expires' => Time.now, # optional
+ 'secure' => true # optional
+ })
+
+ cgi.out({"cookie" => [cookie1, cookie2]}){ "string" }
+
+ name = cookie1.name
+ values = cookie1.value
+ path = cookie1.path
+ domain = cookie1.domain
+ expires = cookie1.expires
+ secure = cookie1.secure
+
+ cookie1.name = 'name'
+ cookie1.value = ['value1', 'value2', ...]
+ cookie1.path = 'path'
+ cookie1.domain = 'domain'
+ cookie1.expires = Time.now + 30
+ cookie1.secure = true
+=end
+ require "delegate"
+ class Cookie < SimpleDelegator
+
+ def initialize(name = "", *value)
+ options = if name.kind_of?(String)
+ { "name" => name, "value" => value }
+ else
+ name
+ end
+ unless options.key?("name")
+ raise ArgumentError, "`name' required"
+ end
+
+ @name = options["name"]
+ @value = Array(options["value"])
+ @path = options["path"]
+ @domain = options["domain"]
+ @expires = options["expires"]
+ @secure = options["secure"] == true ? true : false
+
+ super(@value)
+ end
+
+ attr_accessor("name", "value", "path", "domain", "expires")
+ attr_reader("secure")
+ def secure=(val)
+ @secure = val if val == true or val == false
+ @secure
+ end
+
+ def to_s
+ buf = ""
+ buf.concat(@name + '=')
+
+ if @value.kind_of?(String)
+ buf.concat CGI::escape(@value)
+ else
+ buf.concat(@value.filter{|v| CGI::escape(v) }.join("&"))
+ end
+
+ if @domain
+ buf.concat('; domain=' + @domain)
+ end
+
+ if @path
+ buf.concat('; path=' + @path)
+ end
+
+ if @expires
+ buf.concat('; expires=' + CGI::rfc1123_date(@expires))
+ end
+
+ if @secure == true
+ buf.concat('; secure')
+ end
+
+ buf
+ end
+
+ end # class Cookie
+
+
+=begin
+=== PARSE RAW COOKIE STRING
+ cookies = CGI::Cookie::parse("raw_cookie_string")
+ # { "name1" => cookie1, "name2" => cookie2, ... }
+=end
+ def Cookie::parse(raw_cookie)
+ cookies = Hash.new([])
+
+ raw_cookie.split('; ').each do |pairs|
+ name, values = pairs.split('=',2)
+ name = CGI::unescape(name)
+ values = values.split('&').filter{|v| CGI::unescape(v) }
+ if cookies.key?(name)
+ cookies[name].value.push(*values)
+ else
+ cookies[name] = Cookie::new({ "name" => name, "value" => values })
+ end
+ end
+
+ cookies
+ end
+
+
+=begin
+=== PARSE QUERY STRING
+ params = CGI::parse("query_string")
+ # {"name1" => ["value1", "value2", ...],
+ # "name2" => ["value1", "value2", ...], ... }
+=end
+ def CGI::parse(query)
+ params = Hash.new([])
+
+ query.split(/[&;]/n).each do |pairs|
+ key, value = pairs.split('=',2).filter{|v| CGI::unescape(v) }
+ if params.key?(key)
+ params[key].push(value)
+ else
+ params[key] = [value]
+ end
+ end
+
+ params
+ end
+
+
+ module QueryExtension
+
+ %w[ CONTENT_LENGTH SERVER_PORT ].
+ each{|env|
+ eval( <<-END )
+ def #{env.sub(/^HTTP_/n, '').downcase}
+ env_table["#{env}"] && Integer(env_table["#{env}"])
+ end
+ END
+ }
+
+ %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
+ PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
+ REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
+ SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
+
+ HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
+ HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
+ HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].
+ each{|env|
+ eval( <<-END )
+ def #{env.sub(/^HTTP_/n, '').downcase}
+ env_table["#{env}"]
+ end
+ END
+ }
+
+ def raw_cookie
+ env_table["HTTP_COOKIE"]
+ end
+
+ def raw_cookie2
+ env_table["HTTP_COOKIE2"]
+ end
+
+ attr_accessor("cookies")
+ attr("params")
+ def params=(hash)
+ @params.clear
+ @params.update(hash)
+ end
+
+ def read_multipart(boundary, content_length)
+ params = Hash.new([])
+ boundary = "--" + boundary
+ buf = ""
+ bufsize = 10 * 1024
+
+ # start multipart/form-data
+ stdinput.binmode
+ content_length -= stdinput.read((boundary + EOL).size).size
+
+ require "tempfile.rb"
+
+ until -1 == content_length
+ head = nil
+ body = Tempfile.new("CGI")
+ body.binmode
+
+ until head and (/#{boundary}(?:#{EOL}|--)/n === buf)
+
+ if (not head) and (/#{EOL}#{EOL}/n === buf)
+ buf.sub!(/\A((?:.|\n)*?#{EOL})#{EOL}/n){
+ head = $1.dup
+ ""
+ }
+ next
+ end
+
+ if head and ( (EOL + boundary + EOL).size < buf.size )
+ body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
+ buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
+ end
+
+ c = if bufsize < content_length
+ stdinput.read(bufsize) or ''
+ else
+ stdinput.read(content_length) or ''
+ end
+ buf.concat c
+ content_length -= c.size
+
+ end
+
+ buf.sub!(/\A((?:.|\n)*?)(?:#{EOL})?#{boundary}(#{EOL}|--)/n){
+ body.print $1
+ if "--" == $2
+ content_length = -1
+ end
+ ""
+ }
+
+ body.rewind
+
+ eval <<-END
+ def body.local_path
+ #{body.path.dump}
+ end
+ END
+
+ /Content-Disposition:.* filename="?([^\";]*)"?/ni === head
+ eval <<-END
+ def body.original_filename
+ #{
+ filename = ($1 or "").dup
+ if (/Mac/ni === env_table['HTTP_USER_AGENT']) and
+ (/Mozilla/ni === env_table['HTTP_USER_AGENT']) and
+ (not /MSIE/ni === env_table['HTTP_USER_AGENT'])
+ CGI::unescape(filename)
+ else
+ filename
+ end.dump
+ }
+ end
+ END
+
+ /Content-Type: (.*)/ni === head
+ eval <<-END
+ def body.content_type
+ #{($1 or "").dump}
+ end
+ END
+
+ /Content-Disposition:.* name="?([^\";]*)"?/ni === head
+ name = $1.dup
+
+ if params.key?(name)
+ params[name].push(body)
+ else
+ params[name] = [body]
+ end
+
+ end
+
+ params
+ end # read_multipart
+ private :read_multipart
+
+ # offline mode. read name=value pairs on standard input.
+ def read_from_cmdline
+ require "shellwords.rb"
+
+ unless ARGV.empty?
+ str = ARGV.join(' ')
+ else
+ if STDIN.tty?
+ STDERR.print(
+ %|(offline mode: enter name=value pairs on standard input)\n|
+ )
+ end
+ str = readlines.join(' ')
+ str.gsub!(/\n/n, '')
+ end
+
+ str.gsub!(/\\=/n, '%3D')
+ str.gsub!(/\\&/n, '%26')
+
+ words = Shellwords.shellwords(str)
+
+ if words.find{|x| /=/n === x }
+ words.join('&')
+ else
+ words.join('+')
+ end
+ end
+ private :read_from_cmdline
+
+ def initialize_query()
+ if ("POST" == env_table['REQUEST_METHOD']) and
+ (%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n ===
+ env_table['CONTENT_TYPE'])
+ boundary = $1.dup
+ @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
+ else
+ @params = CGI::parse(
+ case env_table['REQUEST_METHOD']
+ when "GET", "HEAD"
+ if env_table['MOD_RUBY']
+ Apache::request.args or ""
+ else
+ env_table['QUERY_STRING'] or ""
+ end
+ when "POST"
+ stdinput.binmode
+ stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
+ else
+ read_from_cmdline
+ end
+ )
+ end
+
+ @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or
+ env_table['COOKIE'] or ""))
+
+ end
+ private :initialize_query
+
+ def [](*args)
+ @params[*args]
+ end
+
+ def keys(*args)
+ @params.keys(*args)
+ end
+
+ def has_key?(*args)
+ @params.has_key?(*args)
+ end
+ alias key? has_key?
+ alias include? has_key?
+
+ end # QueryExtension
+
+
+=begin
+=== HTML PRETTY FORMAT
+ print CGI::pretty("<HTML><BODY></BODY></HTML>")
+ # <HTML>
+ # <BODY>
+ # </BODY>
+ # </HTML>
+
+ print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
+ # <HTML>
+ # <BODY>
+ # </BODY>
+ # </HTML>
+=end
+ def CGI::pretty_shift(string, shift = " ")
+ shift = " " if true == shift
+ str = string.dup
+ str.gsub!(/\n(?!\z)/n, "\n" + shift)
+ str
+ end
+ def CGI::pretty_nest(string, shift = " ")
+ str = string.dup
+ str.gsub!(/(<(\w+).*?>)((?:.|\n)*?)(<\/\2>)/n){
+ $1 + CGI::pretty_shift(CGI::pretty_nest($3, shift), shift) + $4
+ }
+ str
+ end
+ def CGI::pretty(string, shift = " ")
+ str = string.dup
+ str.gsub!(/<(?:.|\n)*?>/n, "\n\\0")
+ str.gsub!(/<(?:.|\n)*?>(?!\n)/n, "\\0\n")
+ CGI::pretty_nest(str, shift)
+ end
+
+
+=begin
+== HTML ELEMENTS
+
+ cgi = CGI.new("html3") # add HTML generation methods
+ cgi.element
+ cgi.element{ "string" }
+ cgi.element({ "ATTRILUTE1" => "value1", "ATTRIBUTE2" => "value2" })
+ cgi.element({ "ATTRILUTE1" => "value1", "ATTRIBUTE2" => "value2" }){ "string" }
+
+ # add HTML generation methods
+ CGI.new("html3") # html3.2
+ CGI.new("html4") # html4.0 (Strict)
+ CGI.new("html4Tr") # html4.0 Transitional
+ CGI.new("html4Fr") # html4.0 Frameset
+
+=end
+
+
+ module TagMaker
+
+ # - -
+ def nn_element_def(element)
+ <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase)
+ "<element.upcase" + attributes.collect{|name, value|
+ " " + CGI::escapeHTML(name) +
+ if true == value
+ ""
+ else
+ '="' + CGI::escapeHTML(value) + '"'
+ end
+ }.to_s + ">" +
+ if iterator?
+ yield.to_s
+ else
+ ""
+ end +
+ "</element.upcase>"
+ END
+ end
+
+ # - O EMPTY
+ def nOE_element_def(element)
+ <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase)
+ "<element.upcase" + attributes.collect{|name, value|
+ " " + CGI::escapeHTML(name) +
+ if true == value
+ ""
+ else
+ '="' + CGI::escapeHTML(value) + '"'
+ end
+ }.to_s + ">"
+ END
+ end
+
+ # O O or - O
+ def nO_element_def(element)
+ <<-END.gsub(/element\.downcase/n, element.downcase).gsub(/element\.upcase/n, element.upcase)
+ "<element.upcase" + attributes.collect{|name, value|
+ " " + CGI::escapeHTML(name) +
+ if true == value
+ ""
+ else
+ '="' + CGI::escapeHTML(value) + '"'
+ end
+ }.to_s + ">" +
+ if iterator?
+ yield.to_s + "</element.upcase>"
+ else
+ ""
+ end
+ END
+ end
+
+ end # TagMaker
+
+
+ module HtmlExtension
+ extend TagMaker
+
+
+=begin
+=== A ELEMENT
+ a("url")
+ # = a({ "HREF" => "url" })
+=end
+ def a(href = "")
+ attributes = if href.kind_of?(String)
+ { "HREF" => href }
+ else
+ href
+ end
+ if iterator?
+ super(attributes){ yield }
+ else
+ super(attributes)
+ end
+ end
+
+
+=begin
+=== BASE ELEMENT
+ base("url")
+ # = base({ "HREF" => "url" })
+=end
+ def base(href = "")
+ attributes = if href.kind_of?(String)
+ { "HREF" => href }
+ else
+ href
+ end
+ if iterator?
+ super(attributes){ yield }
+ else
+ super(attributes)
+ end
+ end
+
+
+=begin
+=== BLOCKQUOTE ELEMENT
+ blockquote("url"){ "string" }
+ # = blockquote({ "CITE" => "url" }){ "string" }
+=end
+ def blockquote(cite = nil)
+ attributes = if cite.kind_of?(String)
+ { "CITE" => cite }
+ else
+ cite or ""
+ end
+ if iterator?
+ super(attributes){ yield }
+ else
+ super(attributes)
+ end
+ end
+
+
+=begin
+=== CAPTION ELEMENT
+ caption("align"){ "string" }
+ # = caption({ "ALIGN" => "align" }){ "string" }
+=end
+ def caption(align = nil)
+ attributes = if align.kind_of?(String)
+ { "ALIGN" => align }
+ else
+ align or ""
+ end
+ if iterator?
+ super(attributes){ yield }
+ else
+ super(attributes)
+ end
+ end
+
+
+=begin
+=== CHECKBOX
+ checkbox("name")
+ # = checkbox({ "NAME" => "name" })
+
+ checkbox("name", "value")
+ # = checkbox({ "NAME" => "name", "VALUE" => "value" })
+
+ checkbox("name", "value", true)
+ # = checkbox({ "NAME" => "name", "VALUE" => "value", "CHECKED" => true })
+=end
+ def checkbox(name = "", value = nil, checked = nil)
+ attributes = if name.kind_of?(String)
+ { "TYPE" => "checkbox", "NAME" => name,
+ "VALUE" => value, "CHECKED" => checked }
+ else
+ name["TYPE"] = "checkbox"
+ name
+ end
+ input(attributes)
+ end
+
+
+=begin
+=== CHECKBOX_GROUP
+ checkbox_group("name", "foo", "bar", "baz")
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
+
+ checkbox_group("name", ["foo"], ["bar", true], "baz")
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
+ # <INPUT TYPE="checkbox" SELECTED NAME="name" VALUE="bar">bar
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
+
+ checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
+ # <INPUT TYPE="checkbox" SELECTED NAME="name" VALUE="2">Bar
+ # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
+
+ checkbox_group({ "NAME" => "name",
+ "VALUES" => ["foo", "bar", "baz"] })
+
+ checkbox_group({ "NAME" => "name",
+ "VALUES" => [["foo"], ["bar", true], "baz"] })
+
+ checkbox_group({ "NAME" => "name",
+ "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
+=end
+ def checkbox_group(name = "", *values)
+ if name.kind_of?(Hash)
+ values = name["VALUES"]
+ name = name["NAME"]
+ end
+ values.collect{|value|
+ if value.kind_of?(String)
+ checkbox(name, value) + value
+ else
+ if value[value.size - 1] == true
+ checkbox(name, value[0], true) +
+ value[value.size - 2]
+ else
+ checkbox(name, value[0]) +
+ value[value.size - 1]
+ end
+ end
+ }.to_s
+ end
+
+
+=begin
+=== FILE_FIELD
+ file_field("name")
+ # <INPUT TYPE="file" NAME="name" SIZE="20">
+
+ file_field("name", 40)
+ # <INPUT TYPE="file" NAME="name" SIZE="40">
+
+ file_field("name", 40, 100)
+ # <INPUT TYPE="file" NAME="name" SIZE="40", MAXLENGTH="100">
+
+ file_field({ "NAME" => "name", "SIZE" => 40 })
+ # <INPUT TYPE="file" NAME="name" SIZE="40">
+=end
+ def file_field(name = "", size = 20, maxlength = nil)
+ attributes = if name.kind_of?(String)
+ { "TYPE" => "file", "NAME" => name,
+ "SIZE" => size.to_s }
+ else
+ name["TYPE"] = "file"
+ name
+ end
+ attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+ input(attributes)
+ end
+
+
+=begin
+=== FORM ELEMENT
+ form{ "string" }
+ # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+
+ form("get"){ "string" }
+ # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+
+ form("get", "url"){ "string" }
+ # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+
+ form({"METHOD" => "post", ENCTYPE => "enctype"}){ "string" }
+ # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
+=end
+ def form(method = "post", action = nil, enctype = "application/x-www-form-urlencoded")
+ attributes = if method.kind_of?(String)
+ { "METHOD" => method, "ACTION" => action,
+ "ENCTYPE" => enctype }
+ else
+ unless method.key?("METHOD")
+ method["METHOD"] = method
+ end
+ unless method.key?("ENCTYPE")
+ method["ENCTYPE"] = enctype
+ end
+ method
+ end
+ if iterator?
+ body = yield
+ else
+ body = ""
+ end
+ if @output_hidden
+ hidden = @output_hidden.collect{|k,v|
+ "<INPUT TYPE=HIDDEN NAME=\"#{k}\" VALUE=\"#{v}\">"
+ }.to_s
+ body.concat hidden
+ end
+ super(attributes){body}
+ end
+
+=begin
+=== HIDDEN FIELD
+ hidden("name")
+ # <INPUT TYPE="hidden" NAME="name">
+
+ hidden("name", "value")
+ # <INPUT TYPE="hidden" NAME="name" VALUE="value">
+
+ hidden({ "NAME" => "name", "VALUE" => "reset", "ID" => "foo" })
+ # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
+=end
+ def hidden(name = "", value = nil)
+ attributes = if name.kind_of?(String)
+ { "TYPE" => "hidden", "NAME" => name, "VALUE" => value }
+ else
+ name["TYPE"] = "hidden"
+ name
+ end
+ input(attributes)
+ end
+
+
+=begin
+=== HTML ELEMENT
+
+ html{ "string" }
+ # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
+
+ html({ "LANG" => "ja" }){ "string" }
+ # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
+
+ html({ "DOCTYPE" => false }){ "string" }
+ # <HTML>string</HTML>
+
+ html({ "DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">' }){ "string" }
+ # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
+
+ html({ "PRETTY" => " " }){ "<BODY></BODY>" }
+ # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+ # <HTML>
+ # <BODY>
+ # </BODY>
+ # </HTML>
+
+ html({ "PRETTY" => "\t" }){ "<BODY></BODY>" }
+ # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+ # <HTML>
+ # <BODY>
+ # </BODY>
+ # </HTML>
+
+ html("PRETTY"){ "<BODY></BODY>" }
+ # = html({ "PRETTY" => " " }){ "<BODY></BODY>" }
+
+ html(if $VERBOSE then "PRETTY" end){ "HTML string" }
+
+=end
+ def html(attributes = {})
+ if nil == attributes
+ attributes = {}
+ elsif "PRETTY" == attributes
+ attributes = { "PRETTY" => true }
+ end
+ pretty = attributes.delete("PRETTY")
+ buf = ""
+
+ if attributes.key?("DOCTYPE")
+ if attributes["DOCTYPE"]
+ buf.concat( attributes.delete("DOCTYPE") )
+ else
+ attributes.delete("DOCTYPE")
+ end
+ else
+ buf.concat( doctype )
+ end
+
+ if iterator?
+ buf.concat( super(attributes){ yield } )
+ else
+ buf.concat( super(attributes) )
+ end
+
+ if pretty
+ CGI::pretty(buf, pretty)
+ else
+ buf
+ end
+
+ end
+
+
+=begin
+=== IMAGE_BUTTON
+ image_button("url")
+ # <INPUT TYPE="image" SRC="url">
+
+ image_button("url", "name", "string")
+ # <INPUT TYPE="image" SRC="url" NAME="name", ALT="string">
+
+ image_button({ "SRC" => "url", "ATL" => "strng" })
+ # <INPUT TYPE="image" SRC="url" ALT="string">
+=end
+ def image_button(src = "", name = nil, alt = nil)
+ attributes = if src.kind_of?(String)
+ { "TYPE" => "image", "SRC" => src, "NAME" => name,
+ "ALT" => alt }
+ else
+ name["TYPE"] = "image"
+ name
+ end
+ input(attributes)
+ end
+
+
+=begin
+=== IMG ELEMENT
+ img("src", "alt", 100, 50)
+ # <IMG SRC="src" ALT="alt" WIDTH="100", HEIGHT="50">
+
+ img({ "SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50 })
+ # <IMG SRC="src" ALT="alt" WIDTH="100", HEIGHT="50">
+=end
+ def img(src = "", alt = "", width = nil, height = nil)
+ attributes = if src.kind_of?(String)
+ { "SRC" => src, "ALT" => alt }
+ else
+ src
+ end
+ attributes["WIDTH"] = width.to_s if width
+ attributes["HEIGHT"] = height.to_s if height
+ super(attributes)
+ end
+
+
+=begin
+=== MULTIPART FORM
+ multipart_form{ "string" }
+ # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
+
+ multipart_form("url"){ "string" }
+ # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
+=end
+ def multipart_form(action = nil, enctype = "multipart/form-data")
+ attributes = if action == nil
+ { "METHOD" => "post", "ENCTYPE" => enctype }
+ elsif action.kind_of?(String)
+ { "METHOD" => "post", "ACTION" => action,
+ "ENCTYPE" => enctype }
+ else
+ unless action.key?("METHOD")
+ action["METHOD"] = "post"
+ end
+ unless action.key?("ENCTYPE")
+ action["ENCTYPE"] = enctype
+ end
+ action
+ end
+ if iterator?
+ form(attributes){ yield }
+ else
+ form(attributes)
+ end
+ end
+
+
+=begin
+=== PASSWORD_FIELD
+ password_field("name")
+ # <INPUT TYPE="password" NAME="name" SIZE="40">
+
+ password_field("name", "value")
+ # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
+
+ password_field("password", "value", 80, 200)
+ # <INPUT TYPE="password" NAME="name" VALUE="value", SIZE="80", MAXLENGTH="200">
+
+ password_field({ "NAME" => "name", "VALUE" => "value" })
+ # <INPUT TYPE="password" NAME="name" VALUE="value">
+=end
+ def password_field(name = "", value = nil, size = 40, maxlength = nil)
+ attributes = if name.kind_of?(String)
+ { "TYPE" => "password", "NAME" => name,
+ "VALUE" => value, "SIZE" => size.to_s }
+ else
+ name["TYPE"] = "password"
+ name
+ end
+ attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+ input(attributes)
+ end
+
+
+=begin
+=== POPUP_MENU
+ popup_menu("name", "foo", "bar", "baz")
+ # <SELECT NAME="name">
+ # <OPTION VALUE="foo">foo</OPTION>
+ # <OPTION VALUE="bar">bar</OPTION>
+ # <OPTION VALUE="baz">baz</OPTION>
+ # </SELECT>
+
+ popup_menu("name", ["foo"], ["bar", true], "baz")
+ # <SELECT NAME="name">
+ # <OPTION VALUE="foo">foo</OPTION>
+ # <OPTION VALUE="bar" SELECTED>bar</OPTION>
+ # <OPTION VALUE="baz">baz</OPTION>
+ # </SELECT>
+
+ popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+ # <SELECT NAME="name">
+ # <OPTION VALUE="1">Foo</OPTION>
+ # <OPTION SELECTED VALUE="2">Bar</OPTION>
+ # <OPTION VALUE="Baz">Baz</OPTION>
+ # </SELECT>
+
+ popup_menu({"NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
+ "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
+ # <SELECT NAME="name" MULTIPLE SIZE="2">
+ # <OPTION VALUE="1">Foo</OPTION>
+ # <OPTION SELECTED VALUE="2">Bar</OPTION>
+ # <OPTION VALUE="Baz">Baz</OPTION>
+ # </SELECT>
+=end
+ def popup_menu(name = "", *values)
+
+ if name.kind_of?(Hash)
+ values = name["VALUES"]
+ size = name["SIZE"].to_s if name["SIZE"]
+ multiple = name["MULTIPLE"]
+ name = name["NAME"]
+ else
+ size = nil
+ multiple = nil
+ end
+
+ select({ "NAME" => name, "SIZE" => size,
+ "MULTIPLE" => multiple }){
+ values.collect{|value|
+ if value.kind_of?(String)
+ option({ "VALUE" => value }){ value }
+ else
+ if value[value.size - 1] == true
+ option({ "VALUE" => value[0], "SELECTED" => true }){
+ value[value.size - 2]
+ }
+ else
+ option({ "VALUE" => value[0] }){
+ value[value.size - 1]
+ }
+ end
+ end
+ }.to_s
+ }
+
+ end
+
+
+=begin
+=== RADIO_BUTTON
+ radio_button("name", "value")
+ # <INPUT TYPE="radio" NAME="name", VALUE="value">
+
+ radio_button("name", "value", true)
+ # <INPUT TYPE="radio" NAME="name", VALUE="value", CHECKED>
+
+ radio_button({ "NAME" => "name", "VALUE" => "value", "ID" => "foo" })
+ # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
+=end
+ def radio_button(name = "", value = nil, checked = nil)
+ attributes = if name.kind_of?(String)
+ { "TYPE" => "radio", "NAME" => name,
+ "VALUE" => value, "CHECKED" => checked }
+ else
+ name["TYPE"] = "radio"
+ name
+ end
+ input(attributes)
+ end
+
+
+=begin
+=== RADIO_GROUP
+ radio_group("name", "foo", "bar", "baz")
+ # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
+ # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
+ # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
+
+ radio_group("name", ["foo"], ["bar", true], "baz")
+ # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
+ # <INPUT TYPE="radio" SELECTED NAME="name" VALUE="bar">bar
+ # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
+
+ radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+ # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
+ # <INPUT TYPE="radio" SELECTED NAME="name" VALUE="2">Bar
+ # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
+
+ radio_group({ "NAME" => "name",
+ "VALUES" => ["foo", "bar", "baz"] })
+
+ radio_group({ "NAME" => "name",
+ "VALUES" => [["foo"], ["bar", true], "baz"] })
+
+ radio_group({ "NAME" => "name",
+ "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
+=end
+ def radio_group(name = "", *values)
+ if name.kind_of?(Hash)
+ values = name["VALUES"]
+ name = name["NAME"]
+ end
+ values.collect{|value|
+ if value.kind_of?(String)
+ radio_button(name, value) + value
+ else
+ if value[value.size - 1] == true
+ radio_button(name, value[0], true) +
+ value[value.size - 2]
+ else
+ radio_button(name, value[0]) +
+ value[value.size - 1]
+ end
+ end
+ }.to_s
+ end
+
+
+=begin
+=== RESET BUTTON
+ reset
+ # <INPUT TYPE="reset">
+
+ reset("reset")
+ # <INPUT TYPE="reset" VALUE="reset">
+
+ reset({ "VALUE" => "reset", "ID" => "foo" })
+ # <INPUT TYPE="reset" VALUE="reset" ID="foo">
+=end
+ def reset(value = nil, name = nil)
+ attributes = if (not value) or value.kind_of?(String)
+ { "TYPE" => "reset", "VALUE" => value, "NAME" => name }
+ else
+ value["TYPE"] = "reset"
+ value
+ end
+ input(attributes)
+ end
+
+
+=begin
+=== SCROLLING_LIST
+ scrolling_list({"NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
+ "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"] })
+ # <SELECT NAME="name" MULTIPLE SIZE="2">
+ # <OPTION VALUE="1">Foo</OPTION>
+ # <OPTION SELECTED VALUE="2">Bar</OPTION>
+ # <OPTION VALUE="Baz">Baz</OPTION>
+ # </SELECT>
+=end
+ alias scrolling_list popup_menu
+
+
+=begin
+=== SUBMIT BUTTON
+ submit
+ # <INPUT TYPE="submit">
+
+ submit("ok")
+ # <INPUT TYPE="submit" VALUE="ok">
+
+ submit("ok", "button1")
+ # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
+
+ submit({ "VALUE" => "ok", "NAME" => "button1", "ID" => "foo" })
+ # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
+=end
+ def submit(value = nil, name = nil)
+ attributes = if (not value) or value.kind_of?(String)
+ { "TYPE" => "submit", "VALUE" => value, "NAME" => name }
+ else
+ value["TYPE"] = "submit"
+ value
+ end
+ input(attributes)
+ end
+
+
+=begin
+=== TEXT_FIELD
+ text_field("name")
+ # <INPUT TYPE="text" NAME="name" SIZE="40">
+
+ text_field("name", "value")
+ # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
+
+ text_field("name", "value", 80)
+ # <INPUT TYPE="text" NAME="name" VALUE="value", SIZE="80">
+
+ text_field("name", "value", 80, 200)
+ # <INPUT TYPE="text" NAME="name" VALUE="value", SIZE="80", MAXLENGTH="200">
+
+ text_field({ "NAME" => "name", "VALUE" => "value" })
+ # <INPUT TYPE="text" NAME="name" VALUE="value">
+=end
+ def text_field(name = "", value = nil, size = 40, maxlength = nil)
+ attributes = if name.kind_of?(String)
+ { "TYPE" => "text", "NAME" => name, "VALUE" => value,
+ "SIZE" => size.to_s }
+ else
+ name["TYPE"] = "text"
+ name
+ end
+ attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+ input(attributes)
+ end
+
+
+=begin
+=== TEXTAREA ELEMENT
+
+ textarea("name")
+ # = textarea({ "NAME" => "name", "COLS" => 70, "ROWS" => 10 })
+
+ textarea("name", 40, 5)
+ # = textarea({ "NAME" => "name", "COLS" => 40, "ROWS" => 5 })
+=end
+ def textarea(name = "", cols = 70, rows = 10)
+ attributes = if name.kind_of?(String)
+ { "NAME" => name, "COLS" => cols.to_s,
+ "ROWS" => rows.to_s }
+ else
+ name
+ end
+ if iterator?
+ super(attributes){ yield }
+ else
+ super(attributes)
+ end
+ end
+
+ end # HtmlExtension
+
+
+ module Html3
+ extend TagMaker
+
+ def doctype
+ %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">|
+ end
+
+ # - -
+ %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG DFN CODE SAMP KBD VAR
+ CITE FONT ADDRESS DIV center MAP APPLET PRE XMP LISTING DL OL UL DIR
+ MENU SELECT table TITLE STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM
+ BLOCKQUOTE CAPTION ].
+ each{|element|
+ eval( <<-BEGIN + nn_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # - O EMPTY
+ %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT ISINDEX META ].
+ each{|element|
+ eval( <<-BEGIN + nOE_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # O O or - O
+ %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr th td ].
+ each{|element|
+ eval( <<-BEGIN + nO_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ end # Html3
+
+
+ module Html4
+ extend TagMaker
+
+ def doctype
+ %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">|
+ end
+
+ # - -
+ %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD VAR CITE ABBR ACRONYM
+ SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT H1 H2 H3 H4 H5 H6 PRE Q
+ INS DEL DL OL UL LABEL SELECT OPTGROUP FIELDSET LEGEND BUTTON TABLE
+ TITLE STYLE SCRIPT NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ].
+ each{|element|
+ eval( <<-BEGIN + nn_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # - O EMPTY
+ %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ].
+ each{|element|
+ eval( <<-BEGIN + nOE_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # O O or - O
+ %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY COLGROUP TR TH TD HEAD].
+ each{|element|
+ eval( <<-BEGIN + nO_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ end # Html4
+
+
+ module Html4Tr
+ extend TagMaker
+
+ def doctype
+ %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">|
+ end
+
+ # - -
+ %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN CODE SAMP KBD VAR CITE
+ ABBR ACRONYM FONT SUB SUP SPAN BDO ADDRESS DIV CENTER MAP OBJECT
+ APPLET H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL DIR MENU LABEL SELECT
+ OPTGROUP FIELDSET LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE
+ SCRIPT NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ].
+ each{|element|
+ eval( <<-BEGIN + nn_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # - O EMPTY
+ %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT COL ISINDEX META ].
+ each{|element|
+ eval( <<-BEGIN + nOE_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # O O or - O
+ %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY COLGROUP TR TH TD HEAD ].
+ each{|element|
+ eval( <<-BEGIN + nO_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ end # Html4Tr
+
+
+ module Html4Fr
+ include Html4Tr
+ extend TagMaker
+
+ def doctype
+ %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">|
+ end
+
+ # - -
+ %w[ FRAMESET ].
+ each{|element|
+ eval( <<-BEGIN + nn_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ # - O EMPTY
+ %w[ FRAME ].
+ each{|element|
+ eval( <<-BEGIN + nOE_element_def(element) + <<-END )
+ def #{element.downcase}(attributes = {})
+ BEGIN
+ end
+ END
+ }
+
+ end # Html4Fr
+
+
+ def initialize(type = "query")
+ extend QueryExtension
+ initialize_query()
+ # @params, @cookies initialized in initialize_query
+
+ case type
+ when "html3"
+ extend Html3
+ extend HtmlExtension
+ when "html4"
+ extend Html4
+ extend HtmlExtension
+ when "html4Tr"
+ extend Html4Tr
+ extend HtmlExtension
+ when "html4Fr"
+ extend Html4Fr
+ extend HtmlExtension
+ end
+ end
+end
+
+
+=begin
+
+== HISTRY
+
+=== Version 1.00 - wakou
+
+1999/09/13 23:00:58
+
+- COUTION! name change. CGI.rb --> cgi.rb
+
+- CGI#auth_type, CGI#content_length, CGI#content_type, ...
+if not ENV included it, then return nil.
+
+- CGI#content_length and CGI#server_port return Integer.
+
+- if not CGI#params.include?('name'), then CGI#params['name'] return [].
+
+- if not CGI#cookies.include?('name'), then CGI#cookies['name'] return [].
+
+=== Version 0.41 - wakou
+
+1999/08/05 18:04:59
+
+- typo. thanks to MJ Ray <markj@altern.org>
+ HTTP_STATUS["NOT_INPLEMENTED"] --> HTTP_STATUS["NOT_IMPLEMENTED"]
+
+=== Version 0.40 - wakou
+
+1999/07/20 20:44:31
+
+- COUTION! incompatible change.
+ sorry, but probably this change is last big incompatible change.
+
+- CGI::print --> CGI#out
+
+ cgi = CGI.new
+ cgi.out{"string"} # old: CGI::print{"string"}
+
+- CGI::cookie --> CGI::Cookie::new
+
+ cookie1 = CGI::Cookie::new # old: CGI::cookie
+
+- CGI::header --> CGI#header
+
+=== Version 0.30 - wakou
+
+1999/06/29 06:50:21
+
+- COUTION! incompatible change.
+ query = CGI.new
+ cookies = query.cookies # old: query.cookie
+ values = query.cookies[name] # old: query.cookie[name]
+
+=== Version 0.24 - wakou
+
+1999/06/21 21:05:57
+
+- CGI::Cookie::parse() return { name => CGI::Cookie object } pairs.
+
+=== Version 0.23 - wakou
+
+1999/06/20 23:29:12
+
+- modified a bit to clear module separation.
+
+=== Version 0.22 - matz
+
+Mon Jun 14 17:49:32 JST 1999
+
+- Cookies are now CGI::Cookie objects.
+- Cookie modeled after CGI::Cookie.pm.
+
+=== Version 0.21 - matz
+
+Fri Jun 11 11:19:11 JST 1999
+
+- modified a bit to clear module separation.
+
+=== Version 0.20 - wakou
+
+1999/06/03 06:48:15
+
+- support for multipart form.
+
+=== Version 0.10 - wakou
+
+1999/05/24 07:05:41
+
+- first release.
+
+=end
diff --git a/lib/jcode.rb b/lib/jcode.rb
index 92b9284..7a4cddd 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -4,58 +4,82 @@ $vsave, $VERBOSE = $VERBOSE, FALSE
class String
printf STDERR, "feel free for some warnings:\n" if $VERBOSE
- def jlength
- self.split(//).length
- end
-
- alias original_succ succ
- private :original_succ
+ PATTERN_SJIS = '[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]'
+ PATTERN_EUC = '[\xa1-\xfe][\xa1-\xfe]'
+ PATTERN_UTF8 = '[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf]'
+
+ RE_SJIS = Regexp.new(PATTERN_SJIS, 'n')
+ RE_EUC = Regexp.new(PATTERN_EUC, 'n')
+ RE_UTF8 = Regexp.new(PATTERN_UTF8, 'n')
+
+ SUCC = {}
+ SUCC['s'] = Hash.new(1)
+ for i in 0 .. 0x3f
+ SUCC['s'][i.chr] = 0x40 - i
+ end
+ SUCC['s']["\x7e"] = 0x80 - 0x7e
+ SUCC['s']["\xfd"] = 0x100 - 0xfd
+ SUCC['s']["\xfe"] = 0x100 - 0xfe
+ SUCC['s']["\xff"] = 0x100 - 0xff
+ SUCC['e'] = Hash.new(1)
+ for i in 0 .. 0xa0
+ SUCC['e'][i.chr] = 0xa1 - i
+ end
+ SUCC['e']["\xfe"] = 2
+ SUCC['u'] = Hash.new(1)
+ for i in 0 .. 0x7f
+ SUCC['u'][i.chr] = 0x80 - i
+ end
+ SUCC['u']["\xbf"] = 0x100 - 0xbf
def mbchar?
case $KCODE[0]
when ?s, ?S
- self =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
+ self =~ RE_SJIS
when ?e, ?E
- self =~ /[\xa1-\xfe][\xa1-\xfe]/n
+ self =~ RE_EUC
+ when ?u, ?U
+ self =~ RE_UTF8
else
- false
+ nil
end
end
- def succ
- if self[-2] and self[-2, 2].mbchar?
- s = self.dup
- s[-1] += 1
- s[-1] += 1 unless s[-2, 2].mbchar?
- return s
+ def end_regexp
+ case $KCODE[0]
+ when ?s, ?S
+ /#{PATTERN_SJIS}$/o
+ when ?e, ?E
+ /#{PATTERN_EUC}$/o
+ when ?u, ?U
+ /#{PATTERN_UTF8}$/o
else
- original_succ
+ /.$/o
end
end
- def upto(to)
- return if self > to
+ alias original_succ! succ!
+ private :original_succ!
- curr = self
- tail = self[-2..-1]
- if tail.length == 2 and tail =~ /^.$/ then
- if self[0..-2] == to[0..-2]
- first = self[-2].chr
- for c in self[-1] .. to[-1]
- if (first+c.chr).mbchar?
- yield self[0..-2]+c.chr
- end
- end
- end
+ alias original_succ succ
+ private :original_succ
+
+ def succ!
+ reg = end_regexp
+ if self =~ reg
+ succ_table = SUCC[$KCODE[0,1].downcase]
+ begin
+ self[-1] += succ_table[self[-1]]
+ self[-2] += 1 if self[-1] == 0
+ end while self !~ reg
+ self
else
- loop do
- yield curr
- return if curr == to
- curr = curr.succ
- return if curr.length > to.length
- end
+ original_succ!
end
- return nil
+ end
+
+ def succ
+ (str = self.dup).succ! or str
end
private
@@ -159,9 +183,24 @@ class String
(str = self.dup).chop! or str
end
+ def jlength
+ self.gsub(/[^\Wa-zA-Z_\d]/, ' ').length
+ end
+ alias jsize jlength
+
def jcount(str)
self.delete("^#{str}").jlength
end
+ def each_char
+ if iterator?
+ scan(/./) do |x|
+ yield x
+ end
+ else
+ scan(/./)
+ end
+ end
+
end
$VERBOSE = $vsave
diff --git a/re.c b/re.c
index 8bc15c1..04d4978 100644
--- a/re.c
+++ b/re.c
@@ -182,6 +182,21 @@ kcode_reset_option()
}
}
+int
+rb_mbclen2(c, re)
+ unsigned char c;
+ VALUE re;
+{
+ int len;
+
+ if (!FL_TEST(re, KCODE_FIXED))
+ return mbclen(c);
+ kcode_set_option(re);
+ len = mbclen(c);
+ kcode_reset_option();
+ return len;
+}
+
extern int ruby_in_compile;
static void
@@ -538,6 +553,7 @@ rb_reg_search(reg, str, pos, reverse)
}
result = re_search(RREGEXP(reg)->ptr,RSTRING(str)->ptr,RSTRING(str)->len,
pos, range, regs);
+
if (FL_TEST(reg, KCODE_FIXED))
kcode_reset_option();
diff --git a/re.h b/re.h
index dc4cd17..9d3b77f 100644
--- a/re.h
+++ b/re.h
@@ -36,4 +36,7 @@ VALUE rb_reg_regsub _((VALUE, VALUE, struct re_registers *));
int rb_kcode _((void));
extern int ruby_ignorecase;
+
+int rb_mbclen2 _((unsigned char, VALUE));
+#define mbclen2(c,re) rb_mbclen2((c),(re))
#endif
diff --git a/regex.c b/regex.c
index fd8a447..8634dfe 100644
--- a/regex.c
+++ b/regex.c
@@ -1406,7 +1406,8 @@ re_compile_pattern(pattern, size, bufp)
case 'W':
for (c = 0; c < (1 << BYTEWIDTH); c++) {
if (SYNTAX(c) != Sword &&
- (current_mbctype || SYNTAX(c) != Sword2))
+ (current_mbctype && !re_mbctab[c] ||
+ !current_mbctype && SYNTAX(c) != Sword2))
SET_LIST_BIT(c);
}
last = -1;
diff --git a/string.c b/string.c
index 5fb4fdc..a9b8eed 100644
--- a/string.c
+++ b/string.c
@@ -757,6 +757,7 @@ rb_str_upto(beg, end, excl)
int excl;
{
VALUE current;
+ ID succ = rb_intern("succ");
if (TYPE(end) != T_STRING) end = rb_str_to_str(end);
@@ -764,7 +765,7 @@ rb_str_upto(beg, end, excl)
while (rb_str_cmp(current, end) <= 0) {
rb_yield(current);
if (!excl && rb_str_equal(current, end)) break;
- current = rb_str_succ(current);
+ current = rb_funcall(current, succ, 0, 0);
if (excl && rb_str_equal(current, end)) break;
if (RSTRING(current)->len > RSTRING(end)->len)
break;
@@ -1110,7 +1111,7 @@ rb_str_gsub_bang(argc, argv, str)
* Always consume at least one character of the input string
* in order to prevent infinite loops.
*/
- len = mbclen(RSTRING(str)->ptr[END(0)]);
+ len = mbclen2(RSTRING(str)->ptr[END(0)], pat);
if (RSTRING(str)->len > END(0)) {
memcpy(bp, RSTRING(str)->ptr+END(0), len);
bp += len;
@@ -1342,12 +1343,6 @@ rb_str_inspect(str)
*b++ = *p++;
}
}
-#if 0
- else if ((c & 0x80) && rb_kcode() != MBCTYPE_EUC) {
- CHECK(1);
- *b++ = c;
- }
-#endif
else if (c == '"'|| c == '\\') {
CHECK(2);
*b++ = '\\';
@@ -2074,11 +2069,11 @@ rb_str_split_method(argc, argv, str)
regs = RMATCH(rb_backref_get())->regs;
if (start == end && BEG(0) == END(0)) {
if (last_null == 1) {
- rb_ary_push(result, rb_str_substr(str, beg, mbclen(RSTRING(str)->ptr[beg])));
+ rb_ary_push(result, rb_str_substr(str, beg, mbclen2(RSTRING(str)->ptr[beg],spat)));
beg = start;
}
else {
- start += mbclen(RSTRING(str)->ptr[start]);
+ start += mbclen2(RSTRING(str)->ptr[start],spat);
last_null = 1;
continue;
}
@@ -2384,7 +2379,7 @@ scan_once(str, pat, start)
/*
* Always consume at least one character of the input string
*/
- *start = END(0)+mbclen(RSTRING(str)->ptr[END(0)]);
+ *start = END(0)+mbclen2(RSTRING(str)->ptr[END(0)],pat);
}
else {
*start = END(0);
diff --git a/win32/Makefile b/win32/Makefile
index f84c96b..24148b3 100644
--- a/win32/Makefile
+++ b/win32/Makefile
@@ -19,7 +19,7 @@ LDFLAGS = $(CFLAGS) -Fm
XLDFLAGS =
#EXTLIBS =
LIBS = advapi32.lib wsock32.lib $(EXTLIBS)
-MISSING = crypt.obj alloca.obj win32.obj fnmatch.obj isinf.obj isnan.obj
+MISSING = crypt.obj alloca.obj win32.obj isinf.obj isnan.obj
LDSHARED =
DLDFLAGS =
SOLIBS =
@@ -166,9 +166,6 @@ isinf.obj: missing/isinf.c
isnan.obj: missing/isnan.c
$(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/isnan.c
-fnmatch.obj: missing/fnmatch.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/fnmatch.c
-
memcmp.obj: missing/memcmp.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c missing/memcmp.c
diff --git a/win32/ruby.def b/win32/ruby.def
index 008452f..8f1fc48 100644
--- a/win32/ruby.def
+++ b/win32/ruby.def
@@ -99,8 +99,6 @@ EXPORTS
definekey
encrypt
crypt
-;missing/fnmatch.c
- fnmatch
;missing/isinf.c
isinf
;missing/isnan.c
@@ -452,7 +450,6 @@ EXPORTS
rb_get_kcode
rb_set_kcode
;ruby.c
- ruby_require_libraries
rb_load_file
ruby_script
ruby_prog_init