diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 1999-11-04 08:39:57 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 1999-11-04 08:39:57 +0000 |
commit | a9e9697994a08600f5dbb46a1fe2a07233cb4890 (patch) | |
tree | 9976842c343a888dc34f5cc53ecedc5abb358669 | |
parent | 0d684beafb4258da9606b1e3b4448511b709a2e2 (diff) |
19991104
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@557 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | error.c | 9 | ||||
-rw-r--r-- | eval.c | 23 | ||||
-rw-r--r-- | ext/dbm/dbm.c | 10 | ||||
-rw-r--r-- | ext/tcltklib/extconf.rb | 2 | ||||
-rw-r--r-- | ext/tk/lib/tkfont.rb | 15 | ||||
-rw-r--r-- | intern.h | 6 | ||||
-rw-r--r-- | io.c | 6 | ||||
-rw-r--r-- | lib/cgi.rb | 1949 | ||||
-rw-r--r-- | lib/jcode.rb | 111 | ||||
-rw-r--r-- | re.c | 16 | ||||
-rw-r--r-- | re.h | 3 | ||||
-rw-r--r-- | regex.c | 3 | ||||
-rw-r--r-- | string.c | 17 | ||||
-rw-r--r-- | win32/Makefile | 5 | ||||
-rw-r--r-- | win32/ruby.def | 3 |
16 files changed, 2121 insertions, 75 deletions
@@ -1,3 +1,21 @@ +Wed Nov 3 08:52:57 1999 Masaki Fukushima <[email protected]> + + * io.c (Init_IO): forgot to use INT2FIX() around SEEK_SET, etc. + +Wed Nov 3 00:25:20 1999 Yukihiro Matsumoto <[email protected]> + + * string.c (rb_str_split_method): use mbclen2() to handle kcode + option of regexp objects. + +Mon Nov 1 14:22:15 1999 EGUCHI Osamu <[email protected]> + + * eval.c (rb_eval): reduce recursive calls to rb_eval() + case of ||= and &&= . + +Sun Oct 31 13:12:42 1999 WATANABE Hirofumi <[email protected]> + + * regex.c (re_compile_pattern): wrong [\W] match. + Fri Oct 29 16:57:30 1999 Yukihiro Matsumoto <[email protected]> * ext/nkf/lib/kconv.rb: new String methods (kconv, tojis, toeuc, @@ -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 @@ -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 4d83cec1b1..1240f4b9ab 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 e1086855ba..713cc811e5 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 c680d166e7..2683260d69 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 @@ -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)); @@ -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 0000000000..fa98fecc61 --- /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 <[email protected]> + + +== 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, '&') + str.gsub!(/\"/n, '"') + str.gsub!(/>/n, '>') + str.gsub!(/</n, '<') + 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><A HREF="url"></A>" + + print CGI::escapeElement("<BR><A HREF="url"></A>", ["A", "IMG"]) + # "<BR><A HREF="url"></A>" +=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") + # "<BR><A HREF="url"></A>" + + print CGI::unescapeElement( + CGI::escapeHTML("<BR><A HREF="url"></A>"), ["A", "IMG"]) + # "<BR><A HREF="url"></A>" +=end + def CGI::unescapeElement(string, *element) + str = string.dup + str.gsub!(/<\/?(?:#{element.join("|")})(?!\w)(?:.|\n)*?>/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 <[email protected]> + 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 92b9284471..7a4cddd693 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 @@ -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(); @@ -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 @@ -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; @@ -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 f84c96bc3f..24148b3c87 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 008452fa8d..8f1fc4800c 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 |