From 469c1f3f40f279906aceceb7cd4aef80eeffd642 Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> Date: Mon, 4 Jun 2001 09:02:30 +0000 Subject: This commit was manufactured by cvs2svn to create tag 'v1_6_4'. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_6_4@1498 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- .cvsignore | 27 +- COPYING.LIB | 481 ++++++++++++++ ChangeLog | 1360 +++++++++++++++++++++++++++++++++++++-- MANIFEST | 38 +- Makefile.in | 9 +- README | 25 +- README.EXT | 21 +- README.EXT.jp | 19 +- README.jp | 29 +- array.c | 63 +- bignum.c | 20 +- class.c | 75 ++- configure.in | 89 ++- cygwin/GNUmakefile.in | 2 + defines.h | 2 +- dir.c | 125 ++-- djgpp/config.status | 77 --- dln.c | 35 +- dln.h | 2 +- doc/NEWS | 285 ++++++++ doc/forwardable.rd | 84 +++ doc/forwardable.rd.jp | 81 +++ doc/irb/irb-tools.rd.jp | 185 ++++++ doc/irb/irb.rd | 377 +++++++++++ doc/irb/irb.rd.jp | 391 +++++++++++ doc/shell.rd | 348 ++++++++++ doc/shell.rd.jp | 336 ++++++++++ error.c | 7 + eval.c | 742 ++++++++++++++------- ext/.cvsignore | 1 + ext/Win32API/Win32API.c | 6 - ext/Win32API/extconf.rb | 2 +- ext/configsub.rb | 2 +- ext/curses/.cvsignore | 1 + ext/curses/curses.c | 8 +- ext/curses/extconf.rb | 4 + ext/dbm/.cvsignore | 1 + ext/dbm/dbm.c | 123 +++- ext/etc/.cvsignore | 1 + ext/extmk.rb.in | 118 ++-- ext/fcntl/.cvsignore | 1 + ext/gdbm/.cvsignore | 1 + ext/gdbm/gdbm.c | 565 ++++++++++++---- ext/md5/.cvsignore | 1 + ext/md5/md5.txt | 15 +- ext/md5/md5.txt.jp | 13 +- ext/nkf/.cvsignore | 1 + ext/pty/.cvsignore | 1 + ext/pty/extconf.rb | 16 +- ext/pty/pty.c | 4 +- ext/readline/.cvsignore | 1 + ext/readline/extconf.rb | 3 + ext/readline/readline.c | 14 +- ext/sdbm/.cvsignore | 1 + ext/sdbm/_sdbm.c | 4 +- ext/sdbm/init.c | 125 +++- ext/socket/.cvsignore | 1 + ext/socket/extconf.rb | 4 +- ext/tcltklib/.cvsignore | 1 + ext/tcltklib/extconf.rb | 1 + ext/tcltklib/stubs.c | 2 +- ext/tk/.cvsignore | 1 + ext/tk/lib/tk.rb | 167 ++++- ext/tk/lib/tkcanvas.rb | 8 +- ext/tk/lib/tkentry.rb | 2 +- ext/tk/lib/tktext.rb | 8 + ext/tk/lib/tkvirtevent.rb | 33 +- file.c | 174 +++-- gc.c | 120 ++-- hash.c | 14 +- instruby.rb | 2 +- intern.h | 8 +- io.c | 39 +- lib/Env.rb | 14 +- lib/README | 57 +- lib/cgi.rb | 240 ++----- lib/cgi/session.rb | 31 +- lib/date.rb | 38 +- lib/debug.rb | 210 ++++-- lib/delegate.rb | 2 +- lib/forwardable.rb | 94 +++ lib/ftools.rb | 3 +- lib/importenv.rb | 6 +- lib/irb.rb | 314 +++++++++ lib/irb/completion.rb | 152 ++++- lib/irb/context.rb | 289 +++++++++ lib/irb/extend-command.rb | 126 ++++ lib/irb/frame.rb | 2 +- lib/irb/help.rb | 33 + lib/irb/init.rb | 232 +++++++ lib/irb/input-method.rb | 12 +- lib/irb/lc/error.rb | 30 + lib/irb/lc/help-message | 34 + lib/irb/lc/ja/error.rb | 29 + lib/irb/lc/ja/help-message | 35 + lib/irb/loader.rb | 6 +- lib/irb/locale.rb | 187 ++++++ lib/irb/main.rb | 867 ------------------------- lib/irb/multi-irb.rb | 54 +- lib/irb/ruby-lex.rb | 97 +-- lib/irb/ruby-token.rb | 13 +- lib/irb/slex.rb | 22 +- lib/irb/version.rb | 10 +- lib/irb/workspace-binding-2.rb | 15 - lib/irb/workspace-binding.rb | 77 --- lib/irb/workspace.rb | 106 +++ lib/irb/ws-for-case-2.rb | 15 + lib/irb/xmp.rb | 2 +- lib/mkmf.rb | 132 ++-- lib/monitor.rb | 96 +-- lib/net/http.rb | 1118 ++++++++++++++++++-------------- lib/net/imap.rb | 487 +++++++++++++- lib/net/pop.rb | 13 +- lib/net/protocol.rb | 309 +++++---- lib/net/smtp.rb | 29 +- lib/net/telnet.rb | 217 +------ lib/observer.rb | 2 +- lib/open3.rb | 1 + lib/parsedate.rb | 11 +- lib/ping.rb | 2 + lib/pstore.rb | 7 +- lib/shell.rb | 274 ++++++++ lib/shell/builtin-command.rb | 154 +++++ lib/shell/command-processor.rb | 584 +++++++++++++++++ lib/shell/error.rb | 26 + lib/shell/filter.rb | 111 ++++ lib/shell/process-controller.rb | 258 ++++++++ lib/shell/system-command.rb | 168 +++++ lib/shell/version.rb | 16 + lib/shellwords.rb | 2 +- lib/thread.rb | 32 +- marshal.c | 14 +- math.c | 5 + misc/ruby-mode.el | 2 +- missing/alloca.c | 5 +- missing/dir.h | 65 -- missing/flock.c | 120 ++-- missing/hypot.c | 17 + missing/strftime.c | 6 - missing/vsnprintf.c | 6 +- mkconfig.rb | 38 +- node.h | 14 +- numeric.c | 10 +- object.c | 73 +-- pack.c | 8 +- parse.y | 376 +++++------ prec.c | 2 +- process.c | 2 + re.c | 14 +- regex.c | 58 +- ruby.c | 66 +- ruby.h | 37 +- sample/README | 3 - sample/dualstack-fetch.rb | 48 ++ sample/dualstack-httpd.rb | 55 ++ sample/io.rb | 44 -- sample/irb.rb | 12 +- sample/rbc.rb | 1015 ----------------------------- signal.c | 19 +- sprintf.c | 4 +- string.c | 49 +- time.c | 25 +- util.c | 38 +- variable.c | 20 +- version.h | 8 +- win32/Makefile.sub | 4 +- win32/config.h.in | 1 + win32/config.status.in | 4 +- win32/dir.h | 20 + win32/resource.rb | 2 +- win32/win32.c | 93 ++- win32/win32.h | 2 + 172 files changed, 11927 insertions(+), 4933 deletions(-) create mode 100644 COPYING.LIB delete mode 100644 djgpp/config.status create mode 100644 doc/NEWS create mode 100644 doc/forwardable.rd create mode 100644 doc/forwardable.rd.jp create mode 100644 doc/irb/irb-tools.rd.jp create mode 100644 doc/irb/irb.rd create mode 100644 doc/irb/irb.rd.jp create mode 100644 doc/shell.rd create mode 100644 doc/shell.rd.jp create mode 100644 ext/.cvsignore create mode 100644 ext/curses/.cvsignore create mode 100644 ext/dbm/.cvsignore create mode 100644 ext/etc/.cvsignore create mode 100644 ext/fcntl/.cvsignore create mode 100644 ext/gdbm/.cvsignore create mode 100644 ext/md5/.cvsignore create mode 100644 ext/nkf/.cvsignore create mode 100644 ext/pty/.cvsignore create mode 100644 ext/readline/.cvsignore create mode 100644 ext/sdbm/.cvsignore create mode 100644 ext/socket/.cvsignore create mode 100644 ext/tcltklib/.cvsignore create mode 100644 ext/tk/.cvsignore create mode 100644 lib/forwardable.rb create mode 100644 lib/irb.rb create mode 100644 lib/irb/context.rb create mode 100644 lib/irb/extend-command.rb create mode 100644 lib/irb/help.rb create mode 100644 lib/irb/init.rb create mode 100644 lib/irb/lc/error.rb create mode 100644 lib/irb/lc/help-message create mode 100644 lib/irb/lc/ja/error.rb create mode 100644 lib/irb/lc/ja/help-message create mode 100644 lib/irb/locale.rb delete mode 100644 lib/irb/main.rb delete mode 100644 lib/irb/workspace-binding-2.rb delete mode 100644 lib/irb/workspace-binding.rb create mode 100644 lib/irb/workspace.rb create mode 100644 lib/irb/ws-for-case-2.rb create mode 100644 lib/shell.rb create mode 100644 lib/shell/builtin-command.rb create mode 100644 lib/shell/command-processor.rb create mode 100644 lib/shell/error.rb create mode 100644 lib/shell/filter.rb create mode 100644 lib/shell/process-controller.rb create mode 100644 lib/shell/system-command.rb create mode 100644 lib/shell/version.rb delete mode 100644 missing/dir.h create mode 100644 missing/hypot.c create mode 100644 sample/dualstack-fetch.rb create mode 100644 sample/dualstack-httpd.rb delete mode 100644 sample/io.rb delete mode 100644 sample/rbc.rb create mode 100644 win32/dir.h diff --git a/.cvsignore b/.cvsignore index 8fcaffddb2..35fff17b58 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,19 +1,20 @@ -parse.c -newver.rb -ruby -miniruby +*.bak +*.orig +*.rej +*.sav +*~ +.cvsignore +Makefile README.fat-patch -configure +archive config.cache config.h config.log config.status -Makefile +configure +miniruby +newver.rb +parse.c ppack -archive -extmk.rb -*.orig -*.rej -*.bak -*.sav -*~ +rbconfig.rb +ruby diff --git a/COPYING.LIB b/COPYING.LIB new file mode 100644 index 0000000000..eb685a5ec9 --- /dev/null +++ b/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog index c6cd432b49..b46346b4b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1266 @@ +Mon Jun 4 17:57:56 2001 Yukihiro Matsumoto + + * stable version 1.6.4 released. + +Mon Jun 4 04:14:53 2001 Wakou Aoyama + + * lib/shellwords.rb: don't destroy argument. + +Sat Jun 2 23:23:05 2001 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): should push option modifier at the + right place. + +Sat Jun 2 23:05:20 2001 Shugo Maeda + + * lib/cgi/session.rb: don't use module_function for Class. + +Sat Jun 2 00:02:22 2001 Keiju Ishitsuka + + * irb messages: fix typos. + +Fri Jun 1 17:26:24 2001 K.Kosako + + * hash.c (replace_i): ignore when key == Qundef. + +Fri Jun 1 11:21:04 2001 WATANABE Hirofumi + + * configure.in: use waitpid on mingw32. + +Thu May 31 18:34:57 2001 K.Kosako + + * file.c (rb_file_s_unlink): should not allow if $SAFE >= 2. + +Thu May 31 13:30:25 2001 WATANABE Hirofumi + + * mkconfig.rb, ext/configsub.rb: VERSION -> RUBY_VERSION. + +Thu May 31 08:31:22 2001 Usaku Nakamura + + * dln.c: #define S_ISDIR if not defined. + +Thu May 31 01:28:54 2001 Akinori MUSHA + + * configure.in: default --with-libc_r to `no' until the problem is + fixed. (FreeBSD only) + +Wed May 30 14:09:00 2001 K.Kosako + + * object.c (rb_obj_taint): backport from 1.7. + + * object.c (rb_obj_untaint): add frozen status check (backport from 1.7). + +Tue May 29 17:24:23 2001 K.Kosako + + * ruby.c (proc_options): unexpected SecurityError happens when -T4. + +Tue May 29 18:46:04 2001 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): * \1 .. \9 should be + backreferences always. + + * regex.c (re_match): backreferences corresponding to + unclosed/unmatched parentheses should fail always. + +Mon May 28 23:20:43 2001 WATANABE Hirofumi + + * configure.in: remove unnecessary AC_CANONICAL_BUILD + + * defins.h: #define HAVE_SETITIMER on Cygwin(bug fixed). + + * ruby.c: use relative path from LIBRUBY_SO. + + * ruby.c: don't use -mwin32 option on Cygwin. + + * cygwin/GNUmakefile.in: ditto. + + * ext/sdbm/_sdbm: ditto. + + * ext/tcltklib/extconf.rb: ditto. + + * ext/tcltklib/stubs.c: ditto. + +Mon May 28 22:12:01 2001 Nobuyoshi Nakada + + * ext/extconf.rb.in: make the priority of the make rule of .c + higher than .C . + +Mon May 28 02:43:16 2001 Akinori MUSHA + + * dir.c (rb_glob_helper): teach has_magic() to handle flags and + get rb_glob_helper to properly support FNM_NOESCAPE. + + * dir.c (fnmatch): fix a bug when FNM_PATHNAME and FNM_PERIOD are + specified at the same time. + +Sat May 26 07:19:48 2001 Usaku Nakamura + + * win32/win32.c (opendir): add const directive. + +Sat May 26 07:00:05 2001 Usaku Nakamura + + * MANIFEST: add win32/dir.h . + +Sat May 26 00:15:57 2001 Usaku Nakamura + + * win32/dir.h: replace missing/dir.h . + + * dir.c: ditto. + +Fri May 25 14:19:25 2001 K.Kosako + + * string.c (rb_str_replace): add taint status infection + (OBJ_INFECT()). + + * string.c (rb_str_crypt): ditto. + + * string.c (rb_str_ljust): ditto. + + * string.c (rb_str_rjust): ditto. + + * string.c (rb_str_center): ditto. + +Fri May 25 01:55:32 2001 Akinori MUSHA + + * MANIFEST: Re-adjust the entries to coincide with HEAD. + +Fri May 25 01:36:52 2001 Akinori MUSHA + + * MANIFEST: update the entries I forgot to add or remove. + +Thu May 24 16:08:21 2001 WATANABE Hirofumi + + * mkconfig.rb: autoconf 2.50 support. + +Thu May 24 14:23:35 2001 Yukihiro Matsumoto + + * eval.c (rb_yield_0): need argument adjustment for C defined + blocks too. + +Tue May 22 17:10:35 2001 K.Kosako + + * variable.c (rb_alias_variable): should not allow variable + aliasing if $SAFE >= 4. + +Mon May 21 15:26:05 JST 2001 Keiju Ishitsuka + + * lib/irb/multi-irb.rb: delete japanese messages. + +Mon May 21 13:15:25 2001 Yukihiro Matsumoto + + * bignum.c (rb_big2str): t should be protected from GC. + +Sun May 20 00:28:43 2001 Akinori MUSHA + + * ext/socket/extconf.rb: do not clobber $CFLAGS when setting + -DSOCKS. + +Fri May 18 05:42:28 2001 Akinori MUSHA + + * lib/thread.rb: rescue ThreadError in case the thread is dead + just before calling Thread#run. + +Fri May 18 05:29:21 2001 Akinori MUSHA + + * lib/mkmf.rb (xsystem): make a temporary fix to get $(...) macros + properly expanded on a command execution. + +Fri May 18 03:49:55 2001 Brian F. Feldman + + * lib/mkmf.rb: unbreak "make install". lib/* must be installed + under $rubylibdir, not under $libdir. + +Thu May 17 19:36:47 2001 Akinori MUSHA + + * lib/shell.rb, lib/shell/process-controller.rb, + lib/shell/command-processor.rb: translate Japanese comments into + English. + + * doc/shell.rd.jp: RD'ify and make some fixes. + + * doc/shell.rd: RD'ify, delete Japanese leftovers, make overall + English fixes, and sync with doc/shell.rd.jp. + +Thu May 17 19:34:11 2001 Akinori MUSHA + + * doc/shell.rd*, lib/shell*: bring shell.rb 0.6 onto the ruby_1_6 + branch. + +Thu May 17 17:35:04 2001 Yukihiro Matsumoto + + * eval.c (rb_call0): address of local_vars might change during eval. + +Thu May 17 07:30:15 2001 Akinori MUSHA + + * ext/md5/md5.txt, ext/md5/md5.txt.jp: s/SuperClass/Superclass/. + +Thu May 17 06:37:14 2001 Akinori MUSHA + + * ext/md5/md5.txt: make wording fixes. + + * ext/md5/md5.txt.jp: ditto. + +Thu May 17 05:23:52 2001 Keiju Ishitsuka + * lib/irb.rb lib/irb/multi-irb.rb lib/irb/ruby-lex.rb lib/irb/version.rb + resolve ctrl-c problem + +Tue May 15 17:46:37 2001 Yukihiro Matsumoto + + * array.c (rb_ary_and): should not push frozen key string. + + * array.c (rb_ary_or): ditto. + +Mon May 14 13:50:22 2001 Yukihiro Matsumoto + + * eval.c (rb_thread_schedule): should save context before raising + deadlock, saved context for current thread might be obsolete. + + * time.c (make_time_t): non DST timezone shift supported (hopefully). + +Mon May 14 11:54:20 2001 Tanaka Akira + + * signal.c: SIGINFO added. + +Mon May 14 08:57:06 2001 Yukihiro Matsumoto + + * eval.c (rb_ensure): should not SEGV when prot_tag is NULL. + +Sun May 13 23:49:25 2001 Usaku Nakamura + + * win32/resource.rb: Modify copyright in resource script. + +Fri May 11 23:51:54 2001 Usaku Nakamura + + * process.c: silence VC++ warnings. + + * sprintf.c: ditto. + +Fri May 11 03:38:11 2001 Akinori MUSHA + + * README.EXT: Document find_library(), with_config() and + dir_config(). + +Fri May 11 03:37:53 2001 Akinori MUSHA + + * README.EXT.jp: Remove the description of find_header() because + such a function does not actually exist. + + * README.EXT.jp: Update the description of dir_config(). + +Fri May 11 02:42:40 2001 Kazuhiro NISHIYAMA + + * README, README.jp: Fix CVS access and mailing lists info. + +Fri May 11 02:00:44 2001 Ryo HAYASAKA + + * bignum.c (bigdivrem): access boundary bug. + +Wed May 9 14:38:33 2001 K.Kosako + + * eval.c (rb_yield_0): preserve and restore ruby_cref as well. + +Tue May 8 17:12:43 2001 K.Kosako + + * eval.c (is_defined): core dumped during instance_eval for + special constants. + + * eval.c (rb_eval): ditto. + +Tue May 8 08:59:01 2001 Akinori MUSHA + + * doc/forwardable.rd, doc/forwardable.rd.jp: Hit `=begin' and + `=end' in proper places so rd2 can format them without a problem. + + * doc/irb/irb-tools.rd.jp, doc/irb/irb.rd, doc/irb/irb.rd.jp: + ditto. + +Tue May 8 08:56:05 2001 Akinori MUSHA + + * doc/forwardable.rd, doc/forwardable.rd.jp, lib/forwardable.rb: + Bring forwardable 1.1 onto the ruby_1_6 branch. + +Tue May 8 08:35:09 2001 Akinori MUSHA + + * doc/irb/irb-tools.rd.jp, doc/irb/irb.rd.jp: Convert from JIS to + EUC. + +Tue May 8 03:46:24 2001 Akinori MUSHA + + * sample/rbc.rb: Obsoleted by IRB. + +Mon May 7 15:58:45 2001 Yukihiro Matsumoto + + * parse.y (arg): "||=" should not warn for uninitialized instance + variables. + + * eval.c (rb_eval): ditto. + + * eval.c (eval): preserve and restore ruby_cref as well. + +Mon May 7 15:45:48 2001 WATANABE Hirofumi + + * lib/ftools.rb (syscopy): chmod destination file only if + it does not exist. + +Thu May 3 03:41:01 2001 SHIROYAMA Takayuki + + * configure.in: get --enable-shared to work on MacOS X. + + * Makefile.in: make $(LIBRUBY_SO) depend on miniruby properly. + Now `make -jN' should work without a problem. + +Wed May 2 20:39:35 2001 WATANABE Hirofumi + + * dir.c (rb_glob, rb_iglob): remove unnecessary FNM_PATHNAME. + +Wed May 2 11:46:13 2001 K.Kosako + + * eval.c (block_pass): should not downgrade safe level. + +Tue May 1 17:55:58 2001 Yukihiro Matsumoto + + * parse.y (yylex): lex_state after RESCUE_MOD should be EXPR_BEG. + +Tue May 1 03:36:50 2001 Akinori MUSHA + + * sample/irb.rb, lib/irb.rb, lib/irb/*, doc/irb/*: Merge from irb + 0.7.3 and irb-tools 0.7.1. + + * instruby.rb: Install help-message's too. + + * lib/irb/main.rb: This file is not needed anymore. + +Thu Apr 26 22:36:11 2001 WATANABE Hirofumi + + * configure.in: don't use tzname on cygwin 1.3.1+. + + * configure.in: add -mieee/-ieee to CFLAGS on OSF1/Alpha + to disable "DIVISION BY ZERO" exception. + +Thu Apr 26 22:30:43 2001 Yukihiro Matsumoto + + * eval.c (rb_eval): should preserve value of ruby_errinfo. + +Thu Apr 26 10:36:09 2001 Yukihiro Matsumoto + + * eval.c (rb_thread_schedule): infinite sleep should not cause + dead lock. + +Wed Apr 25 16:40:44 2001 Yukihiro Matsumoto + + * array.c (rb_ary_flatten_bang): proper recursive detection. + +Wed Apr 25 15:36:15 2001 K.Kosako + + * eval.c (yield_under): need not to prohibit at safe level 4. + +Tue Apr 24 16:03:25 2001 Hiroshi Igarashi + + * ext/extmk.rb.in: add target `distclean' in Makefile for extlib. + target `clean' doesn't remove Makefile. + +Tue Apr 24 15:57:45 2001 Akinori MUSHA + + * ext/extmk.rb.in, lib/mkmf.rb: (dir_config) do not add the + specified include directory if already included in $CPPFLAGS. + + * ext/extmk.rb.in, lib/mkmf.rb: (dir_config) return a more useful + value, [include_dir, lib_dir]. + +Tue Apr 24 15:35:32 2001 Yukihiro Matsumoto + + * ruby.c (set_arg0): wrong predicate when new $0 value is bigger + than original space. + +Mon Apr 23 14:43:59 2001 Yukihiro Matsumoto + + * gc.c (id2ref): should use NUM2ULONG() + + * object.c (rb_mod_const_get): check whether name is a class + variable name. + + * object.c (rb_mod_const_set): ditto. + + * object.c (rb_mod_const_defined): ditto. + +Sun Apr 22 17:44:37 2001 WATANABE Hirofumi + + * configure.in: add -mieee to CFLAGS on Linux/Alpha + to disable "DIVISION BY ZERO" exception. + + * configure.in: remove -ansi on OSF/1. + +Sat Apr 21 22:33:26 2001 Yukihiro Matsumoto + + * marshal.c (w_float): precision changed to "%.16g" + +Sat Apr 21 22:07:58 2001 Guy Decoux + + * eval.c (rb_call0): wrong retry behavior. + +Fri Apr 20 19:12:20 2001 Yukihiro Matsumoto + + * numeric.c (fix_aref): a bug on long>int architecture. + +Fri Apr 20 14:57:15 2001 K.Kosako + + * eval.c (rb_eval_string_wrap): should restore ruby_wrapper. + +Wed Apr 18 04:37:51 2001 Wakou Aoyama + + * lib/cgi.rb: CGI::Cookie: no use PATH_INFO. + +Wed Apr 18 00:24:40 2001 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): char class at either edge of range + should be invalid. + +Tue Apr 17 16:54:39 2001 K.Kosako + + * eval.c (safe_getter): should use INT2NUM(). + +Tue Apr 17 15:12:56 2001 Yukihiro Matsumoto + + * bignum.c (rb_big2long): 2**31 cannot fit in 31 bit long. + +Sat Apr 14 22:46:43 2001 Guy Decoux + + * regex.c (calculate_must_string): wrong length calculation. + +Sat Apr 14 13:33:32 2001 Usaku Nakamura + + * win32/config.status.in: no longer use missing/alloca.c. + + * win32/Makefile.sub: ditto. + +Fri Apr 13 12:40:48 2001 K.Kosako + + * eval.c (rb_thread_start_0): fixed memory leak. + +Fri Apr 13 16:41:18 2001 Yukihiro Matsumoto + + * parse.y (none): should clear cmdarg_stack too. + +Fri Apr 13 06:19:29 2001 GOTOU YUUZOU + + * io.c (rb_fopen): use setvbuf() to avoid recursive malloc() on + some platforms. + +Wed Apr 11 23:36:26 2001 Yukihiro Matsumoto + + * file.c (rb_stat_dev): device functions should honor stat field + types (except long long such as dev_t). + +Wed Apr 11 18:07:53 2001 K.Kosako + + * eval.c (rb_mod_nesting): should not push nil for nesting array. + + * eval.c (rb_mod_s_constants): should not search array by + rb_mod_const_at() for nil (happens for singleton class). + +Wed Apr 11 13:29:26 2001 Yukihiro Matsumoto + + * class.c (rb_singleton_class_attached): should modify iv_tbl by + itself, no longer use rb_iv_set() to avoid freeze check error. + + * variable.c (rb_const_get): error message "uninitialized constant + Foo at Bar::Baz" instead of "uninitialized constant Bar::Baz::Foo". + +Tue Apr 10 02:24:40 2001 Nobuyoshi Nakada + + * io.c (opt_i_set): should strdup() inplace_edit string. + +Mon Apr 9 23:29:54 2001 Yukihiro Matsumoto + + * eval.c (exec_under): need to push cref too. + +Mon Apr 9 12:05:44 2001 Yukihiro Matsumoto + + * file.c (Init_File): should redifine "new" class method. + +Mon Apr 9 11:56:52 2001 Shugo Maeda + + * lib/net/imap.rb: fix typo. + +Thu Apr 5 22:40:12 2001 Yukihiro Matsumoto + + * variable.c (rb_const_get): no recursion to show full class path + for modules. + + * eval.c (rb_set_safe_level): should set safe level in curr_thread + as well. + + * eval.c (safe_setter): ditto. + +Thu Apr 5 13:46:06 2001 K.Kosako + + * object.c (rb_obj_is_instance_of): nil belongs to false, not true. + +Thu Apr 5 02:19:03 2001 Yukihiro Matsumoto + + * time.c (make_time_t): proper (I hope) daylight saving time + handling for both US and Europe. I HATE SUMMER TIME! + + * eval.c (rb_thread_wait_for): non blocked signal interrupt should + stop the interval. + +Wed Apr 4 03:47:03 2001 Yukihiro Matsumoto + + * class.c (rb_mod_clone): should copy method bodies too. + + * bignum.c (bigdivrem): should trim trailing zero bdigits of + remainder, even if dd == 0. + +Tue Apr 3 15:29:10 2001 Akinori MUSHA + + * Makefile.in: Introduce MAINLIBS. + + * configure.in: Link libc_r against the ruby executable on + FreeBSD, which is the first attempt to work around a certain + problem regarding pthread on FreeBSD. It should make ruby/libruby + happy when it loads an extention to a library compiled and linked + with -pthread. Note, however, that libruby is _not_ linked with + libc_r so as not to mess up pthread unfriendly stuff including + apache+mod_ruby and vim6+ruby_interp. + +Tue Apr 3 09:56:20 2001 WATANABE Hirofumi + + * ext/extmk.rb.in (create_makefile): create def file only if + it does not yet exist. + + * lib/mkmf.rb: ditto. + +Tue Apr 3 00:05:07 2001 Yukihiro Matsumoto + + * time.c (make_time_t): remove HAVE_TM_ZONE code since it + sometimes reports wrong time. + + * time.c (make_time_t): remove unnecessary range check for + platforms where negative time_t is available. + +Mon Apr 2 14:25:49 2001 Shugo Maeda + + * lib/monitor.rb (wait): ensure reentrance. + + * lib/monitor.rb (wait): fix timeout support. + +Mon Apr 2 12:44:53 2001 Shugo Maeda + + * lib/net/imap.rb: backport from ruby-1.7. + +Mon Apr 2 01:16:24 2001 WATANABE Hirofumi + + * win32/win32.c: use ruby's opendir on mingw32. + + * missing/dir.h, dir.c, Makefile: ditto. + +Sun Apr 1 23:26:14 2001 TOYOFUKU Chikanobu + + * numeric.c (flodivmod): a bug in no fmod case. + +Sun Apr 1 18:36:14 2001 Koji Arai + + * process.c (pst_wifsignaled): should apply WIFSIGNALED for status + (int), not st (VALUE). + +Sat Mar 31 03:24:10 2001 Yukihiro Matsumoto + + * class.c (rb_include_module): module inclusion should be check + taints. + +Fri Mar 30 12:51:19 2001 Yukihiro Matsumoto + + * class.c (rb_include_module): freeze check at first. + +Thu Mar 29 17:05:09 2001 Yukihiro Matsumoto + + * eval.c (rb_attr): sprintf() and rb_intern() moved into + conditional body. + +Wed Mar 28 23:43:00 2001 Nobuyoshi Nakada + + * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C + rules for the mswin32 platforms. + +Wed Mar 28 19:29:21 2001 Akinori MUSHA + + * ext/extmk.rb.in, lib/mkmf.rb: move C++ rules to the right place. + +Wed Mar 28 17:39:04 2001 Yukihiro Matsumoto + + * object.c (rb_str2cstr): warn if string contains \0 and length + value is ignored. + +Wed Mar 28 15:00:31 2001 K.Kosako + + * class.c (rb_singleton_class_clone): should copy class constant + table as well. + +Wed Mar 28 15:03:23 2001 Yukihiro Matsumoto + + * class.c (rb_include_module): sometimes cache was mistakenly left + uncleared - based on the patch by K.Kosako. + +Wed Mar 28 09:52:33 2001 WATANABE Hirofumi + + * win32/Makefile.sub: disable global optimization. + +Tue Mar 27 15:00:54 2001 K.Kosako + + * eval.c (rb_mod_define_method): should have clear method cache. + + * eval.c (rb_mod_define_method): should have raised exception for + type error. + +Tue Mar 27 14:48:17 2001 Yukihiro Matsumoto + + * ruby.h: changed "extern INLINE" to "static inline". + +Mon Mar 26 23:19:33 2001 WATANABE Hirofumi + + * time.c (rb_strftime): check whether strftime returns empty string. + +Mon Mar 26 18:14:47 2001 Yukihiro Matsumoto + + * dir.c (rb_glob_helper): part of 1.7 globber backported to proper + following of symlinks. + +Mon Mar 26 17:21:07 2001 Yukihiro Matsumoto + + * eval.c: remove TMP_PROTECT_END to prevent C_ALLOCA crash. + +Mon Mar 26 14:04:41 2001 WATANABE Hirofumi + + * ext/Win32API/Win32API.c: remove Init_win32api(). + +Sat Mar 24 23:44:50 2001 Yukihiro Matsumoto + + * eval.c (ev_const_defined): should ignore toplevel cbase (Object). + + * eval.c (ev_const_get): ditto. + +Fri Mar 23 12:18:44 2001 SHIROYAMA Takayuki + + * ext/curses/curses.c: curses on Mac OS X public beta does not + have _maxx etc. + +Fri Mar 23 10:50:31 2001 Yukihiro Matsumoto + + * marshal.c (w_object): should truncate trailing zero short for + bignums. + +Thu Mar 22 22:15:45 2001 WATANABE Hirofumi + + * ext/Win32API/extconf.rb: add -fno-omit-frame-pointer. + +Thu Mar 22 17:43:44 2001 Yukihiro Matsumoto + + * ruby.h: better inline function support. + + * configure.in (NO_C_INLINE): check if inline is available for the + C compiler. + +Wed Mar 21 23:07:45 2001 WATANABE Hirofumi + + * win32/win32.c (win32_stat): WinNT/2k "//host/share" support. + +Wed Mar 21 01:26:14 2001 Yukihiro Matsumoto + + * gc.c (id2ref): sometimes confused symbol and reference. + +Tue Mar 20 23:09:33 2001 WATANABE Hirofumi + + * win32/win32.c (win32_stat): UNC support. + + * dir.c (extract_path): fix "./*" problem. + +Mon Mar 19 19:14:47 2001 Guy Decoux + + * marshal.c (shortlen): shortlen should return number of bytes + written. + +Mon Mar 19 18:56:55 2001 Yukihiro Matsumoto + + * stable version 1.6.3 released. + +Mon Mar 19 16:52:23 2001 K.Kosako + + * eval.c (ev_const_defined): need not to check if cbase->nd_class + is rb_cObject. + + * eval.c (ev_const_get): ditto. + +Mon Mar 19 16:27:32 2001 Yukihiro Matsumoto + + * eval.c (THREAD_ALLOC): flags should be initialized. + + * signal.c (rb_f_kill): should use FIX2INT, not FIX2UINT. + +Mon Mar 19 11:03:10 2001 Koji Arai + + * marshal.c (r_object): len calculation patch was wrong for + machines SIZEOF_BDIGITS == SIZEOF_SHORT. + + * gc.c: alloca prototype reorganized for C_ALLOCA machine. + +Sun Mar 18 08:58:18 2001 Wakou Aoyama + + * lib/cgi.rb: // === '' --> //.match('') + + * lib/cgi.rb: cgi#header(): improvement for mod_ruby. + + * lib/cgi.rb: cgi#rfc1123date(): improvement. + thanks to TADA Tadashi . + + * lib/cgi.rb: cgi#rfc1123date(): document bug fix. + thanks to Kazuhiro NISHIYAMA . + + * lib/cgi.rb: cgi#header(): bug fix. + thanks to IWATSUKI Hiroyuki . + +Fri Mar 16 17:21:25 2001 Akinori MUSHA + + * configure.in: Set SOLIBS properly for all ELF and + FreeBSD/NetBSD/OpenBSD a.out platforms so that the shlib + dependencies are recorded in the libruby shlib. + +Wed Mar 14 16:41:45 2001 Yukihiro Matsumoto + + * eval.c (rb_thread_schedule): raise FATAL just once to + THREAD_TO_KILL. + +Wed Mar 14 10:41:34 2001 Yukihiro Matsumoto + + * eval.c (rb_yield_0): 0 (= Qfalse) is a valid value, so that + default self should be checked by klass == 0. + + * bignum.c (rb_cstr2inum): should disallow '++1', '+-1', etc. + +Tue Mar 13 17:51:09 2001 Yukihiro Matsumoto + + * eval.c (ev_const_defined): add new parameter self for special + const fallback. + + * eval.c (ev_const_get): ditto. + +Tue Mar 13 16:39:45 2001 WATANABE Hirofumi + + * dir.c (rb_glob_helper): fix drive letter handling on DOSISH. + +Tue Mar 13 15:01:12 2001 Minero Aoki + + * lib/net/http.rb: add HTTPRequest#basic_auth. + + * lib/net/smtp.rb: raise if only account or password is given. + + * lib/net/protocol.rb: WriteAdapter#<< returns self. + +Tue Mar 13 14:41:16 2001 Yukihiro Matsumoto + + * io.c (argf_seek): wrong calling sequence of rb_io_seek(). + +Mon Mar 12 18:59:38 2001 WATANABE Hirofumi + + * lib/mkmf.rb (create_makefile): save/restore $libs and $LIBPATH. + +Sun Mar 11 00:55:31 2001 WATANABE Hirofumi + + * lib/mkmf.rb (install_rb): fix handling of destination path. + +Sat Mar 10 02:34:18 2001 WATANABE Hirofumi + + * math.c (math_log, math_log10): use nan() instead of 0.0/0.0 on Cygwin. + +Thu Mar 8 17:43:59 2001 Minero Aoki + + * lib/net/protocol.rb: one write(2) per one line. + +Wed Mar 7 14:26:11 2001 WATANABE Hirofumi + + * math.c (math_log, math_log10): should return NaN if x < 0.0 + on Cygwin. + +Thu Mar 7 10:31:26 2001 Nobuyoshi Nakada + + * parse.y (stmt): while/until modifier must work for empty body. + +Tue Mar 6 22:53:58 2001 Kazuhiro Yoshida + + * ruby.c (ruby_set_argv): clear ARGV contents before adding args. + +Tue Mar 6 10:50:29 2001 Yukihiro Matsumoto + + * parse.y (primary): rescue and ensure clauses should be allowed + to appear in singleton method body. + +Mon Mar 5 17:25:13 2001 Yukihiro Matsumoto + + * eval.c (proc_eq): compare Procs using blocktag equality. + + * eval.c (proc_to_s): stringify according to block tag address. + +Mon Mar 5 17:19:56 2001 WATANABE Hirofumi + + * win32/win32.c (gettimeofday): use GetLocalTime() instead of ftime() + for high-resolution timing. + +Sun Mar 4 20:45:20 2001 Akinori MUSHA + + * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C + rules. + +Sun Mar 4 17:01:09 2001 WATANABE Hirofumi + + * string.c (trnext): support backslash escape in String#tr. + +Wed Feb 28 11:02:41 2001 Yukihiro Matsumoto + + * string.c (rb_str_delete_bang): delete! should take at least 1 + argument. + +Tue Feb 27 16:38:15 2001 Yukihiro Matsumoto + + * eval.c (ev_const_get): retrieve Object's caonstat if no current + class is available (e.g. defining singleton class for Fixnums). + + * eval.c (ev_const_defined): check Object's constant if no current + class is available (e.g. defining singleton class for Fixnums). + + * eval.c (proc_call): ignore block to `call' always, despite of + being orphan or not. + +Wed Feb 27 10:16:32 2001 Nobuyoshi Nakada + + * eval.c (rb_yield_0): should check based on rb_block_given_p() + and rb_f_block_given_p(). + +Mon Feb 26 16:20:27 2001 Yukihiro Matsumoto + + * ruby.c (proc_options): call ruby_show_version() just once. + +Mon Feb 26 00:04:52 2001 Yukihiro Matsumoto + + * eval.c (proc_call): should not modify ruby_block->frame.iter + based on ruby_frame->iter altered by PUSH_ITER(). + +Mon Feb 26 05:27:52 2001 Wakou Aoyama + + * lib/net/telnet.rb: #telnetmode(), #binmode(): bug fix. + thanks to nobu.nakada@nifty.ne.jp. + +Mon Feb 26 04:55:50 2001 Wakou Aoyama + + * lib/cgi.rb: CGI#form(): bug fix. + thanks to MoonWolf . + + * lib/cgi.rb: CGI#rfc1123_date(): improvement. + thanks to Tomoyasu Akita . + + * lib/cgi.rb: CGI#header(): improvement for mod_ruby. + thanks to Shugo Maeda . + +Sun Feb 25 02:45:30 2001 WATANABE Hirofumi + + * file.c (rb_file_s_rename): avoid Cygwin's bug. + +Sat Feb 24 23:32:55 2001 Yukihiro Matsumoto + + * eval.c (rb_thread_fd_close): should save current context before + raising exception. + +Sat Feb 24 22:14:00 2001 WATANABE Hirofumi + + * win32/win32.c (myrename): fix error handling. + +Sat Feb 24 15:43:31 2001 Minero Aoki + + * lib/net/protocol.rb: use net 1.2 for also ruby 1.6 branch. + + * lib/net/smtp.rb: ditto. + + * lib/net/pop.rb: ditto. + + * lib/net/http.rb: ditto. + +Fri Feb 23 16:36:09 2001 Minero Aoki + + * lib/net/http.rb: always close connection if body is not exist. + +Fri Feb 23 13:27:05 2001 Minero Aoki + + * lib/net/http.rb: keep-alive detection was incomplete. + +Fri Feb 23 08:24:53 2001 Minero Aoki + + * lib/net/protocol.rb: clear read buffer after reopen. + + * lib/net/http.rb: update RD document. + +Tue Feb 20 16:37:58 2001 Yukihiro Matsumoto + + * bignum.c (rb_big2long): should not raise RangeError for Bignum + LONG_MIN value. + +Mon Feb 19 17:46:37 2001 Yukihiro Matsumoto + + * string.c (rb_str_substr): "a"[1,2] should return ""; need + rubicon upgrade. + +Mon Feb 19 01:55:43 2001 Yukihiro Matsumoto + + * eval.c (secure_visibility): visibility check for untainted modules. + +Mon Feb 19 00:29:29 2001 Nobuyoshi Nakada + + * signal.c (sigpipe): sighandler which does nothing. + + * signal.c (trap): set sigpipe function for SIGPIPE. + + * signal.c (Init_signal): default SIGPIPE handler should be + sigpipe function. + +Sun Feb 18 15:42:38 2001 WATANABE Hirofumi + + * ext/curses/extconf.rb: add dir_config. + + * missing/flock.c: use fcntl(2) instead of lockf(2). + +Sun Feb 18 13:02:03 2001 Yasushi Shoji + + * array.c (rb_ary_subseq): wrong boundary check. + +Fri Feb 16 01:44:56 2001 Yukihiro Matsumoto + + * io.c (set_outfile): f should be the FILE* from the assigning value. + +Thu Feb 15 11:33:49 2001 Shugo Maeda + + * lib/cgi/session.rb (close): fixed reversed condition. + +Wed Feb 14 17:28:24 2001 Shugo Maeda + + * lib/net/imap.rb: supports unknown resp_text_code. + +Wed Feb 14 00:44:17 2001 Yukihiro Matsumoto + + * dir.c (dir_s_glob): call rb_yield directly (via push_pattern) if + block is given to the method. + + * dir.c (push_pattern): do not call rb_ary_push; yield directly. + +Tue Feb 13 23:05:38 2001 WATANABE Hirofumi + + * dir.c (lstat): should use rb_sys_stat if lstat(2) is not + available. + +Tue Feb 13 17:00:18 2001 Minero Aoki + + * lib/net/http.rb: supports HTTP 1.0 server. + +Tue Feb 13 01:13:43 2001 Yukihiro Matsumoto + + * parse.y (primary): preserve and clear in_single and in_def using + stack to prevent nested method errors in singleton class bodies. + +Sun Feb 11 16:00:30 2001 WATANABE Hirofumi + + * eval.c (stack_length): use __builtin_frame_address() only if + GCC and i386 CPU. + + * gc.c (rb_gc, Init_stack): ditto. + + * configure.in: add ac_cv_func_getpgrp_void=yes on DJGPP. + +Sat Feb 10 23:43:49 2001 Nobuyoshi Nakada + + * hash.c (rb_any_hash): dumped core on machines sizeof(int) != sizeof(long). + +Sat Feb 10 23:07:15 2001 Yukihiro Matsumoto + + * regex.c (PREV_IS_A_LETTER): should not treat c>0x7f as a word + character if -Kn. + +Sat Feb 10 00:06:28 2001 Nobuyoshi Nakada + + * win32/win32.c (win32_stat): replace stat for enable when pathname + ends with '/' or '\' for mswin32 on Win9X / Win2k. + + * win32/win32.h: ditto. + + * ruby.h: ditto. + + * dir.c (rb_glob_helper): ditto. + + * file.c (rb_stat, rb_file_s_stat, eaccess, check3rdbyte): ditto. + +Fri Feb 9 22:54:57 2001 WATANABE Hirofumi + + * ruby.c (ruby_init_loadpath): convert '\\' to '/' + before finding executable file path. + +Fri Feb 9 17:41:53 2001 Triet H. Lai + + * dir.c (rb_glob_helper): do not follow symbolic links. + +Fri Feb 8 23:53:08 2001 Usaku Nakamura + + * win32/config.h.in (inline): add inline definition. + +Thu Feb 8 21:27:24 2001 WATANABE Hirofumi + + * lib/mkmf.rb (install_rb): fix handling of relative path. + + * lib/mkmf.rb (create_makefile): add srcdir. + +Wed Feb 7 16:05:22 2001 Nobuyoshi Nakada + + * parse.y (parse_quotedwords): %w should allow parenthesis escape. + +Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto + + * parse.y (parse_qstring): %q should allow terminator escape. + +Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto + + * re.c (rb_reg_equal): all option flags should be same to be equal. + +Tue Feb 6 21:01:29 2001 Minero Aoki + + * lib/net/protocol.rb: ignore EOFError on only specified case. + + * lib/net/http.rb: take HTTP 1.0 server into account. + +Mon Feb 5 00:39:06 2001 KANEKO Naoshi + + * dir.c: use ISXXX() instead of isxxx(). + + * dln.c (aix_loaderror): ditto. + + * file.c (rb_file_s_expand_path): ditto. + + * string.c (rb_str_upcase_bang): ditto. + + * win32/win32.c (do_spawn): ditto. + + * win32/win32.c (NtMakeCmdVector): ditto. + + * win32/win32.c (opendir): ditto. + +Fri Feb 3 00:48:50 2001 Usaku Nakamura + + * win32/win32.c (isInternalCmd): ignore case for shell's internal + command. (marge from HEAD) + +Fri Feb 2 16:14:51 2001 Yukihiro Matsumoto + + * eval.c (POP_VARS): propagate DVAR_DONT_RECYCLE, if + SCOPE_DONT_RECYCLE of ruby_scope is set. + +Wed Jan 31 22:27:29 2001 WATANABE Hirofumi + + * configure.in: gcc-2.95.2-7(cygwin) support. + add -mwin32 if available. + + * cygwin/GNUmakefile: ditto. + +Mon Jan 29 17:36:19 2001 TOYOFUKU Chikanobu + + * eval.c (rb_eval): nd_iter evaluation should be wrapped by + BEGIN_CALLARGS and END_CALLARGS. + +Mon Jan 29 01:40:27 2001 Yukihiro Matsumoto + + * string.c (str_independent): should not clear str->orig here. + it's too early. + +Wed Jan 24 01:45:49 2001 Yukihiro Matsumoto + + * eval.c (POP_BLOCK_TAG): call rb_gc_force_recycle() if block has + not been objectified. + + * eval.c (rb_callcc): should nail down block->tag history to avoid + rb_gc_force_recycle(). + +Tue Jan 23 18:51:57 2001 Yukihiro Matsumoto + + * gc.c (rb_gc_call_finalizer_at_exit): should finalize objects in + deferred_final_list too. + +Tue Jan 23 16:10:12 2001 Yukihiro Matsumoto + + * gc.c (os_live_obj): do not list terminated object. + + * gc.c (os_obj_of): ditto. + + * gc.c (rb_gc_mark): support new T_BLKTAG tag. + + * gc.c (obj_free): ditto. + + * eval.c (new_blktag): creation of new block tag, which holds + destination of global jump and orphan status. + + * eval.c (block_pass): break from orphan Proc object will raise a + LocalJumpError exception. + +Mon Jan 22 16:33:16 2001 WATANABE Hirofumi + + * mkconfig.rb: autoconf 2.49 support. + +Sat Jan 20 03:54:00 2001 Yukihiro Matsumoto + + * parse.y (yylex): fixed serious syntax misbehavior. do's + preceding was too high. a block in `foo bar do .. end' should + be passed to `foo', not `bar'. + + * parse.y (block_call): syntax restructure. + +Fri Jan 19 04:04:31 2001 Akinori MUSHA + + * lib/irb/ruby-lex.rb: Merge from HEAD: rev.1.4 + +Wed Jan 17 13:28:26 2001 WATANABE Hirofumi + + * configure.in: remove DEFS definition. + + * mkconfig.rb: ditto. + + * win32/config.status.in: ditto. + +Tue Jan 16 16:59:14 2001 Minero Aoki + + * lib/net/protocol.rb: ignore EOFError for read + +Sun Jan 14 21:49:28 2001 Koji Arai + + * sprintf.c (rb_f_sprintf): simple typo. binary base should be 2, + not '2'. + +Sun Jan 14 02:49:57 2001 Minero Aoki + + * lib/net/protocol.rb (adding): too few "yield" in case of arg is + not String/File. + +Sat Jan 13 19:18:18 2001 WATANABE Hirofumi + + * re.c (rb_reg_desc): separate RE_OPTION_MULTILINE + + * re.c (rb_reg_options): add RE_OPTION_{POSIXLINE,RE_OPTION_MULTILINE, + RE_OPTION_EXTENDED} + +Thu Jan 11 06:45:55 2001 Yukihiro Matsumoto + + * object.c (rb_mod_dup): should propagate FL_SINGLETON. + + * object.c (inspect_obj): handles the case of no instance variable. + +Wed Jan 10 01:50:45 2001 Yukihiro Matsumoto + + * string.c (rb_str_reverse_bang): forgot to call rb_str_modify(). + +Tue Jan 9 17:41:40 2001 Yukihiro Matsumoto + + * object.c (rb_obj_taint): check frozen status before modifying + taint status. + + * object.c (rb_obj_untaint): ditto. + +Mon Jan 8 21:35:10 2001 Guy Decoux + + * file.c (path_check_1): should restore modified path. + +Mon Jan 8 21:24:37 2001 Yukihiro Matsumoto + + * bignum.c (bigdivrem): t2 might be too big for signed long; do + not use rb_int2big(), but rb_uint2big(). + +Mon Jan 8 03:09:58 2001 Yukihiro Matsumoto + + * error.c (rb_load_fail): new func to report LoadError. + + * ruby.c (load_file): use rb_load_fail. + +Sat Jan 6 00:55:59 2001 Yukihiro Matsumoto + + * pack.c (pack_pack): template "m2" or "u2" caused inifinite loop. + +Fri Jan 5 01:02:17 2001 Yukihiro Matsumoto + + * eval.c (ruby_finalize): should enclosed by PUSH_TAG/POP_TAG. + +Sun Dec 31 01:39:16 2000 Guy Decoux + + * eval.c (rb_mod_define_method): wrong comparison for blocks. + +Sat Dec 30 19:28:50 2000 Yukihiro Matsumoto + + * gc.c (id2ref): should handle Symbol too. + + * gc.c (id2ref): should print original ptr value + +Sat Dec 30 03:14:22 2000 Yukihiro Matsumoto + + * eval.c (rb_iterate): NODE_CFUNC does not protect its data + (nd_tval), so create new node NODE_IFUNC for iteration C + function. + + * eval.c (rb_yield_0): use NODE_IFUNC. + + * gc.c (rb_gc_mark): support NODE_IFUNC. + +Fri Dec 29 11:41:55 2000 Yukihiro Matsumoto + + * gc.c (mem_error): prohibit recursive mem_error(). + (ruby-bugs-ja:PR#36) + +Fri Dec 29 11:05:41 2000 Yukihiro Matsumoto + + * eval.c (rb_thread_fd_writable): should not switch context if + rb_thread_critical is set. + + * eval.c (rb_thread_wait_fd): ditto. + + * eval.c (rb_thread_wait_for): ditto. + + * eval.c (rb_thread_select): ditto. + + * eval.c (rb_thread_join): join during critical section causes + deadlock. + +Tue Dec 26 18:46:41 2000 NAKAMURA Hiroshi + + * lib/debug.rb: Avoid thread deadlock in debugging stopped thread. + + * lib/debug.rb: Uncleared 'finish' state. + +Tue Dec 26 16:53:55 2000 Yukihiro Matsumoto + + * eval.c (rb_yield_0): remove dvar node by rb_gc_force_recycle() + more eagerly. + + * eval.c (rb_f_binding): recycling should be stopped for outer + scope too. + + * eval.c (proc_new): ditto. + +Tue Dec 26 15:45:35 2000 Yukihiro Matsumoto + + * string.c (rb_str_inspect): should treat multibyte chracters + properly. + +Mon Dec 25 17:49:08 2000 K.Kosako + + * string.c (rb_str_replace_m): unexpected string share happens if + replace is done for associated (STR_NO_ORIG) string. + +Tue Dec 26 15:01:53 2000 Yukihiro Matsumoto + + * io.c (rb_f_p): should not call rb_io_flush() if rb_defout is not + a IO (T_FILE). + +Mon Dec 25 15:52:39 2000 Yukihiro Matsumoto + + * stable version 1.6.2 released. + Mon Dec 25 05:11:04 2000 Wakou Aoyama * lib/cgi.rb: version 2.1.2 (some bug fixes). @@ -21,10 +1284,6 @@ Mon Dec 25 00:04:54 2000 Nobuyoshi Nakada * eval.c (rb_thread_schedule): initial value of `max' changed to -1. -Fri Dec 22 17:59:30 2000 Yukihiro Matsumoto - - * stable version 1.6.2 released. - Mon Dec 25 00:16:14 2000 Yukihiro Matsumoto * string.c (rb_str_replace_m): copy-on-write replace. @@ -85,7 +1344,7 @@ Tue Dec 19 13:44:50 2000 K.Kosako Tue Dec 19 00:57:10 2000 Yukihiro Matsumoto - * time.c (time_minus): usec might overflow (ruby-bugs-ja:#PR#35). + * time.c (time_minus): usec might overflow. (ruby-bugs-ja:PR#35) * eval.c (rb_obj_extend): Object#extend should take at least one argument. @@ -837,7 +2096,7 @@ Sat Sep 23 03:06:25 2000 Yukihiro Matsumoto Fri Sep 22 15:46:21 2000 Minero Aoki - * lib/net/http.rb: too early parameter expantion in string. + * lib/net/http.rb: too early parameter expansion in string. Fri Sep 22 13:58:51 2000 WATANABE Hirofumi @@ -894,7 +2153,7 @@ Wed Sep 20 23:21:38 2000 Yukihiro Matsumoto Wed Sep 20 14:01:45 2000 Yukihiro Matsumoto - * eval.c (rb_provided): detect infnite load loop. + * eval.c (rb_provided): detect infinite load loop. * eval.c (rb_provided): too weak filename comparison. @@ -959,7 +2218,7 @@ Thu Sep 14 02:46:54 2000 Yukihiro Matsumoto Wed Sep 13 17:01:03 2000 Yukihiro Matsumoto - * bignum.c (rb_big_eq): imcomplete value compare of bignums. + * bignum.c (rb_big_eq): incomplete value comparison of bignums. Wed Sep 13 06:39:54 2000 Yukihiro Matsumoto @@ -1084,7 +2343,7 @@ Fri Sep 1 10:36:29 2000 Yukihiro Matsumoto * parse.y (aref_args,opt_call_args): add block_call to allow a method without parentheses and with block as a last argument. - * hash.c (rb_hash_sort): should not retrun nil. + * hash.c (rb_hash_sort): should not return nil. * re.c (match_aref): should use rb_reg_nth_match(). @@ -1252,7 +2511,7 @@ Fri Aug 11 15:43:46 2000 Yukihiro Matsumoto Thu Aug 10 08:05:03 2000 Yukihiro Matsumoto - * eval.c (rb_callcc): returned current thread instaed of + * eval.c (rb_callcc): returned current thread instead of continuation wrongly. Thu Aug 10 05:40:28 2000 WATANABE Hirofumi @@ -1425,7 +2684,7 @@ Tue Jul 18 14:58:30 2000 Yukihiro Matsumoto Mon Jul 17 04:29:50 2000 Minero Aoki - * lib/mkmf.rb: converts extention of $objs into $OBJEXT. + * lib/mkmf.rb: converts extension of $objs into $OBJEXT. Sun Jul 16 03:02:34 2000 Dave Thomas @@ -1522,7 +2781,7 @@ Mon Jul 10 09:07:54 2000 Yukihiro Matsumoto Sat Jul 8 23:08:40 2000 Yukihiro Matsumoto * eval.c (rb_thread_start_0): should copy previous scopes to - prevent rb_gc_force_recylce(). + prevent rb_gc_force_recycle(). Fri Jul 7 23:36:36 2000 Katsuyuki Komatsu @@ -1597,7 +2856,7 @@ Wed Jul 5 09:47:14 2000 Yukihiro Matsumoto * time.c (time_arg): Time::local, Time::gm now take 7th optional argument for usec. - * numeric.c (num_ceil, etc): default ceil, floor, round, trancate + * numeric.c (num_ceil, etc): default ceil, floor, round, truncate implementation for Numeric, using `to_f'. * io.c (rb_io_reopen): clear fptr->path after free() to prevent @@ -1688,7 +2947,7 @@ Mon Jul 3 13:15:02 2000 Yukihiro Matsumoto * bignum.c (rb_big_divmod): ditto. - * numeric.c (fixdivmod): does not depend C's undifined % + * numeric.c (fixdivmod): does not depend C's undefined % behavior. adopt to fmod(3m) behavior. * numeric.c (flo_mod): modulo now reserves fmod(3m) behavior. @@ -1731,7 +2990,7 @@ Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto * eval.c (rb_eval): the value from RTEST() is not valid Ruby - objct. result should be either true or false. + object. result should be either true or false. Sat Jul 1 09:30:06 2000 Katsuyuki Komatsu @@ -2107,12 +3366,12 @@ Fri Jun 9 15:11:35 2000 Yukihiro Matsumoto Thu Jun 8 14:25:45 2000 Hiroshi Igarashi * lib/mkmf.rb: add target `distclean' in Makefile for extlib. - target `clean' doesn't remove Makefile. + target `clean' doesn't remove Makefile. Thu Jun 8 13:34:03 2000 Dave Thomas * numeric.c: add nan?, infinite?, and finite? to Float - + Thu Jun 8 00:31:04 2000 WATANABE Hirofumi * regex.h: export re_mbctab properly on cygwin. @@ -2217,11 +3476,11 @@ Sun May 28 19:21:43 2000 WATANABE Hirofumi * ruby.h: ditto. * main.c: turn off command line mingw32's globbing. - + Wed May 25 22:25:13 2000 WATANABE Hirofumi - + * ext/extmk.rb.in: use "ftools" instead of "rm -f". - + * lib/mkmf.rb: ditto. Thu May 25 22:01:32 2000 Katsuyuki Komatsu @@ -2623,7 +3882,7 @@ Mon May 1 23:42:44 2000 WATANABE Hirofumi * defines.h: use dllimport, dllexport for Cygwin 1.1.x. * ruby.h: ditto. - + * cygwin/GNUmakefile.in: ditto. * ext/Win32API/Win32API.c: directly "call" in asm statement for @@ -2824,6 +4083,13 @@ Sat Mar 25 23:21:10 2000 Yukihiro Matsumoto * marshal.c (w_object): symbols should be converted to ID before dumping out. +Sun Mar 25 16:52:48 2001 Koji Arai + + * file.c (rb_file_flock): do not trap EINTR. + + * missing/flock.c (flock): returns the value from lockf(2) + directly. + Fri Mar 24 18:26:51 2000 Yukihiro Matsumoto * file.c (test_check): should have checked exact number of arguments. @@ -3924,7 +5190,7 @@ Thu Oct 21 16:14:19 1999 Yukihiro Matsumoto * ruby.c (proc_options): use RUBYOPT environment variable to retrieve the default options. - * dir.c (fnmatch): use eban's fnmatch; do not depend on systems's + * dir.c (fnmatch): use eban's fnmatch; do not depend on system's fnmatch (which may have portability problem) anymore. Wed Oct 20 15:14:24 1999 Yukihiro Matsumoto @@ -4832,7 +6098,7 @@ Thu Jun 10 16:41:48 1999 Yukihiro Matsumoto * io.c: do not call `initialize' for IO objects. So with Array, Hash, Range, and Time objects. - + * ext/curses/curses.c (curses_getch): made thread aware using rb_read_check(). @@ -6433,22 +7699,28 @@ Sun Nov 15 15:44:07 1998 Tadayoshi Funaba Sat Nov 14 11:02:05 1998 Motoyuki Kasahara * Makefile.in (install): Give the argument `$(DESTDIR)' to - `instruby.rb'. + `instruby.rb'. + * instruby.rb: Recognize ARG[0] as `destdir'. + * instruby.rb: Give the argument `destdir' to `extmk.rb'. + * ext/extmk.rb.in: Recognize ARG[1] as `$destdir'. * instruby.rb: Create the installation directories (bindir, libdir, - archdir, pkglibdir, archdir, and mandir) under `destdir', and - install all files under there. + archdir, pkglibdir, archdir, and mandir) under `destdir', and + install all files under there. + * ext/extmk.rb.in: Likewise. - + Sat Nov 14 10:56:55 1998 Motoyuki Kasahara * instruby.rb: Add the variable `pkglibdir'. + * instruby.rb: Set the variable `libdir' to `$(libdir)', not - `$(libdir)/$(ruby_install_name)'. `libruby.so' and `libruby.so.LIB' - are installed at `libdir'. + `$(libdir)/$(ruby_install_name)'. `libruby.so' and `libruby.so.LIB' + are installed at `libdir'. + * instruby.rb: Set the variable `archdir' to `$(pkglibdir)/$(arch)'. Fri Nov 13 19:43:29 1998 KIMURA Koichi @@ -6519,7 +7791,7 @@ Sun Nov 1 01:18:52 1998 EGUCHI Osamu Sat Oct 31 23:18:34 1998 Yukihiro Matsumoto * string.c (rb_str_split_method): negative LIMIT means number of - splitted fields are unlimited, as in perl. + split fields are unlimited, as in perl. * string.c (rb_str_split_method): if LIMIT is unspecified, trailing null fields are stripped. @@ -6583,18 +7855,26 @@ Wed Oct 21 14:21:06 1998 Yukihiro Matsumoto Mon Oct 19 11:50:00 1998 Motoyuki Kasahara * ext/extmk.rb: Load '@top_srcdir@/lib/find.rb', not - '../lib/find.rb'. + '../lib/find.rb'. + * ext/extmk.rb: Distinguish between `top_srcdir' and `topdir'. + * Makefile.in (CFLAGS): Add `-I.'. + * Makefile.in (lex.c): Give `@srcdir@/keywords' to gperf, not - `keywords'. + `keywords'. + * instruby.rb: Use `CONFIG["bindir"]', instead of `prefix + "/bin"'. + * instruby.rb: Use `CONFIG["libdir"]', instead of `prefix + "/lib"'. + * instruby.rb Use `CONFIG["mandir"]', instead of `prefix + "/man"'. + * instruby.rb (wdir): Add the variable to preserve the current - working directory. + working directory. + * instruby.rb: Chdir to wdir before install `config.h' and - `rbconfig.rb'. + `rbconfig.rb'. Mon Oct 19 10:07:01 1998 EGUCHI Osamu @@ -7346,7 +8626,7 @@ Mon May 18 16:40:50 1998 MAEDA shugo * glob.c: #include added. Mon May 18 14:52:21 1998 Yukihiro Matsumoto - + * experimental release 1.1b9_21. Mon May 18 03:27:57 1998 MAEDA shugo @@ -8648,7 +9928,7 @@ Thu Dec 11 13:14:35 1997 Yukihiro Matsumoto not exist. * ext/curses/curses.c: remove CHECK macro for BSD curses. - + Thu Dec 11 12:44:01 1997 WATANABE Hirofumi * pack.c: sun4 cc patch @@ -8775,7 +10055,7 @@ Wed Nov 12 13:44:47 1997 Yukihiro Matsumoto Mon Nov 10 11:24:51 1997 Yukihiro Matsumoto - * regex.c (re_compile_pattern): non-resitering parens (?:..). + * regex.c (re_compile_pattern): non-registering parens (?:..). * regex.c (re_compile_pattern): new meta character \< (wordbeg) and \> (wordend). @@ -9031,7 +10311,7 @@ Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto * ruby.c (ruby_prog_init): close stdaux and stdprn for MSDOS. * ruby.c (ruby_prog_init): should not add path from environment - variable, if ruby is running under seuid. + variable, if ruby is running under setuid. * process.c (init_ids): check suid check for setuid/seteuid etc. @@ -9113,7 +10393,7 @@ Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto * parse.y: did not generate here document strings properly. Mon Sep 1 11:43:57 1997 WATANABE Hirofumi - + * parse.y (yylex): heredoc dropped an extra character. Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto @@ -9256,7 +10536,7 @@ Sat Aug 16 00:17:44 1997 Yukihiro Matsumoto Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto * eval.c (call_trace_func): block context switch in the trace - function. + function. * eval.c (rb_eval): clear method cache at class extension. diff --git a/MANIFEST b/MANIFEST index 17e8924bb7..0df950b0c8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -77,9 +77,18 @@ djgpp/config.sed djgpp/configure.bat djgpp/mkver.sed cygwin/GNUmakefile.in +doc/NEWS +doc/forwardable.rd +doc/forwardable.rd.jp +doc/irb/irb-tools.rd.jp +doc/irb/irb.rd +doc/irb/irb.rd.jp +doc/shell.rd +doc/shell.rd.jp ext/Setup ext/Setup.dj ext/Setup.emx +ext/Setup.nt ext/Setup.x68 ext/aix_mksym.rb ext/configsub.rb @@ -101,24 +110,33 @@ lib/eregex.rb lib/find.rb lib/final.rb lib/finalize.rb +lib/forwardable.rb lib/ftplib.rb lib/ftools.rb lib/getopts.rb lib/getoptlong.rb lib/importenv.rb +lib/irb.rb lib/irb/completion.rb +lib/irb/context.rb +lib/irb/extend-command.rb lib/irb/frame.rb +lib/irb/help.rb +lib/irb/init.rb lib/irb/input-method.rb -lib/irb/irb.rb +lib/irb/lc/error.rb +lib/irb/lc/help-message +lib/irb/lc/ja/error.rb +lib/irb/lc/ja/help-message lib/irb/loader.rb -lib/irb/main.rb +lib/irb/locale.rb lib/irb/multi-irb.rb lib/irb/ruby-lex.rb lib/irb/ruby-token.rb lib/irb/slex.rb lib/irb/version.rb -lib/irb/workspace-binding-2.rb -lib/irb/workspace-binding.rb +lib/irb/workspace.rb +lib/irb/ws-for-case-2.rb lib/irb/xmp.rb lib/jcode.rb lib/mailread.rb @@ -144,6 +162,14 @@ lib/profile.rb lib/pstore.rb lib/rational.rb lib/readbytes.rb +lib/shell.rb +lib/shell/builtin-command.rb +lib/shell/command-processor.rb +lib/shell/error.rb +lib/shell/filter.rb +lib/shell/process-controller.rb +lib/shell/system-command.rb +lib/shell/version.rb lib/shellwords.rb lib/singleton.rb lib/sync.rb @@ -161,11 +187,11 @@ misc/rubydb2x.el misc/rubydb3x.el missing/alloca.c missing/crypt.c -missing/dir.h missing/dup2.c missing/file.h missing/finite.c missing/flock.c +missing/hypot.c missing/isinf.c missing/isnan.c missing/memcmp.c @@ -175,7 +201,6 @@ missing/os2.c missing/strcasecmp.c missing/strncasecmp.c missing/strchr.c -missing/strdup.c missing/strerror.c missing/strftime.c missing/strstr.c @@ -239,6 +264,7 @@ win32/README.win32 win32/config.h.in win32/config.status.in win32/configure.bat +win32/dir.h win32/mkexports.rb win32/resource.rb win32/setup.mak diff --git a/Makefile.in b/Makefile.in index b1b0166b89..37f644d786 100644 --- a/Makefile.in +++ b/Makefile.in @@ -22,6 +22,7 @@ MISSING = @LIBOBJS@ @ALLOCA@ LDSHARED = @LIBRUBY_LDSHARED@ DLDFLAGS = @LIBRUBY_DLDFLAGS@ SOLIBS = @SOLIBS@ +MAINLIBS = @MAINLIBS@ RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@ RUBY_SO_NAME=@RUBY_SO_NAME@ @@ -91,13 +92,13 @@ miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) dmyext.@OBJEXT@ $(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(EXTOBJS) @rm -f $@ - $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@ + $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@ $(LIBRUBY_A): $(OBJS) dmyext.@OBJEXT@ @AR@ rcu $@ $(OBJS) dmyext.@OBJEXT@ @-@RANLIB@ $@ 2> /dev/null || true -$(LIBRUBY_SO): $(OBJS) dmyext.@OBJEXT@ +$(LIBRUBY_SO): $(OBJS) dmyext.@OBJEXT@ miniruby$(EXEEXT) $(LDSHARED) $(DLDFLAGS) $(OBJS) dmyext.@OBJEXT@ $(SOLIBS) -o $@ @-@MINIRUBY@ -e 'ARGV.each{|link| File.delete link if File.exist? link; \ File.symlink "$(LIBRUBY_SO)", link}' \ @@ -123,7 +124,7 @@ realclean: distclean test: miniruby$(EXEEXT) @./miniruby$(EXEEXT) $(srcdir)/rubytest.rb -rbconfig.rb: miniruby$(EXEEXT) +rbconfig.rb: miniruby$(EXEEXT) $(srcdir)/mkconfig.rb config.status @@MINIRUBY@ $(srcdir)/mkconfig.rb rbconfig.rb fake.rb: miniruby$(EXEEXT) @@ -230,7 +231,7 @@ dl_os2.@OBJEXT@: $(srcdir)/missing/dl_os2.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $(srcdir)/missing/dl_os2.c win32.@OBJEXT@: $(srcdir)/win32/win32.c - $(CC) $(CFLAGS) $(CPPFLAGS) -c $(srcdir)/win32/win32.c + $(CC) $(CFLAGS) $(CPPFLAGS) -I$(srcdir)/missing -c $(srcdir)/win32/win32.c # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: diff --git a/README b/README index 5794f5daf6..760291d1ba 100644 --- a/README +++ b/README @@ -26,10 +26,10 @@ The Ruby distribution can be found on: You can get it by anonymous CVS. How to check out is: - $ cvs -d :pserver:anonymous@cvs.netlab.co.jp:/home/cvs login - (Logging in to anonymous@cvs.netlab.co.jp) - CVS password: guest - $ cvs -d :pserver:anonymous@cvs.netlab.co.jp:/home/cvs checkout ruby + $ cvs -d :pserver:anonymous@cvs.ruby-lang.org:/src login + (Logging in to anonymous@cvs.ruby-lang.org) + CVS password: anonymous + $ cvs -z4 -d :pserver:anonymous@cvs.ruby-lang.org:/src checkout ruby * Mailing list @@ -40,17 +40,20 @@ To subscribe this list, please send the following phrase e.g. subscribe Joseph Smith -in the mail body (not subject) to the address . +in the mail body (not subject) to the address . * How to compile and install This is what you need to do to compile and install Ruby: - 1. Run ./configure, which will generate config.h and Makefile. + 1. If ./configure does not exist or is older than configure.in, + run autoconf to (re)generate configure. - 2. Edit defines.h if you need. Probably this step will not need. + 2. Run ./configure, which will generate config.h and Makefile. - 3. Remove comment mark(#) before the module names from ext/Setup (or + 3. Edit defines.h if you need. Probably this step will not need. + + 4. Remove comment mark(#) before the module names from ext/Setup (or add module names if not present), if you want to link modules statically. @@ -59,13 +62,13 @@ This is what you need to do to compile and install Ruby: remove comment mark from the line "#option nodynamic" in ext/Setup. - 4. Run make. + 5. Run make. - 5. Optionally, run 'make test' to check whether the compiled Ruby + 6. Optionally, run 'make test' to check whether the compiled Ruby interpreter works well. If you see the message "test succeeded", your ruby works as it should (hopefully). - 6. Run 'make install' + 7. Run 'make install' You may have to be a super user to install ruby. diff --git a/README.EXT b/README.EXT index 5079adb558..f3db6fa45b 100644 --- a/README.EXT +++ b/README.EXT @@ -985,6 +985,11 @@ These functions are available in extconf.rb: Checks whether library which contains specified function exists. Returns true if the library exists. + find_library(lib, func, path...) + +Checks whether library which contains specified function exists in +path. Returns true if the library exists. + have_func(func, header) Checks whether func exists with header. Returns true if the function @@ -993,13 +998,27 @@ check that library first using have_library(). have_header(header) -Checks for the header files. Returns true if the header file exists. +Checks whether header exists. Returns true if the header file exists. create_makefile(target) Generates the Makefile for the extension library. If you don't invoke this method, the compilation will not be done. + with_config(withval[, default=nil]) + +Parses the command line options and returns the value specified by +--with-. + + dir_config(target[, default_dir]) + dir_config(target[, default_include, default_lib]) + +Parses the command line options and adds the directories specified by +--with--dir, --with--include, and/or --with--lib +to $CFLAGS and/or $LDFLAGS. --with--dir=/path is equivalent to +--with--include=/path/include --with--lib=/path/lib. +Returns an array of the added directories ([include_dir, lib_dir]). + /* * Local variables: * fill-column: 70 diff --git a/README.EXT.jp b/README.EXT.jp index 0db954818e..07a9e8b39d 100644 --- a/README.EXT.jp +++ b/README.EXT.jp @@ -1160,11 +1160,6 @@ have_header(header) ¥Ø¥Ã¥À¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò¥Á¥§¥Ã¥¯¤¹¤ë¡¥¥Ø¥Ã¥À¥Õ¥¡¥¤¥ë¤¬Â¸ºß¤¹ ¤ë»þtrue¤òÊÖ¤¹¡¥ -find_header(header) - - ¥Ø¥Ã¥À¥Õ¥¡¥¤¥ë¤Î¸ºß¤ò -Ipath ¤òÄɲ䷤ʤ¬¤é¥Á¥§¥Ã¥¯¤¹¤ë¡¥ - ¥Ø¥Ã¥À¥Õ¥¡¥¤¥ë¤¬¸«ÉÕ¤«¤Ã¤¿»þtrue¤òÊÖ¤¹¡¥ - create_makefile(target) ³ÈÄ¥¥é¥¤¥Ö¥é¥êÍѤÎMakefile¤òÀ¸À®¤¹¤ë¡¥¤³¤Î´Ø¿ô¤ò¸Æ¤Ð¤Ê¤±¤ì @@ -1173,13 +1168,17 @@ create_makefile(target) with_config(withval[, default=nil]) - --with-¤Ç»ØÄꤵ¤ì¤¿¥ª¥×¥·¥ç¥óÃͤòÆÀ¤ë¡¥ + ¥³¥Þ¥ó¥É¥é¥¤¥ó¾å¤Î--with-¤Ç»ØÄꤵ¤ì¤¿¥ª¥×¥·¥ç¥óÃͤòÆÀ¤ë¡¥ -dir_config(target) +dir_config(target[, default_dir]) +dir_config(target[, default_include, default_lib]) - --with--dir, --with--include, --with--lib - ¤Î¤¤¤º¤ì¤«¤Ç»ØÄꤵ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê¤ò $CFLAGS ¤ä $LDFLAGS - ¤ËÄɲ乤롥 + ¥³¥Þ¥ó¥É¥é¥¤¥ó¾å¤Î--with--dir, --with--include, + --with--lib¤Î¤¤¤º¤ì¤«¤Ç»ØÄꤵ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê¤ò + $CFLAGS ¤ä $LDFLAGS ¤ËÄɲ乤롥--with--dir=/path¤Ï + --with--include=/path/include --with--lib=/path/lib + ¤ÈÅù²Á¤Ç¤¢¤ë¡¥Äɲ䵤줿 include ¥Ç¥£¥ì¥¯¥È¥ê¤È lib ¥Ç¥£¥ì¥¯¥È¥ê¤Î + ÇÛÎó¤òÊÖ¤¹¡¥ ([include_dir, lib_dir]) /* * Local variables: diff --git a/README.jp b/README.jp index fccedb2f99..9af1f15bb5 100644 --- a/README.jp +++ b/README.jp @@ -34,10 +34,10 @@ Ruby ** CVS¤Ç - $ cvs -d :pserver:anonymous@cvs.netlab.co.jp:/home/cvs login - (Logging in to anonymous@cvs.netlab.co.jp) - CVS password: guest - $ cvs -d :pserver:anonymous@cvs.netlab.co.jp:/home/cvs checkout ruby + $ cvs -d :pserver:anonymous@cvs.ruby-lang.org:/src login + (Logging in to anonymous@cvs.ruby-lang.org) + CVS password: anonymous + $ cvs -z4 -d :pserver:anonymous@cvs.ruby-lang.org:src checkout ruby * ¥Û¡¼¥à¥Ú¡¼¥¸ @@ -53,7 +53,7 @@ Ruby Ruby¤Î¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤¬¤¢¤ê¤Þ¤¹¡£»²²Ã´õ˾¤ÎÊý¤Ï - ruby-list-ctl@netlab.co.jp + ruby-list-ctl@ruby-lang.org ¤Þ¤ÇËÜʸ¤Ë @@ -65,11 +65,12 @@ Ruby ¥°¡¢¾­Íè¤Î»ÅÍͳÈÄ¥¤Ê¤É¼ÂÁõ¾å¤ÎÌäÂê¤Ë¤Ä¤¤¤ÆµÄÏÀ¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ »²²Ã´õ˾¤ÎÊý¤Ï - ruby-dev-ctl@netlab.co.jp + ruby-dev-ctl@ruby-lang.org ¤Þ¤Çruby-list¤ÈƱÍͤÎÊýË¡¤Ç¥á¡¼¥ë¤·¤Æ¤¯¤À¤µ¤¤¡£ Ruby³ÈÄ¥¥â¥¸¥å¡¼¥ë¤Ë¤Ä¤¤¤ÆÏ䷹礦ruby-ext¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤È +¿ô³Ø´Ø·¸¤ÎÏÃÂê¤Ë¤Ä¤¤¤ÆÏ䷹礦ruby-math¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤È ±Ñ¸ì¤ÇÏ䷹礦ruby-talk¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤â¤¢¤ê¤Þ¤¹¡£»²²ÃÊýË¡ ¤Ï¤É¤ì¤âƱ¤¸¤Ç¤¹¡£ @@ -78,13 +79,17 @@ Ruby °Ê²¼¤Î¼ê½ç¤Ç¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡¥ - 1. configure¤ò¼Â¹Ô¤·¤ÆMakefile¤Ê¤É¤òÀ¸À®¤¹¤ë + 1. ¤â¤·configure¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤é¤Ê¤¤¡¢¤â¤·¤¯¤Ï + configure.in¤è¤ê¸Å¤¤¤è¤¦¤Ê¤é¡¢autoconf¤ò¼Â¹Ô¤·¤Æ + ¿·¤·¤¯configure¤òÀ¸À®¤¹¤ë - 2. (ɬÍפʤé¤Ð)defines.h¤òÊÔ½¸¤¹¤ë + 2. configure¤ò¼Â¹Ô¤·¤ÆMakefile¤Ê¤É¤òÀ¸À®¤¹¤ë + + 3. (ɬÍפʤé¤Ð)defines.h¤òÊÔ½¸¤¹¤ë ¿ʬ¡¤É¬Í×̵¤¤¤È»×¤¤¤Þ¤¹¡¥ - 3. (ɬÍפʤé¤Ð)ext/Setup¤ËÀÅŪ¤Ë¥ê¥ó¥¯¤¹¤ë³ÈÄ¥¥â¥¸¥å¡¼¥ë¤ò + 4. (ɬÍפʤé¤Ð)ext/Setup¤ËÀÅŪ¤Ë¥ê¥ó¥¯¤¹¤ë³ÈÄ¥¥â¥¸¥å¡¼¥ë¤ò »ØÄꤹ¤ë ext/Setup¤Ëµ­½Ò¤·¤¿¥â¥¸¥å¡¼¥ë¤ÏÀÅŪ¤Ë¥ê¥ó¥¯¤µ¤ì¤Þ¤¹¡¥ @@ -95,14 +100,14 @@ Ruby ³ÈÄ¥¥â¥¸¥å¡¼¥ë¤òÍøÍѤ¹¤ë¤¿¤á¤Ë¤Ï¡¤¤¢¤é¤«¤¸¤áÀÅŪ¤Ë¥ê¥ó ¥¯¤·¤Æ¤ª¤¯É¬Íפ¬¤¢¤ê¤Þ¤¹¡¥ - 4. make¤ò¼Â¹Ô¤·¤Æ¥³¥ó¥Ñ¥¤¥ë¤¹¤ë + 5. make¤ò¼Â¹Ô¤·¤Æ¥³¥ó¥Ñ¥¤¥ë¤¹¤ë - 5. make test¤Ç¥Æ¥¹¥È¤ò¹Ô¤¦¡¥ + 6. make test¤Ç¥Æ¥¹¥È¤ò¹Ô¤¦¡¥ ¡Ötest succeeded¡×¤Èɽ¼¨¤µ¤ì¤ì¤ÐÀ®¸ù¤Ç¤¹¡¥¤¿¤À¤·¥Æ¥¹¥È ¤ËÀ®¸ù¤·¤Æ¤â´°àú¤À¤ÈÊݾڤµ¤ì¤Æ¤¤¤ëÌõ¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡¥ - 6. make install + 7. make install root¤Çºî¶È¤¹¤ëɬÍפ¬¤¢¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡¥ diff --git a/array.c b/array.c index 638b392753..0b36460dbd 100644 --- a/array.c +++ b/array.c @@ -1171,7 +1171,7 @@ rb_ary_replace_m(ary, ary2) return ary; } -static VALUE +VALUE rb_ary_clear(ary) VALUE ary; { @@ -1468,7 +1468,7 @@ rb_ary_and(ary1, ary2) for (i=0; ilen; i++) { VALUE v = RARRAY(ary1)->ptr[i]; if (st_delete(RHASH(hash)->tbl, &v, 0)) { - rb_ary_push(ary3, v); + rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); } } @@ -1490,13 +1490,13 @@ rb_ary_or(ary1, ary2) for (i=0; ilen; i++) { v = RARRAY(ary1)->ptr[i]; if (st_delete(RHASH(hash)->tbl, &v, 0)) { - rb_ary_push(ary3, v); + rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); } } for (i=0; ilen; i++) { v = RARRAY(ary2)->ptr[i]; if (st_delete(RHASH(hash)->tbl, &v, 0)) { - rb_ary_push(ary3, v); + rb_ary_push(ary3, RARRAY(ary2)->ptr[i]); } } @@ -1520,7 +1520,7 @@ rb_ary_uniq_bang(ary) while (p < end) { VALUE v = *p++; if (st_delete(RHASH(hash)->tbl, &v, 0)) { - *q++ = v; + *q++ = *(p-1); } } RARRAY(ary)->len = (q - RARRAY(ary)->ptr); @@ -1584,35 +1584,54 @@ rb_ary_nitems(ary) return INT2NUM(n); } +static int +flatten(ary, idx, ary2, memo) + VALUE ary; + long idx; + VALUE ary2, memo; +{ + VALUE id; + long i = idx; + long n, lim = idx + RARRAY(ary2)->len; + + id = rb_obj_id(ary2); + if (rb_ary_includes(memo, id)) { + rb_raise(rb_eArgError, "tried to flatten recursive array"); + } + rb_ary_push(memo, id); + rb_ary_replace(ary, idx, 1, ary2); + while (i < lim) { + if (TYPE(RARRAY(ary)->ptr[i]) == T_ARRAY) { + n = flatten(ary, i, RARRAY(ary)->ptr[i], memo); + i += n; lim += n; + } + i++; + } + rb_ary_pop(memo); + + return lim - idx - 1; /* returns number of increased items */ +} + static VALUE rb_ary_flatten_bang(ary) VALUE ary; { - long i; + long i = 0; int mod = 0; - VALUE flattening = Qnil; + VALUE memo = Qnil; rb_ary_modify(ary); - for (i=0; ilen; i++) { + while (ilen) { VALUE ary2 = RARRAY(ary)->ptr[i]; + if (TYPE(ary2) == T_ARRAY) { - if (ary == ary2) { - ary2 = Qnil; - } else { - VALUE id; - - if (NIL_P(flattening)) { - flattening = rb_ary_new(); - } - id = rb_obj_id(ary2); - if (rb_ary_includes(flattening, id)) { - rb_raise(rb_eArgError, "tried to flatten recursive array"); - } - rb_ary_push(flattening, id); + if (NIL_P(memo)) { + memo = rb_ary_new(); } - rb_ary_replace(ary, i--, 1, ary2); + i += flatten(ary, i, ary2, memo); mod = 1; } + i++; } if (mod == 0) return Qnil; return ary; diff --git a/bignum.c b/bignum.c index daf131b042..3159d143c7 100644 --- a/bignum.c +++ b/bignum.c @@ -209,6 +209,10 @@ rb_cstr2inum(str, base) str++; sign = 0; } + if (str[0] == '+' || str[0] == '-') { + if (badcheck) goto bad; + return INT2FIX(0); + } if (base == 0) { if (str[0] == '0') { if (str[1] == 'x' || str[1] == 'X') { @@ -359,7 +363,7 @@ rb_big2str(x, base) VALUE x; int base; { - VALUE t; + volatile VALUE t; BDIGIT *ds; long i, j, hbase; VALUE ss; @@ -467,7 +471,7 @@ rb_big2long(x) { unsigned long num = big2ulong(x, "int"); - if ((long)num < 0) { + if ((long)num < 0 && (RBIGNUM(x)->sign || (long)num != LONG_MIN)) { rb_raise(rb_eRangeError, "bignum too big to convert into `int'"); } if (!RBIGNUM(x)->sign) return -(long)num; @@ -831,8 +835,10 @@ bigdivrem(x, y, divp, modp) t2 %= dd; } RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign; - if (!RBIGNUM(x)->sign) t2 = -(long)t2; - if (modp) *modp = rb_int2big((long)t2); + if (modp) { + *modp = rb_uint2big((unsigned long)t2); + RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; + } if (divp) *divp = z; return; } @@ -911,10 +917,10 @@ bigdivrem(x, y, divp, modp) } if (modp) { /* just normalize remainder */ *modp = rb_big_clone(z); + zds = BDIGITS(*modp); + while (ny-- && !zds[ny]); ++ny; if (dd) { - zds = BDIGITS(*modp); - while (ny-- && !zds[ny]) ; - t2 = 0; i = ++ny; + t2 = 0; i = ny; while(i--) { t2 = (t2 | zds[i]) >> dd; q = zds[i]; diff --git a/class.c b/class.c index 2eedb262dc..b5caf3082a 100644 --- a/class.c +++ b/class.c @@ -33,16 +33,6 @@ rb_class_new(super) return (VALUE)klass; } -VALUE -rb_singleton_class_new(super) - VALUE super; -{ - VALUE klass = rb_class_new(super); - - FL_SET(klass, FL_SINGLETON); - return klass; -} - static int clone_method(mid, body, tbl) ID mid; @@ -53,6 +43,47 @@ clone_method(mid, body, tbl) return ST_CONTINUE; } +VALUE +rb_mod_clone(module) + VALUE module; +{ + NEWOBJ(clone, struct RClass); + CLONESETUP(clone, module); + + clone->super = RCLASS(module)->super; + if (RCLASS(module)->iv_tbl) { + clone->iv_tbl = st_copy(RCLASS(module)->iv_tbl); + } + if (RCLASS(module)->m_tbl) { + clone->m_tbl = st_init_numtable(); + st_foreach(RCLASS(module)->m_tbl, clone_method, clone->m_tbl); + } + + return (VALUE)clone; +} + +VALUE +rb_mod_dup(mod) + VALUE mod; +{ + VALUE dup = rb_mod_clone(mod); + OBJSETUP(dup, RBASIC(mod)->klass, BUILTIN_TYPE(mod)); + if (FL_TEST(mod, FL_SINGLETON)) { + FL_SET(dup, FL_SINGLETON); + } + return dup; +} + +VALUE +rb_singleton_class_new(super) + VALUE super; +{ + VALUE klass = rb_class_new(super); + + FL_SET(klass, FL_SINGLETON); + return klass; +} + VALUE rb_singleton_class_clone(klass) VALUE klass; @@ -67,6 +98,9 @@ rb_singleton_class_clone(klass) clone->super = RCLASS(klass)->super; clone->iv_tbl = 0; clone->m_tbl = 0; + if (RCLASS(klass)->iv_tbl) { + clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); + } clone->m_tbl = st_init_numtable(); st_foreach(RCLASS(klass)->m_tbl, clone_method, clone->m_tbl); FL_SET(clone, FL_SINGLETON); @@ -78,8 +112,12 @@ void rb_singleton_class_attached(klass, obj) VALUE klass, obj; { - if (FL_TEST(klass, FL_SINGLETON)) - rb_iv_set(klass, "__attached__", obj); + if (FL_TEST(klass, FL_SINGLETON)) { + if (!RCLASS(klass)->iv_tbl) { + RCLASS(klass)->iv_tbl = st_init_numtable(); + } + st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj); + } } VALUE @@ -217,7 +255,12 @@ rb_include_module(klass, module) VALUE klass, module; { VALUE p; + int changed = 0; + rb_frozen_class_p(klass); + if (!OBJ_TAINTED(klass)) { + rb_secure(4); + } if (NIL_P(module)) return; if (klass == module) return; @@ -238,16 +281,16 @@ rb_include_module(klass, module) if (RCLASS(module)->super) { rb_include_module(p, RCLASS(module)->super); } + if (changed) rb_clear_cache(); return; } } - rb_frozen_class_p(klass); - RCLASS(klass)->super = - include_class_new(module, RCLASS(klass)->super); + RCLASS(klass)->super = include_class_new(module, RCLASS(klass)->super); klass = RCLASS(klass)->super; module = RCLASS(module)->super; + changed = 1; } - rb_clear_cache(); + if (changed) rb_clear_cache(); } VALUE diff --git a/configure.in b/configure.in index b24f492665..961a558fcb 100644 --- a/configure.in +++ b/configure.in @@ -27,7 +27,6 @@ fi AC_CANONICAL_HOST AC_CANONICAL_TARGET -AC_CANONICAL_BUILD dnl checks for fat-binary fat_binary=no @@ -90,13 +89,13 @@ AC_CHECK_TOOL(AR, ar) AC_CHECK_PROGS(AR, ar aal, ar) case "$target_os" in - cygwin*|mingw*) - AC_CHECK_TOOL(NM, nm) - AC_CHECK_TOOL(DLLWRAP, dllwrap) - AC_CHECK_TOOL(AS, as) - AC_CHECK_TOOL(DLLTOOL, dlltool) - AC_CHECK_TOOL(WINDRES, windres) - ;; +cygwin*|mingw*) + AC_CHECK_TOOL(NM, nm) + AC_CHECK_TOOL(DLLWRAP, dllwrap) + AC_CHECK_TOOL(AS, as) + AC_CHECK_TOOL(DLLTOOL, dlltool) + AC_CHECK_TOOL(WINDRES, windres) + ;; esac AC_PROG_LN_S @@ -163,6 +162,14 @@ if test "$rb_cv_have_attr_noreturn" = yes; then AC_DEFINE(HAVE_ATTR_NORETURN) fi +dnl wheather link libc_r or not +AC_ARG_WITH(libc_r, + [--with-libc_r link libc_r if possible (FreeBSD only)], [ + case $withval in + yes) with_libc_r=yes;; + *) with_libc_r=no;; + esac], [with_libc_r=no]) + dnl Checks for libraries. case "$target_os" in nextstep*) ;; @@ -171,7 +178,8 @@ rhapsody*) ;; darwin*) LIBS="-lobjc $LIBS";; human*) ac_cv_func_getpgrp_void=yes;; beos*) ;; -cygwin*) rb_cv_have_daylight=no;; +cygwin*) rb_cv_have_daylight=no + ac_cv_var_tzname=no;; mingw*) LIBS="-lwsock32 -lmsvcrt $LIBS" ac_cv_header_a_out_h=no ac_cv_header_pwd_h=no @@ -181,9 +189,12 @@ mingw*) LIBS="-lwsock32 -lmsvcrt $LIBS" ac_cv_header_sys_resource_h=no ac_cv_header_sys_select_h=no ac_cv_header_sys_times_h=no - ac_cv_func_times=yes;; + ac_cv_func_times=yes + ac_cv_func_waitpid=yes;; os2_emx*) LIBS="-lm $LIBS" ac_cv_lib_dir_opendir=no;; +msdosdjgpp*) LIBS="-lm $LIBS" + ac_cv_func_getpgrp_void=yes;; freebsd*) LIBS="-lm $LIBS" AC_CACHE_CHECK([whether -lxpg4 has to be linked], rb_cv_lib_xpg4_needed, @@ -200,7 +211,38 @@ freebsd*) LIBS="-lm $LIBS" if test "$rb_cv_lib_xpg4_needed" = yes; then AC_CHECK_LIB(xpg4, setlocale) fi + if test "$with_libc_r" = yes; then + AC_CACHE_CHECK([whether libc_r is supplementary to libc], + rb_cv_supplementary_lib_c_r, + [AC_TRY_CPP([ +#include +#if 500016 <= __FreeBSD_version +#error libc_r is supplementary to libc +#endif + ], + rb_cv_supplementary_lib_c_r=no, + rb_cv_supplementary_lib_c_r=yes, + rb_cv_supplementary_lib_c_r=yes)]) + if test "$rb_cv_supplementary_lib_c_r" = yes; then + MAINLIBS="-lc_r $MAINLIBS" + else + MAINLIBS="-pthread $MAINLIBS" + CFLAGS="-D_THREAD_SAFE $CFLAGS" + fi + fi ;; +linux*) LIBS="-lm $LIBS" + case "$target_cpu" in + alpha*) + CFLAGS="-mieee $CFLAGS" ;; + esac ;; +osf*) LIBS="-lm $LIBS" + case "$target_cpu"::"$without_gcc" in + alpha*::no) + CFLAGS="-mieee $CFLAGS" ;; + alpha*::yes) + CFLAGS="-ieee $CFLAGS" ;; + esac ;; *) LIBS="-lm $LIBS";; esac AC_CHECK_LIB(crypt, crypt) @@ -316,6 +358,7 @@ test $rb_cv_func_strtod = no && LIBOBJS="$LIBOBJS strtod.o" AC_C_BIGENDIAN AC_C_CONST AC_C_CHAR_UNSIGNED +AC_C_INLINE AC_CACHE_CHECK(whether right shift preserve sign bit, rb_cv_rshift_sign, [AC_TRY_RUN([ @@ -380,7 +423,7 @@ AC_ARG_WITH(default-kcode, esac]) AC_DEFINE_UNQUOTED(DEFAULT_KCODE, $DEFAULT_KCODE) -dnl wheather use dln_a_out ot not +dnl wheather use dln_a_out or not AC_ARG_WITH(dln-a-out, [--with-dln-a-out use dln_a_out if possible], [ case $withval in @@ -452,7 +495,7 @@ if test "$with_dln_a_out" != yes; then nextstep*) ;; openstep*) ;; rhapsody*) ;; - darwin*) ;; + darwin*) CCDLFLAGS=-fno-common;; human*) ;; bsdi*) ;; beos*) ;; @@ -494,6 +537,8 @@ if test "$with_dln_a_out" != yes; then rb_cv_dlopen=yes;; sysv4*) LDSHARED='ld -G' rb_cv_dlopen=yes;; + nto-qnx*) LDSHARED="qcc -shared" + rb_cv_dlopen=yes ;; esix*|uxpds*) LDSHARED="ld -G" rb_cv_dlopen=yes ;; osf*) LDSHARED="$CC -shared" @@ -757,6 +802,9 @@ if test "$enable_shared" = 'yes'; then LIBRUBYARG='-L. -l$(RUBY_INSTALL_NAME)' CFLAGS="$CFLAGS $CCDLFLAGS" ENABLE_SHARED=yes + if test "$rb_cv_binary_elf" = yes; then + SOLIBS='$(LIBS)' + fi case "$target_os" in sunos4*) LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_INSTALL_NAME).so' @@ -766,6 +814,7 @@ if test "$enable_shared" = 'yes'; then LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_INSTALL_NAME).so' ;; freebsd*) + SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_INSTALL_NAME).so.$(MAJOR)$(MINOR)' if test "$rb_cv_binary_elf" != "yes" ; then LIBRUBY_SO="$LIBRUBY_SO.\$(TEENY)" @@ -773,6 +822,7 @@ if test "$enable_shared" = 'yes'; then fi ;; netbsd*) + SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).$(MINOR)' if test "$rb_cv_binary_elf" = yes; then # ELF platforms LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).so.$(MAJOR) lib$(RUBY_INSTALL_NAME).so' @@ -780,6 +830,9 @@ if test "$enable_shared" = 'yes'; then LIBRUBY_ALIASES= # a.out platforms fi ;; + openbsd*) + SOLIBS='$(LIBS)' + ;; solaris*) XLDFLAGS='-R${prefix}/lib' ;; @@ -806,6 +859,12 @@ if test "$enable_shared" = 'yes'; then ;; esac ;; + darwin*) + LIBRUBY_SO='lib$(RUBY_INSTALL_NAME).$(MAJOR).$(MINOR).$(TEENY).dylib' + LIBRUBY_LDSHARED='cc -dynamiclib -undefined suppress' + LIBRUBY_DLDFLAGS='-install_name lib$(RUBY_INSTALL_NAME).dylib -current_version $(MAJOR).$(MINOR).$(TEENY) -compatibility_version $(MAJOR).$(MINOR)' + LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).$(MAJOR).$(MINOR).dylib lib$(RUBY_INSTALL_NAME).dylib' + ;; *) ;; esac @@ -828,9 +887,7 @@ case "$target_os" in CFLAGS="$CFLAGS -DOS2" ;; osf*) - if test "$without_gcc" = "no" ; then - CFLAGS="$CFLAGS -ansi" - else + if test "$without_gcc" = "yes" ; then # compile something small: taint.c is fine for this. # the main point is the '-v' flag of 'cc'. case "`cc -v -I. -c main.c -o /tmp/main.o 2>&1`" in @@ -893,6 +950,7 @@ AC_SUBST(LIBRUBYARG) AC_SUBST(SOLIBS) AC_SUBST(DLDLIBS) AC_SUBST(ENABLE_SHARED) +AC_SUBST(MAINLIBS) ri_prefix= test "$program_prefix" != NONE && @@ -963,5 +1021,6 @@ fi echo "creating config.h" tr -d '\015' < confdefs.h > config.h +: > confdefs.h AC_OUTPUT($FIRSTMAKEFILE Makefile ext/extmk.rb) diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in index 76ce832a31..4fc628f4da 100644 --- a/cygwin/GNUmakefile.in +++ b/cygwin/GNUmakefile.in @@ -5,6 +5,8 @@ ENABLE_SHARED=@ENABLE_SHARED@ ifneq (,$(findstring no, $(ENABLE_SHARED))) EXTOBJS = $(RUBY_INSTALL_NAME).exp LIBRUBYARG = $(LIBRUBY_A) +else + CPPFLAGS += -DLIBRUBY_SO=\"$(LIBRUBY_SO)\" endif ifneq (,$(findstring ruby, $(RUBY_INSTALL_NAME))) diff --git a/defines.h b/defines.h index fefddee23b..e4ae64839e 100644 --- a/defines.h +++ b/defines.h @@ -73,7 +73,7 @@ #undef HAVE_SETITIMER #endif -#if defined(DJGPP) || defined(__BOW__) || defined __CYGWIN__ +#if defined(DJGPP) || defined(__BOW__) #undef HAVE_SETITIMER #endif diff --git a/dir.c b/dir.c index 37cf332cb5..187ae1896e 100644 --- a/dir.c +++ b/dir.c @@ -26,10 +26,10 @@ #include #endif -#if HAVE_DIRENT_H +#if defined HAVE_DIRENT_H && !defined NT # include # define NAMLEN(dirent) strlen((dirent)->d_name) -#elif HAVE_DIRECT_H +#elif defined HAVE_DIRECT_H && !defined NT # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else @@ -44,8 +44,8 @@ # if HAVE_NDIR_H # include # endif -# if defined(NT) && defined(_MSC_VER) -# include "missing/dir.h" +# if defined(NT) +# include "win32/dir.h" # endif #endif @@ -61,6 +61,10 @@ char *strchr _((char*,char)); #include +#ifndef HAVE_LSTAT +#define lstat rb_sys_stat +#endif + #define FNM_NOESCAPE 0x01 #define FNM_PATHNAME 0x02 #define FNM_PERIOD 0x04 @@ -69,7 +73,7 @@ char *strchr _((char*,char)); #define FNM_NOMATCH 1 #define FNM_ERROR 2 -#define downcase(c) (nocase && isupper(c) ? tolower(c) : (c)) +#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) #if defined DOSISH #define isdirsep(c) ((c) == '/' || (c) == '\\') @@ -126,17 +130,18 @@ range(pat, test, flags) return 0; } +#define ISDIRSEP(c) (pathname && isdirsep(c)) #define PERIOD(s) (period && *(s) == '.' && \ - ((s) == string || pathname && isdirsep(*(s)))) + ((s) == string || ISDIRSEP((s)[-1]))) static int fnmatch(pat, string, flags) - char *pat; - char *string; + const char *pat; + const char *string; int flags; { int c; int test; - char *s = string; + const char *s = string; int escape = !(flags & FNM_NOESCAPE); int pathname = flags & FNM_PATHNAME; int period = flags & FNM_PERIOD; @@ -145,7 +150,7 @@ fnmatch(pat, string, flags) while (c = *pat++) { switch (c) { case '?': - if (!*s || pathname && isdirsep(*s) || PERIOD(s)) + if (!*s || ISDIRSEP(*s) || PERIOD(s)) return FNM_NOMATCH; s++; break; @@ -162,7 +167,7 @@ fnmatch(pat, string, flags) else return 0; } - else if (pathname && isdirsep(c)) { + else if (ISDIRSEP(c)) { s = find_dirsep(s); if (s) break; @@ -176,14 +181,14 @@ fnmatch(pat, string, flags) if ((c == '[' || downcase(*s) == test) && !fnmatch(pat, s, flags & ~FNM_PERIOD)) return 0; - else if (pathname && isdirsep(*s)) + else if (ISDIRSEP(*s)) break; s++; } return FNM_NOMATCH; case '[': - if (!*s || pathname && isdirsep(*s) || PERIOD(s)) + if (!*s || ISDIRSEP(*s) || PERIOD(s)) return FNM_NOMATCH; pat = range(pat, *s, flags); if (!pat) @@ -207,7 +212,7 @@ fnmatch(pat, string, flags) default: #if defined DOSISH - if (pathname && isdirsep(c) && isdirsep(*s)) + if (ISDIRSEP(c) && isdirsep(*s)) ; else #endif @@ -490,12 +495,14 @@ dir_s_rmdir(obj, dir) /* Return nonzero if S has any special globbing chars in it. */ static int -has_magic(s, send) +has_magic(s, send, flags) char *s, *send; + int flags; { register char *p = s; register char c; int open = 0; + int escape = !(flags & FNM_NOESCAPE); while ((c = *p++) != '\0') { switch (c) { @@ -512,7 +519,7 @@ has_magic(s, send) continue; case '\\': - if (*p++ == '\0') + if (escape && *p++ == '\0') return Qfalse; } @@ -531,7 +538,11 @@ extract_path(p, pend) len = pend - p; alloc = ALLOC_N(char, len+1); memcpy(alloc, p, len); - if (len > 1 && pend[-1] == '/') { + if (len > 1 && pend[-1] == '/' +#if defined DOSISH + && pend[-2] != ':' +#endif + ) { alloc[len-1] = 0; } else { @@ -558,17 +569,17 @@ extract_elem(path) #endif void -rb_glob_helper(path, flag, func, arg) +rb_glob_helper(path, flags, func, arg) char *path; - int flag; + int flags; void (*func)(); VALUE arg; { struct stat st; char *p, *m; - if (!has_magic(path, 0)) { - if (stat(path, &st) == 0) { + if (!has_magic(path, 0, flags)) { + if (rb_sys_stat(path, &st) == 0) { (*func)(path, arg); } return; @@ -578,7 +589,7 @@ rb_glob_helper(path, flag, func, arg) while (p) { if (*p == '/') p++; m = strchr(p, '/'); - if (has_magic(p, m)) { + if (has_magic(p, m, flags)) { char *dir, *base, *magic, *buf; DIR *dirp; struct dirent *dp; @@ -598,15 +609,30 @@ rb_glob_helper(path, flag, func, arg) recursive = 1; buf = ALLOC_N(char, strlen(base)+strlen(m)+3); sprintf(buf, "%s%s%s", base, (*base)?"":".", m); - rb_glob_helper(buf, flag, func, arg); + rb_glob_helper(buf, flags, func, arg); free(buf); } - dirp = opendir(dir); - if (dirp == NULL) { - free(base); - break; + if (rb_sys_stat(dir, &st) < 0) { + free(base); + break; } + if (S_ISDIR(st.st_mode)) { + dirp = opendir(dir); + if (dirp == NULL) { + free(base); + break; + } + } + else { + free(base); + break; + } + +#if defined DOSISH +#define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3]))) +#else #define BASE (*base && !(*base == '/' && !base[1])) +#endif for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if (recursive) { @@ -614,11 +640,19 @@ rb_glob_helper(path, flag, func, arg) continue; buf = ALLOC_N(char, strlen(base)+NAMLEN(dp)+strlen(m)+6); sprintf(buf, "%s%s%s/**%s", base, (BASE)?"/":"", dp->d_name, m); - rb_glob_helper(buf, flag, func, arg); + sprintf(buf, "%s%s%s", base, (BASE)?"/":"", dp->d_name); + if (lstat(buf, &st) < 0) { + continue; + } + if (S_ISDIR(st.st_mode)) { + strcat(buf, "/**"); + strcat(buf, m); + rb_glob_helper(buf, flags, func, arg); + } free(buf); continue; } - if (fnmatch(magic, dp->d_name, flag) == 0) { + if (fnmatch(magic, dp->d_name, flags) == 0) { buf = ALLOC_N(char, strlen(base)+NAMLEN(dp)+2); sprintf(buf, "%s%s%s", base, (BASE)?"/":"", dp->d_name); if (!m) { @@ -643,7 +677,7 @@ rb_glob_helper(path, flag, func, arg) char *t = ALLOC_N(char, len+mlen+1); sprintf(t, "%s%s", link->path, m); - rb_glob_helper(t, flag, func, arg); + rb_glob_helper(t, flags, func, arg); free(t); } tmp = link; @@ -662,7 +696,7 @@ rb_glob(path, func, arg) void (*func)(); VALUE arg; { - rb_glob_helper(path, FNM_PERIOD|FNM_PATHNAME, func, arg); + rb_glob_helper(path, FNM_PERIOD, func, arg); } void @@ -671,7 +705,7 @@ rb_iglob(path, func, arg) void (*func)(); VALUE arg; { - rb_glob_helper(path, FNM_PERIOD|FNM_PATHNAME|FNM_NOCASE, func, arg); + rb_glob_helper(path, FNM_PERIOD|FNM_NOCASE, func, arg); } static void @@ -679,7 +713,14 @@ push_pattern(path, ary) char *path; VALUE ary; { - rb_ary_push(ary, rb_tainted_str_new2(path)); + VALUE str = rb_tainted_str_new2(path); + + if (ary) { + rb_ary_push(ary, str); + } + else { + rb_yield(str); + } } static void @@ -750,15 +791,19 @@ dir_s_glob(dir, str) VALUE dir, str; { char *p, *pend; - char buffer[MAXPATHLEN], *buf = buffer; + char buffer[MAXPATHLEN], *buf; char *t; int nest; - VALUE ary; + VALUE ary = 0; Check_SafeStr(str); - ary = rb_ary_new(); + if (!rb_block_given_p()) { + ary = rb_ary_new(); + } if (RSTRING(str)->len >= MAXPATHLEN) buf = xmalloc(RSTRING(str)->len + 1); + else + buf = buffer; p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; @@ -783,14 +828,6 @@ dir_s_glob(dir, str) } if (buf != buffer) free(buf); - if (rb_block_given_p()) { - long len = RARRAY(ary)->len; - VALUE *ptr = RARRAY(ary)->ptr; - - while (len--) { - rb_yield(*ptr++); - } - } return ary; } diff --git a/djgpp/config.status b/djgpp/config.status deleted file mode 100644 index 7a10754d1d..0000000000 --- a/djgpp/config.status +++ /dev/null @@ -1,77 +0,0 @@ -/^SHELL/s,/bin/sh,$(COMPSEC), -s%@srcdir@%.%g -s%@top_srcdir@%..% -s%@CFLAGS@%-O2%g -s%@CPPFLAGS@%%g -s%@CXXFLAGS@%%g -s%@LDFLAGS@%%g -s%@LIBS@%-lm %g -s%@exec_prefix@%${prefix}%g -s%@prefix@%/usr/local%g -s%@program_transform_name@%s,x,x,%g -s%@bindir@%${exec_prefix}/bin%g -s%@sbindir@%${exec_prefix}/sbin%g -s%@libexecdir@%${exec_prefix}/libexec%g -s%@datadir@%${prefix}/share%g -s%@sysconfdir@%${prefix}/etc%g -s%@sharedstatedir@%${prefix}/com%g -s%@localstatedir@%${prefix}/var%g -s%@libdir@%${exec_prefix}/lib%g -s%@includedir@%${prefix}/include%g -s%@oldincludedir@%/usr/include%g -s%@infodir@%${prefix}/info%g -s%@mandir@%${prefix}/man%g -s%@host@%i386-pc-msdosdjgpp%g -s%@host_alias@%i386-msdosdjgpp%g -s%@host_cpu@%i386%g -s%@host_vendor@%pc%g -s%@host_os@%msdosdjgpp%g -s%@CC@%gcc%g -s%@CPP@%gcc -E%g -s%@YACC@%bison -y%g -s%@RANLIB@%ranlib%g -s%@AR@%ar%g -s%@INSTALL_PROGRAM@%${INSTALL}%g -s%@INSTALL_DATA@%${INSTALL} -m 644%g -s%@SET_MAKE@%%g -s%@LIBOBJS@% crypt.o flock.o vsnprintf.o%g -s%@ALLOCA@%%g -s%@DEFAULT_KCODE@%%g -s%@EXEEXT@%.exe%g -s%@OBJEXT@%o%g -s%@XLDFLAGS@%%g -s%@DLDFLAGS@%%g -s%@STATIC@%%g -s%@CCDLFLAGS@%%g -s%@LDSHARED@%ld%g -s%@DLEXT@%o%g -s%@STRIP@%strip%g -s%@EXTSTATIC@%%g -s%@binsuffix@%.exe%g -s%@setup@%Setup.dj%g -s%@LIBRUBY@%libruby.a%g -s%@LIBRUBY_A@%libruby.a%g -s%@LIBRUBYARG@%libruby.a%g -s%@LIBRUBY_SO@%%g -s%@SOLIBS@%%g -s%@arch@%i386-msdosdjgpp%g -;s%/bin/rm%rm% -s%@DLDLIBS@%-lc%g -s%@PREP@%% -s%@RUBY_INSTALL_NAME@%ruby%g -s%@RUBY_SO_NAME@%%g -s%@arch@%i386-msdosdjgpp%g -s%@sitedir@%${prefix}/lib/ruby/site_ruby%g -s%@MINIRUBY@%./miniruby% -s%@archlib@%/usr/local/lib/ruby/i386-msdosdjgpp% -;s%|| true%% -;/\/dev\/null/ { -;s,/dev/null 2>&1, nul, -;s,2> /dev/null,, -;} -;/^config.status/ { -; N;N;N;N;N;d -;} -;s%y\.tab\.c%y_tab.c% -/^,THIS_IS_DUMMY_PATTERN_/i\ -ac_given_srcdir=. diff --git a/dln.c b/dln.c index c843bee57b..a481d806ea 100644 --- a/dln.c +++ b/dln.c @@ -50,6 +50,10 @@ void *xrealloc(); #include #include +#ifndef S_ISDIR +# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#endif + #ifdef HAVE_SYS_PARAM_H # include #else @@ -1166,7 +1170,7 @@ dln_strerror() } -#if defined(_AIX) +#if defined(_AIX) && ! defined(_IA64) static void aix_loaderror(const char *pathname) { @@ -1214,7 +1218,7 @@ aix_loaderror(const char *pathname) } #endif -void +void* dln_load(file) const char *file; { @@ -1234,23 +1238,21 @@ dln_load(file) /* Load file */ if ((handle = LoadLibraryExA(winfile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) { - printf("LoadLibraryExA: %s\n", winfile); goto failed; } if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { - printf("GetProcAddress %s\n", buf); - goto failed; + rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file); } /* Call the init code */ (*init_fct)(); - return; + return handle; #else #ifdef USE_DLN_A_OUT if (load(file) == -1) { goto failed; } - return; + return 0; #else char buf[MAXPATHLEN]; @@ -1276,11 +1278,12 @@ dln_load(file) } if ((init_fct = (void(*)())dlsym(handle, buf)) == NULL) { + dlclose(handle); goto failed; } /* Call the init code */ (*init_fct)(); - return; + return handle; } #endif /* USE_DLN_DLOPEN */ @@ -1306,11 +1309,11 @@ dln_load(file) } } (*init_fct)(); - return; + return (void*)lib; } #endif /* hpux */ -#if defined(_AIX) +#if defined(_AIX) && ! defined(_IA64) #define DLN_DEFINED { void (*init_fct)(); @@ -1323,7 +1326,7 @@ dln_load(file) aix_loaderror(file); } (*init_fct)(); - return; + return (void*)init_fct; } #endif /* _AIX */ @@ -1362,7 +1365,7 @@ dln_load(file) init_fct = (void(*)())init_address; (*init_fct)(); - return; + return (void*)init_address; } #else/* OPENSTEP dyld functions */ { @@ -1392,7 +1395,7 @@ dln_load(file) init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); (*init_fct)(); - return; + return (void*)init_fct; } #endif /* rld or dyld */ #endif @@ -1440,7 +1443,7 @@ dln_load(file) /* call module initialize function. */ (*init_fct)(); - return; + return (void*)img_id; } #endif /* __BEOS__*/ @@ -1488,7 +1491,7 @@ dln_load(file) init_fct = (void (*)())symAddr; (*init_fct)(); - return; + return (void*)init_fct; } #endif /* __MACOS__ */ @@ -1669,7 +1672,7 @@ dln_find_1(fname, path, exe_flag) if (stat(fbuf, &st) == 0) { if (exe_flag == 0) return fbuf; /* looking for executable */ - if (eaccess(fbuf, X_OK) == 0) return fbuf; + if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0) return fbuf; } #else if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) { diff --git a/dln.h b/dln.h index 7e3ab9fabb..c29d3bd8e9 100644 --- a/dln.h +++ b/dln.h @@ -29,5 +29,5 @@ char *dln_find_file _((const char*,const char*)); extern char *dln_argv0; #endif -void dln_load _((const char*)); +void *dln_load _((const char*)); #endif diff --git a/doc/NEWS b/doc/NEWS new file mode 100644 index 0000000000..703508ae2e --- /dev/null +++ b/doc/NEWS @@ -0,0 +1,285 @@ +Summary of the changes since 1.6.3: + +: Hash#replace + + Fixed so the following code does not fail in core dump. + + h = { 10 => 100, 20 => 200 } + h2 = { } + + h.each { |k, v| + if (k == 10) + h.delete(10) + h2.replace(h) # => Abort core dumped + end + } + +: File::unlink + + Changed to be forbidden under $SAFE >= 2. + +: ruby -T4 + + Fixed. ARGV is now properly marked as tainted so ruby -T4 no longer + fails in SecurityError. + +: Regexp + + Fixed. Now \1 .. \9 always mean backreferences, and referring to + unclosed/unmatched parentheses always fails. + +: String taint infection + + Fixed for the following cases. [ruby-dev:13340] + + # []= + s1 = "abc" + s2 = "cde".taint + s1[0]= s2 + p s1.tainted? # => false + + # crypt + s = "abc".taint + p s.crypt("cd").tainted? # => false + + # ljust + s = "abc".taint + p s.ljust(10).tainted? # => false + + # rjust + s = "abc".taint + p s.rjust(10).tainted? # => false + + # center + s = "abc".taint + p s.center(10).tainted? # => false + + Now they will all be marked as tainted. + +: rb_yield_0() + + Fixed so it adjusts a 1-element array when yielded from C API, as + well. Previously, the following code produced a wrong result: + + class X + include Enumerable + + def each(&block) + block.call(1) + block.call(2) + block.call(3) + end + end + + x = X.new + p x.to_a #=> [[1], [2], [3]] + + Now it properly produces [1, 2, 3]. + +: $SAFE + + Fixed so aliasing global valiables is disallowed under $SAFE = 4. + (()) + +: Open3::popen3 + + Fixed to do exit! instead of exit so the dying process does not + invoke at_exit. (()) + +: SizedQueue#pop + + Fixed so the following code does not cause a dead lock. + (()) + + ruby -r thread -e 'q = SizedQueue.new(1); q.push(1);' + -e 'Thread.new{sleep 1; q.pop}; q.push(1);' + +: SizedQueue#max= + + Fixed so it really works. (()) + +: Queue +: SizedQueue + + Fixed to rescue ThreadError in case the thread is dead just before + calling Thread#run. (()) + +: Array#& +: Array#| +: Array#uniq + + Fixed so they do not freeze the elements. (()) + + (%w(foo bar) & %w(foo baz))[0].upcase! + => -:1:in `upcase!': can't modify frozen string (TypeError) + + %w(foo bar bar baz).uniq[0].upcase! + => -:1:in `upcase!': can't modify frozen string (TypeError) + +: shell.rb + + shell.rb 0.6 is newly imported as a standard library, along with + documents. + +: forwardable.rb + + forwardable.rb 1.1 is newly imported as a standard library, along with + documents. + +: irb & irb-tools + + irb and irb-tolls are updated to 0.7.4 and 0.7.1, respectively. + +: Daylight saving time + + Fixed so it is handled correctly. [ruby-bugs-ja (PR#46)] + + env TZ=America/Managua ruby -e 'p Time.local(1998,12,1,0,59,59)' + => Mon Nov 30 01:59:59 EST 1998 + env TZ=America/Managua ruby -e 'p Time.local(1998,12,1,0,59,59).tv_sec' + => 912409199 + +: SIGINFO + + Support SIGINFO of 4.4BSD. [ruby-bugs-ja (PR#45)] + +: Modifier rescue + + Fixed so the following code does not emit a parse error any more. + (()), (()) + + raise "" rescue [] + raise "" rescue (p "foo"; true) + raise "" rescue -1 + raise "" rescue (-1) + +: Thread + + Fixed so the following code does not cause a dead lock any more. + + Thread.start { Thread.stop } + sleep + + => deadlock 0x40199b58: 2:0 - -:1 + deadlock 0x401a2528: 2:4 (main) - -:2 + -:2:in `sleep': Thread: deadlock (fatal) + from -:2 + ruby 1.6.3 (2001-03-19) [i586-linux] + +: Module#const_defined? +: Module#const_get +: Module#const_set + + Fixed so they do not access to anything other than constants. + (()) + +: Marshal.dump + + Improved so it dumps Float with better precision: "%.12g" -> "%.16g" + (()) + +: Fixnum#[] + + Fixed a bug on the platforms which sizeof(long) > sizeof(int). + +: Regular Expression + + Fixed a couple of minor bugs. (()), (()) + +: retry + + Fixed so the following code works correctly again. (()) + + def WHILE(cond) + return if not cond + yield + retry + end + + i=0 + WHILE(i<3) { + print i + i+=1 + } + + ruby 1.6.2 (2000-12-25) [i586-linux] + => 012 + + ruby 1.6.3 (2001-03-19) [i586-linux] + => 0 + + ruby 1.6.4 (2001-05-02) [i586-linux] + => 012 + +: (())#size + + Fixed to return a correct value for files larger than 1G bytes. + + File.open("/tmp/1GB", "w") {|f| + f.seek(2**30-1, 0) + f.puts + f.flush + p f.stat.size + } + + # => ruby 1.6.3 (2001-04-03) [i586-linux] + -1073741824 + # => ruby 1.6.4 (2001-04-19) [i586-linux] + 1073741824 + +: (())#modulo, (())#divmod + + Fixed. (()) + +: (())#_id2ref + + Fixed so it does not raise a exception. + +: recursive malloc problem + + Fixed by preallocating a buffer for stdio using setvbuf(). + (()) + +: (())#flock + + Fixed so it does not raise Errno::EACCES when the file to flock is + already locked. (only applicable to the platforms which lack + flock()) + +: (()).new(filename) + + Added. (()) + +: (())#% miscalculation + + (Re-)Fixed. + + a = 677330545177305025495135714080 + b = 14269972710765292560 + p a % b #=> 0 + p -a % b #=> + + => ruby 1.6.3 (2001-04-02) [i386-cygwin] + 0 + 14269972710765292560 + + => ruby 1.6.4 (2001-04-19) [i586-linux] + 0 + 0 + +: (()) + + Fixed so a Bignum is properly restored through dump & load. + +: Universal Naming Convention(UNC) support (win32) + + Added. Now the UNC form (//host/share) is supported. Use slash + (`(({/}))') instead of backslash (`(({\}))') for separating + components. + +: (()).glob (win32) + + Fixed so it works for the current directory as well. + + p Dir["./*.c"] + => [] diff --git a/doc/forwardable.rd b/doc/forwardable.rd new file mode 100644 index 0000000000..7272c374b6 --- /dev/null +++ b/doc/forwardable.rd @@ -0,0 +1,84 @@ + -- forwardable.rb + + $Release Version: 1.1 $ + $Revision$ + $Date$ + Original version by Tosh + +=begin + += Forwardable + +A Module to define delegations for selected methods to a class. + +== Usage + +Using through extending the class. + + class Foo + extend Forwardable + + def_delegators("@out", "printf", "print") + def_delegators(:@in, :gets) + def_delegator(:@contents, :[], "content_at") + end + f = Foo.new + f.printf ... + f.gets + f.content_at(1) + +== Methods + +--- Forwardable#def_instance_delegators(accessor, *methods) + + adding the delegations for each method of ((|methods|)) to + ((|accessor|)). + +--- Forwardable#def_instance_delegator(accessor, method, ali = method) + + adding the delegation for ((|method|)) to ((|accessor|)). When + you give optional argument ((|ali|)), ((|ali|)) is used as the + name of the delegation method, instead of ((|method|)). + +--- Forwardable#def_delegators(accessor, *methods) + + the alias of ((|Forwardable#def_instance_delegators|)). + +--- Forwardable#def_delegator(accessor, method, ali = method) + + the alias of ((|Forwardable#def_instance_delegator|)). + += SingleForwardable + +a Module to define delegations for selected methods to an object. + +== Usage + +Using through extending the object. + + g = Goo.new + g.extend SingleForwardable + g.def_delegator("@out", :puts) + g.puts ... + +== Methods + +--- SingleForwardable#def_singleton_delegators(accessor, *methods) + + adding the delegations for each method of ((|methods|)) to + ((|accessor|)). + +--- SingleForwardable#def_singleton_delegator(accessor, method, ali = method) + + adding the delegation for ((|method|)) to ((|accessor|)). When + you give optional argument ((|ali|)), ((|ali|)) is used as the + name of the delegation method, instead of ((|method|)). + +--- SingleForwardable#def_delegators(accessor, *methods) + + the alias of ((|SingleForwardable#def_instance_delegators|)). + +--- SingleForwardable#def_delegator(accessor, method, ali = method) + + the alias of ((|SingleForwardable#def_instance_delegator|)). +=end diff --git a/doc/forwardable.rd.jp b/doc/forwardable.rd.jp new file mode 100644 index 0000000000..d928fddc5e --- /dev/null +++ b/doc/forwardable.rd.jp @@ -0,0 +1,81 @@ + -- forwatable.rb + $Release Version: 1.1 $ + $Revision$ + $Date$ + +=begin += Forwardable + +¥¯¥é¥¹¤ËÂФ·¥á¥½¥Ã¥É¤Î°Ñ¾ùµ¡Ç½¤òÄêµÁ¤·¤Þ¤¹. + +== »È¤¤Êý + +¥¯¥é¥¹¤ËÂФ·¤Æextend¤·¤Æ»È¤¤¤Þ¤¹. + + class Foo + extend Forwardable + + def_delegators("@out", "printf", "print") + def_delegators(:@in, :gets) + def_delegator(:@contents, :[], "content_at") + end + f = Foo.new + f.printf ... + f.gets + f.content_at(1) + +== ¥á¥½¥Ã¥É + +--- Forwardable#def_instance_delegators(accessor, *methods) + + ((|methods|))¤ÇÅϤµ¤ì¤¿¥á¥½¥Ã¥É¤Î¥ê¥¹¥È¤ò((|accessor¤Ë|))°Ñ¾ù¤¹¤ë + ¤è¤¦¤Ë¤·¤Þ¤¹. + +--- Forwardable#def_instance_delegator(accessor, method, ali = method) + + ((||method|))¤ÇÅϤµ¤ì¤¿¥á¥½¥Ã¥É¤ò((|accessor|))¤Ë°Ñ¾ù¤¹¤ë¤è¤¦¤Ë¤· + ¤Þ¤¹. ((|ali|))¤¬°ú¿ô¤È¤·¤ÆÅϤµ¤ì¤¿¤È¤­¤Ï, ¥á¥½¥Ã¥É((|ali|))¤¬¸Æ¤Ð + ¤ì¤¿¤È¤­¤Ë¤Ï, ((|accessor|))¤ËÂФ·((|method|))¤ò¸Æ¤Ó½Ð¤·¤Þ¤¹. + +--- Forwardable#def_delegators(accessor, *methods) + + ((|Forwardable#def_instance_delegators|))¤ÎÊÌ̾¤Ç¤¹. + +--- Forwardable#def_delegator(accessor, method, ali = method) + + ((|Forwardable#def_instance_delegator|))¤ÎÊÌ̾¤Ç¤¹. + += SingleForwardable + +¥ª¥Ö¥¸¥§¥¯¥È¤ËÂФ·, ¥á¥½¥Ã¥É¤Î°Ñ¾ùµ¡Ç½¤òÄêµÁ¤·¤Þ¤¹. + +== »È¤¤Êý + +¥ª¥Ö¥¸¥§¥¯¥È¤ËÂФ·¤Æ((|extend|))¤·¤Æ»È¤¤¤Þ¤¹. + + g = Goo.new + g.extend SingleForwardable + g.def_delegator("@out", :puts) + g.puts ... + +== ¥á¥½¥Ã¥É + +--- SingleForwardable#def_singleton_delegators(accessor, *methods) + + ((|methods|))¤ÇÅϤµ¤ì¤¿¥á¥½¥Ã¥É¤Î¥ê¥¹¥È¤ò((|accessor|))¤Ë°Ñ¾ù¤¹¤ë + ¤è¤¦¤Ë¤·¤Þ¤¹. + +--- SingleForwardable#def_singleton_delegator(accessor, method, ali = method) + + ((|method|))¤ÇÅϤµ¤ì¤¿¥á¥½¥Ã¥É¤ò((|accessor|))¤Ë°Ñ¾ù¤¹¤ë¤è¤¦¤Ë¤·¤Þ + ¤¹. ((|ali|))¤¬°ú¿ô¤È¤·¤ÆÅϤµ¤ì¤¿¤È¤­¤Ï, ¥á¥½¥Ã¥É((|ali|))¤¬¸Æ¤Ð¤ì + ¤¿¤È¤­¤Ë¤Ï, ((|accessor|))¤ËÂФ·((|method|))¤ò¸Æ¤Ó½Ð¤·¤Þ¤¹. + +--- SingleForwardable#def_delegators(accessor, *methods) + + ((|SingleForwardable#def_singleton_delegators|))¤ÎÊÌ̾¤Ç¤¹. + +--- SingleForwardable#def_delegator(accessor, method, ali = method) + + ((|SingleForwardable#def_singleton_delegator|))¤ÎÊÌ̾¤Ç¤¹. +=end diff --git a/doc/irb/irb-tools.rd.jp b/doc/irb/irb-tools.rd.jp new file mode 100644 index 0000000000..64d9ab29c8 --- /dev/null +++ b/doc/irb/irb-tools.rd.jp @@ -0,0 +1,185 @@ +irb´ØÏ¢¤ª¤Þ¤±¥³¥Þ¥ó¥É¤È¥é¥¤¥Ö¥é¥ê + $Release Version: 0.7.1 $ + $Revision$ + $Date$ + by Keiju ISHITSUKA(Nihon Rational Co.,Ltd.) + +=begin + +:¥³¥Þ¥ó¥É: +* rtags -- ruby tags command + +:´Ø¿ô¥é¥¤¥Ö¥é¥ê: +* xmp -- irb version of gotoken xmp-function + +:¥¯¥é¥¹¥é¥¤¥Ö¥é¥ê: +* frame.rb -- frame tracer +* completion.rb -- irb completor + += rtags + +rtags¤ÏemacsµÚ¤ÓviÍѤÎ, TAG¥Õ¥¡¥¤¥ë¤ò¤Ä¤¯¤ë¥³¥Þ¥ó¥É¤Ç¤¹. + +== »È¤¤Êý + + rtags [-vi] file.... + +¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤ËemacsÍѤÎTAGS¥Õ¥¡¥¤¥ë¤¬¤Ç¤­¤Þ¤¹. -vi¥ª¥×¥·¥ç¥ó¤ò +¤Ä¤±¤¿»þ¤Ë¤ÏviÍѤÎtags¥Õ¥¡¥¤¥ë¤òºîÀ®¤·¤Þ¤¹. + +emacs¤Î¾ì¹ç, Ä̾ï¤Îetags.el¤¬¤½¤Î¤Þ¤Þ»È¤¨¤Þ¤¹. ¸¡º÷²Äǽ¤Ê¤Î¤Ï, + +* ¥¯¥é¥¹ +* ¥á¥½¥Ã¥É +* ÆÃ°Û¥á¥½¥Ã¥É +* alias +* attr¤ÇÀë¸À¤µ¤ì¤¿¥¢¥¯¥»¥µ(¥Ñ¥é¥á¡¼¥¿¤¬¥·¥ó¥Ü¥ë¤«Ê¸»úÎó¥ê¥Æ¥é¥ë¤Ë¸Â¤ë) +* attr_XXX¤ÇÀë¸À¤µ¤ì¤¿¥¢¥¯¥»¥µ(¥Ñ¥é¥á¡¼¥¿¤¬¥·¥ó¥Ü¥ë¤«Ê¸»úÎó¥ê¥Æ¥é¥ë¤Ë¸Â¤ë) + +¤Ç¤¹. + +C¤Ê¤É¤Ç»È¤Ã¤Æ¤¤¤ë¤Î¤È°ã¤¦¤Î¤Ï, ¥³¥ó¥×¥ê¡¼¥·¥ç¥ó¤Ë´Ø¤¹¤ëÉôʬ¤Ç, + +´Ø¿ô̾¤Ï, + + ´Ø¿ô̾( + +¥¯¥é¥¹¤Ï, + + ::¥¯¥é¥¹Ì¾::....::¥¯¥é¥¹Ì¾ + +¥á¥½¥Ã¥É¤Ï, + + ::¥¯¥é¥¹Ì¾::....::¥¯¥é¥¹Ì¾#¥á¥½¥Ã¥É̾ + +ÆÃ°Û¥á¥½¥Ã¥É(¥¯¥é¥¹¥á¥½¥Ã¥É)¤Ï + + ::¥¯¥é¥¹Ì¾::....::¥¯¥é¥¹Ì¾.¥á¥½¥Ã¥É̾ + +¤Ç¥³¥ó¥×¥ê¡¼¥·¥ç¥ó¤ò¹Ô¤Ê¤¦¤È¤³¤í¤Ç¤¹. + += xmp.rb + +¤´¤È¤±¤óxmp¤Î¾å°Ì¸ß´¹¥Ð¡¼¥¸¥ç¥ó¤Ç¤¹. ¤¿¤À, Èó¾ï¤Ë½Å¤¤¤Î¤Ç¤´¤È¤±¤óxmp¤Ç +¤ÏÂбþ¤Ç¤­¤Ê¤¤»þ¤Ë, »ÈÍѤ¹¤ë¤ÈÎɤ¤¤Ç¤·¤ç¤¦. + +== »È¤¤Êý + +=== ´Ø¿ô¤È¤·¤Æ»È¤¦. + + require "irb/xmp" + xmp <1 + foo + ==>1 + +=== XMP¥¤¥ó¥¹¥¿¥ó¥¹¤òÍѤ¤¤ë. + +¤³¤Î¾ì¹ç¤Ï, XMP¤¬¥³¥ó¥Æ¥­¥¹¥È¾ðÊó¤ò»ý¤Ä¤Î¤Ç, ÊÑ¿ô¤ÎÃͤʤɤòÊÝ»ý¤·¤Æ¤¤ +¤Þ¤¹. + + require "irb/xmp" + xmp = XMP.new + xmp.puts <1 + foo + ==>1 + foo + ==>1 + +== ¥³¥ó¥Æ¥­¥¹¥È¤Ë´Ø¤·¤Æ + +XMP¥á¥½¥Ã¥É·²¤Î¥³¥ó¥Æ¥­¥¹¥È¤Ï, ¸Æ¤Ó½Ð¤¹Á°¤Î¥³¥ó¥Æ¥­¥¹¥È¤Çɾ²Á¤µ¤ì¤Þ¤¹. +ÌÀ¼¨Åª¤Ë¥³¥ó¥Æ¥­¥¹¥È¤ò»ØÄꤹ¤ë¤È¤½¤Î¥³¥ó¥Æ¥­¥¹¥È¤Çɾ²Á¤·¤Þ¤¹. + +Îã: + + xmp "foo", an_binding + +:Ãí: +¥Þ¥ë¥Á¥¹¥ì¥Ã¥É¤Ë¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó. + += frame.rb +¸½ºß¼Â¹ÔÃæ¤Î¥Õ¥ì¡¼¥à¾ðÊó¤ò¼è¤ê°·¤¦¤¿¤á¤Î¥¯¥é¥¹¤Ç¤¹. + +* IRB::Frame.top(n = 0) + ¾å¤«¤énÈÖÌܤΥ³¥ó¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤·¤Þ¤¹. n¤Ï0¤¬ºÇ¾å°Ì¤Ë¤Ê¤ê¤Þ¤¹. +* IRB::Frame.bottom(n = 0) + ²¼¤«¤énÈÖÌܤΥ³¥ó¥Æ¥­¥¹¥È¤ò¼è¤ê½Ð¤·¤Þ¤¹. n¤Ï0¤¬ºÇ²¼°Ì¤Ë¤Ê¤ê¤Þ¤¹. +* IRB::Frame.sender + ¥»¥ó¥À¤Ë¤Ê¤Ã¤Æ¤¤¤ë¥ª¥Ö¥¸¥§¥¯¥È¤ò¼è¤ê½Ð¤·¤Þ¤¹. ¥»¥ó¥À¤È¤Ï, ¤½¤Î¥á¥½¥Ã + ¥É¤ò¸Æ¤Ó½Ð¤·¤¿Â¦¤Îself¤Î¤³¤È¤Ç¤¹. + +:Ãí: +set_trace_func¤òÍѤ¤¤ÆRuby¤Î¼Â¹Ô¤ò¥È¥ì¡¼¥¹¤·¤Æ¤¤¤Þ¤¹. ¥Þ¥ë¥Á¥¹¥ì¥Ã¥É¤Ë +¤ÏÂбþ¤·¤Æ¤¤¤Þ¤»¤ó. + += completion.rb +irb¤Îcompletionµ¡Ç½¤òÄ󶡤¹¤ë¤â¤Î¤Ç¤¹. + +== »È¤¤Êý + + % irb -r irb/completion + +¤È¤¹¤ë¤«, ~/.irbrc Ãæ¤Ë + + require "irb/completion" + +¤òÆþ¤ì¤Æ¤¯¤À¤µ¤¤. irb¼Â¹ÔÃæ¤Ë require "irb/completion" ¤·¤Æ¤â¤è¤¤¤Ç¤¹. + +irb¼Â¹ÔÃæ¤Ë (TAB) ¤ò²¡¤¹¤È¥³¥ó¥×¥ì¡¼¥·¥ç¥ó¤·¤Þ¤¹. + +¥È¥Ã¥×¥ì¥Ù¥ë¤Ç(TAB)¤ò²¡¤¹¤È¤¹¤Ù¤Æ¤Î¹½Ê¸Í×ÁÇ, ¥¯¥é¥¹, ¥á¥½¥Ã¥É¤Î¸õÊ䤬¤Ç +¤Þ¤¹. ¸õÊ䤬ͣ°ì¤Ê¤é¤Ð´°Á´¤ËÊä´°¤·¤Þ¤¹. + + irb(main):001:0> in + in inspect instance_eval + include install_alias_method instance_of? + initialize install_aliases instance_variables + irb(main):001:0> inspect + "main" + irb(main):002:0> foo = Object.new + # + + ((|ÊÑ¿ô̾.|))¤Î¸å¤Ë(TAB)¤ò²¡¤¹¤È, ¤½¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Î¥á¥½¥Ã¥É°ìÍ÷¤¬¤Ç¤Þ + ¤¹. + + irb(main):003:0> foo. + foo.== foo.frozen? foo.protected_methods + foo.=== foo.hash foo.public_methods + foo.=~ foo.id foo.respond_to? + foo.__id__ foo.inspect foo.send + foo.__send__ foo.instance_eval foo.singleton_methods + foo.class foo.instance_of? foo.taint + foo.clone foo.instance_variables foo.tainted? + foo.display foo.is_a? foo.to_a + foo.dup foo.kind_of? foo.to_s + foo.eql? foo.method foo.type + foo.equal? foo.methods foo.untaint + foo.extend foo.nil? + foo.freeze foo.private_methods + +=end + +% Begin Emacs Environment +% Local Variables: +% mode: text +% comment-column: 0 +% comment-start: "%" +% comment-end: "\n" +% End: +% + diff --git a/doc/irb/irb.rd b/doc/irb/irb.rd new file mode 100644 index 0000000000..a1daa1ed6b --- /dev/null +++ b/doc/irb/irb.rd @@ -0,0 +1,377 @@ +irb -- interactive ruby + $Release Version: 0.5 $ + $Revision$ + $Date$ + by Keiju ISHITSUKA(keiju@ishitsuka.com) + translate from japanese by gotoken-san + +=begin += What is irb? + +irb stands for `interactive ruby'. irb is a tool to execute interactively +ruby expressions read from stdin. + += Invoking + + % ruby -r irb -e0 + % irb + +Either of the aboves. In the former style, options can be specified +as follows: + + % ruby -r irb -e0 -- -v + += Usage + +Use of irb is easy if you know ruby. Executing irb, prompts are +displayed as follows. Then, enter expression of ruby. A input is +executed when it is syntacticaly completed. + + dim% irb + irb(main):001:0> 1+2 + 3 + irb(main):002:0> class Foo + irb(main):003:1> def foo + irb(main):004:2> print 1 + irb(main):005:2> end + irb(main):006:1> end + nil + irb(main):007:0> + +And, Readline extesion module can be used with irb. Using Readline +is the standard default action if Readline is installed. + += Command line option + + irb.rb [options] file_name opts + options: + -f suppress read ~/.irbrc + -m bc mode (fraction or matrix are available) + -d set $DEBUG to true (same as `ruby -d') + -r load-module same as `ruby -r' + --inspect uses `inspect' for output (the default except bc mode) + --noinspect doesn't uses inspect for output + --readline uses Readline extension module + --noreadline doesn't use Readline extension module + --prompt prompt-mode + --prompt-mode prompt-mode + switches prompt mode. Pre-defined prompt modes are + `default', `simple', `xmp' and `inf-ruby' + + --inf-ruby-mode uses prompt appreciate for inf-ruby-mode on emacs. + Suppresses --readline. + --simple-prompt simple prompt mode + --noprompt no prompt + --tracer display trace for each execution of commands. + --back-trace-limit n + displayes backtrace top n and tail n. The default + value is 16. + --irb_debug n sets internal debug level to n (It shouldn't be used) + -v, --version prints the version of irb + + + += Configurations + +irb reads `~/.irbrc' when it is invoked. If `~/.irbrb' doesn't exist +irb try to read in the order `.irbrc', `irb.rc', `_irbrc' then `$irbrc'. + +The following is altanative to the command line option. To use them +type as follows in an irb session. + + IRB.conf[:IRB_NAME]="irb" + IRB.conf[:MATH_MODE]=false + IRB.conf[:USE_TRACER]=false + IRB.conf[:USE_LOADER]=false + IRB.conf[:IGNORE_SIGINT]=true + IRB.conf[:IGNORE_EOF]=false + IRB.conf[:INSPECT_MODE]=nil + IRB.conf[:IRB_RC] = nil + IRB.conf[:BACK_TRACE_LIMIT]=16 + IRB.conf[:USE_LOADER] = false + IRB.conf[:USE_READLINE] = nil + IRB.conf[:USE_TRACER] = false + IRB.conf[:IGNORE_SIGINT] = true + IRB.conf[:IGNORE_EOF] = false + IRB.conf[:PROMPT_MODE] = :DEFALUT + IRB.conf[:PROMPT] = {...} + IRB.conf[:DEBUG_LEVEL]=0 + IRB.conf[:VERBOSE]=true + +== Customizing prompt + +To costomize the prompt you set a variable + + IRB.conf[:PROMPT] + +For example, describe as follows in `.irbrc'. + + IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode + :PROMPT_I => nil, # normal prompt + :PROMPT_S => nil, # prompt for continuated strings + :PROMPT_C => nil, # prompt for continuated statement + :RETURN => " ==>%s\n" # format to return value + } + +Then, invoke irb with the above prompt mode by + + % irb --prompt my-prompt + +Or add the following in `.irbrc'. + + IRB.conf[:PROMPT_MODE] = :MY_PROMPT + +Constants PROMPT_I, PROMPT_S and PROMPT_C specifies the format. +In the prompt specification, some special strings are available. + + %N command name which is running + %m to_s of main object (self) + %M inspect of main object (self) + %l type of string(", ', /, ]), `]' is inner %w[...] + %NNi indent level. NN is degits and means as same as printf("%NNd"). + It can be ommited + %NNn line number. + %% % + +For instance, the default prompt mode is defined as follows: + +IRB.conf[:PROMPT_MODE][:DEFAULT] = { + :PROMPT_I => "%N(%m):%03n:%i> ", + :PROMPT_S => "%N(%m):%03n:%i%l ", + :PROMPT_C => "%N(%m):%03n:%i* ", + :RETURN => "%s\n" +} + +RETURN is used to printf. + +== Configurating subirb + +The command line option or IRB.conf specify the default behavior of +(sub)irb. On the other hand, each conf of in the next sction `6. Command' +is used to individually configurate (sub)irb. + +If proc is set to IRB.conf[:IRB_RC], its subirb will be invoked after +execution of that proc under giving the context of irb as its +aregument. By this mechanism each subirb can be configurated. + += Command + +For irb commands, both simple name and `irb_'-prefixed name are prepared. + +--- exit, quit, irb_exit + Quits (sub)irb. + if you've done cb (see below), exit from the binding mode. + +--- conf, irb_context + Displays current configuration. Modifing the configuration is + achieved by sending message to `conf'. + +--- conf.back_trace_limit + Sets display lines of backtrace as top n and tail n. + The default value is 16. + +--- conf.debug_level = N + Sets debug level of irb. + +--- conf.ignore_eof = true/false + Whether ^D (control-d) will be ignored or not. + If false is set, ^D means quit. + +--- conf.ignore_sigint= true/false + Whether ^C (control-c) will be ignored or not. + If false is set, ^D means quit. If true, + during input: cancel inputing then return to top level. + during execute: abondon current execution. + +--- conf.inf_ruby_mode = true/false + Whether inf-ruby-mode or not. The default value is false. + +--- conf.inspect_mode = true/false/nil + Specifies inspect mode. + true: display inspect + false: display to_s + nil: inspect mode in non math mode, + non inspect mode in math mode. + +--- conf.irb_level + The level of cb. + +--- conf.math_mode + Whether bc mode or not. + +--- conf.use_loader = true/false + Whether irb's own file reader method is used when load/require or not. + This mode is globaly affected (irb wide). + +--- conf.prompt_c + prompt for a continuating statement (e.g, immediately after of `if') + +--- conf.prompt_i + standard prompt + +--- conf.prompt_s + prompt for a continuating string + +--- conf.rc + Whether ~/.irbrc is read or not. + +--- conf.use_prompt = true/false + Prompting or not. + +--- conf.use_readline = true/false/nil + Whether readline is used or not. + true: uses + false: doen't use + nil: intends to use readline except for inf-reuby-mode (default) + +--- conf.verbose=T/F + Whether verbose messages are display or not. + +--- cb, irb_change_binding [obj] + Enter new binding which has a distinct scope of local variables. + If obj is given, obj will be self. + +--- irb [obj] + Invoke subirb. If obj is given, obj will be self. + +--- jobs, irb_jobs + List of subirb + +--- fg n, irb_fg n + Switch into specified subirb. The following is candidates of n: + + irb number + thhread + irb object + self(obj which is specified of irb obj) + +--- kill n, irb_kill n + Kill subirb. The means of n is as same as the case of irb_fg. + += System variable + + _ The latest value of evaluation (it is local) + + += Session Example + + dim% ruby irb.rb + irb(main):001:0> irb # invoke subirb + irb#1(main):001:0> jobs # list of subirbs + #0->irb on main (# : stop) + #1->irb#1 on main (# : running) + nil + irb#1(main):002:0> fg 0 # switch job + nil + irb(main):002:0> class Foo;end + nil + irb(main):003:0> irb Foo # invoke subirb which has the + # context of Foo + irb#2(Foo):001:0> def foo # define Foo#foo + irb#2(Foo):002:1> print 1 + irb#2(Foo):003:1> end + nil + irb#2(Foo):004:0> fg 0 # switch job + nil + irb(main):004:0> jobs # list of job + #0->irb on main (# : running) + #1->irb#1 on main (# : stop) + #2->irb#2 on Foo (# : stop) + nil + irb(main):005:0> Foo.instance_methods # Foo#foo is defined asurely + ["foo"] + irb(main):006:0> fg 2 # switch job + nil + irb#2(Foo):005:0> def bar # define Foo#bar + irb#2(Foo):006:1> print "bar" + irb#2(Foo):007:1> end + nil + irb#2(Foo):010:0> Foo.instance_methods + ["bar", "foo"] + irb#2(Foo):011:0> fg 0 + nil + irb(main):007:0> f = Foo.new + # + irb(main):008:0> irb f # invoke subirb which has the + # context of f (instance of Foo) + irb#3(#):001:0> jobs + #0->irb on main (# : stop) + #1->irb#1 on main (# : stop) + #2->irb#2 on Foo (# : stop) + #3->irb#3 on # (# : running) + nil + irb#3(#):002:0> foo # evaluate f.foo + 1nil + irb#3(#):003:0> bar # evaluate f.bar + barnil + irb#3(#):004:0> kill 1, 2, 3# kill job + nil + irb(main):009:0> jobs + #0->irb on main (# : running) + nil + irb(main):010:0> exit # exit + dim% + += Restrictions + +Because irb evaluates the inputs immediately after the imput is +syntactically completed, irb gives slight different result than +directly use ruby. Known difference is pointed out here. + + +== Declaration of the local variable + +The following causes an error in ruby: + + eval "foo = 0" + foo + -- + -:2: undefined local variable or method `foo' for # (NameError) + --- + NameError + +Though, the above will successfully done by irb. + + >> eval "foo = 0" + => 0 + >> foo + => 0 + +Ruby evaluates a code after reading entire of code and determination +of the scope of local variables. On the other hand, irb do +immediately. More precisely, irb evaluate at first + + evel "foo = 0" + +then foo is defined on this timing. It is because of this +incompatibility. + +If you'd like to detect those differences, begin...end can be used: + + >> begin + ?> eval "foo = 0" + >> foo + >> end + NameError: undefined local variable or method `foo' for # + (irb):3 + (irb_local_binding):1:in `eval' + +== Here-document + +Implementation of Here-document is incomplete. + +== Symbol + +Irb can not always recognize a symbol as to be Symbol. Concretely, an +expression have completed, however Irb regard it as continuation line. + +=end + +% Begin Emacs Environment +% Local Variables: +% mode: text +% comment-column: 0 +% comment-start: "%" +% comment-end: "\n" +% End: +% diff --git a/doc/irb/irb.rd.jp b/doc/irb/irb.rd.jp new file mode 100644 index 0000000000..5068f4536f --- /dev/null +++ b/doc/irb/irb.rd.jp @@ -0,0 +1,391 @@ +irb -- interactive ruby + $Release Version: 0.6 $ + $Revision$ + $Date$ + by Keiju ISHITSUKA(keiju@ishitsuka.com) +=begin += irb¤È¤Ï? + +irb¤Ïinteractive ruby¤Îά¤Ç¤¹. ruby¤Î¼°¤òɸ½àÆþÎϤ«¤é´Êñ¤ËÆþÎÏ/¼Â¹Ô¤¹ +¤ë¤¿¤á¤Î¥Ä¡¼¥ë¤Ç¤¹. + += µ¯Æ° + + % ruby -r irb -e0 + % irb + +¤Î¤¤¤º¤ì¤«¤Ç¹Ô¤Ê¤¤¤Þ¤¹. Á°¼Ô¤Î¾ì¹çirb¤Ø¤Î¥ª¥×¥·¥ç¥ó»ØÄê¤Ï, °Ê²¼¤Î¤è¤¦¤Ë +¤Ê¤ê¤Þ¤¹. + + % ruby -r irb -e0 -- -v + += »È¤¤Êý + +irb¤Î»È¤¤Êý¤Ï, Ruby¤µ¤¨ÃΤäƤ¤¤ì¤Ð¤¤¤¿¤Ã¤Æ´Êñ¤Ç¤¹. ´ðËÜŪ¤Ë¤Ï irb ¤È +¤¤¤¦¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤¹¤ë¤À¤±¤Ç¤¹. irb¤ò¼Â¹Ô¤¹¤ë¤È, °Ê²¼¤Î¤è¤¦¤Ê¥×¥í¥ó¥× +¥È¤¬É½¤ì¤Æ¤­¤Þ¤¹. ¸å¤Ï, ruby¤Î¼°¤òÆþ¤ì¤Æ²¼¤µ¤¤. ¼°¤¬´°·ë¤·¤¿»þÅÀ¤Ç¼Â¹Ô +¤µ¤ì¤Þ¤¹. + + dim% irb + irb(main):001:0> 1+2 + 3 + irb(main):002:0> class Foo + irb(main):003:1> def foo + irb(main):004:2> print 1 + irb(main):005:2> end + irb(main):006:1> end + nil + irb(main):007:0> + +¤Þ¤¿, irb¤ÏReadline¥â¥¸¥å¡¼¥ë¤Ë¤âÂбþ¤·¤Æ¤¤¤Þ¤¹. Readline¥â¥¸¥å¡¼¥ë¤¬ +¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë»þ¤Ë¤Ï, ¤½¤ì¤ò»È¤¦¤Î¤¬É¸½à¤Îưºî¤Ë¤Ê¤ê¤Þ¤¹. + += ¥³¥Þ¥ó¥É¥ª¥×¥·¥ç¥ó + + irb.rb [options] file_name opts + options: + -f ~/.irbrc ¤òÆÉ¤ß¹þ¤Þ¤Ê¤¤. + -m bc¥â¡¼¥É(ʬ¿ô, ¹ÔÎó¤Î·×»»¤¬¤Ç¤­¤ë) + -d $DEBUG ¤òtrue¤Ë¤¹¤ë(ruby -d ¤ÈƱ¤¸) + -r load-module ruby -r ¤ÈƱ¤¸. + --inspect ·ë²Ì½ÐÎϤËinspect¤òÍѤ¤¤ë(bc¥â¡¼¥É°Ê³°¤Ï¥Ç¥Õ¥©¥ë¥È). + --noinspect ·ë²Ì½ÐÎϤËinspect¤òÍѤ¤¤Ê¤¤. + --readline readline¥é¥¤¥Ö¥é¥ê¤òÍøÍѤ¹¤ë. + --noreadline readline¥é¥¤¥Ö¥é¥ê¤òÍøÍѤ·¤Ê¤¤. ¥Ç¥Õ¥©¥ë¥È¤Îưºî¤Ï, + inf-reuby-mode°Ê³°¤Çreadline¥é¥¤¥Ö¥é¥ê¤òÍøÍѤ·¤è¤¦ + ¤È¤¹¤ë. + --prompt prompt-mode + --prompt-mode prompt-mode + ¥×¥í¥ó¥×¥È¥â¡¼¥É¤òÀÚÂØ¤¨¤Þ¤¹. ¸½ºßÄêµÁ¤µ¤ì¤Æ¤¤¤ë¥× + ¥í¥ó¥×¥È¥â¡¼¥É¤Ï, default, simple, xmp, inf-ruby¤¬ + ÍѰդµ¤ì¤Æ¤¤¤Þ¤¹. ¥Ç¥Õ¥©¥ë¥È¤Ïdefault¥×¥í¥ó¥×¥È¥â¡¼ + ¥É¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹. + + --inf-ruby-mode emacs¤Îinf-ruby-modeÍѤΥץí¥ó¥×¥Èɽ¼¨¤ò¹Ô¤Ê¤¦. ÆÃ + ¤Ë»ØÄ꤬¤Ê¤¤¸Â¤ê, readline¥é¥¤¥Ö¥é¥ê¤Ï»È¤ï¤Ê¤¯¤Ê¤ë. + --simple-prompt + Èó¾ï¤Ë¥·¥ó¥×¥ë¤Ê¥×¥í¥ó¥×¥È¤òÍѤ¤¤ë¥â¡¼¥É¤Ç¤¹. + --noprompt ¥×¥í¥ó¥×¥Èɽ¼¨¤ò¹Ô¤Ê¤ï¤Ê¤¤. + --tracer ¥³¥Þ¥ó¥É¼Â¹Ô»þ¤Ë¥È¥ì¡¼¥¹¤ò¹Ô¤Ê¤¦. + --back-trace-limit n + ¥Ð¥Ã¥¯¥È¥ì¡¼¥¹É½¼¨¤ò¥Ð¥Ã¥¯¥È¥ì¡¼¥¹¤ÎƬ¤«¤é n, ¸å¤í + ¤«¤én¤À¤±¹Ô¤Ê¤¦. ¥Ç¥Õ¥©¥ë¥È¤Ï16 + --irb_debug n irb¤Î¥Ç¥Ð¥Ã¥°¥Ç¥Ð¥Ã¥°¥ì¥Ù¥ë¤òn¤ËÀßÄꤹ¤ë(ÍøÍѤ·¤Ê + ¤¤Êý¤¬ÌµÆñ¤Ç¤·¤ç¤¦). + -v, --version irb¤Î¥Ð¡¼¥¸¥ç¥ó¤òɽ¼¨¤¹¤ë + += ¥³¥ó¥Õ¥£¥®¥å¥ì¡¼¥·¥ç¥ó + +irbµ¯Æ°»þ¤Ë``~/.irbrc''¤òÆÉ¤ß¹þ¤ß¤Þ¤¹. ¤â¤·Â¸ºß¤·¤Ê¤¤¾ì¹ç¤Ï, +``.irbrc'', ``irb.rc'', ``_irbrc'', ``$irbrc''¤Î½ç¤Ëload¤ò»î¤ß¤Þ¤¹. + +¥ª¥×¥·¥ç¥ó¤òÀßÄꤹ¤ëÂå¤ï¤ê¤Ë, °Ê²¼¤Î¥³¥Þ¥ó¥É¤Ç¤â¥Ç¥Õ¥©¥ë¥È¤Îưºî¤òÀßÄê +¤Ç¤­¤Þ¤¹. + + IRB.conf[:IRB_NAME]="irb" + IRB.conf[:MATH_MODE]=false + IRB.conf[:USE_TRACER]=false + IRB.conf[:USE_LOADER]=false + IRB.conf[:IGNORE_SIGINT]=true + IRB.conf[:IGNORE_EOF]=false + IRB.conf[:INSPECT_MODE]=nil + IRB.conf[:IRB_RC] = nil + IRB.conf[:BACK_TRACE_LIMIT]=16 + IRB.conf[:USE_LOADER] = false + IRB.conf[:USE_READLINE] = nil + IRB.conf[:USE_TRACER] = false + IRB.conf[:IGNORE_SIGINT] = true + IRB.conf[:IGNORE_EOF] = false + IRB.conf[:PROMPT_MODE] = :DEFALUT + IRB.conf[:PROMPT] = {...} + IRB.conf[:DEBUG_LEVEL]=0 + IRB.conf[:VERBOSE]=true + +== ¥×¥í¥ó¥×¥È¤ÎÀßÄê + +¥×¥í¥ó¥×¥È¤ò¥«¥¹¥¿¥Þ¥¤¥º¤·¤¿¤¤»þ¤Ë¤Ï, + + IRB.conf[:PROMPT] + +¤òÍѤ¤¤Þ¤¹. Î㤨¤Ð, .irbrc¤ÎÃæ¤Ç²¼¤Î¤è¤¦¤Ê¼°¤òµ­½Ò¤·¤Þ¤¹: + + IRB.conf[:PROMPT][:MY_PROMPT] = { # ¥×¥í¥ó¥×¥È¥â¡¼¥É¤Î̾Á° + :PROMPT_I => nil, # Ä̾ï¤Î¥×¥í¥ó¥×¥È + :PROMPT_S => nil, # ʸ»úÎó¤Ê¤É¤Î·Ñ³¹Ô¤Î¥×¥í¥ó¥×¥È + :PROMPT_C => nil, # ¼°¤¬·Ñ³¤·¤Æ¤¤¤ë»þ¤Î¥×¥í¥ó¥×¥È + :RETURN => " ==>%s\n" # ¥ê¥¿¡¼¥ó»þ¤Î¥×¥í¥ó¥×¥È + } + +¥×¥í¥ó¥×¥È¥â¡¼¥É¤ò»ØÄꤷ¤¿¤¤»þ¤Ë¤Ï, + + irb --prompt my-prompt + +¤Ç¤½¤Î¥×¥í¥ó¥×¥È¥â¡¼¥É¤Çµ¯Æ°¤µ¤ì¤Þ¤¹. ¤Þ¤¿¤Ï, .irbrc¤Ë²¼¼°¤òµ­½Ò¤·¤Æ¤â +OK¤Ç¤¹. + + IRB.conf[:PROMPT_MODE] = :MY_PROMPT + +PROMPT_I, PROMPT_S, PROMPT_C¤Ï, ¥Õ¥©¡¼¥Þ¥Ã¥È¤ò»ØÄꤷ¤Þ¤¹. + + %N µ¯Æ°¤·¤Æ¤¤¤ë¥³¥Þ¥ó¥É̾¤¬½ÐÎϤµ¤ì¤ë. + %m main¥ª¥Ö¥¸¥§¥¯¥È(self)¤¬to_s¤Ç½ÐÎϤµ¤ì¤ë. + %M main¥ª¥Ö¥¸¥§¥¯¥È(self)¤¬inspect¤µ¤ì¤Æ½ÐÎϤµ¤ì¤ë. + %l ʸ»úÎóÃæ¤Î¥¿¥¤¥×¤òɽ¤¹(", ', /, ], `]'¤Ï%w¤ÎÃæ¤Î»þ) + %NNi ¥¤¥ó¥Ç¥ó¥È¤Î¥ì¥Ù¥ë¤òɽ¤¹. NN¤Ï¿ô»ú¤¬Æþ¤êprintf¤Î%NNd¤ÈƱ¤¸. ¾Ê + ά²Äǽ + %NNn ¹ÔÈÖ¹æ¤òɽ¤·¤Þ¤¹. + %% % + +Î㤨¤Ð, ¥Ç¥Õ¥©¥ë¥È¤Î¥×¥í¥ó¥×¥È¥â¡¼¥É¤Ï: + + IRB.conf[:PROMPT_MODE][:DEFAULT] = { + :PROMPT_I => "%N(%m):%03n:%i> ", + :PROMPT_S => "%N(%m):%03n:%i%l ", + :PROMPT_C => "%N(%m):%03n:%i* ", + :RETURN => "%s\n" + } + +¤È¤Ê¤Ã¤Æ¤¤¤Þ¤¹. + +RETURN¤Ï, ¸½ºß¤Î¤È¤³¤íprintf·Á¼°¤Ç¤¹. ¾­Íè»ÅÍͤ¬ÊѤï¤ë¤«¤âÃΤì¤Þ¤»¤ó. + +== ¥µ¥Öirb¤ÎÀßÄê + +¥³¥Þ¥ó¥É¥é¥¤¥ó¥ª¥×¥·¥ç¥ó¤ª¤è¤ÓIRB.conf¤Ï(¥µ¥Ö)irbµ¯Æ°»þ¤Î¥Ç¥Õ¥©¥ë¥È¤Î +ÀßÄê¤ò·è¤á¤ë¤â¤Î¤Ç, `5. ¥³¥Þ¥ó¥É'¤Ë¤¢¤ëconf¤Ç¸ÄÊ̤Î(¥µ¥Ö)irb¤ÎÀßÄ꤬¤Ç +¤­¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹. + +IRB.conf[:IRB_RC]¤Ëproc¤¬ÀßÄꤵ¤ì¤Æ¤¤¤ë¤È, ¥µ¥Öirb¤òµ¯Æ°¤¹¤ë»þ¤Ë¤½¤Î +proc¤òirb¤Î¥³¥ó¥Æ¥­¥¹¥È¤ò°ú¿ô¤È¤·¤Æ¸Æ¤Ó½Ð¤·¤Þ¤¹. ¤³¤ì¤Ë¤è¤Ã¤Æ¸ÄÊ̤Υµ +¥Öirb¤´¤È¤ËÀßÄê¤òÊѤ¨¤ë¤³¤È¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤Ê¤ê¤Þ¤¹. + + += ¥³¥Þ¥ó¥É + +irb³ÈÄ¥¥³¥Þ¥ó¥É¤Ï, ´Êñ¤Ê̾Á°¤ÈƬ¤Ë`irb_'¤ò¤Ä¤±¤¿Ì¾Á°¤ÈξÊýÄêµÁ¤µ¤ì¤Æ +¤¤¤Þ¤¹. ¤³¤ì¤Ï, ´Êñ¤Ê̾Á°¤¬override¤µ¤ì¤¿»þ¤Î¤¿¤á¤Ç¤¹. + +--- exit, quit, irb_exit + ½ªÎ»¤¹¤ë. + ¥µ¥Öirb¤Î¾ì¹ç, ¤½¤Î¥µ¥Öirb¤ò½ªÎ»¤¹¤ë. + cb¤·¤Æ¤¤¤ë¾ì¹ç, ¤½¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤Î¥â¡¼¥É¤ò½ªÎ»¤¹¤ë. + +--- conf, irb_context + irb¤Î¸½ºß¤ÎÀßÄê¤òɽ¼¨¤¹¤ë. ÀßÄê¤ÎÊѹ¹¤Ï, conf¤Ë¥á¥Ã¥»¡¼¥¸¤òÁ÷¤ë¤³ + ¤È¤Ë¤è¤Ã¤Æ¹Ô¤Ê¤¨¤ë. + +--- conf.back_trace_limit + ¥Ð¥Ã¥¯¥È¥ì¡¼¥¹É½¼¨¤ò¥Ð¥Ã¥¯¥È¥ì¡¼¥¹¤ÎƬ¤«¤én, ¸å¤í¤«¤én¤À¤±¹Ô¤Ê¤¦. + ¥Ç¥Õ¥©¥ë¥È¤Ï16 + +--- conf.debug_level = N + irbÍѤΥǥХå°¥ì¥Ù¥ë¤ÎÀßÄê + +--- conf.ignore_eof = true/false + ^D¤¬ÆþÎϤµ¤ì¤¿»þ¤Îưºî¤òÀßÄꤹ¤ë. true¤Î»þ¤Ï^D¤ò̵»ë¤¹¤ë, false¤Î + »þ¤Ïirb¤ò½ªÎ»¤¹¤ë. + +--- conf.ignore_sigint= true/false + ^C¤¬ÆþÎϤµ¤ì¤¿»þ¤Îưºî¤òÀßÄꤹ¤ë. false»þ¤Ï, irb¤ò½ªÎ»¤¹¤ë. true¤Î + »þ¤Îưºî¤Ï°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ë: + ÆþÎÏÃæ: ¤³¤ì¤Þ¤ÇÆþÎϤ·¤¿¤â¤Î¤ò¥­¥ã¥ó¥»¥ë¤·¥È¥Ã¥×¥ì¥Ù¥ë¤ËÌá¤ë. + ¼Â¹ÔÃæ: ¼Â¹Ô¤òÃæ»ß¤¹¤ë. + +--- conf.inf_ruby_mode = true/false + inf-ruby-modeÍѤΥץí¥ó¥×¥Èɽ¼¨¤ò¹Ô¤Ê¤¦. ¥Ç¥Õ¥©¥ë¥È¤Ïfalse. + +--- conf.inspect_mode = true/false/nil + ¥¤¥ó¥¹¥Ú¥¯¥È¥â¡¼¥É¤òÀßÄꤹ¤ë. + true: ¥¤¥ó¥¹¥Ú¥¯¥È¤·¤ÆÉ½¼¨¤¹¤ë. + false: Ä̾ï¤Îprint¤Çɽ¼¨¤¹¤ë. + nil: Ä̾ï¥â¡¼¥É¤Ç¤¢¤ì¤Ð, inspect mode¤È¤Ê¤ê, math¥â¡¼¥É¤Î»þ¤Ï, non + inspect mode¤È¤Ê¤ë. + +--- conf.irb_level + »²¾È¤Î¤ß. irb¤¬²¿ÃÊcb¤·¤Æ¤¤¤ë¤«? + +--- conf.math_mode + »²¾È¤Î¤ß. bc¥â¡¼¥É(ʬ¿ô, ¹ÔÎó¤Î·×»»¤¬¤Ç¤­¤Þ¤¹)¤«¤É¤¦¤«? + +--- conf.use_loader = true/false + load/require»þ¤Ëirb¤ÎfileÆÉ¤ß¹þ¤ßµ¡Ç½¤òÍѤ¤¤ë¥â¡¼¥É¤Î¥¹¥¤¥Ã¥Á(¥Ç¥Õ¥© + ¥ë¥È¤ÏÍѤ¤¤Ê¤¤). ¤³¤Î¥â¡¼¥É¤ÏIRBÁ´ÂΤËÈ¿±Ç¤µ¤ì¤ë. + +--- conf.prompt_c + if¤Îľ¸å¤Ê¤É, ¹Ô¤¬·Ñ³¤·¤Æ¤¤¤ë»þ¤Î¥×¥í¥ó¥×¥È. + +--- conf.prompt_i + Ä̾ï¤Î¥×¥í¥ó¥×¥È. + +--- conf.prompt_s + ʸ»úÎóÃæ¤Ê¤É¤òɽ¤¹¥×¥í¥ó¥×¥È. + +--- conf.rc + ~/.irbrc¤òÆÉ¤ß¹þ¤ó¤À¤«¤É¤¦¤«? + +--- conf.use_prompt = true/false + ¥×¥í¥ó¥×¥Èɽ¼¨¤¹¤ë¤«¤É¤¦¤«? ¥Ç¥Õ¥©¥ë¥È¤Ç¤Ï¥×¥í¥ó¥×¥È¤òɽ¼¨¤¹¤ë. + +--- conf.use_readline = true/false/nil + readline¤ò»È¤¦¤«¤É¤¦¤«? + true: readline¤ò»È¤¦. + false: readline¤ò»È¤ï¤Ê¤¤. + nil: (¥Ç¥Õ¥©¥ë¥È)inf-reuby-mode°Ê³°¤Çreadline¥é¥¤¥Ö¥é¥ê¤òÍøÍѤ·¤è + ¤¦¤È¤¹¤ë. + +--- conf.verbose=T/F + irb¤«¤é¤¤¤í¤¤¤í¤Ê¥á¥Ã¥»¡¼¥¸¤ò½ÐÎϤ¹¤ë¤«? + +--- cb, irb_change_binding [obj] + ¥í¡¼¥«¥ëÊÑ¿ô¤Î¥¹¥³¡¼¥×¤¬°ã¤¦¿·¤¿¤Êbinding¤Ë°Ü¤ë. obj¤¬»ØÄꤵ¤ì¤¿ + »þ¤Ï, ¤½¤Îobj¤òself¤È¤¹¤ë. + +--- irb [obj] + ¥µ¥Öirb¤òΩ¤Á¤¢¤²¤ë. obj¤¬»ØÄꤵ¤ì¤¿»þ¤Ï, ¤½¤Îobj¤òself¤È¤¹¤ë. + +--- jobs, irb_jobs + ¥µ¥Öirb¤Î¥ê¥¹¥È + +--- fg n, irb_fg n + »ØÄꤷ¤¿¥µ¥Öirb¤Ë¥¹¥¤¥Ã¥Á¤¹¤ë. n¤Ï, ¼¡¤Î¤â¤Î¤ò»ØÄꤹ¤ë. + + irbÈÖ¹æ + ¥¹¥ì¥Ã¥É + irb¥ª¥Ö¥¸¥§¥¯¥È + self(irb obj¤Çµ¯Æ°¤·¤¿»þ¤Îobj) + +--- kill n, irb_kill n + ¥µ¥Öirb¤òkill¤¹¤ë. n¤Ïfg¤ÈƱ¤¸. + + += ¥·¥¹¥Æ¥àÊÑ¿ô + + _ Á°¤Î·×»»¤Î¼Â¹Ô·ë²Ì¤ò³Ð¤¨¤Æ¤¤¤ë(¥í¡¼¥«¥ëÊÑ¿ô). + += »ÈÍÑÎã + +°Ê²¼¤Î¤è¤¦¤Ê´¶¤¸¤Ç¤¹. + + dim% ruby irb.rb + irb(main):001:0> irb # ¥µ¥Öirb¤ÎΩ¤Á¤¢¤² + irb#1(main):001:0> jobs # ¥µ¥Öirb¤Î¥ê¥¹¥È + #0->irb on main (# : stop) + #1->irb#1 on main (# : running) + nil + irb#1(main):002:0> fg 0 # job¤Î¥¹¥¤¥Ã¥Á + nil + irb(main):002:0> class Foo;end + nil + irb(main):003:0> irb Foo # Foo¤ò¥³¥ó¥Æ¥­¥¹¥È¤·¤Æirb + # Ω¤Á¤¢¤² + irb#2(Foo):001:0> def foo # Foo#foo¤ÎÄêµÁ + irb#2(Foo):002:1> print 1 + irb#2(Foo):003:1> end + nil + irb#2(Foo):004:0> fg 0 # job¤ò¥¹¥¤¥Ã¥Á + nil + irb(main):004:0> jobs # job¤Î¥ê¥¹¥È + #0->irb on main (# : running) + #1->irb#1 on main (# : stop) + #2->irb#2 on Foo (# : stop) + nil + irb(main):005:0> Foo.instance_methods # Foo#foo¤¬¤Á¤ã¤ó¤ÈÄêµÁ¤µ + # ¤ì¤Æ¤¤¤ë + ["foo"] + irb(main):006:0> fg 2 # job¤ò¥¹¥¤¥Ã¥Á + nil + irb#2(Foo):005:0> def bar # Foo#bar¤òÄêµÁ + irb#2(Foo):006:1> print "bar" + irb#2(Foo):007:1> end + nil + irb#2(Foo):010:0> Foo.instance_methods + ["bar", "foo"] + irb#2(Foo):011:0> fg 0 + nil + irb(main):007:0> f = Foo.new + # + irb(main):008:0> irb f # Foo¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤Çirb¤ò + # Ω¤Á¤¢¤²¤ë. + irb#3(#):001:0> jobs + #0->irb on main (# : stop) + #1->irb#1 on main (# : stop) + #2->irb#2 on Foo (# : stop) + #3->irb#3 on # (# : running) + nil + irb#3(#):002:0> foo # f.foo¤Î¼Â¹Ô + nil + irb#3(#):003:0> bar # f.bar¤Î¼Â¹Ô + barnil + irb#3(#):004:0> kill 1, 2, 3# job¤Îkill + nil + irb(main):009:0> jobs + #0->irb on main (# : running) + nil + irb(main):010:0> exit # ½ªÎ» + dim% + += »ÈÍѾå¤ÎÀ©¸Â + +irb¤Ï, ɾ²Á¤Ç¤­¤ë»þÅÀ(¼°¤¬ÊĤ¸¤¿»þÅÀ)¤Ç¤ÎÃ༡¼Â¹Ô¤ò¹Ô¤Ê¤¤¤Þ¤¹. ¤·¤¿¤¬¤Ã +¤Æ, ruby¤òľÀܻȤä¿»þ¤È, ¼ã´³°Û¤Ê¤ëưºî¤ò¹Ô¤Ê¤¦¾ì¹ç¤¬¤¢¤ê¤Þ¤¹. + +¸½ºßÌÀ¤é¤«¤Ë¤Ê¤Ã¤Æ¤¤¤ëÌäÂêÅÀ¤òÀâÌÀ¤·¤Þ¤¹. + +== ¥í¡¼¥«¥ëÊÑ¿ô¤ÎÀë¸À + +ruby¤Ç¤Ï, °Ê²¼¤Î¥×¥í¥°¥é¥à¤Ï¥¨¥é¡¼¤Ë¤Ê¤ê¤Þ¤¹. + + eval "foo = 0" + foo + -- + -:2: undefined local variable or method `foo' for # (NameError) + --- + NameError + +¤È¤³¤í¤¬, irb¤òÍѤ¤¤ë¤È + + >> eval "foo = 0" + => 0 + >> foo + => 0 + +¤È¤Ê¤ê, ¥¨¥é¡¼¤òµ¯¤³¤·¤Þ¤»¤ó. ¤³¤ì¤Ï, ruby¤¬ºÇ½é¤Ë¥¹¥¯¥ê¥×¥ÈÁ´ÂΤò¥³¥ó +¥Ñ¥¤¥ë¤·¤Æ¥í¡¼¥«¥ëÊÑ¿ô¤ò·èÄꤹ¤ë¤«¤é¤Ç¤¹. ¤½¤ì¤ËÂФ·, irb¤Ï¼Â¹Ô²Äǽ¤Ë +¤Ê¤ë(¼°¤¬ÊĤ¸¤ë)¤È¼«Æ°Åª¤Ëɾ²Á¤·¤Æ¤¤¤ë¤«¤é¤Ç¤¹. ¾åµ­¤ÎÎã¤Ç¤Ï, + + evel "foo = 0" + +¤ò¹Ô¤Ê¤Ã¤¿»þÅÀ¤Çɾ²Á¤ò¹Ô¤Ê¤¤, ¤½¤Î»þÅÀ¤ÇÊÑ¿ô¤¬ÄêµÁ¤µ¤ì¤ë¤¿¤á, ¼¡¼°¤Ç +ÊÑ¿ôfoo¤ÏÄêµÁ¤µ¤ì¤Æ¤¤¤ë¤«¤é¤Ç¤¹. + +¤³¤Î¤è¤¦¤Êruby¤Èirb¤Îưºî¤Î°ã¤¤¤ò²ò·è¤·¤¿¤¤¾ì¹ç¤Ï, begin...end¤Ç³ç¤Ã¤Æ +¥Ð¥Ã¥ÁŪ¤Ë¼Â¹Ô¤·¤Æ²¼¤µ¤¤: + + >> begin + ?> eval "foo = 0" + >> foo + >> end + NameError: undefined local variable or method `foo' for # + (irb):3 + (irb_local_binding):1:in `eval' + +== ¥Ò¥¢¥É¥­¥å¥á¥ó¥È + +¸½ºß¤Î¤È¤³¤í¥Ò¥¢¥É¥­¥å¥á¥ó¥È¤Î¼ÂÁõ¤ÏÉÔ´°Á´¤Ç¤¹. + +== ¥·¥ó¥Ü¥ë + +¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¤«¤É¤¦¤«¤ÎȽÃǤò´Ö°ã¤¨¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹. ¶ñÂÎŪ¤Ë¤Ï¼°¤¬´°Î» +¤·¤Æ¤¤¤ë¤Î¤Ë·Ñ³¹Ô¤È¸«¤Ê¤¹¤³¤È¤¬¤¢¤ê¤Þ¤¹. + +=end + +% Begin Emacs Environment +% Local Variables: +% mode: text +% comment-column: 0 +% comment-start: "%" +% comment-end: "\n" +% End: +% + diff --git a/doc/shell.rd b/doc/shell.rd new file mode 100644 index 0000000000..02ee1b020a --- /dev/null +++ b/doc/shell.rd @@ -0,0 +1,348 @@ + -- shell.rb + $Release Version: 0.6.0 $ + $Revision$ + $Date$ + by Keiju ISHITSUKA(keiju@ishitsuka.com) + +=begin + += What's shell.rb? + +It realizes a wish to do execution of commands with filters and pipes +like sh/csh by using just native facilities of ruby. + += Main classes + +== Shell + +Every shell object has its own current working directory, and executes +each command as if it stands in the directory. + +--- Shell#cwd +--- Shell#dir +--- Shell#getwd +--- Shell#pwd + + Returns the current directory + +--- Shell#system_path + + Returns the command search path in an array + +--- Shell#umask + + Returns the umask + +== Filter + +Any result of command exection is a Filter. Filter include +Enumerable, therefore a Filter object can use all Enumerable +facilities. + += Main methods + +== Command definitions + +In order to execute a command on your OS, you need to define it as a +Shell method. + +Alternatively, you can execute any command via Shell#system even if it +is not defined. + +--- Shell.def_system_command(command, path = command) + + Defines a command. Registers as a Shell method + . + + ex) + Shell.def_system_command "ls" + Defines ls. + + Shell.def_system_command "sys_sort", "sort" + Defines sys_sort as sort. + +--- Shell.undef_system_command(command) + + Undefines a commmand + +--- Shell.alias_command(ali, command, *opts) {...} + + Aliases a command. + + ex) + Shell.alias_command "lsC", "ls", "-CBF", "--show-control-chars" + Shell.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]} + +--- Shell.unalias_command(ali) + + Unaliases a command. + +--- Shell.install_system_commands(pre = "sys_") + + Defines all commands in the default_system_path as Shell method, + all with
 prefixed to their names.
+
+== Creation
+
+--- Shell.new
+
+      Creates a Shell object which current directory is set to the
+      process current directory.
+
+--- Shell.cd(path)
+
+      Creates a Shell object which current directory is set to
+      .
+
+== Process management
+
+--- Shell#jobs
+
+      Returns a list of scheduled jobs.
+
+--- Shell#kill sig, job
+
+      Sends a signal  to .
+
+== Current directory operations
+
+--- Shell#cd(path, &block)
+--- Shell#chdir
+
+      Changes the current directory to .  If a block is given,
+      it restores the current directory when the block ends.
+
+--- Shell#pushd(path = nil, &block)
+--- Shell#pushdir
+
+      Pushes the current directory to the directory stack, changing
+      the current directory to .  If  is omitted, it
+      exchanges its current directory and the top of its directory
+      stack.  If a block is given, it restores the current directory
+      when the block ends.
+
+--- Shell#popd
+--- Shell#popdir
+
+      Pops a directory from the directory stack, and sets the current
+      directory to it.
+
+== File and directory operations
+
+--- Shell#foreach(path = nil, &block)
+
+      Same as:
+        File#foreach (when path is a file)
+        Dir#foreach (when path is a directory)
+
+--- Shell#open(path, mode)
+
+      Same as:
+        File#open (when path is a file)
+        Dir#open (when path is a directory)
+
+--- Shell#unlink(path)
+
+      Same as:
+        Dir#open (when path is a file)
+        Dir#unlink (when path is a directory)
+
+--- Shell#test(command, file1, file2)
+--- Shell#[command, file1, file2]
+
+      Same as test().
+      ex)
+          sh[?e, "foo"]
+          sh[:e, "foo"]
+          sh["e", "foo"]
+          sh[:exists?, "foo"]
+          sh["exists?", "foo"]
+
+--- Shell#mkdir(*path)
+
+      Same as Dir.mkdir (with multiple directories allowed)
+
+--- Shell#rmdir(*path)
+
+      Same as Dir.rmdir (with multiple directories allowed)
+
+== Command execution
+
+--- System#system(command, *opts)
+
+      Executes  with .
+
+      ex)
+        print sh.system("ls", "-l")
+        sh.system("ls", "-l") | sh.head > STDOUT
+
+--- System#rehash
+
+      Does rehash.
+
+--- Shell#transact &block
+
+      Executes a block as self.
+      ex)
+        sh.transact{system("ls", "-l") | head > STDOUT}
+
+--- Shell#out(dev = STDOUT, &block)
+
+      Does transact, with redirecting the result output to .
+
+== Internal commands
+
+--- Shell#echo(*strings)
+--- Shell#cat(*files)
+--- Shell#glob(patten)
+--- Shell#tee(file)
+
+      Return Filter objects, which are results of their execution.
+
+--- Filter#each &block
+
+      Iterates a block for each line of it.
+
+--- Filter#<(src)
+
+      Inputs from , which is either a string of a file name or an
+      IO.
+
+--- Filter#>(to)
+
+      Outputs to , which is either a string of a file name or an
+      IO.
+
+--- Filter#>>(to)
+
+      Appends the ouput to , which is either a string of a file
+      name or an IO.
+
+--- Filter#|(filter)
+
+      Processes a pipeline.
+
+--- Filter#+(filter)
+
+      (filter1 + filter2) outputs filter1, and then outputs filter2.
+
+--- Filter#to_a
+--- Filter#to_s
+
+== Built-in commands
+
+--- Shell#atime(file)
+--- Shell#basename(file, *opt)
+--- Shell#chmod(mode, *files)
+--- Shell#chown(owner, group, *file)
+--- Shell#ctime(file)
+--- Shell#delete(*file)
+--- Shell#dirname(file)
+--- Shell#ftype(file)
+--- Shell#join(*file)
+--- Shell#link(file_from, file_to)
+--- Shell#lstat(file)
+--- Shell#mtime(file)
+--- Shell#readlink(file)
+--- Shell#rename(file_from, file_to)
+--- Shell#split(file)
+--- Shell#stat(file)
+--- Shell#symlink(file_from, file_to)
+--- Shell#truncate(file, length)
+--- Shell#utime(atime, mtime, *file)
+
+      Equivalent to the class methods of File with the same names.
+
+--- Shell#blockdev?(file)
+--- Shell#chardev?(file)
+--- Shell#directory?(file)
+--- Shell#executable?(file)
+--- Shell#executable_real?(file)
+--- Shell#exist?(file)/Shell#exists?(file)
+--- Shell#file?(file)
+--- Shell#grpowned?(file)
+--- Shell#owned?(file)
+--- Shell#pipe?(file)
+--- Shell#readable?(file)
+--- Shell#readable_real?(file)
+--- Shell#setgid?(file)
+--- Shell#setuid?(file)
+--- Shell#size(file)/Shell#size?(file)
+--- Shell#socket?(file)
+--- Shell#sticky?(file)
+--- Shell#symlink?(file)
+--- Shell#writable?(file)
+--- Shell#writable_real?(file)
+--- Shell#zero?(file)
+
+      Equivalent to the class methods of FileTest with the same names.
+
+--- Shell#syscopy(filename_from, filename_to)
+--- Shell#copy(filename_from, filename_to)
+--- Shell#move(filename_from, filename_to)
+--- Shell#compare(filename_from, filename_to)
+--- Shell#safe_unlink(*filenames)
+--- Shell#makedirs(*filenames)
+--- Shell#install(filename_from, filename_to, mode)
+
+      Equivalent to the class methods of FileTools with the same
+      names.
+
+      And also, there are some aliases for convenience:
+
+--- Shell#cmp	<- Shell#compare
+--- Shell#mv	<- Shell#move
+--- Shell#cp	<- Shell#copy
+--- Shell#rm_f	<- Shell#safe_unlink
+--- Shell#mkpath	<- Shell#makedirs
+
+= Samples
+
+== ex1
+
+  sh = Shell.cd("/tmp")
+  sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1")
+  sh.cd("shell-test-1")
+  for dir in ["dir1", "dir3", "dir5"]
+    if !sh.exists?(dir)
+      sh.mkdir dir
+      sh.cd(dir) do
+	f = sh.open("tmpFile", "w")
+	f.print "TEST\n"
+	f.close
+      end
+      print sh.pwd
+    end
+  end
+
+== ex2
+
+  sh = Shell.cd("/tmp")
+  sh.transact do
+    mkdir "shell-test-1" unless exists?("shell-test-1")
+    cd("shell-test-1")
+    for dir in ["dir1", "dir3", "dir5"]
+      if !exists?(dir)
+	mkdir dir
+	cd(dir) do
+	  f = open("tmpFile", "w")
+	  f.print "TEST\n"
+	  f.close
+	end
+	print pwd
+      end
+    end
+  end
+
+== ex3
+
+  sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2"
+  (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12"
+  sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2"
+  (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12"
+
+== ex4
+
+  print sh.cat("/etc/passwd").head.collect{|l| l =~ /keiju/}
+
+=end
diff --git a/doc/shell.rd.jp b/doc/shell.rd.jp
new file mode 100644
index 0000000000..073e71ea42
--- /dev/null
+++ b/doc/shell.rd.jp
@@ -0,0 +1,336 @@
+ -- shell.rb
+				$Release Version: 0.6.0 $
+			   	$Revision$
+			   	$Date$
+			   	by Keiju ISHITSUKA(keiju@ishitsuka.com)
+
+=begin
+
+= ÌÜŪ
+
+ruby¾å¤Çsh/csh¤Î¤è¤¦¤Ë¥³¥Þ¥ó¥É¤Î¼Â¹ÔµÚ¤Ó¥Õ¥£¥ë¥¿¥ê¥ó¥°¤ò¼ê·Ú¤Ë¹Ô¤¦.
+sh/csh¤ÎÀ©¸æÊ¸¤Ïruby¤Îµ¡Ç½¤òÍѤ¤¤Æ¼Â¸½¤¹¤ë.
+
+= ¼ç¤Ê¥¯¥é¥¹°ìÍ÷
+
+== Shell
+
+Shell¥ª¥Ö¥¸¥§¥¯¥È¤Ï¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤ò»ý¤Á, ¥³¥Þ¥ó¥É¼Â¹Ô¤Ï¤½¤³¤«¤é¤Î
+ÁêÂХѥ¹¤Ë¤Ê¤ê¤Þ¤¹.
+
+--- Shell#cwd
+--- Shell#dir
+--- Shell#getwd
+--- Shell#pwd
+
+      ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤òÊÖ¤¹¡£
+
+--- Shell#system_path
+
+      ¥³¥Þ¥ó¥É¥µ¡¼¥Á¥Ñ¥¹¤ÎÇÛÎó¤òÊÖ¤¹¡£
+
+--- Shell#umask
+
+      umask¤òÊÖ¤¹¡£
+
+== Filter
+
+¥³¥Þ¥ó¥É¤Î¼Â¹Ô·ë²Ì¤Ï¤¹¤Ù¤ÆFilter¤È¤·¤Æ¤«¤¨¤ê¤Þ¤¹. Enumerable¤òinclude¤·
+¤Æ¤¤¤Þ¤¹.
+
+= ¼ç¤Ê¥á¥½¥Ã¥É°ìÍ÷
+
+== ¥³¥Þ¥ó¥ÉÄêµÁ
+
+OS¾å¤Î¥³¥Þ¥ó¥É¤ò¼Â¹Ô¤¹¤ë¤Ë¤Ï¤Þ¤º, Shell¤Î¥á¥½¥Ã¥É¤È¤·¤ÆÄêµÁ¤·¤Þ¤¹.
+
+Ãí) ¥³¥Þ¥ó¥É¤òÄêµÁ¤·¤Ê¤¯¤È¤âľÀܼ¹ԤǤ­¤ëShell#system¥³¥Þ¥ó¥É¤â¤¢¤ê¤Þ¤¹.
+
+--- Shell.def_system_command(command, path = command)
+
+      Shell¤Î¥á¥½¥Ã¥É¤È¤·¤Æcommand¤òÅÐÏ¿¤·¤Þ¤¹. 
+
+      Îã)
+      Shell.def_system_command "ls"
+        ls ¤òÄêµÁ
+
+      Shell.def_system_command "sys_sort", "sort"
+        sort¥³¥Þ¥ó¥É¤òsys_sort¤È¤·¤ÆÄêµÁ
+
+--- Shell.undef_system_command(command)
+
+      command¤òºï½ü¤·¤Þ¤¹.
+
+--- Shell.alias_command(ali, command, *opts) {...}
+
+      command¤Îalias¤ò¤·¤Þ¤¹. 
+
+      Îã)
+        Shell.alias_command "lsC", "ls", "-CBF", "--show-control-chars"
+        Shell.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]}
+
+--- Shell.unalias_command(ali)
+
+      command¤Îalias¤òºï½ü¤·¤Þ¤¹.
+
+--- Shell.install_system_commands(pre = "sys_")
+
+      system_path¾å¤Ë¤¢¤ëÁ´¤Æ¤Î¼Â¹Ô²Äǽ¥Õ¥¡¥¤¥ë¤òShell¤ËÄêµÁ¤¹¤ë. ¥á¥½¥Ã
+      ¥É̾¤Ï¸µ¤Î¥Õ¥¡¥¤¥ë̾¤ÎƬ¤Ëpre¤ò¤Ä¤±¤¿¤â¤Î¤È¤Ê¤ë.
+
+== À¸À®
+
+--- Shell.new
+
+      ¥×¥í¥»¥¹¤Î¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤ò¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤È¤¹¤ëShell¥ª
+      ¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¤Þ¤¹.
+
+--- Shell.cd(path)
+
+      path¤ò¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤È¤¹¤ëShell¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤·¤Þ¤¹.
+
+== ¥×¥í¥»¥¹´ÉÍý
+
+--- Shell#jobs
+
+      ¥¹¥±¥¸¥å¡¼¥ê¥ó¥°¤µ¤ì¤Æ¤¤¤ëjob¤Î°ìÍ÷¤òÊÖ¤¹.
+
+--- Shell#kill sig, job
+
+      job¤Ë¥·¥°¥Ê¥ësig¤òÁ÷¤ë
+
+== ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥êÁàºî
+
+--- Shell#cd(path, &block)
+--- Shell#chdir
+
+      ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤òpath¤Ë¤¹¤ë. ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ¸Æ¤Ð¤ì¤¿¤È¤­¤Ë¤Ï
+      ¥Ö¥í¥Ã¥¯¼Â¹ÔÃæ¤Î¤ß¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤òÊѹ¹¤¹¤ë.
+
+--- Shell#pushd(path = nil, &block)
+--- Shell#pushdir
+
+      ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤ò¥Ç¥£¥ì¥¯¥È¥ê¥¹¥¿¥Ã¥¯¤Ë¤Ä¤ß, ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯
+      ¥È¥ê¤òpath¤Ë¤¹¤ë. path¤¬¾Êά¤µ¤ì¤¿¤È¤­¤Ë¤Ï, ¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤È
+      ¥Ç¥£¥ì¥¯¥È¥ê¥¹¥¿¥Ã¥¯¤Î¥È¥Ã¥×¤ò¸ò´¹¤¹¤ë. ¥¤¥Æ¥ì¡¼¥¿¤È¤·¤Æ¸Æ¤Ð¤ì¤¿¤È
+      ¤­¤Ë¤Ï, ¥Ö¥í¥Ã¥¯¼Â¹ÔÃæ¤Î¤ßpushd¤¹¤ë.
+
+--- Shell#popd
+--- Shell#popdir
+
+      ¥Ç¥£¥ì¥¯¥È¥ê¥¹¥¿¥Ã¥¯¤«¤é¥Ý¥Ã¥×¤·, ¤½¤ì¤ò¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤Ë¤¹¤ë.
+
+== ¥Õ¥¡¥¤¥ë/¥Ç¥£¥ì¥¯¥È¥êÁàºî
+
+--- Shell#foreach(path = nil, &block)
+
+      path¤¬¥Õ¥¡¥¤¥ë¤Ê¤é, File#foreach
+      path¤¬¥Ç¥£¥ì¥¯¥È¥ê¤Ê¤é, Dir#foreach
+
+--- Shell#open(path, mode)
+
+      path¤¬¥Õ¥¡¥¤¥ë¤Ê¤é, File#open
+      path¤¬¥Ç¥£¥ì¥¯¥È¥ê¤Ê¤é, Dir#open
+
+--- Shell#unlink(path)
+
+      path¤¬¥Õ¥¡¥¤¥ë¤Ê¤é, File#unlink
+      path¤¬¥Ç¥£¥ì¥¯¥È¥ê¤Ê¤é, Dir#unlink
+
+--- Shell#test(command, file1, file2)
+--- Shell#[command, file1, file2]
+
+      ¥Õ¥¡¥¤¥ë¥Æ¥¹¥È´Ø¿ôtest¤ÈƱ¤¸. 
+      Îã)
+          sh[?e, "foo"]
+          sh[:e, "foo"]
+          sh["e", "foo"]
+          sh[:exists?, "foo"]
+          sh["exists?", "foo"]
+
+--- Shell#mkdir(*path)
+
+      Dir.mkdir¤ÈƱ¤¸(Ê£¿ô²Ä)
+
+--- Shell#rmdir(*path)
+
+      Dir.rmdir¤ÈƱ¤¸(Ê£¿ô²Ä)
+
+== ¥³¥Þ¥ó¥É¼Â¹Ô
+
+--- System#system(command, *opts)
+
+      command¤ò¼Â¹Ô¤¹¤ë.
+      Îã)
+        print sh.system("ls", "-l")
+        sh.system("ls", "-l") | sh.head > STDOUT
+
+--- System#rehash
+
+      ¥ê¥Ï¥Ã¥·¥å¤¹¤ë
+
+--- Shell#transact &block
+
+      ¥Ö¥í¥Ã¥¯Ãæ¤Ç¤Ïshell¤òself¤È¤·¤Æ¼Â¹Ô¤¹¤ë.
+      Îã)
+        sh.transact{system("ls", "-l") | head > STDOUT}
+
+--- Shell#out(dev = STDOUT, &block)
+
+      transact¤ò¸Æ¤Ó½Ð¤·¤½¤Î·ë²Ì¤òdev¤Ë½ÐÎϤ¹¤ë.
+
+== ÆâÉô¥³¥Þ¥ó¥É
+
+--- Shell#echo(*strings)
+--- Shell#cat(*files)
+--- Shell#glob(patten)
+--- Shell#tee(file)
+
+      ¤³¤ì¤é¤Ï¼Â¹Ô¤¹¤ë¤È, ¤½¤ì¤é¤òÆâÍÆ¤È¤¹¤ëFilter¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤·¤Þ¤¹. 
+
+--- Filter#each &block
+
+      ¥Õ¥£¥ë¥¿¤Î°ì¹Ô¤º¤Ä¤òblock¤ËÅϤ¹.
+
+--- Filter#<(src)
+
+      src¤ò¥Õ¥£¥ë¥¿¤ÎÆþÎϤȤ¹¤ë. src¤¬, ʸ»úÎó¤Ê¤é¤Ð¥Õ¥¡¥¤¥ë¤ò, IO¤Ç¤¢¤ì
+      ¤Ð¤½¤ì¤ò¤½¤Î¤Þ¤ÞÆþÎϤȤ¹¤ë.
+
+--- Filter#>(to)
+
+      src¤ò¥Õ¥£¥ë¥¿¤Î½ÐÎϤȤ¹¤ë. to¤¬, ʸ»úÎó¤Ê¤é¤Ð¥Õ¥¡¥¤¥ë¤Ë, IO¤Ç¤¢¤ì
+      ¤Ð¤½¤ì¤ò¤½¤Î¤Þ¤Þ½ÐÎϤȤ¹¤ë.
+
+--- Filter#>>(to)
+
+      src¤ò¥Õ¥£¥ë¥¿¤ËÄɲ乤ë. to¤¬, ʸ»úÎó¤Ê¤é¤Ð¥Õ¥¡¥¤¥ë¤Ë, IO¤Ç¤¢¤ì¤Ð
+      ¤½¤ì¤ò¤½¤Î¤Þ¤Þ½ÐÎϤȤ¹¤ë.
+
+--- Filter#|(filter)
+
+      ¥Ñ¥¤¥×·ë¹ç
+
+--- Filter#+(filter)
+
+      filter1 + filter2 ¤Ï filter1¤Î½ÐÎϤθå, filter2¤Î½ÐÎϤò¹Ô¤¦.
+
+--- Filter#to_a
+--- Filter#to_s
+
+== Áȹþ¤ß¥³¥Þ¥ó¥É
+
+--- Shell#atime(file)
+--- Shell#basename(file, *opt)
+--- Shell#chmod(mode, *files)
+--- Shell#chown(owner, group, *file)
+--- Shell#ctime(file)
+--- Shell#delete(*file)
+--- Shell#dirname(file)
+--- Shell#ftype(file)
+--- Shell#join(*file)
+--- Shell#link(file_from, file_to)
+--- Shell#lstat(file)
+--- Shell#mtime(file)
+--- Shell#readlink(file)
+--- Shell#rename(file_from, file_to)
+--- Shell#split(file)
+--- Shell#stat(file)
+--- Shell#symlink(file_from, file_to)
+--- Shell#truncate(file, length)
+--- Shell#utime(atime, mtime, *file)
+
+      ¤³¤ì¤é¤ÏFile¥¯¥é¥¹¤Ë¤¢¤ëƱ̾¤Î¥¯¥é¥¹¥á¥½¥Ã¥É¤ÈƱ¤¸¤Ç¤¹.
+
+--- Shell#blockdev?(file)
+--- Shell#chardev?(file)
+--- Shell#directory?(file)
+--- Shell#executable?(file)
+--- Shell#executable_real?(file)
+--- Shell#exist?(file)/Shell#exists?(file)
+--- Shell#file?(file)
+--- Shell#grpowned?(file)
+--- Shell#owned?(file)
+--- Shell#pipe?(file)
+--- Shell#readable?(file)
+--- Shell#readable_real?(file)
+--- Shell#setgid?(file)
+--- Shell#setuid?(file)
+--- Shell#size(file)/Shell#size?(file)
+--- Shell#socket?(file)
+--- Shell#sticky?(file)
+--- Shell#symlink?(file)
+--- Shell#writable?(file)
+--- Shell#writable_real?(file)
+--- Shell#zero?(file)
+
+      ¤³¤ì¤é¤ÏFileTest¥¯¥é¥¹¤Ë¤¢¤ëƱ̾¤Î¥¯¥é¥¹¥á¥½¥Ã¥É¤ÈƱ¤¸¤Ç¤¹.
+
+--- Shell#syscopy(filename_from, filename_to)
+--- Shell#copy(filename_from, filename_to)
+--- Shell#move(filename_from, filename_to)
+--- Shell#compare(filename_from, filename_to)
+--- Shell#safe_unlink(*filenames)
+--- Shell#makedirs(*filenames)
+--- Shell#install(filename_from, filename_to, mode)
+
+      ¤³¤ì¤é¤ÏFileTools¥¯¥é¥¹¤Ë¤¢¤ëƱ̾¤Î¥¯¥é¥¹¥á¥½¥Ã¥É¤ÈƱ¤¸¤Ç¤¹.
+
+      ¤½¤Î¾, °Ê²¼¤Î¤â¤Î¤¬¥¨¥¤¥ê¥¢¥¹¤µ¤ì¤Æ¤¤¤Þ¤¹.
+
+--- Shell#cmp	<- Shell#compare
+--- Shell#mv	<- Shell#move
+--- Shell#cp	<- Shell#copy
+--- Shell#rm_f	<- Shell#safe_unlink
+--- Shell#mkpath	<- Shell#makedirs
+
+= ¥µ¥ó¥×¥ë
+
+== ex1
+
+  sh = Shell.cd("/tmp")
+  sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1")
+  sh.cd("shell-test-1")
+  for dir in ["dir1", "dir3", "dir5"]
+    if !sh.exists?(dir)
+      sh.mkdir dir
+      sh.cd(dir) do
+	f = sh.open("tmpFile", "w")
+	f.print "TEST\n"
+	f.close
+      end
+      print sh.pwd
+    end
+  end
+
+== ex2
+
+  sh = Shell.cd("/tmp")
+  sh.transact do
+    mkdir "shell-test-1" unless exists?("shell-test-1")
+    cd("shell-test-1")
+    for dir in ["dir1", "dir3", "dir5"]
+      if !exists?(dir)
+	mkdir dir
+	cd(dir) do
+	  f = open("tmpFile", "w")
+	  f.print "TEST\n"
+	  f.close
+	end
+	print pwd
+      end
+    end
+  end
+
+== ex3
+
+  sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2"
+  (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12"
+  sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2"
+  (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12"
+
+== ex4
+
+  print sh.cat("/etc/passwd").head.collect{|l| l =~ /keiju/}
+
+=end
diff --git a/error.c b/error.c
index 4527128030..6a008cdac5 100644
--- a/error.c
+++ b/error.c
@@ -694,6 +694,13 @@ rb_sys_fail(mesg)
     rb_exc_raise(ee);
 }
 
+void
+rb_load_fail(path)
+    char *path;
+{
+    rb_loaderror("%s -- %s", strerror(errno), path);
+}
+
 void
 rb_error_frozen(what)
     char *what;
diff --git a/eval.c b/eval.c
index ae2ce62da9..6a8cf3f552 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,7 @@
   $Date$
   created at: Thu Jun 10 14:22:17 JST 1993
 
-  Copyright (C) 1993-2000 Yukihiro Matsumoto
+  Copyright (C) 1993-2001 Yukihiro Matsumoto
   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
   Copyright (C) 2000  Information-technology Promotion Agency, Japan
 
@@ -15,6 +15,7 @@
 #include "ruby.h"
 #include "node.h"
 #include "env.h"
+#include "util.h"
 #include "rubysig.h"
 
 #include 
@@ -22,6 +23,25 @@
 #include "st.h"
 #include "dln.h"
 
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+# ifndef atarist
+#  ifndef alloca
+#   define alloca __builtin_alloca
+#  endif
+# endif /* atarist */
+#else
+# if defined(HAVE_ALLOCA_H)
+#  include 
+# elif !defined(alloca)
+char *alloca();
+# endif
+#endif /* __GNUC__ */
+
+#ifdef _AIX
+#pragma alloca
+#endif
+
 #ifdef HAVE_STDARG_PROTOTYPES
 #include 
 #define va_init_list(a,b) va_start(a,b)
@@ -109,33 +129,8 @@ int ruby_safe_level = 0;
    4 - no global (non-tainted) variable modification/no direct output
 */
 
-void
-rb_set_safe_level(level)
-    int level;
-{
-    if (level > ruby_safe_level) {
-	ruby_safe_level = level;
-    }
-}
-
-static VALUE
-safe_getter()
-{
-    return INT2FIX(ruby_safe_level);
-}
-
-static void
-safe_setter(val)
-    VALUE val;
-{
-    int level = NUM2INT(val);
-
-    if (level < ruby_safe_level) {
-	rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d",
-		 ruby_safe_level, level);
-    }
-    ruby_safe_level = level;
-}
+static VALUE safe_getter _((void));
+static void safe_setter _((VALUE val));
 
 void
 rb_secure(level)
@@ -483,9 +478,9 @@ rb_attr(klass, id, read, write, ex)
 	rb_clear_cache_by_id(id);
 	rb_funcall(klass, added, 1, ID2SYM(id));
     }
-    sprintf(buf, "%s=", name);
-    id = rb_intern(buf);
     if (write) {
+	sprintf(buf, "%s=", name);
+	id = rb_intern(buf);
 	rb_add_method(klass, id, NEW_ATTRSET(attriv), noex);
 	rb_clear_cache_by_id(id);
 	rb_funcall(klass, added, 1, ID2SYM(id));
@@ -527,14 +522,20 @@ static struct SCOPE *top_scope;
     ruby_sourceline = _frame.line;	\
     ruby_frame = _frame.prev; }
 
+struct BLOCKTAG {
+    struct RBasic super;
+    long dst;
+    long flags;
+};
+
 struct BLOCK {
     NODE *var;
     NODE *body;
     VALUE self;
     struct FRAME frame;
     struct SCOPE *scope;
+    struct BLOCKTAG *tag;
     VALUE klass;
-    struct tag *tag;
     int iter;
     int vmode;
     int flags;
@@ -545,12 +546,23 @@ struct BLOCK {
 
 #define BLOCK_D_SCOPE 1
 #define BLOCK_DYNAMIC 2
+#define BLOCK_ORPHAN  4
 
 static struct BLOCK *ruby_block;
 
+static struct BLOCKTAG*
+new_blktag()
+{
+    NEWOBJ(blktag, struct BLOCKTAG);
+    OBJSETUP(blktag, 0, T_BLKTAG);
+    blktag->dst = 0;
+    blktag->flags = 0;
+    return blktag;
+}
+
 #define PUSH_BLOCK(v,b) {		\
     struct BLOCK _block;		\
-    _block.tag = prot_tag;		\
+    _block.tag = new_blktag();		\
     _block.var = v;			\
     _block.body = b;			\
     _block.self = self;			\
@@ -566,19 +578,18 @@ static struct BLOCK *ruby_block;
     _block.dyna_vars = ruby_dyna_vars;	\
     ruby_block = &_block;
 
+#define POP_BLOCK_TAG(tag) do {		\
+   if ((tag)->flags & BLOCK_DYNAMIC)	\
+       (tag)->flags |= BLOCK_ORPHAN;	\
+   else					\
+       rb_gc_force_recycle((VALUE)tag); \
+} while (0)
+
 #define POP_BLOCK() 			\
+   POP_BLOCK_TAG(_block.tag);		\
    ruby_block = _block.prev; 		\
 }
 
-#define PUSH_BLOCK2(b) {		\
-    struct BLOCK * volatile _old;	\
-    _old = ruby_block;			\
-    ruby_block = b;
-
-#define POP_BLOCK2() 			\
-   ruby_block = _old;	 		\
-}
-
 struct RVarmap *ruby_dyna_vars;
 #define PUSH_VARS() {			\
     struct RVarmap * volatile _old;	\
@@ -586,6 +597,8 @@ struct RVarmap *ruby_dyna_vars;
     ruby_dyna_vars = 0;
 
 #define POP_VARS()			\
+   if (_old && (ruby_scope->flag & SCOPE_DONT_RECYCLE)) \
+       FL_SET(_old, DVAR_DONT_RECYCLE); \
     ruby_dyna_vars = _old;		\
 }
 
@@ -739,7 +752,6 @@ static struct tag *prot_tag;
     _tag.frame = ruby_frame;		\
     _tag.iter = ruby_iter;		\
     _tag.prev = prot_tag;		\
-    _tag.retval = Qnil;			\
     _tag.scope = ruby_scope;		\
     _tag.tag = ptag;			\
     _tag.dst = 0;			\
@@ -785,6 +797,11 @@ static VALUE ruby_wrapper;	/* security wrapper */
 
 #define POP_CLASS() ruby_class = _class; }
 
+static NODE *ruby_cref = 0;
+static NODE *top_cref;
+#define PUSH_CREF(c) ruby_cref = rb_node_newnode(NODE_CREF,(c),0,ruby_cref)
+#define POP_CREF() ruby_cref = ruby_cref->nd_next
+
 #define PUSH_SCOPE() {			\
     volatile int _vmode = scope_vmode;	\
     struct SCOPE * volatile _old;	\
@@ -1011,7 +1028,9 @@ ruby_init()
 	rb_call_inits();
 	ruby_class = rb_cObject;
 	ruby_frame->self = ruby_top_self;
-	ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,rb_cObject,0,0);
+	top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0);
+	ruby_cref = top_cref;
+	ruby_frame->cbase = (VALUE)ruby_cref;
 	rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self));
 #ifdef __MACOS__
 	_macruby_init();
@@ -1051,7 +1070,7 @@ static int
 error_handle(ex)
     int ex;
 {
-    switch (ex & 0xf) {
+    switch (ex & TAG_MASK) {
       case 0:
 	ex = 0;
 	break;
@@ -1122,9 +1141,13 @@ void rb_exec_end_proc _((void));
 void
 ruby_finalize()
 {
-    rb_trap_exit();
-    rb_exec_end_proc();
-    rb_gc_call_finalizer_at_exit();
+    PUSH_TAG(PROT_NONE);
+    if (EXEC_TAG() == 0) {
+	rb_trap_exit();
+	rb_exec_end_proc();
+	rb_gc_call_finalizer_at_exit();
+    }
+    POP_TAG();
 }
 
 void
@@ -1235,6 +1258,7 @@ rb_eval_string_wrap(str, state)
 {
     int status;
     VALUE self = ruby_top_self;
+    VALUE wrapper = ruby_wrapper;
     VALUE val;
 
     PUSH_CLASS();
@@ -1246,6 +1270,7 @@ rb_eval_string_wrap(str, state)
     ruby_top_self = self;
 
     POP_CLASS();
+    ruby_wrapper = wrapper;
     if (state) {
 	*state = status;
     }
@@ -1255,6 +1280,34 @@ rb_eval_string_wrap(str, state)
     return val;
 }
 
+static void
+jump_tag_but_local_jump(state)
+    int state;
+{
+    switch (state) {
+      case 0:
+	break;
+      case TAG_RETURN:
+	rb_raise(rb_eLocalJumpError, "unexpected return");
+	break;
+      case TAG_NEXT:
+	rb_raise(rb_eLocalJumpError, "unexpected next");
+	break;
+      case TAG_BREAK:
+	rb_raise(rb_eLocalJumpError, "unexpected break");
+	break;
+      case TAG_REDO:
+	rb_raise(rb_eLocalJumpError, "unexpected redo");
+	break;
+      case TAG_RETRY:
+	rb_raise(rb_eLocalJumpError, "retry outside of rescue clause");
+	break;
+      default:
+	JUMP_TAG(state);
+	break;
+    }
+}
+
 VALUE
 rb_eval_cmd(cmd, arg)
     VALUE cmd, arg;
@@ -1290,28 +1343,7 @@ rb_eval_cmd(cmd, arg)
     POP_TAG();
     POP_CLASS();
 
-    switch (state) {
-      case 0:
-	break;
-      case TAG_RETURN:
-	rb_raise(rb_eLocalJumpError, "unexpected return");
-	break;
-      case TAG_NEXT:
-	rb_raise(rb_eLocalJumpError, "unexpected next");
-	break;
-      case TAG_BREAK:
-	rb_raise(rb_eLocalJumpError, "unexpected break");
-	break;
-      case TAG_REDO:
-	rb_raise(rb_eLocalJumpError, "unexpected redo");
-	break;
-      case TAG_RETRY:
-	rb_raise(rb_eLocalJumpError, "retry outside of rescue clause");
-	break;
-      default:
-	JUMP_TAG(state);
-	break;
-    }
+    jump_tag_but_local_jump(state);
     return val;
 }
 
@@ -1373,17 +1405,18 @@ superclass(self, node)
 #define ruby_cbase (RNODE(ruby_frame->cbase)->nd_clss)
 
 static VALUE
-ev_const_defined(cref, id)
+ev_const_defined(cref, id, self)
     NODE *cref;
     ID id;
+    VALUE self;
 {
     NODE *cbase = cref;
 
-    while (cbase && cbase->nd_clss != rb_cObject) {
+    while (cbase && cbase->nd_next) {
 	struct RClass *klass = RCLASS(cbase->nd_clss);
 
-	if (klass->iv_tbl &&
-	    st_lookup(klass->iv_tbl, id, 0)) {
+	if (NIL_P(klass)) return rb_const_defined(CLASS_OF(self), id);
+	if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) {
 	    return Qtrue;
 	}
 	cbase = cbase->nd_next;
@@ -1392,16 +1425,18 @@ ev_const_defined(cref, id)
 }
 
 static VALUE
-ev_const_get(cref, id)
+ev_const_get(cref, id, self)
     NODE *cref;
     ID id;
+    VALUE self;
 {
     NODE *cbase = cref;
     VALUE result;
 
-    while (cbase && cbase->nd_clss != rb_cObject) {
+    while (cbase && cbase->nd_next) {
 	struct RClass *klass = RCLASS(cbase->nd_clss);
 
+	if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id);
 	if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) {
 	    return result;
 	}
@@ -1410,35 +1445,14 @@ ev_const_get(cref, id)
     return rb_const_get(cref->nd_clss, id);
 }
 
-static VALUE
-ev_const_set(cref, id, val)
-    NODE *cref;
-    ID id;
-    VALUE val;
-{
-    NODE *cbase = cref;
-
-    while (cbase && cbase->nd_clss != rb_cObject) {
-	struct RClass *klass = RCLASS(cbase->nd_clss);
-
-	if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) {
-	    st_insert(klass->iv_tbl, id, val);
-	    return val;
-	}
-	cbase = cbase->nd_next;
-    }
-    rb_const_assign(cbase->nd_clss, id, val);
-    return val;
-}
-
 static VALUE
 rb_mod_nesting()
 {
     NODE *cbase = RNODE(ruby_frame->cbase);
     VALUE ary = rb_ary_new();
 
-    while (cbase && cbase->nd_clss != rb_cObject) {
-	rb_ary_push(ary, cbase->nd_clss);
+    while (cbase && cbase->nd_next) {
+	if (!NIL_P(cbase->nd_clss)) rb_ary_push(ary, cbase->nd_clss);
 	cbase = cbase->nd_next;
     }
     return ary;
@@ -1450,12 +1464,12 @@ rb_mod_s_constants()
     NODE *cbase = RNODE(ruby_frame->cbase);
     VALUE ary = rb_ary_new();
 
-    while (cbase && cbase->nd_clss != rb_cObject) {
-	rb_mod_const_at(cbase->nd_clss, ary);
+    while (cbase) {
+	if (!NIL_P(cbase->nd_clss)) rb_mod_const_at(cbase->nd_clss, ary);
 	cbase = cbase->nd_next;
     }
 
-    rb_mod_const_of(ruby_cbase, ary);
+    if (!NIL_P(ruby_cbase)) rb_mod_const_of(ruby_cbase, ary);
     return ary;
 }
 
@@ -1576,22 +1590,32 @@ rb_mod_alias_method(mod, newname, oldname)
     return mod;
 }
 
+static NODE*
+copy_node_scope(node, rval)
+    NODE *node;
+    VALUE rval;
+{
+    NODE *copy = rb_node_newnode(NODE_SCOPE,0,rval,node->nd_next);
+
+    if (node->nd_tbl) {
+	copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1);
+	MEMCPY(copy->nd_tbl, node->nd_tbl, ID, node->nd_tbl[0]+1);
+    }
+    else {
+	copy->nd_tbl = 0;
+    }
+    return copy;
+}
+
 #ifdef C_ALLOCA
 # define TMP_PROTECT NODE * volatile tmp__protect_tmp=0
 # define TMP_ALLOC(n)							\
     (tmp__protect_tmp = rb_node_newnode(NODE_ALLOCA,			\
 			     ALLOC_N(VALUE,n),tmp__protect_tmp,n),	\
      (void*)tmp__protect_tmp->nd_head)
-# define TMP_PROTECT_END do {\
-    if (tmp__protect_tmp) {\
-	rb_gc_force_recycle((VALUE)tmp__protect_tmp);\
-	alloca(0);\
-    }\
-} while (0)
 #else
 # define TMP_PROTECT typedef int foobazzz
 # define TMP_ALLOC(n) ALLOCA_N(VALUE,n)
-# define TMP_PROTECT_END
 #endif
 
 #define SETUP_ARGS(anode) {\
@@ -1776,12 +1800,18 @@ is_defined(self, node, buf)
 	break;
 
       case NODE_CONST:
-	if (ev_const_defined(RNODE(ruby_frame->cbase), node->nd_vid)) {
+	if (ev_const_defined(RNODE(ruby_frame->cbase), node->nd_vid, self)) {
 	    return "constant";
 	}
 	break;
 
       case NODE_CVAR:
+	if (NIL_P(ruby_cbase)) {
+	    if (rb_cvar_defined(CLASS_OF(self), node->nd_vid)) {
+		return "class variable";
+	    }
+	    break;
+	}
 	if (!FL_TEST(ruby_cbase, FL_SINGLETON)) {
 	    if (rb_cvar_defined(ruby_cbase, node->nd_vid)) {
 		return "class variable";
@@ -1821,14 +1851,14 @@ is_defined(self, node, buf)
 	break;
 
       case NODE_NTH_REF:
-	if (rb_reg_nth_defined(node->nd_nth, MATCH_DATA)) {
+	if (RTEST(rb_reg_nth_defined(node->nd_nth, MATCH_DATA))) {
 	    sprintf(buf, "$%d", node->nd_nth);
 	    return buf;
 	}
 	break;
 
       case NODE_BACK_REF:
-	if (rb_reg_nth_defined(0, MATCH_DATA)) {
+	if (RTEST(rb_reg_nth_defined(0, MATCH_DATA))) {
 	    sprintf(buf, "$%c", node->nd_nth);
 	    return buf;
 	}
@@ -2207,15 +2237,14 @@ rb_eval(self, n)
       case NODE_FOR:
 	{
 	  iter_retry:
-	    PUSH_BLOCK(node->nd_var, node->nd_body);
 	    PUSH_TAG(PROT_FUNC);
+	    PUSH_BLOCK(node->nd_var, node->nd_body);
 
 	    state = EXEC_TAG();
 	    if (state == 0) {
+		PUSH_ITER(ITER_PRE);
 		if (nd_type(node) == NODE_ITER) {
-		    PUSH_ITER(ITER_PRE);
 		    result = rb_eval(self, node->nd_iter);
-		    POP_ITER();
 		}
 		else {
 		    VALUE recv;
@@ -2223,13 +2252,14 @@ rb_eval(self, n)
 		    int line = ruby_sourceline;
 
 		    _block.flags &= ~BLOCK_D_SCOPE;
+		    BEGIN_CALLARGS;
 		    recv = rb_eval(self, node->nd_iter);
-		    PUSH_ITER(ITER_PRE);
+		    END_CALLARGS;
 		    ruby_sourcefile = file;
 		    ruby_sourceline = line;
 		    result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
-		    POP_ITER();
 		}
+		POP_ITER();
 	    }
 	    else if (_block.tag->dst == state) {
 		state &= TAG_MASK;
@@ -2237,8 +2267,8 @@ rb_eval(self, n)
 		    result = prot_tag->retval;
 		}
 	    }
-	    POP_TAG();
 	    POP_BLOCK();
+	    POP_TAG();
 	    switch (state) {
 	      case 0:
 		break;
@@ -2348,9 +2378,11 @@ rb_eval(self, n)
 	POP_TAG();
 	if (node->nd_ensr) {
 	    VALUE retval = prot_tag->retval; /* save retval */
+	    VALUE errinfo = ruby_errinfo;
 
 	    rb_eval(self, node->nd_ensr);
 	    return_value(retval);
+	    ruby_errinfo = errinfo;
 	}
 	if (state) JUMP_TAG(state);
 	break;
@@ -2460,7 +2492,6 @@ rb_eval(self, n)
 	    END_CALLARGS;
 
 	    result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
-	    TMP_PROTECT_END;
 	}
 	break;
 
@@ -2474,7 +2505,6 @@ rb_eval(self, n)
 	    END_CALLARGS;
 
 	    result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
-	    TMP_PROTECT_END;
 	}
 	break;
 
@@ -2507,13 +2537,13 @@ rb_eval(self, n)
 			     ruby_frame->self, ruby_frame->last_func,
 			     argc, argv, 3);
 	    POP_ITER();
-	    TMP_PROTECT_END;
 	}
 	break;
 
       case NODE_SCOPE:
 	{
 	    struct FRAME frame;
+	    NODE *saved_cref = 0;
 
 	    frame = *ruby_frame;
 	    frame.tmp = ruby_frame;
@@ -2521,7 +2551,11 @@ rb_eval(self, n)
 
 	    PUSH_SCOPE();
 	    PUSH_TAG(PROT_NONE);
-	    if (node->nd_rval) ruby_frame->cbase = node->nd_rval;
+	    if (node->nd_rval) {
+		saved_cref = ruby_cref;
+		ruby_cref = (NODE*)node->nd_rval;
+		ruby_frame->cbase = node->nd_rval;
+	    }
 	    if (node->nd_tbl) {
 		VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
 		*vars++ = (VALUE)node;
@@ -2539,6 +2573,8 @@ rb_eval(self, n)
 	    POP_TAG();
 	    POP_SCOPE();
 	    ruby_frame = frame.tmp;
+	    if (saved_cref)
+		ruby_cref = saved_cref;
 	    if (state) JUMP_TAG(state);
 	}
 	break;
@@ -2569,7 +2605,6 @@ rb_eval(self, n)
 	    argv[argc-1] = val;
 	    val = rb_funcall2(recv, aset, argc, argv);
 	    result = val;
-	    TMP_PROTECT_END;
 	}
 	break;
 
@@ -2606,10 +2641,12 @@ rb_eval(self, n)
 	goto again;
 
       case NODE_OP_ASGN_OR:
-	result = rb_eval(self, node->nd_head);
-	if (RTEST(result)) break;
-	node = node->nd_value;
-	goto again;
+	if ((node->nd_aid && !rb_ivar_defined(self, node->nd_aid)) ||
+	    !RTEST(result = rb_eval(self, node->nd_head))) {
+	    node = node->nd_value;
+	    goto again;
+	}
+	break;
 
       case NODE_MASGN:
 	result = massign(self, node, rb_eval(self, node->nd_value),0);
@@ -2688,10 +2725,14 @@ rb_eval(self, n)
 	break;
 
       case NODE_CONST:
-	result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid);
+	result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid, self);
 	break;
 
       case NODE_CVAR:		/* normal method */
+	if (NIL_P(ruby_cbase)) {
+	    result = rb_cvar_get(CLASS_OF(self), node->nd_vid);
+	    break;
+	}
 	if (!FL_TEST(ruby_cbase, FL_SINGLETON)) {
 	    result = rb_cvar_get(ruby_cbase, node->nd_vid);
 	    break;
@@ -2878,7 +2919,7 @@ rb_eval(self, n)
 
       case NODE_DEFN:
 	if (node->nd_defn) {
-	    NODE *body;
+	    NODE *body,  *defn;
 	    VALUE origin;
 	    int noex;
 
@@ -2920,11 +2961,13 @@ rb_eval(self, n)
 	    if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) {
 		noex |= NOEX_UNDEF;
 	    }
-	    rb_add_method(ruby_class, node->nd_mid, node->nd_defn, noex);
+
+	    defn = copy_node_scope(node->nd_defn, ruby_cref);
+	    rb_add_method(ruby_class, node->nd_mid, defn, noex);
 	    rb_clear_cache_by_id(node->nd_mid);
 	    if (scope_vmode == SCOPE_MODFUNC) {
 		rb_add_method(rb_singleton_class(ruby_class),
-			      node->nd_mid, node->nd_defn, NOEX_PUBLIC);
+			      node->nd_mid, defn, NOEX_PUBLIC);
 		rb_funcall(ruby_class, singleton_added, 1, ID2SYM(node->nd_mid));
 	    }
 	    if (FL_TEST(ruby_class, FL_SINGLETON)) {
@@ -2942,7 +2985,7 @@ rb_eval(self, n)
 	if (node->nd_defn) {
 	    VALUE recv = rb_eval(self, node->nd_recv);
 	    VALUE klass;
-	    NODE *body = 0;
+	    NODE *body = 0, *defn;
 
 	    if (rb_safe_level() >= 4 && !OBJ_TAINTED(recv)) {
 		rb_raise(rb_eSecurityError, "Insecure; can't define singleton method");
@@ -2964,7 +3007,9 @@ rb_eval(self, n)
 		    rb_warning("redefine %s", rb_id2name(node->nd_mid));
 		}
 	    }
-	    rb_add_method(klass, node->nd_mid, node->nd_defn, 
+	    defn = copy_node_scope(node->nd_defn, ruby_cref);
+	    defn->nd_rval = (VALUE)ruby_cref;
+	    rb_add_method(klass, node->nd_mid, defn, 
 			  NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
 	    rb_clear_cache_by_id(node->nd_mid);
 	    rb_funcall(recv, singleton_added, 1, ID2SYM(node->nd_mid));
@@ -3162,16 +3207,11 @@ module_setup(module, n)
     frame.tmp = ruby_frame;
     ruby_frame = &frame;
 
-    /* fill c-ref */
-    node->nd_clss = module;
-    node = node->nd_body;
-
     PUSH_CLASS();
     ruby_class = module;
     PUSH_SCOPE();
     PUSH_VARS();
 
-    if (node->nd_rval) ruby_frame->cbase = node->nd_rval;
     if (node->nd_tbl) {
 	VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1);
 	*vars++ = (VALUE)node;
@@ -3184,6 +3224,8 @@ module_setup(module, n)
 	ruby_scope->local_tbl  = 0;
     }
 
+    PUSH_CREF(module);
+    ruby_frame->cbase = (VALUE)ruby_cref;
     PUSH_TAG(PROT_NONE);
     if ((state = EXEC_TAG()) == 0) {
 	if (trace_func) {
@@ -3194,6 +3236,7 @@ module_setup(module, n)
 	result = rb_eval(ruby_class, node->nd_next);
     }
     POP_TAG();
+    POP_CREF();
     POP_VARS();
     POP_SCOPE();
     POP_CLASS();
@@ -3203,7 +3246,6 @@ module_setup(module, n)
 	call_trace_func("end", file, line, 0,
 			ruby_frame->last_func, ruby_frame->last_class);
     }
-    TMP_PROTECT_END;
     if (state) JUMP_TAG(state);
 
     return result;
@@ -3461,13 +3503,14 @@ rb_yield_0(val, self, klass, acheck)
 {
     NODE *node;
     volatile VALUE result = Qnil;
+    volatile VALUE old_cref;
     struct BLOCK *block;
     struct SCOPE *old_scope;
     struct FRAME frame;
     int state;
     static unsigned serial = 1;
 
-    if (!ruby_frame->iter || !ruby_block) {
+    if (!(rb_block_given_p() || rb_f_block_given_p()) || !ruby_block) {
 	rb_raise(rb_eLocalJumpError, "yield called out of block");
     }
 
@@ -3477,6 +3520,8 @@ rb_yield_0(val, self, klass, acheck)
     frame = block->frame;
     frame.prev = ruby_frame;
     ruby_frame = &(frame);
+    old_cref = (VALUE)ruby_cref;
+    ruby_cref = (NODE*)ruby_frame->cbase;
     old_scope = ruby_scope;
     ruby_scope = block->scope;
     ruby_block = block->prev;
@@ -3489,7 +3534,7 @@ rb_yield_0(val, self, klass, acheck)
 	ruby_dyna_vars = block->dyna_vars;
     }
     ruby_class = klass?klass:block->klass;
-    if (!self) self = block->self;
+    if (!klass) self = block->self;
     node = block->body;
 
     if (block->var) {
@@ -3518,6 +3563,13 @@ rb_yield_0(val, self, klass, acheck)
 	POP_TAG();
 	if (state) goto pop_state;
     }
+    else {
+	/* argument adjust for proc_call etc. */
+	if (acheck && val != Qundef &&
+	    TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) {
+	    val = RARRAY(val)->ptr[0];
+	}
+    }
 
     PUSH_ITER(block->iter);
     PUSH_TAG(PROT_NONE);
@@ -3526,7 +3578,7 @@ rb_yield_0(val, self, klass, acheck)
 	if (!node) {
 	    result = Qnil;
 	}
-	else if (nd_type(node) == NODE_CFUNC) {
+	else if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) {
 	    if (val == Qundef) val = rb_ary_new2(0);
 	    result = (*node->nd_cfnc)(val, node->nd_tval, self);
 	}
@@ -3548,7 +3600,7 @@ rb_yield_0(val, self, klass, acheck)
 	  case TAG_RETURN:
 	    state |= (serial++ << 8);
 	    state |= 0x10;
-	    block->tag->dst = state; 
+	    block->tag->dst = state;
 	    break;
 	  default:
 	    break;
@@ -3558,26 +3610,57 @@ rb_yield_0(val, self, klass, acheck)
   pop_state:
     POP_ITER();
     POP_CLASS();
-    if ((block->flags & BLOCK_D_SCOPE) &&
+#if 0
+    if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) &&
+	(!(ruby_scope->flags & SCOPE_DONT_RECYCLE) ||
+	 !(block->tag->flags & BLOCK_DYNAMIC) ||
+	 !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE))) {
+	struct RVarmap *vars, *tmp;
+
+	if (ruby_dyna_vars->id == 0) {
+	    vars = ruby_dyna_vars->next;
+	    rb_gc_force_recycle((VALUE)ruby_dyna_vars);
+	    while (vars && vars->id != 0) {
+		tmp = vars->next;
+		rb_gc_force_recycle((VALUE)vars);
+		vars = tmp;
+	    }
+	}
+    }
+#else
+    if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) &&
 	!FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) {
 	struct RVarmap *vars = ruby_dyna_vars;
 
-	while (vars && vars->id != 0) {
-	    struct RVarmap *tmp = vars->next;
-	    rb_gc_force_recycle((VALUE)vars);
-	    vars = tmp;
-	}
-	if (ruby_dyna_vars && ruby_dyna_vars->id == 0) {
+	if (ruby_dyna_vars->id == 0) {
+	    vars = ruby_dyna_vars->next;
 	    rb_gc_force_recycle((VALUE)ruby_dyna_vars);
+	    while (vars && vars->id != 0) {
+		struct RVarmap *tmp = vars->next;
+		rb_gc_force_recycle((VALUE)vars);
+		vars = tmp;
+	    }
 	}
     }
+#endif
     POP_VARS();
     ruby_block = block;
     ruby_frame = ruby_frame->prev;
+    ruby_cref = (NODE*)old_cref;
     if (ruby_scope->flag & SCOPE_DONT_RECYCLE)
        scope_dup(old_scope);
     ruby_scope = old_scope;
-    if (state) JUMP_TAG(state);
+    if (state) {
+	if (!block->tag) {
+	    switch (state & TAG_MASK) {
+	      case TAG_BREAK:
+	      case TAG_RETURN:
+		jump_tag_but_local_jump(state & TAG_MASK);
+		break;
+	    }
+	}
+	JUMP_TAG(state);
+    }
     return result;
 }
 
@@ -3744,7 +3827,7 @@ rb_iterate(it_proc, data1, bl_proc, data2)
 {
     int state;
     volatile VALUE retval = Qnil;
-    NODE *node = NEW_CFUNC(bl_proc, data2);
+    NODE *node = NEW_IFUNC(bl_proc, data2);
     VALUE self = ruby_top_self;
 
   iter_retry:
@@ -3809,7 +3892,6 @@ handle_rescue(self, node)
 	if (rb_obj_is_kind_of(ruby_errinfo, argv[0])) return 1;
 	argv++;
     }
-    TMP_PROTECT_END;
     return 0;
 }
 
@@ -3921,9 +4003,9 @@ rb_ensure(b_proc, data1, e_proc, data2)
 	result = (*b_proc)(data1);
     }
     POP_TAG();
-    retval = prot_tag->retval;	/* save retval */
+    retval = prot_tag ? prot_tag->retval : Qnil;	/* save retval */
     (*e_proc)(data2);
-    return_value(retval);
+    if (prot_tag) return_value(retval);
 
     if (state) JUMP_TAG(state);
     return result;
@@ -4053,6 +4135,7 @@ static int STACK_LEVEL_MAX = 65535;
 #ifdef __human68k__
 extern int _stacksize;
 # define STACK_LEVEL_MAX (_stacksize - 4096)
+#undef HAVE_GETRLIMIT
 #else
 #ifdef HAVE_GETRLIMIT
 static int STACK_LEVEL_MAX = 655300;
@@ -4072,7 +4155,7 @@ stack_length(p)
     alloca(0);
 # define STACK_END (&stack_end)
 #else
-# if defined(__GNUC__) && !defined(__alpha__) && !defined(__APPLE__)
+# if defined(__GNUC__) && (defined(__i386__) || defined(__m68k__))
     VALUE *stack_end = __builtin_frame_address(0);
 # else
     VALUE *stack_end = alloca(1);
@@ -4081,7 +4164,7 @@ stack_length(p)
 #endif
     if (p) *p = STACK_END;
 
-#ifdef sparc
+#ifdef __sparc__
     return rb_gc_stack_start - STACK_END + 0x80;
 #else
     return (STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END
@@ -4266,14 +4349,19 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper)
 	result = proc_call(body->nd_cval, rb_ary_new4(argc, argv));
 	break;
 
-      default:
+      case NODE_SCOPE:
 	{
 	    int state;
 	    VALUE *local_vars;	/* OK */
+	    NODE *saved_cref = 0;
 
 	    PUSH_SCOPE();
 
-	    if (body->nd_rval) ruby_frame->cbase = body->nd_rval;
+	    if (body->nd_rval) {
+		saved_cref = ruby_cref;
+		ruby_cref = (NODE*)body->nd_rval;
+		ruby_frame->cbase = body->nd_rval;
+	    }
 	    if (body->nd_tbl) {
 		local_vars = TMP_ALLOC(body->nd_tbl[0]+1);
 		*local_vars++ = (VALUE)body;
@@ -4345,10 +4433,13 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper)
 			    rb_eval(recv, opt);
 			}
 			if (node->nd_rest >= 0) {
+			    VALUE v;
+
 			    if (argc > 0)
-				local_vars[node->nd_rest]=rb_ary_new4(argc,argv);
+				v = rb_ary_new4(argc,argv);
 			    else
-				local_vars[node->nd_rest]=rb_ary_new2(0);
+				v = rb_ary_new2(0);
+			    local_vars[node->nd_rest] = v;
 			}
 		    }
 		}
@@ -4366,6 +4457,7 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper)
 	    POP_TAG();
 	    POP_VARS();
 	    POP_SCOPE();
+	    ruby_cref = saved_cref;
 	    if (trace_func) {
 		char *file = ruby_frame->prev->file;
 		int line = ruby_frame->prev->line;
@@ -4379,27 +4471,24 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper)
 	      case 0:
 		break;
 
-	      case TAG_NEXT:
-		rb_raise(rb_eLocalJumpError, "unexpected next");
-		break;
-	      case TAG_BREAK:
-		rb_raise(rb_eLocalJumpError, "unexpected break");
-		break;
-	      case TAG_REDO:
-		rb_raise(rb_eLocalJumpError, "unexpected redo");
-		break;
 	      case TAG_RETRY:
-		if (!rb_block_given_p()) {
-		    rb_raise(rb_eLocalJumpError, "retry outside of rescue clause");
+		if (rb_block_given_p()) {
+                   JUMP_TAG(state);
 		}
+		/* fall through */
 	      default:
-		JUMP_TAG(state);
+		jump_tag_but_local_jump(state);
+		break;
 	    }
 	}
+	break;
+
+      default:
+	rb_bug("unknown node type %d", nd_type(body));
+	break;
     }
     POP_FRAME();
     POP_ITER();
-    TMP_PROTECT_END;
     return result;
 }
 
@@ -4416,6 +4505,9 @@ rb_call(klass, recv, mid, argc, argv, scope)
     ID     id = mid;
     struct cache_entry *ent;
 
+    if (!klass) {
+	rb_raise(rb_eNotImpError, "method call on terminated object");
+    }
     /* is it in the method cache? */
     ent = cache + EXPR1(klass, mid);
     if (ent->mid == mid && ent->klass == klass) {
@@ -4683,6 +4775,7 @@ eval(self, src, scope, file, line)
     struct SCOPE * volatile old_scope;
     struct BLOCK * volatile old_block;
     struct RVarmap * volatile old_dyna_vars;
+    VALUE volatile old_cref;
     int volatile old_vmode;
     struct FRAME frame;
     char *filesave = ruby_sourcefile;
@@ -4701,7 +4794,6 @@ eval(self, src, scope, file, line)
 	}
 
 	Data_Get_Struct(scope, struct BLOCK, data);
-
 	/* PUSH BLOCK from data */
 	frame = data->frame;
 	frame.tmp = ruby_frame;	/* gc protection */
@@ -4714,6 +4806,8 @@ eval(self, src, scope, file, line)
 	ruby_dyna_vars = data->dyna_vars;
 	old_vmode = scope_vmode;
 	scope_vmode = data->vmode;
+	old_cref = (VALUE)ruby_cref;
+	ruby_cref = (NODE*)ruby_frame->cbase;
 
 	self = data->self;
 	ruby_frame->iter = data->iter;
@@ -4747,14 +4841,34 @@ eval(self, src, scope, file, line)
     POP_CLASS();
     ruby_in_eval--;
     if (!NIL_P(scope)) {
+	int dont_recycle = ruby_scope->flag & SCOPE_DONT_RECYCLE;
+
+	ruby_cref  = (NODE*)old_cref;
 	ruby_frame = frame.tmp;
-	if (ruby_scope->flag & SCOPE_DONT_RECYCLE)
-           scope_dup(old_scope);
 	ruby_scope = old_scope;
 	ruby_block = old_block;
 	ruby_dyna_vars = old_dyna_vars;
 	data->vmode = scope_vmode; /* write back visibility mode */
 	scope_vmode = old_vmode;
+	if (dont_recycle) {
+	   struct tag *tag;
+	   struct RVarmap *vars;
+
+           scope_dup(ruby_scope);
+	   for (tag=prot_tag; tag; tag=tag->prev) {
+	       scope_dup(tag->scope);
+	   }
+	   if (ruby_block) {
+	       struct BLOCK *block = ruby_block;
+	       while (block) {
+		   block->tag->flags |= BLOCK_DYNAMIC;
+		   block = block->prev;
+	       }
+	   }
+	   for (vars = ruby_dyna_vars; vars; vars = vars->next) {
+	       FL_SET(vars, DVAR_DONT_RECYCLE);
+	   }
+	}
     }
     else {
 	ruby_frame->iter = iter;
@@ -4849,6 +4963,7 @@ exec_under(func, under, args)
     if (ruby_cbase != under) {
 	ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,ruby_frame->cbase);
     }
+    PUSH_CREF(under);
 
     mode = scope_vmode;
     SCOPE_SET(SCOPE_PUBLIC);
@@ -4857,6 +4972,7 @@ exec_under(func, under, args)
 	val = (*func)(args);
     }
     POP_TAG();
+    POP_CREF();
     SCOPE_SET(mode);
     POP_FRAME();
     POP_CLASS();
@@ -4932,8 +5048,6 @@ static VALUE
 yield_under(under, self)
     VALUE under, self;
 {
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(self))
-	rb_raise(rb_eSecurityError, "Insecure: can't eval");
     return exec_under(yield_under_i, under, self);
 }
 
@@ -5014,6 +5128,7 @@ rb_load(fname, wrap)
     volatile ID last_func;
     volatile VALUE wrapper = 0;
     volatile VALUE self = ruby_top_self;
+    NODE *saved_cref = ruby_cref;
     TMP_PROTECT;
 
     if (wrap) {
@@ -5031,6 +5146,7 @@ rb_load(fname, wrap)
     PUSH_VARS();
     PUSH_CLASS();
     wrapper = ruby_wrapper;
+    ruby_cref = top_cref;
     if (!wrap) {
 	rb_secure(4);		/* should alter global state */
 	ruby_class = rb_cObject;
@@ -5041,6 +5157,7 @@ rb_load(fname, wrap)
 	ruby_class = ruby_wrapper = rb_module_new();
 	self = rb_obj_clone(ruby_top_self);
 	rb_extend_object(self, ruby_class);
+	PUSH_CREF(ruby_wrapper);
     }
     PUSH_FRAME();
     ruby_frame->last_func = 0;
@@ -5083,6 +5200,7 @@ rb_load(fname, wrap)
 	    free(ruby_scope->local_tbl);
     }
     POP_TAG();
+    ruby_cref = saved_cref;
     POP_SCOPE();
     POP_FRAME();
     POP_CLASS();
@@ -5092,8 +5210,7 @@ rb_load(fname, wrap)
 	ruby_nerrs = 0;
 	rb_exc_raise(ruby_errinfo);
     }
-    TMP_PROTECT_END;
-    if (state) JUMP_TAG(state);
+    if (state) jump_tag_but_local_jump(state);
     if (!NIL_P(ruby_errinfo))	/* exception during load */
 	rb_exc_raise(ruby_errinfo);
 }
@@ -5126,6 +5243,7 @@ rb_f_load(argc, argv)
     return Qtrue;
 }
 
+VALUE ruby_dln_librefs;
 static VALUE rb_features;
 static st_table *loading_tbl;
 
@@ -5167,7 +5285,7 @@ rb_feature_p(feature, wait)
 
 	    while (st_lookup(loading_tbl, f, &th)) {
 		if (th == curr_thread) {
-		    rb_raise(rb_eLoadError, "infinite load loop -- %s", f);
+		    return Qtrue;
 		}
 		CHECK_INTS;
 		rb_thread_schedule();
@@ -5293,9 +5411,12 @@ rb_f_require(obj, fname)
 
     PUSH_TAG(PROT_NONE);
     if ((state = EXEC_TAG()) == 0) {
+	void *handle;
+
 	load = rb_str_new2(file);
 	file = RSTRING(load)->ptr;
-	dln_load(file);
+	handle = dln_load(file);
+	rb_ary_push(ruby_dln_librefs, INT2NUM((long)handle));
     }
     POP_TAG();
     if (state) JUMP_TAG(state);
@@ -5332,6 +5453,15 @@ rb_require(fname)
     return rb_f_require(Qnil, rb_str_new2(fname));
 }
 
+static void
+secure_visibility(self)
+    VALUE self;
+{
+    if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) {
+	rb_raise(rb_eSecurityError, "Insecure: can't change method visibility");
+    }
+}
+
 static void
 set_method_visibility(self, argc, argv, ex)
     VALUE self;
@@ -5341,6 +5471,7 @@ set_method_visibility(self, argc, argv, ex)
 {
     int i;
 
+    secure_visibility(self);
     for (i=0; iself);
 	rb_gc_mark(data->dyna_vars);
 	rb_gc_mark(data->klass);
+	rb_gc_mark(data->tag);
 	data = data->prev;
     }
 }
@@ -5916,6 +6055,7 @@ blk_copy_prev(block)
     struct BLOCK *block;
 {
     struct BLOCK *tmp;
+    struct RVarmap* vars;
 
     while (block->prev) {
 	tmp = ALLOC_N(struct BLOCK, 1);
@@ -5925,6 +6065,13 @@ blk_copy_prev(block)
 	    MEMCPY(tmp->frame.argv, block->prev->frame.argv, VALUE, tmp->frame.argc);
 	}
 	scope_dup(tmp->scope);
+	tmp->tag->flags |= BLOCK_DYNAMIC;
+
+	for (vars = tmp->dyna_vars; vars; vars = vars->next) {
+	    if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
+	    FL_SET(vars, DVAR_DONT_RECYCLE);
+	}
+
 	block->prev = tmp;
 	block = tmp;
     }
@@ -5980,7 +6127,7 @@ static VALUE
 rb_f_binding(self)
     VALUE self;
 {
-    struct BLOCK *data;
+    struct BLOCK *data, *p;
     struct RVarmap *vars;
     VALUE bind;
 
@@ -6002,10 +6149,14 @@ rb_f_binding(self)
     else {
 	data->prev = 0;
     }
+    data->flags |= BLOCK_DYNAMIC;
+    data->tag->flags |= BLOCK_DYNAMIC;
 
-    for (vars = data->dyna_vars; vars; vars = vars->next) {
-	if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
-	FL_SET(vars, DVAR_DONT_RECYCLE);
+    for (p = data; p; p = p->prev) {
+	for (vars = p->dyna_vars; vars; vars = vars->next) {
+	    if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
+	    FL_SET(vars, DVAR_DONT_RECYCLE);
+	}
     }
     scope_dup(data->scope);
     POP_BLOCK();
@@ -6063,11 +6214,11 @@ proc_new(klass)
     VALUE klass;
 {
     volatile VALUE proc;
-    struct BLOCK *data;
+    struct BLOCK *data, *p;
     struct RVarmap *vars;
 
     if (!rb_block_given_p() && !rb_f_block_given_p()) {
-	rb_raise(rb_eArgError, "tried to create Procedure-Object without a block");
+	rb_raise(rb_eArgError, "tried to create Proc object without a block");
     }
 
     proc = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data);
@@ -6075,7 +6226,6 @@ proc_new(klass)
 
     data->orig_thread = rb_thread_current();
     data->iter = data->prev?Qtrue:Qfalse;
-    data->tag = 0;		/* should not point into stack */
     frame_dup(&data->frame);
     if (data->iter) {
 	blk_copy_prev(data);
@@ -6084,10 +6234,13 @@ proc_new(klass)
 	data->prev = 0;
     }
     data->flags |= BLOCK_DYNAMIC;
+    data->tag->flags |= BLOCK_DYNAMIC;
 
-    for (vars = data->dyna_vars; vars; vars = vars->next) {
-	if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
-	FL_SET(vars, DVAR_DONT_RECYCLE);
+    for (p = data; p; p = p->prev) {
+	for (vars = p->dyna_vars; vars; vars = vars->next) {
+	    if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
+	    FL_SET(vars, DVAR_DONT_RECYCLE);
+	}
     }
     scope_dup(data->scope);
     proc_save_safe_level(proc);
@@ -6165,6 +6318,8 @@ proc_call(proc, args)
     old_block = ruby_block;
     _block = *data;
     ruby_block = &_block;
+    ruby_block->frame.iter = ITER_NOT;
+
     PUSH_ITER(ITER_CUR);
     ruby_frame->iter = ITER_CUR;
 
@@ -6172,17 +6327,7 @@ proc_call(proc, args)
 	args = callargs(args);
     }
 
-    if (orphan) {/* orphan procedure */
-	if (rb_block_given_p()) {
-	    ruby_block->frame.iter = ITER_CUR;
-	}
-	else {
-	    ruby_block->frame.iter = ITER_NOT;
-	}
-    }
-
     PUSH_TAG(PROT_NONE);
-    _block.tag = prot_tag;
     state = EXEC_TAG();
     if (state == 0) {
 	proc_set_safe_level(proc);
@@ -6242,6 +6387,39 @@ proc_arity(proc)
     }
 }
 
+static VALUE
+proc_eq(self, other)
+    VALUE self, other;
+{
+    struct BLOCK *data, *data2;
+
+    if (self == other) return Qtrue;
+    if (TYPE(other) != T_DATA) return Qfalse;
+    if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse;
+    if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse;
+    Data_Get_Struct(self, struct BLOCK, data);
+    Data_Get_Struct(other, struct BLOCK, data2);
+    if (data->tag == data2->tag) return Qtrue;
+    return Qfalse;
+}
+
+static VALUE
+proc_to_s(self, other)
+    VALUE self, other;
+{
+    struct BLOCK *data;
+    char *cname = rb_class2name(CLASS_OF(self));
+    VALUE str;
+
+    Data_Get_Struct(self, struct BLOCK, data);
+    str = rb_str_new(0, strlen(cname)+6+16+1); /* 6:tags 16:addr 1:eos */
+    sprintf(RSTRING(str)->ptr, "#<%s:0x%lx>", cname, data->tag);
+    RSTRING(str)->len = strlen(RSTRING(str)->ptr);
+    if (OBJ_TAINTED(self)) OBJ_TAINT(str);
+
+    return str;
+}
+
 static VALUE
 block_pass(self, node)
     VALUE self;
@@ -6278,10 +6456,11 @@ block_pass(self, node)
     ruby_frame->iter = ITER_PRE;
 
     PUSH_TAG(PROT_NONE);
-    _block.tag = prot_tag;
     state = EXEC_TAG();
     if (state == 0) {
 	proc_set_safe_level(block);
+	if (safe > ruby_safe_level)
+	    ruby_safe_level = safe;
 	result = rb_eval(self, node->nd_iter);
     }
     POP_TAG();
@@ -6300,25 +6479,33 @@ block_pass(self, node)
 		}
 		ptr = ptr->prev;
 	    }
+	    if (!ptr) {
+		state &= TAG_MASK;
+	    }
 	}
     }
     ruby_block = old_block;
     ruby_safe_level = safe;
 
-    if (state) {
-	switch (state) {/* escape from orphan procedure */
-	  case TAG_BREAK:
+    switch (state) {/* escape from orphan procedure */
+      case 0:
+	break;
+      case TAG_BREAK:
+	if (orphan) {
 	    rb_raise(rb_eLocalJumpError, "break from proc-closure");
-	    break;
-	  case TAG_RETRY:
-	    rb_raise(rb_eLocalJumpError, "retry from proc-closure");
-	    break;
-	  case TAG_RETURN:
+	}
+	break;
+      case TAG_RETRY:
+	rb_raise(rb_eLocalJumpError, "retry from proc-closure");
+	break;
+      case TAG_RETURN:
+	if (orphan) {
 	    rb_raise(rb_eLocalJumpError, "return from proc-closure");
-	    break;
 	}
+      default:
 	JUMP_TAG(state);
     }
+
     return result;
 }
 
@@ -6445,8 +6632,8 @@ method_call(argc, argv, method)
     Data_Get_Struct(method, struct METHOD, data);
     PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
     PUSH_TAG(PROT_NONE);
-    if (OBJ_TAINTED(method)) {
-	if (ruby_safe_level < 4) ruby_safe_level = 4;
+    if (OBJ_TAINTED(method) && ruby_safe_level < 4) {
+	ruby_safe_level = 4;
     }
     if ((state = EXEC_TAG()) == 0) {
 	result = rb_call0(data->klass,data->recv,data->id,argc,argv,data->body,0);
@@ -6611,7 +6798,7 @@ rb_mod_define_method(argc, argv, mod)
     VALUE mod;
 {
     ID id;
-    VALUE name, body;
+    VALUE body;
 
     if (argc == 1) {
 	id = rb_to_id(argv[0]);
@@ -6626,17 +6813,20 @@ rb_mod_define_method(argc, argv, mod)
     }
     if (TYPE(body) != T_DATA) {
 	/* type error */
+	rb_raise(rb_eTypeError, "wrong argument type (expected Proc)");
     }
     if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) {
 	rb_add_method(mod, id, NEW_DMETHOD(method_unbind(body)), NOEX_PUBLIC);
     }
-    else if (RDATA(body)->dmark != (RUBY_DATA_FUNC)blk_mark) {
+    else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) {
 	rb_add_method(mod, id, NEW_BMETHOD(body), NOEX_PUBLIC);
     }
     else {
 	/* type error */
+	rb_raise(rb_eTypeError, "wrong argument type (expected Proc)");
     }
 
+    rb_clear_cache_by_id(id);
     return body;
 }
 
@@ -6652,6 +6842,8 @@ Init_Proc()
     rb_define_method(rb_cProc, "call", proc_call, -2);
     rb_define_method(rb_cProc, "arity", proc_arity, 0);
     rb_define_method(rb_cProc, "[]", proc_call, -2);
+    rb_define_method(rb_cProc, "==", proc_eq, 1);
+    rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
     rb_define_global_function("proc", rb_f_lambda, 0);
     rb_define_global_function("lambda", rb_f_lambda, 0);
     rb_define_global_function("binding", rb_f_binding, 0);
@@ -6725,6 +6917,7 @@ struct thread {
     struct tag *tag;
     VALUE klass;
     VALUE wrapper;
+    NODE *cref;
 
     int flags;		/* misc. states (vmode/rb_trap_immediate/raised) */
 
@@ -6758,7 +6951,9 @@ struct thread {
     VALUE thread;
 };
 
-#define THREAD_RAISED 0x200
+#define THREAD_RAISED 0x200	 /* temporary flag */
+#define THREAD_TERMINATING 0x400 /* persistent flag */
+#define THREAD_FLAGS_MASK  0x400 /* mask for persistent flags */
 
 #define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
 #define END_FOREACH_FROM(f,x) } while (x != f)
@@ -6766,6 +6961,37 @@ struct thread {
 #define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
 #define END_FOREACH(x)    END_FOREACH_FROM(curr_thread,x)
 
+/* $SAFE accessor */
+void
+rb_set_safe_level(level)
+    int level;
+{
+    if (level > ruby_safe_level) {
+	ruby_safe_level = level;
+	curr_thread->safe = level;
+    }
+}
+
+static VALUE
+safe_getter()
+{
+    return INT2NUM(ruby_safe_level);
+}
+
+static void
+safe_setter(val)
+    VALUE val;
+{
+    int level = NUM2INT(val);
+
+    if (level < ruby_safe_level) {
+	rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d",
+		 ruby_safe_level, level);
+    }
+    ruby_safe_level = level;
+    curr_thread->safe = level;
+}
+
 /* Return the current time as a floating-point number */
 static double
 timeofday()
@@ -6791,6 +7017,7 @@ thread_mark(th)
 
     rb_gc_mark(th->klass);
     rb_gc_mark(th->wrapper);
+    rb_gc_mark(th->cref);
 
     rb_gc_mark(th->scope);
     rb_gc_mark(th->dyna_vars);
@@ -6868,6 +7095,8 @@ rb_thread_check(data)
     return (rb_thread_t)RDATA(data)->data;
 }
 
+static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t));
+
 static int   th_raise_argc;
 static VALUE th_raise_argv[2];
 static char *th_raise_file;
@@ -6906,9 +7135,11 @@ rb_thread_save_context(th)
     th->scope = ruby_scope;
     th->klass = ruby_class;
     th->wrapper = ruby_wrapper;
+    th->cref = ruby_cref;
     th->dyna_vars = ruby_dyna_vars;
     th->block = ruby_block;
-    th->flags = scope_vmode | (rb_trap_immediate<<8);
+    th->flags &= THREAD_FLAGS_MASK;
+    th->flags |= (rb_trap_immediate<<8) | scope_vmode;
     th->iter = ruby_iter;
     th->tag = prot_tag;
     th->tracing = tracing;
@@ -6995,6 +7226,7 @@ rb_thread_restore_context(th, exit)
     ruby_scope = th->scope;
     ruby_class = th->klass;
     ruby_wrapper = th->wrapper;
+    ruby_cref = th->cref;
     ruby_dyna_vars = th->dyna_vars;
     ruby_block = th->block;
     scope_vmode = th->flags&SCOPE_MASK;
@@ -7055,13 +7287,8 @@ rb_thread_fd_close(fd)
 
     FOREACH_THREAD(th) {
 	if ((th->wait_for & WAIT_FD) && fd == th->fd) {
-	    th_raise_argc = 1;
-	    th_raise_argv[0] = rb_exc_new2(rb_eIOError, "stream closed");
-	    th_raise_file = ruby_sourcefile;
-	    th_raise_line = ruby_sourceline;
-	    curr_thread = th;
-	    rb_thread_ready(th);
-	    rb_thread_restore_context(curr_thread, RESTORE_RAISE);
+	    VALUE exc = rb_exc_new2(rb_eIOError, "stream closed");
+	    rb_thread_raise(1, &exc, th);
 	}
     }
     END_FOREACH(th);
@@ -7220,6 +7447,9 @@ rb_thread_schedule()
 		delay = th_delay;
 		need_select = 1;
 	    }
+	    if (th->delay == DELAY_INFTY) {
+		need_select = 1;
+	    }
 	}
     }
     END_FOREACH_FROM(curr, th);
@@ -7323,6 +7553,7 @@ rb_thread_schedule()
 	next->gid = 0;
 	rb_thread_ready(next);
 	next->status = THREAD_TO_KILL;
+	rb_thread_save_context(curr_thread);
 	rb_thread_deadlock();
     }
     next->wait_for = 0;
@@ -7339,8 +7570,11 @@ rb_thread_schedule()
 
     curr_thread = next;
     if (next->status == THREAD_TO_KILL) {
-	/* execute ensure-clause if any */
-	rb_thread_restore_context(next, RESTORE_FATAL);
+	if (!(next->flags & THREAD_TERMINATING)) {
+	    next->flags |= THREAD_TERMINATING;
+	    /* terminate; execute ensure-clause if any */
+	    rb_thread_restore_context(next, RESTORE_FATAL);
+	}
     }
     rb_thread_restore_context(next, RESTORE_NORMAL);
 }
@@ -7349,6 +7583,7 @@ void
 rb_thread_wait_fd(fd)
     int fd;
 {
+    if (rb_thread_critical) return;
     if (curr_thread == curr_thread->next) return;
     if (curr_thread->status == THREAD_TO_KILL) return;
 
@@ -7362,9 +7597,9 @@ int
 rb_thread_fd_writable(fd)
     int fd;
 {
+    if (rb_thread_critical) return Qtrue;
     if (curr_thread == curr_thread->next) return Qtrue;
     if (curr_thread->status == THREAD_TO_KILL) return Qtrue;
-
     curr_thread->status = THREAD_STOPPED;
     FD_ZERO(&curr_thread->readfds);
     FD_ZERO(&curr_thread->writefds);
@@ -7382,7 +7617,8 @@ rb_thread_wait_for(time)
 {
     double date;
 
-    if (curr_thread == curr_thread->next ||
+    if (rb_thread_critical ||
+	curr_thread == curr_thread->next ||
 	curr_thread->status == THREAD_TO_KILL) {
 	int n;
 #ifndef linux
@@ -7394,7 +7630,14 @@ rb_thread_wait_for(time)
 	    n = select(0, 0, 0, 0, &time);
 	    TRAP_END;
 	    if (n == 0) return;
-
+	    if (n < 0) {
+		switch (errno) {
+		  case EINTR:
+		    return;
+		  default:
+		    rb_sys_fail("sleep");
+		}
+	    }
 #ifndef linux
 	    d = limit - timeofday();
 
@@ -7447,7 +7690,8 @@ rb_thread_select(max, read, write, except, timeout)
 	    (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6;
     }
 
-    if (curr_thread == curr_thread->next ||
+    if (rb_thread_critical ||
+	curr_thread == curr_thread->next ||
 	curr_thread->status == THREAD_TO_KILL) {
 #ifndef linux
 	struct timeval tv, *tvp = timeout;
@@ -7513,6 +7757,7 @@ rb_thread_join(thread)
     rb_thread_t th = rb_thread_check(thread);
     enum thread_status last_status = THREAD_RUNNABLE;
 
+    if (rb_thread_critical) rb_thread_deadlock();
     if (!rb_thread_dead(th)) {
 	if (th == curr_thread)
 	    rb_raise(rb_eThreadError, "thread tried to join itself");
@@ -7612,8 +7857,8 @@ rb_thread_kill(thread)
     rb_thread_ready(th);
     th->gid = 0;
     th->status = THREAD_TO_KILL;
-    rb_thread_schedule();
-    return Qnil;		/* not reached */
+    if (!rb_thread_critical) rb_thread_schedule();
+    return thread;
 }
 
 static VALUE
@@ -7780,6 +8025,7 @@ rb_thread_abort_exc_set(thread, val)
 \
     th->status = THREAD_RUNNABLE;\
     th->result = 0;\
+    th->flags = 0;\
 \
     th->stk_ptr = 0;\
     th->stk_len = 0;\
@@ -7795,6 +8041,7 @@ rb_thread_abort_exc_set(thread, val)
     th->scope = 0;\
     th->klass = 0;\
     th->wrapper = 0;\
+    th->cref = ruby_cref;\
     th->dyna_vars = ruby_dyna_vars;\
     th->block = 0;\
     th->iter = 0;\
@@ -7846,8 +8093,6 @@ catch_timer(sig)
 int rb_thread_tick = THREAD_TICK;
 #endif
 
-static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t));
-
 #define SCOPE_SHARED  FL_USER1
 
 #if defined(HAVE_SETITIMER)
@@ -7886,6 +8131,7 @@ rb_thread_start_0(fn, arg, th_arg)
 {
     volatile rb_thread_t th = th_arg;
     volatile VALUE thread = th->thread;
+    struct BLOCK* saved_block = 0;
     enum thread_status status;
     int state;
 
@@ -7903,7 +8149,11 @@ rb_thread_start_0(fn, arg, th_arg)
 #endif
 
     if (ruby_block) {		/* should nail down higher scopes */
-	blk_copy_prev(ruby_block);
+	struct BLOCK dummy;
+
+	dummy.prev = ruby_block;
+	blk_copy_prev(&dummy);
+	saved_block = ruby_block = dummy.prev;
     }
     scope_dup(ruby_scope);
     FL_SET(ruby_scope, SCOPE_SHARED);
@@ -7930,6 +8180,16 @@ rb_thread_start_0(fn, arg, th_arg)
     }
     POP_TAG();
     status = th->status;
+
+    while (saved_block) {
+	struct BLOCK *tmp = saved_block;
+
+	if (tmp->frame.argc > 0)
+	    free(tmp->frame.argv);
+	saved_block = tmp->prev;
+	free(tmp);
+    }
+
     if (th == main_thread) ruby_stop(state);
     rb_thread_remove(th);
     if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
@@ -8018,8 +8278,6 @@ static VALUE
 rb_thread_start(klass, args)
     VALUE klass, args;
 {
-    rb_thread_t th;
-
     if (!rb_block_given_p()) {
 	rb_raise(rb_eThreadError, "must be called with a block");
     }
@@ -8366,6 +8624,14 @@ rb_callcc(self)
     for (tag=prot_tag; tag; tag=tag->prev) {
 	scope_dup(tag->scope);
     }
+    if (ruby_block) {
+	struct BLOCK *block = ruby_block;
+
+	while (block) {
+	    block->tag->flags |= BLOCK_DYNAMIC;
+	    block = block->prev;
+	}
+    }
     th->thread = curr_thread->thread;
 
     for (vars = th->dyna_vars; vars; vars = vars->next) {
diff --git a/ext/.cvsignore b/ext/.cvsignore
new file mode 100644
index 0000000000..d8b8a61d92
--- /dev/null
+++ b/ext/.cvsignore
@@ -0,0 +1 @@
+extmk.rb
diff --git a/ext/Win32API/Win32API.c b/ext/Win32API/Win32API.c
index dcfdd7caab..0ee28f05ac 100644
--- a/ext/Win32API/Win32API.c
+++ b/ext/Win32API/Win32API.c
@@ -305,9 +305,3 @@ Init_Win32API()
     rb_define_method(cWin32API, "call", Win32API_Call, -1);
     rb_define_alias(cWin32API,  "Call", "call");
 }
-
-void
-Init_win32api()
-{
-    Init_Win32API();
-}
diff --git a/ext/Win32API/extconf.rb b/ext/Win32API/extconf.rb
index f8d78e1465..5e42f62558 100644
--- a/ext/Win32API/extconf.rb
+++ b/ext/Win32API/extconf.rb
@@ -1,6 +1,6 @@
 case RUBY_PLATFORM
 when /cygwin/,/mingw/
-  $CFLAGS = "-fno-defer-pop"
+  $CFLAGS = "-fno-defer-pop -fno-omit-frame-pointer"
   create_makefile("Win32API")
 when /win32/
   create_makefile("Win32API")
diff --git a/ext/configsub.rb b/ext/configsub.rb
index 315cdaf868..4db6c22a69 100644
--- a/ext/configsub.rb
+++ b/ext/configsub.rb
@@ -3,7 +3,7 @@
 BEGIN {
   CONFIG = {}
 
-  VERSION.scan(/(\d+)\.(\d+)\.(\d+)/) do
+  RUBY_VERSION.scan(/(\d+)\.(\d+)\.(\d+)/) do
     # overridden if config.status has version
     CONFIG['MAJOR'] = $1
     CONFIG['MINOR'] = $2
diff --git a/ext/curses/.cvsignore b/ext/curses/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/curses/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/curses/curses.c b/ext/curses/curses.c
index db620654bd..4a8c46f483 100644
--- a/ext/curses/curses.c
+++ b/ext/curses/curses.c
@@ -16,16 +16,16 @@
 #  include 
 # else
 #  include 
-#  if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxx)
+#  if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__) ) && !defined(_maxx)
 #   define _maxx maxx
 #  endif
-#  if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxy)
+#  if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)) && !defined(_maxy)
 #   define _maxy maxy
 #  endif
-#  if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begx)
+#  if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)) && !defined(_begx)
 #   define _begx begx
 #  endif
-#  if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begy)
+#  if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)) && !defined(_begy)
 #   define _begy begy
 #  endif
 # endif
diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb
index 5c6881164a..c16ab00f28 100644
--- a/ext/curses/extconf.rb
+++ b/ext/curses/extconf.rb
@@ -1,5 +1,9 @@
 require 'mkmf'
 
+dir_config('curses')
+dir_config('ncurses')
+dir_config('termcap')
+
 make=false
 have_library("mytinfo", "tgetent") if /bow/ =~ RUBY_PLATFORM
 if have_header("ncurses.h") and have_library("ncurses", "initscr")
diff --git a/ext/dbm/.cvsignore b/ext/dbm/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/dbm/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c
index 55c60bf3b3..b0446d1060 100644
--- a/ext/dbm/dbm.c
+++ b/ext/dbm/dbm.c
@@ -6,7 +6,7 @@
   $Date$
   created at: Mon Jan 24 15:59:52 JST 1994
 
-  Copyright (C) 1995-1998 Yukihiro Matsumoto
+  Copyright (C) 1995-2001 Yukihiro Matsumoto
 
 ************************************************/
 
@@ -22,7 +22,7 @@
 #include 
 #include 
 
-VALUE cDBM;
+VALUE cDBM, rb_eDBMError;
 
 struct dbmdata {
     int  di_size;
@@ -37,6 +37,7 @@ closed_dbm()
 
 #define GetDBM(obj, dbmp) {\
     Data_Get_Struct(obj, struct dbmdata, dbmp);\
+    if (dbmp == 0) closed_dbm();\
     if (dbmp->di_dbm == 0) closed_dbm();\
 }
 
@@ -44,21 +45,35 @@ static void
 free_dbm(dbmp)
     struct dbmdata *dbmp;
 {
-    if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
-    free(dbmp);
+    if (dbmp) {
+	if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
+	free(dbmp);
+    }
 }
 
+static VALUE fdbm_close _((VALUE));
+
 static VALUE
-fdbm_s_open(argc, argv, klass)
+fdbm_s_new(argc, argv, klass)
     int argc;
     VALUE *argv;
     VALUE klass;
+{
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+    rb_obj_call_init(obj, argc, argv);
+    return obj;
+}
+
+static VALUE
+fdbm_initialize(argc, argv, obj)
+    int argc;
+    VALUE *argv;
+    VALUE obj;
 {
     VALUE file, vmode;
     DBM *dbm;
     struct dbmdata *dbmp;
     int mode;
-    VALUE obj;
 
     if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
 	mode = 0666;		/* default value */
@@ -69,6 +84,7 @@ fdbm_s_open(argc, argv, klass)
     else {
 	mode = NUM2INT(vmode);
     }
+    file = rb_str_to_str(file);
     Check_SafeStr(file);
 
     dbm = 0;
@@ -87,13 +103,33 @@ fdbm_s_open(argc, argv, klass)
 	rb_sys_fail(RSTRING(file)->ptr);
     }
 
-    obj = Data_Make_Struct(klass,struct dbmdata,0,free_dbm,dbmp);
+    dbmp = ALLOC(struct dbmdata);
+    DATA_PTR(obj) = dbmp;
     dbmp->di_dbm = dbm;
     dbmp->di_size = -1;
 
     return obj;
 }
 
+static VALUE
+fdbm_s_open(argc, argv, klass)
+    int argc;
+    VALUE *argv;
+    VALUE klass;
+{
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+
+    if (NIL_P(fdbm_initialize(argc, argv, obj))) {
+	return Qnil;
+    }
+
+    if (rb_block_given_p()) {
+        return rb_ensure(rb_yield, obj, fdbm_close, obj);
+    }
+
+    return obj;
+}
+
 static VALUE
 fdbm_close(obj)
     VALUE obj;
@@ -115,7 +151,7 @@ fdbm_fetch(obj, keystr, ifnone)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
@@ -143,10 +179,14 @@ fdbm_fetch_m(argc, argv, obj)
     VALUE *argv;
     VALUE obj;
 {
-    VALUE keystr, ifnone;
+    VALUE keystr, valstr, ifnone;
 
     rb_scan_args(argc, argv, "11", &keystr, &ifnone);
-    return fdbm_fetch(obj, keystr, ifnone);
+    valstr = fdbm_fetch(obj, keystr, ifnone);
+    if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
+	rb_raise(rb_eIndexError, "key not found");
+
+    return valstr;
 }
 
 static VALUE
@@ -157,7 +197,7 @@ fdbm_index(obj, valstr)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(valstr, T_STRING);
+    valstr = rb_str_to_str(valstr);
     val.dptr = RSTRING(valstr)->ptr;
     val.dsize = RSTRING(valstr)->len;
 
@@ -166,8 +206,9 @@ fdbm_index(obj, valstr)
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
 	val = dbm_fetch(dbm, key);
 	if (val.dsize == RSTRING(valstr)->len &&
-	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
+	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) {
 	    return rb_tainted_str_new(key.dptr, key.dsize);
+	}
     }
     return Qnil;
 }
@@ -198,7 +239,7 @@ fdbm_delete(obj, keystr)
     DBM *dbm;
 
     rb_secure(4);
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
@@ -213,7 +254,7 @@ fdbm_delete(obj, keystr)
 
     if (dbm_delete(dbm, key)) {
 	dbmp->di_size = -1;
-	rb_raise(rb_eRuntimeError, "dbm_delete failed");
+	rb_raise(rb_eDBMError, "dbm_delete failed");
     }
     else if (dbmp->di_size >= 0) {
 	dbmp->di_size--;
@@ -233,14 +274,15 @@ fdbm_shift(obj)
     rb_secure(4);
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
+    dbmp->di_size = -1;
 
     key = dbm_firstkey(dbm); 
     if (!key.dptr) return Qnil;
     val = dbm_fetch(dbm, key);
-    dbm_delete(dbm, key);
-
     keystr = rb_tainted_str_new(key.dptr, key.dsize);
     valstr = rb_tainted_str_new(val.dptr, val.dsize);
+    dbm_delete(dbm, key);
+
     return rb_assoc_new(keystr, valstr);
 }
 
@@ -252,20 +294,35 @@ fdbm_delete_if(obj)
     struct dbmdata *dbmp;
     DBM *dbm;
     VALUE keystr, valstr;
+    VALUE ret, ary = rb_ary_new();
+    int i, status = 0, n;
 
     rb_secure(4);
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
+    n = dbmp->di_size;
+    dbmp->di_size = -1;
+
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
 	val = dbm_fetch(dbm, key);
 	keystr = rb_tainted_str_new(key.dptr, key.dsize);
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
-	if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) {
-	    if (dbm_delete(dbm, key)) {
-		rb_raise(rb_eRuntimeError, "dbm_delete failed");
-	    }
+        ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
+        if (status != 0) goto delete;
+	if (RTEST(ret)) rb_ary_push(ary, keystr);
+    }
+ delete:
+    for (i = 0; i < RARRAY(ary)->len; i++) {
+	keystr = RARRAY(ary)->ptr[i];
+	key.dptr = RSTRING(keystr)->ptr;
+	key.dsize = RSTRING(keystr)->len;
+	if (dbm_delete(dbm, key)) {
+	    rb_raise(rb_eDBMError, "dbm_delete failed");
 	}
     }
+    if (status) rb_jump_tag(status);
+    if (n > 0) dbmp->di_size = n - RARRAY(ary)->len;
+
     return obj;
 }
 
@@ -281,11 +338,16 @@ fdbm_clear(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     dbmp->di_size = -1;
-    for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
-	if (dbm_delete(dbm, key)) {
-	    rb_raise(rb_eRuntimeError, "dbm_delete failed");
-	}
+    while (key = dbm_firstkey(dbm), key.dptr) {
+        do {
+	    if (dbm_delete(dbm, key)) {
+		rb_raise(rb_eDBMError, "dbm_delete failed");
+	    }
+	    key = dbm_nextkey(dbm);
+	} while (key.dptr);
     }
+    dbmp->di_size = 0;
+
     return obj;
 }
 
@@ -374,7 +436,7 @@ fdbm_store(obj, keystr, valstr)
 	dbm_clearerr(dbm);
 #endif
 	if (errno == EPERM) rb_sys_fail(0);
-	rb_raise(rb_eRuntimeError, "dbm_store failed");
+	rb_raise(rb_eDBMError, "dbm_store failed");
     }
 
     return valstr;
@@ -529,7 +591,7 @@ fdbm_has_key(obj, keystr)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
@@ -548,7 +610,7 @@ fdbm_has_value(obj, valstr)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(valstr, T_STRING);
+    valstr = rb_str_to_str(valstr);
     val.dptr = RSTRING(valstr)->ptr;
     val.dsize = RSTRING(valstr)->len;
 
@@ -618,10 +680,13 @@ void
 Init_dbm()
 {
     cDBM = rb_define_class("DBM", rb_cObject);
+    rb_eDBMError = rb_define_class("DBMError", rb_eStandardError);
     rb_include_module(cDBM, rb_mEnumerable);
 
+    rb_define_singleton_method(cDBM, "new", fdbm_s_new, -1);
     rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1);
-    rb_define_singleton_method(cDBM, "new", fdbm_s_open, -1);
+
+    rb_define_method(cDBM, "initialize", fdbm_initialize, -1);
     rb_define_method(cDBM, "close", fdbm_close, 0);
     rb_define_method(cDBM, "[]", fdbm_aref, 1);
     rb_define_method(cDBM, "fetch", fdbm_fetch_m, -1);
@@ -639,7 +704,7 @@ Init_dbm()
     rb_define_method(cDBM, "each_pair", fdbm_each_pair, 0);
     rb_define_method(cDBM, "keys", fdbm_keys, 0);
     rb_define_method(cDBM, "values", fdbm_values, 0);
-    rb_define_method(cDBM, "shift", fdbm_shift, 1);
+    rb_define_method(cDBM, "shift", fdbm_shift, 0);
     rb_define_method(cDBM, "delete", fdbm_delete, 1);
     rb_define_method(cDBM, "delete_if", fdbm_delete_if, 0);
     rb_define_method(cDBM, "reject!", fdbm_delete_if, 0);
diff --git a/ext/etc/.cvsignore b/ext/etc/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/etc/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in
index 92d11d0f6e..3f98afc474 100644
--- a/ext/extmk.rb.in
+++ b/ext/extmk.rb.in
@@ -12,7 +12,13 @@ elsif ARGV[0] == 'install'
   $destdir = ARGV[1] || ''
   ARGV.shift
 elsif ARGV[0] == 'clean'
-  $clean = true
+  $clean = "clean"
+  ARGV.shift
+elsif ARGV[0] == 'distclean'
+  $clean = "distclean"
+  ARGV.shift
+elsif ARGV[0] == 'realclean'
+  $clean = "realclean"
   ARGV.shift
 end
 
@@ -332,21 +338,27 @@ def dir_config(target, idefault=nil, ldefault=nil)
     idefault = default + "/include"
     ldefault = default + "/lib"
   end
-  dir = with_config("%s-dir"%target, default)
-  if dir
-    idir = " -I"+dir+"/include"
-    ldir = dir+"/lib"
-  end
-  unless idir
-    dir = with_config("%s-include"%target, idefault)
-    idir = " -I"+dir if dir
+
+  dir = with_config(target + "-dir", default)
+
+  idir, ldir = if dir then [
+      dir + "/include",
+      dir + "/lib"
+    ] else [
+      with_config(target + "-include", idefault),
+      with_config(target + "-lib", ldefault)
+    ] end
+
+  if idir
+    idircflag = "-I" + idir
+    $CPPFLAGS += " " + idircflag unless $CPPFLAGS.split.include?(idircflag)
   end
-  unless ldir
-    ldir = with_config("%s-lib"%target, ldefault)
+
+  if ldir
+    $LIBPATH << ldir unless $LIBPATH.include?(ldir)
   end
 
-  $CPPFLAGS += idir if idir
-  $LIBPATH |= [ldir] if ldir
+  [idir, ldir]
 end
 
 def create_makefile(target)
@@ -370,13 +382,15 @@ def create_makefile(target)
 
   if $configure_args['--enable-shared'] or "@LIBRUBY@" != "@LIBRUBY_A@"
     $libs = "@LIBRUBYARG@ " + $libs
-    $LIBPATH |= [$topdir]
+    $LIBPATH.unshift $topdir
   end
 
   defflag = ''
   if RUBY_PLATFORM =~ /cygwin|mingw/ and not $static
-    open(target + '.def', 'wb') do |f|
-      f.print "EXPORTS\n", "Init_", target, "\n"
+    if not File.exist? target + '.def'
+      open(target + '.def', 'wb') do |f|
+        f.print "EXPORTS\n", "Init_", target, "\n"
+      end
     end
     defflag = "--def=" + target + ".def"
   end
@@ -488,23 +502,44 @@ EOS
   install_rb(mfile, $srcdir)
   mfile.printf "\n"
 
-  if /mswin32/ !~ RUBY_PLATFORM
+  unless /nmake/i =~ $make
+    unless /mswin32/ =~ RUBY_PLATFORM
+      src = '$<'
+    else
+      src = '$(subst /,\\\\,$<)'
+    end
     mfile.puts "
+.cc.@OBJEXT@:
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c #{src}
+.cpp.@OBJEXT@:
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c #{src}
+.cxx.@OBJEXT@:
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c #{src}
+.C.@OBJEXT@:
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c #{src}
+
 .c.@OBJEXT@:
-	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c #{src}
 "
-  elsif /nmake/i =~ $make
+  else
     mfile.print "
 {$(srcdir)}.c{}.@OBJEXT@:
 	$(CC) -I. -I$(
 #include 
 
-VALUE cGDBM;
+static VALUE cGDBM, rb_eGDBMError;
 
 #define MY_BLOCK_SIZE (2048)
 #define MY_FATAL_FUNC (0)
@@ -32,6 +32,7 @@ closed_dbm()
 
 #define GetDBM(obj, dbmp) {\
     Data_Get_Struct(obj, struct dbmdata, dbmp);\
+    if (dbmp == 0) closed_dbm();\
     if (dbmp->di_dbm == 0) closed_dbm();\
 }
 
@@ -39,23 +40,37 @@ static void
 free_dbm(dbmp)
     struct dbmdata *dbmp;
 {
-    if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
-    free(dbmp);
+    if (dbmp) {
+	if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
+	free(dbmp);
+    }
 }
 
+static VALUE fgdbm_close _((VALUE));
+
 static VALUE
-fgdbm_s_open(argc, argv, klass)
+fgdbm_s_new(argc, argv, klass)
     int argc;
     VALUE *argv;
     VALUE klass;
 {
-    VALUE file, vmode;
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+    rb_obj_call_init(obj, argc, argv);
+    return obj;
+}
+
+static VALUE
+fgdbm_initialize(argc, argv, obj)
+    int argc;
+    VALUE *argv;
+    VALUE obj;
+{
+    VALUE file, vmode, vflags;
     GDBM_FILE dbm;
     struct dbmdata *dbmp;
-    int mode;
-    VALUE obj;
+    int mode, flags = 0;
 
-    if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
+    if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
 	mode = 0666;		/* default value */
     }
     else if (NIL_P(vmode)) {
@@ -64,31 +79,62 @@ fgdbm_s_open(argc, argv, klass)
     else {
 	mode = NUM2INT(vmode);
     }
+
+    if (!NIL_P(vflags))
+        flags = NUM2INT(vflags);
+
+    file = rb_str_to_str(file);
     Check_SafeStr(file);
 
     dbm = 0;
     if (mode >= 0)
 	dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, 
-			O_RDWR|O_CREAT, mode, MY_FATAL_FUNC);
+			GDBM_WRCREAT|flags, mode, MY_FATAL_FUNC);
     if (!dbm)
 	dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, 
-			O_RDWR, 0, MY_FATAL_FUNC);
+			GDBM_WRITER|flags, 0, MY_FATAL_FUNC);
     if (!dbm)
 	dbm = gdbm_open(RSTRING(file)->ptr, MY_BLOCK_SIZE, 
-			O_RDONLY, 0, MY_FATAL_FUNC);
+			GDBM_READER|flags, 0, MY_FATAL_FUNC);
 
     if (!dbm) {
 	if (mode == -1) return Qnil;
-	rb_sys_fail(RSTRING(file)->ptr);
+
+	if (gdbm_errno == GDBM_FILE_OPEN_ERROR ||
+	    gdbm_errno == GDBM_CANT_BE_READER ||
+	    gdbm_errno == GDBM_CANT_BE_WRITER)
+	    rb_sys_fail(RSTRING(file)->ptr);
+	else
+	    rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
     }
 
-    obj = Data_Make_Struct(klass,struct dbmdata,0,free_dbm,dbmp);
+    dbmp = ALLOC(struct dbmdata);
+    DATA_PTR(obj) = dbmp;
     dbmp->di_dbm = dbm;
     dbmp->di_size = -1;
 
     return obj;
 }
 
+static VALUE
+fgdbm_s_open(argc, argv, klass)
+    int argc;
+    VALUE *argv;
+    VALUE klass;
+{
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+
+    if (NIL_P(fgdbm_initialize(argc, argv, obj))) {
+	return Qnil;
+    }
+
+    if (rb_block_given_p()) {
+        return rb_ensure(rb_yield, obj, fgdbm_close, obj);
+    }
+
+    return obj;
+}
+
 static VALUE
 fgdbm_close(obj)
     VALUE obj;
@@ -102,34 +148,131 @@ fgdbm_close(obj)
     return Qnil;
 }
 
+static VALUE
+rb_gdbm_fetch(dbm, key)
+    GDBM_FILE dbm;
+    datum key;
+{
+    datum val;
+    NEWOBJ(str, struct RString);
+    OBJSETUP(str, rb_cString, T_STRING);
+
+    val = gdbm_fetch(dbm, key);
+    if (val.dptr == 0)
+        return Qnil;
+
+    str->ptr = 0;
+    str->len = val.dsize;
+    str->orig = 0;
+    str->ptr = REALLOC_N(val.dptr,char,val.dsize+1);
+    str->ptr[str->len] = '\0';
+
+    OBJ_TAINT(str);
+    return (VALUE)str;
+}
+
+static VALUE
+rb_gdbm_fetch2(dbm, keystr)
+    GDBM_FILE dbm;
+    VALUE keystr;
+{
+    datum key;
+
+    keystr = rb_str_to_str(keystr);
+    key.dptr = RSTRING(keystr)->ptr;
+    key.dsize = RSTRING(keystr)->len;
+
+    return rb_gdbm_fetch(dbm, key);
+}
+
+static VALUE
+rb_gdbm_fetch3(obj, keystr)
+    VALUE obj, keystr;
+{
+    struct dbmdata *dbmp;
+    GDBM_FILE dbm;
+
+    GetDBM(obj, dbmp);
+    dbm = dbmp->di_dbm;
+    return rb_gdbm_fetch2(dbm, keystr);
+}
+
+static VALUE
+rb_gdbm_firstkey(dbm)
+    GDBM_FILE dbm;
+{
+    datum key;
+    NEWOBJ(str, struct RString);
+    OBJSETUP(str, rb_cString, T_STRING);
+
+    key = gdbm_firstkey(dbm);
+    if (key.dptr == 0)
+        return Qnil;
+
+    str->ptr = 0;
+    str->len = key.dsize;
+    str->orig = 0;
+    str->ptr = REALLOC_N(key.dptr,char,key.dsize+1);
+    str->ptr[str->len] = '\0';
+
+    OBJ_TAINT(str);
+    return (VALUE)str;
+}
+
+static VALUE
+rb_gdbm_nextkey(dbm, keystr)
+    GDBM_FILE dbm;
+    VALUE keystr;
+{
+    datum key, key2;
+    NEWOBJ(str, struct RString);
+    OBJSETUP(str, rb_cString, T_STRING);
+
+    key.dptr = RSTRING(keystr)->ptr;
+    key.dsize = RSTRING(keystr)->len;
+    key2 = gdbm_nextkey(dbm, key);
+    if (key2.dptr == 0)
+        return Qnil;
+
+    str->ptr = 0;
+    str->len = key2.dsize;
+    str->orig = 0;
+    str->ptr = REALLOC_N(key2.dptr,char,key2.dsize+1);
+    str->ptr[str->len] = '\0';
+
+    OBJ_TAINT(str);
+    return (VALUE)str;
+}
+
 static VALUE
 fgdbm_fetch(obj, keystr, ifnone)
     VALUE obj, keystr, ifnone;
 {
-    datum key, value;
+    datum key;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
+    VALUE valstr;
 
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    value = gdbm_fetch(dbm, key);
-    if (value.dptr == 0) {
+    valstr = rb_gdbm_fetch(dbm, key);
+    if (NIL_P(valstr)) {
 	if (ifnone == Qnil && rb_block_given_p())
 	    return rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
 	return ifnone;
     }
-    return rb_tainted_str_new(value.dptr, value.dsize);
+    return valstr;
 }
 
 static VALUE
 fgdbm_aref(obj, keystr)
     VALUE obj, keystr;
 {
-    return fgdbm_fetch(obj, keystr, Qnil);
+    return rb_gdbm_fetch3(obj, keystr);
 }
 
 static VALUE
@@ -138,31 +281,37 @@ fgdbm_fetch_m(argc, argv, obj)
     VALUE *argv;
     VALUE obj;
 {
-    VALUE keystr, ifnone;
+    VALUE keystr, valstr, ifnone;
 
     rb_scan_args(argc, argv, "11", &keystr, &ifnone);
-    return fgdbm_fetch(obj, keystr, ifnone);
+    valstr = fgdbm_fetch(obj, keystr, ifnone);
+    if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
+	rb_raise(rb_eIndexError, "key not found");
+
+    return valstr;
 }
 
 static VALUE
 fgdbm_index(obj, valstr)
     VALUE obj, valstr;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
+    VALUE keystr, valstr2;
 
-    Check_Type(valstr, T_STRING);
-    val.dptr = RSTRING(valstr)->ptr;
-    val.dsize = RSTRING(valstr)->len;
-
+    valstr = rb_str_to_str(valstr);
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	if (val.dsize == RSTRING(valstr)->len &&
-	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
-	    return rb_tainted_str_new(key.dptr, key.dsize);
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+	valstr2 = rb_gdbm_fetch2(dbm, keystr);
+        if (!NIL_P(valstr2) &&
+            RSTRING(valstr)->len == RSTRING(valstr2)->len &&
+            memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr,
+                   RSTRING(valstr)->len) == 0) {
+	    return keystr;
+        }
     }
     return Qnil;
 }
@@ -178,37 +327,66 @@ fgdbm_indexes(argc, argv, obj)
 
     new = rb_ary_new2(argc);
     for (i=0; iptr;
+    key.dsize = RSTRING(keystr)->len;
+
+    GetDBM(obj, dbmp);
+    dbm = dbmp->di_dbm;
+
+    if (!gdbm_exists(dbm, key)) {
+	return Qnil;
+    }
+
+    if (gdbm_delete(dbm, key)) {
+	dbmp->di_size = -1;
+	rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+    }
+    else if (dbmp->di_size >= 0) {
+	dbmp->di_size--;
+    }
+    return obj;
+}
+
 static VALUE
 fgdbm_delete(obj, keystr)
     VALUE obj, keystr;
 {
-    datum key, value;
+    datum key;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
 
     rb_secure(4);
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
-    value = gdbm_fetch(dbm, key);
-    if (value.dptr == 0) {
+    if (!gdbm_exists(dbm, key)) {
 	if (rb_block_given_p()) rb_yield(keystr);
 	return Qnil;
     }
 
     if (gdbm_delete(dbm, key)) {
 	dbmp->di_size = -1;
-	rb_raise(rb_eRuntimeError, "gdbm_delete failed");
+	rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
     }
     else if (dbmp->di_size >= 0) {
 	dbmp->di_size--;
@@ -220,7 +398,6 @@ static VALUE
 fgdbm_shift(obj)
     VALUE obj;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
     VALUE keystr, valstr;
@@ -229,13 +406,11 @@ fgdbm_shift(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
-    key = gdbm_firstkey(dbm); 
-    if (!key.dptr) return Qnil;
-    val = gdbm_fetch(dbm, key);
-    gdbm_delete(dbm, key);
+    keystr = rb_gdbm_firstkey(dbm);
+    if (NIL_P(keystr)) return Qnil;
+    valstr = rb_gdbm_fetch2(dbm, keystr);
+    rb_gdbm_delete(obj, keystr);
 
-    keystr = rb_tainted_str_new(key.dptr, key.dsize);
-    valstr = rb_tainted_str_new(val.dptr, val.dsize);
     return rb_assoc_new(keystr, valstr);
 }
 
@@ -243,24 +418,34 @@ static VALUE
 fgdbm_delete_if(obj)
     VALUE obj;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
     VALUE keystr, valstr;
+    VALUE ret, ary = rb_ary_new();
+    int i, status = 0, n;
 
     rb_secure(4);
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	keystr = rb_tainted_str_new(key.dptr, key.dsize);
-	valstr = rb_tainted_str_new(val.dptr, val.dsize);
-	if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) {
-	    if (gdbm_delete(dbm, key)) {
-		rb_raise(rb_eRuntimeError, "gdbm_delete failed");
-	    }
-	}
+    n = dbmp->di_size;
+    dbmp->di_size = -1;
+
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+	valstr = rb_gdbm_fetch2(dbm, keystr);
+        ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
+        if (status != 0) goto delete;
+	if (RTEST(ret)) rb_ary_push(ary, keystr);
+	else dbmp->di_size++;
     }
+
+ delete:
+    for (i = 0; i < RARRAY(ary)->len; i++)
+        rb_gdbm_delete(obj, RARRAY(ary)->ptr[i]);
+    if (status) rb_jump_tag(status);
+    if (n > 0) dbmp->di_size = n - RARRAY(ary)->len;
+
     return obj;
 }
 
@@ -276,12 +461,20 @@ fgdbm_clear(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     dbmp->di_size = -1;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
-	nextkey = gdbm_nextkey(dbm, key);
-	if (gdbm_delete(dbm, key)) {
-	    rb_raise(rb_eRuntimeError, "gdbm_delete failed");
-	}
+
+    while (key = gdbm_firstkey(dbm), key.dptr) {
+        for (; key.dptr; key = nextkey) {
+            nextkey = gdbm_nextkey(dbm, key);
+            if (gdbm_delete(dbm, key)) {
+                free(key.dptr);
+                if (nextkey.dptr) free(nextkey.dptr);
+                rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+            }
+            free(key.dptr);
+        }
     }
+    dbmp->di_size = 0;
+
     return obj;
 }
 
@@ -289,7 +482,6 @@ static VALUE
 fgdbm_invert(obj)
     VALUE obj;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
     VALUE keystr, valstr;
@@ -297,10 +489,10 @@ fgdbm_invert(obj)
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	keystr = rb_tainted_str_new(key.dptr, key.dsize);
-	valstr = rb_tainted_str_new(val.dptr, val.dsize);
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+	valstr = rb_gdbm_fetch2(dbm, keystr);
+
 	rb_hash_aset(hash, valstr, keystr);
     }
     return hash;
@@ -353,12 +545,11 @@ fgdbm_store(obj, keystr, valstr)
     GDBM_FILE dbm;
 
     rb_secure(4);
-    keystr = rb_obj_as_string(keystr);
-
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
-    valstr = rb_obj_as_string(valstr);
+    valstr = rb_str_to_str(valstr);
     val.dptr = RSTRING(valstr)->ptr;
     val.dsize = RSTRING(valstr)->len;
 
@@ -367,7 +558,7 @@ fgdbm_store(obj, keystr, valstr)
     dbm = dbmp->di_dbm;
     if (gdbm_store(dbm, key, val, GDBM_REPLACE)) {
 	if (errno == EPERM) rb_sys_fail(0);
-	rb_raise(rb_eRuntimeError, "gdbm_store failed");
+	rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
     }
 
     return valstr;
@@ -377,7 +568,7 @@ static VALUE
 fgdbm_length(obj)
     VALUE obj;
 {
-    datum key;
+    datum key, nextkey;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
     int i = 0;
@@ -386,7 +577,9 @@ fgdbm_length(obj)
     if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
     dbm = dbmp->di_dbm;
 
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
+    for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
+        nextkey = gdbm_nextkey(dbm, key);
+        free(key.dptr);
 	i++;
     }
     dbmp->di_size = i;
@@ -398,23 +591,23 @@ static VALUE
 fgdbm_empty_p(obj)
     VALUE obj;
 {
-    datum key;
+    datum key, nextkey;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
-    int i = 0;
 
     GetDBM(obj, dbmp);
     if (dbmp->di_size < 0) {
 	dbm = dbmp->di_dbm;
 
-	for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	    i++;
+	key = gdbm_firstkey(dbm);
+        if (key.dptr) {
+            free(key.dptr);
+            return Qfalse;
 	}
+        return Qtrue;
     }
-    else {
-	i = dbmp->di_size;
-    }
-    if (i == 0) return Qtrue;
+
+    if (dbmp->di_size == 0) return Qtrue;
     return Qfalse;
 }
 
@@ -422,15 +615,17 @@ static VALUE
 fgdbm_each_value(obj)
     VALUE obj;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
+    VALUE keystr;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	rb_yield(rb_tainted_str_new(val.dptr, val.dsize));
+
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+        rb_yield(rb_gdbm_fetch2(dbm, keystr));
     }
     return obj;
 }
@@ -439,14 +634,17 @@ static VALUE
 fgdbm_each_key(obj)
     VALUE obj;
 {
-    datum key;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
+    VALUE keystr;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
+
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+        rb_yield(rb_str_dup(keystr));
     }
     return obj;
 }
@@ -455,19 +653,18 @@ static VALUE
 fgdbm_each_pair(obj)
     VALUE obj;
 {
-    datum key, val;
     GDBM_FILE dbm;
     struct dbmdata *dbmp;
-    VALUE keystr, valstr;
+    VALUE keystr;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	keystr = rb_tainted_str_new(key.dptr, key.dsize);
-	valstr = rb_tainted_str_new(val.dptr, val.dsize);
-	rb_yield(rb_assoc_new(keystr, valstr));
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+        rb_yield(rb_assoc_new(rb_str_dup(keystr), 
+                              rb_gdbm_fetch2(dbm, keystr)));
     }
 
     return obj;
@@ -477,17 +674,18 @@ static VALUE
 fgdbm_keys(obj)
     VALUE obj;
 {
-    datum key;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
-    VALUE ary;
+    VALUE keystr, ary;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
     ary = rb_ary_new();
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize));
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+        rb_ary_push(ary, keystr);
     }
 
     return ary;
@@ -497,18 +695,20 @@ static VALUE
 fgdbm_values(obj)
     VALUE obj;
 {
-    datum key, val;
+    datum key, nextkey;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
-    VALUE ary;
+    VALUE valstr, ary;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
     ary = rb_ary_new();
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize));
+    for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
+        nextkey = gdbm_nextkey(dbm, key);
+	valstr = rb_gdbm_fetch(dbm, key);
+        free(key.dptr);
+	rb_ary_push(ary, valstr);
     }
 
     return ary;
@@ -518,18 +718,18 @@ static VALUE
 fgdbm_has_key(obj, keystr)
     VALUE obj, keystr;
 {
-    datum key, val;
+    datum key;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
 
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    val = gdbm_fetch(dbm, key);
-    if (val.dptr) return Qtrue;
+    if (gdbm_exists(dbm, key))
+        return Qtrue;
     return Qfalse;
 }
 
@@ -537,21 +737,24 @@ static VALUE
 fgdbm_has_value(obj, valstr)
     VALUE obj, valstr;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
+    VALUE keystr, valstr2;
 
-    Check_Type(valstr, T_STRING);
-    val.dptr = RSTRING(valstr)->ptr;
-    val.dsize = RSTRING(valstr)->len;
-
+    valstr = rb_str_to_str(valstr);
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	if (val.dsize == RSTRING(valstr)->len &&
-	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+	valstr2 = rb_gdbm_fetch2(dbm, keystr);
+
+        if (!NIL_P(valstr2) &&
+            RSTRING(valstr)->len == RSTRING(valstr2)->len &&
+            memcmp(RSTRING(valstr)->ptr, RSTRING(valstr2)->ptr,
+                   RSTRING(valstr)->len) == 0) {
 	    return Qtrue;
+        }
     }
     return Qfalse;
 }
@@ -560,19 +763,19 @@ static VALUE
 fgdbm_to_a(obj)
     VALUE obj;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
-    VALUE ary;
+    VALUE keystr, ary;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
     ary = rb_ary_new();
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
-				rb_tainted_str_new(val.dptr, val.dsize)));
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+        rb_ary_push(ary, rb_assoc_new(rb_str_dup(keystr),
+                                      rb_gdbm_fetch2(dbm, keystr)));
     }
 
     return ary;
@@ -592,23 +795,101 @@ fgdbm_reorganize(obj)
     return obj;
 }
 
+static VALUE
+fgdbm_sync(obj)
+    VALUE obj;
+{
+    struct dbmdata *dbmp;
+    GDBM_FILE dbm;
+
+    rb_secure(4);
+    GetDBM(obj, dbmp);
+    dbm = dbmp->di_dbm;
+    gdbm_sync(dbm);
+    return obj;
+}
+
+static VALUE
+fgdbm_set_cachesize(obj, val)
+    VALUE obj, val;
+{
+    struct dbmdata *dbmp;
+    GDBM_FILE dbm;
+    int optval;
+
+    GetDBM(obj, dbmp);
+    dbm = dbmp->di_dbm;
+
+    optval = FIX2INT(val);
+    if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) {
+	rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+    }
+    return val;
+}
+
+static VALUE
+fgdbm_set_fastmode(obj, val)
+    VALUE obj, val;
+{
+    struct dbmdata *dbmp;
+    GDBM_FILE dbm;
+    int optval;
+
+    GetDBM(obj, dbmp);
+    dbm = dbmp->di_dbm;
+
+    optval = 0;
+    if (RTEST(val))
+        optval = 1;
+
+    if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
+	rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+    }
+    return val;
+}
+
+static VALUE
+fgdbm_set_syncmode(obj, val)
+    VALUE obj, val;
+{
+#if !defined(GDBM_SYNCMODE)
+    fgdbm_set_fastmode(obj, RTEST(val) ? Qfalse : Qtrue);
+    return val;
+#else
+    struct dbmdata *dbmp;
+    GDBM_FILE dbm;
+    int optval;
+
+    GetDBM(obj, dbmp);
+    dbm = dbmp->di_dbm;
+
+    optval = 0;
+    if (RTEST(val))
+        optval = 1;
+
+    if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
+	rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+    }
+    return val;
+#endif
+}
+
 static VALUE
 fgdbm_to_hash(obj)
     VALUE obj;
 {
-    datum key, val;
     struct dbmdata *dbmp;
     GDBM_FILE dbm;
-    VALUE hash;
+    VALUE keystr, hash;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
 
     hash = rb_hash_new();
-    for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
-	rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize),
-		           rb_tainted_str_new(val.dptr, val.dsize));
+    for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
+         keystr = rb_gdbm_nextkey(dbm, keystr)) {
+
+        rb_hash_aset(hash, keystr, rb_gdbm_fetch2(dbm, keystr));
     }
 
     return hash;
@@ -625,10 +906,13 @@ void
 Init_gdbm()
 {
     cGDBM = rb_define_class("GDBM", rb_cObject);
+    rb_eGDBMError = rb_define_class("GDBMError", rb_eStandardError);
     rb_include_module(cGDBM, rb_mEnumerable);
 
+    rb_define_singleton_method(cGDBM, "new", fgdbm_s_new, -1);
     rb_define_singleton_method(cGDBM, "open", fgdbm_s_open, -1);
-    rb_define_singleton_method(cGDBM, "new", fgdbm_s_open, -1);
+
+    rb_define_method(cGDBM, "initialize", fgdbm_initialize, -1);
     rb_define_method(cGDBM, "close", fgdbm_close, 0);
     rb_define_method(cGDBM, "[]", fgdbm_aref, 1);
     rb_define_method(cGDBM, "fetch", fgdbm_fetch_m, -1);
@@ -646,7 +930,7 @@ Init_gdbm()
     rb_define_method(cGDBM, "each_pair", fgdbm_each_pair, 0);
     rb_define_method(cGDBM, "keys", fgdbm_keys, 0);
     rb_define_method(cGDBM, "values", fgdbm_values, 0);
-    rb_define_method(cGDBM, "shift", fgdbm_shift, 1);
+    rb_define_method(cGDBM, "shift", fgdbm_shift, 0);
     rb_define_method(cGDBM, "delete", fgdbm_delete, 1);
     rb_define_method(cGDBM, "delete_if", fgdbm_delete_if, 0);
     rb_define_method(cGDBM, "reject!", fgdbm_delete_if, 0);
@@ -656,6 +940,11 @@ Init_gdbm()
     rb_define_method(cGDBM,"update", fgdbm_update, 1);
     rb_define_method(cGDBM,"replace", fgdbm_replace, 1);
     rb_define_method(cGDBM,"reorganize", fgdbm_reorganize, 0);
+    rb_define_method(cGDBM,"sync", fgdbm_sync, 0);
+    /* rb_define_method(cGDBM,"setopt", fgdbm_setopt, 2); */
+    rb_define_method(cGDBM,"cachesize=", fgdbm_set_cachesize, 1);
+    rb_define_method(cGDBM,"fastmode=", fgdbm_set_fastmode, 1);
+    rb_define_method(cGDBM,"syncmode=", fgdbm_set_syncmode, 1);
 
     rb_define_method(cGDBM, "include?", fgdbm_has_key, 1);
     rb_define_method(cGDBM, "has_key?", fgdbm_has_key, 1);
@@ -666,4 +955,24 @@ Init_gdbm()
 
     rb_define_method(cGDBM, "to_a", fgdbm_to_a, 0);
     rb_define_method(cGDBM, "to_hash", fgdbm_to_hash, 0);
+
+    /* flags for gdbm_opn() */
+    /*
+    rb_define_const(cGDBM, "READER",  INT2FIX(GDBM_READER));
+    rb_define_const(cGDBM, "WRITER",  INT2FIX(GDBM_WRITER));
+    rb_define_const(cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT));
+    rb_define_const(cGDBM, "NEWDB",   INT2FIX(GDBM_NEWDB));
+    */
+    rb_define_const(cGDBM, "FAST", INT2FIX(GDBM_FAST));
+    /* this flag is obsolete in gdbm 1.8.
+       On gdbm 1.8, fast mode is default behavior. */
+
+    /* gdbm version 1.8 specific */
+#if defined(GDBM_SYNC)
+    rb_define_const(cGDBM, "SYNC",    INT2FIX(GDBM_SYNC));
+#endif
+#if defined(GDBM_NOLOCK)
+    rb_define_const(cGDBM, "NOLOCK",  INT2FIX(GDBM_NOLOCK));
+#endif
+    rb_define_const(cGDBM, "VERSION",  rb_str_new2(gdbm_version));
 }
diff --git a/ext/md5/.cvsignore b/ext/md5/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/md5/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/md5/md5.txt b/ext/md5/md5.txt
index e2b072401b..1d58306cf5 100644
--- a/ext/md5/md5.txt
+++ b/ext/md5/md5.txt
@@ -5,30 +5,31 @@
 A class to implement MD5 Message-Digest Algorithm by RSA Data
 Security, Inc., described in RFC1321.
 
-SuperClass: Object
+Superclass: Object
 
 Class Methods:
 
    new([str])
    md5([str])
 
-	creates a new MD5 object.  If a string argument is given, it
+	Creates a new MD5 object.  If a string argument is given, it
         is added to the object. (see update.)
 
 Methods:
 
    clone
 
-	copies the MD5 object.
+	Copies the MD5 object.
 
    digest
 
-	returns have value of the added strings as a 16 bytes string.
+	Returns the MD5 hash of the added strings as a string of 16
+	bytes.
 
    hexdigest
 
-	returns have value of the added strings as an 32 bytes ASCII
-	string. This method is equal to:
+	Returns the MD5 hash of the added strings as a string of 32
+	hexadecimal digits.  This method is equal to:
 
 	def hexdigest
 	  ret = ''
@@ -38,7 +39,7 @@ Methods:
 
    update(str)
 
-	Update the MD5 object with the string.  Repeated calls are
+	Update the MD5 object with the string str.  Repeated calls are
 	equivalent to a single call with the concatenation of all the
 	arguments, i.e. m.update(a); m.update(b) is equivalent to
 	m.update(a+b).
diff --git a/ext/md5/md5.txt.jp b/ext/md5/md5.txt.jp
index 04cf32908d..b71dd9bfc9 100644
--- a/ext/md5/md5.txt.jp
+++ b/ext/md5/md5.txt.jp
@@ -3,9 +3,9 @@
 ** MD5(¥¯¥é¥¹)
 
 RFC1321¤Ëµ­½Ò¤µ¤ì¤Æ¤¤¤ëRSA Data Security, Inc. ¤Î MD5 Message-Digest
-Algorithm¤ò¼ÂÁõ¤¹¤ë¥¯¥é¥¹¡¥
+Algorithm¤ò¼ÂÁõ¤¹¤ë¥¯¥é¥¹¡£
 
-SuperClass: Object
+Superclass: Object
 
 Class Methods:
 
@@ -13,18 +13,18 @@ Class Methods:
    md5([str])
 
         ¿·¤·¤¤MD5¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤¹¤ë¡¥Ê¸»úÎó°ú¿ô¤¬Í¿¤¨¤é¤ì¤ë¤È¤½¤ì
-        ¤òÄɲ乤ë(see update)¡¥
+        ¤òÄɲ乤ë(see update)¡£
 
 Methods:
 
    clone
 
-	MD5¥ª¥Ö¥¸¥§¥¯¥È¤ÎÊ£À½¤òºî¤ë
+	MD5¥ª¥Ö¥¸¥§¥¯¥È¤ÎÊ£À½¤òºî¤ë¡£
 
    digest
 
         º£¤Þ¤Ç¤ËÄɲä·¤¿Ê¸»úÎó¤ËÂФ¹¤ë¥Ï¥Ã¥·¥åÃͤò16¥Ð¥¤¥ÈŤÎʸ»úÎó¤Ç
-        ÊÖ¤¹¡¥
+        ÊÖ¤¹¡£
 
    hexdigest
 
@@ -41,7 +41,8 @@ Methods:
    update(str)
 
         MD5¥ª¥Ö¥¸¥§¥¯¥È¤Ëʸ»úÎó¤òÄɲ乤롣ʣ¿ô²óupdate¤ò¸Æ¤Ö¤³¤È¤Ïʸ
-        »úÎó¤òÏ¢·ë¤·¤Æupdate¤ò¸Æ¤Ö¤³¤È¤ÈÅù¤·¤¤¡¥
+        »úÎó¤òÏ¢·ë¤·¤Æupdate¤ò¸Æ¤Ö¤³¤È¤ÈÅù¤·¤¤¡£¤¹¤Ê¤ï¤Á m.update(a);
+	m.update(b) ¤Ï m.update(a+b) ¤ÈÅù²Á¤Ç¤¢¤ë¡£
 
 -------------------------------------------------------
 Local variables:
diff --git a/ext/nkf/.cvsignore b/ext/nkf/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/nkf/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/pty/.cvsignore b/ext/pty/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/pty/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb
index 4df2011eb5..ba2b44c70b 100644
--- a/ext/pty/extconf.rb
+++ b/ext/pty/extconf.rb
@@ -1,10 +1,12 @@
 require 'mkmf'
 
-have_header("sys/stropts.h")
-have_func("setresuid")
-$CFLAGS << "-DHAVE_DEV_PTMX" if /cygwin/ === RUBY_PLATFORM
-if have_func("openpty") or
-    have_func("_getpty") or
-    have_func("ioctl")
-  create_makefile('pty')
+if /mswin32|mingw/ !~ RUBY_PLATFORM
+  have_header("sys/stropts.h")
+  have_func("setresuid")
+  $CFLAGS << "-DHAVE_DEV_PTMX" if /cygwin/ === RUBY_PLATFORM
+  if have_func("openpty") or
+      have_func("_getpty") or
+      have_func("ioctl")
+    create_makefile('pty')
+  end
 end
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 66907416eb..35e4080e62 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -374,7 +374,7 @@ getDevice(master,slave)
 	    if(unlockpt(i) != -1) {
 		if((pn = ptsname(i)) != NULL) {
 		    if((j = open(pn, O_RDWR, 0)) != -1) {
-#if defined I_PUSH
+#if defined I_PUSH && !defined linux
 			if(ioctl(j, I_PUSH, "ptem") != -1) {
 			    if(ioctl(j, I_PUSH, "ldterm") != -1) {
 #endif
@@ -382,7 +382,7 @@ getDevice(master,slave)
 				*slave = j;
 				strcpy(SlaveName, pn);
 				return;
-#if defined I_PUSH
+#if defined I_PUSH && !defined linux
 			    }
 			}
 #endif
diff --git a/ext/readline/.cvsignore b/ext/readline/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/readline/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb
index 7db62745f3..431ed213bb 100644
--- a/ext/readline/extconf.rb
+++ b/ext/readline/extconf.rb
@@ -9,5 +9,8 @@ have_library("ncurses", "tgetnum") or
 if have_header("readline/readline.h") and
     have_header("readline/history.h") and
     have_library("readline", "readline")
+  if have_func("rl_filename_completion_function")
+    $CFLAGS += "-DREADLINE_42_OR_LATER"
+  end
   create_makefile("readline")
 end
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
index 02b29796af..876207c224 100644
--- a/ext/readline/readline.c
+++ b/ext/readline/readline.c
@@ -15,6 +15,12 @@ static VALUE mReadline;
 #define COMPLETION_PROC "completion_proc"
 #define COMPLETION_CASE_FOLD "completion_case_fold"
 
+#ifndef READLINE_42_OR_LATER
+# define rl_filename_completion_function filename_completion_function
+# define rl_username_completion_function username_completion_function
+# define rl_completion_matches completion_matches
+#endif
+
 static int
 readline_event()
 {
@@ -321,8 +327,8 @@ filename_completion_proc_call(self, str)
     char **matches;
     int i;
 
-    matches = completion_matches(STR2CSTR(str),
-				 filename_completion_function);
+    matches = rl_completion_matches(STR2CSTR(str),
+				    rl_filename_completion_function);
     if (matches) {
 	result = rb_ary_new();
 	for (i = 0; matches[i]; i++) {
@@ -348,8 +354,8 @@ username_completion_proc_call(self, str)
     char **matches;
     int i;
 
-    matches = completion_matches(STR2CSTR(str),
-				 username_completion_function);
+    matches = rl_completion_matches(STR2CSTR(str),
+				    rl_username_completion_function);
     if (matches) {
 	result = rb_ary_new();
 	for (i = 0; matches[i]; i++) {
diff --git a/ext/sdbm/.cvsignore b/ext/sdbm/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/sdbm/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/sdbm/_sdbm.c b/ext/sdbm/_sdbm.c
index 7a31472930..d8bfae80b2 100644
--- a/ext/sdbm/_sdbm.c
+++ b/ext/sdbm/_sdbm.c
@@ -103,11 +103,9 @@ static int   duppair proto((char *, datum));
 /*
  * externals
  */
-#ifndef sun
-#ifndef MSDOS
+#if !defined sun && !defined MSDOS && !defined _WIN32 && !defined __CYGWIN__
 extern int errno;
 #endif
-#endif
 
 /*
  * forward
diff --git a/ext/sdbm/init.c b/ext/sdbm/init.c
index 87136e9bdb..458695fc2b 100644
--- a/ext/sdbm/init.c
+++ b/ext/sdbm/init.c
@@ -6,7 +6,7 @@
   $Date$
   created at: Fri May  7 08:34:24 JST 1999
 
-  Copyright (C) 1995-1998 Yukihiro Matsumoto
+  Copyright (C) 1995-2001 Yukihiro Matsumoto
 
 ************************************************/
 
@@ -16,7 +16,7 @@
 #include 
 #include 
 
-VALUE cSDBM;
+static VALUE cSDBM;
 
 struct dbmdata {
     int  di_size;
@@ -44,16 +44,28 @@ free_sdbm(dbmp)
 }
 
 static VALUE
-fsdbm_s_open(argc, argv, klass)
+fsdbm_close(obj)
+    VALUE obj;
+{
+    struct dbmdata *dbmp;
+
+    GetDBM(obj, dbmp);
+    sdbm_close(dbmp->di_dbm);
+    dbmp->di_dbm = 0;
+
+    return Qnil;
+}
+
+static VALUE
+fsdbm_initialize(argc, argv, obj)
     int argc;
     VALUE *argv;
-    VALUE klass;
+    VALUE obj;
 {
     VALUE file, vmode;
     DBM *dbm;
     struct dbmdata *dbmp;
     int mode;
-    VALUE obj;
 
     if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
 	mode = 0666;		/* default value */
@@ -64,6 +76,7 @@ fsdbm_s_open(argc, argv, klass)
     else {
 	mode = NUM2INT(vmode);
     }
+    file = rb_str_to_str(file);
     Check_SafeStr(file);
 
     dbm = 0;
@@ -79,7 +92,8 @@ fsdbm_s_open(argc, argv, klass)
 	rb_sys_fail(RSTRING(file)->ptr);
     }
 
-    obj = Data_Make_Struct(klass,struct dbmdata,0,free_sdbm,dbmp);
+    dbmp = ALLOC(struct dbmdata);
+    DATA_PTR(obj) = dbmp;
     dbmp->di_dbm = dbm;
     dbmp->di_size = -1;
 
@@ -87,16 +101,33 @@ fsdbm_s_open(argc, argv, klass)
 }
 
 static VALUE
-fsdbm_close(obj)
-    VALUE obj;
+fsdbm_s_new(argc, argv, klass)
+    int argc;
+    VALUE *argv;
+    VALUE klass;
 {
-    struct dbmdata *dbmp;
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_sdbm, 0);
+    rb_obj_call_init(obj, argc, argv);
+    return obj;
+}
 
-    GetDBM(obj, dbmp);
-    sdbm_close(dbmp->di_dbm);
-    dbmp->di_dbm = 0;
+static VALUE
+fsdbm_s_open(argc, argv, klass)
+    int argc;
+    VALUE *argv;
+    VALUE klass;
+{
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_sdbm, 0);
 
-    return Qnil;
+    if (NIL_P(fsdbm_initialize(argc, argv, obj))) {
+	return Qnil;
+    }
+
+    if (rb_block_given_p()) {
+        return rb_ensure(rb_yield, obj, fsdbm_close, obj);
+    }
+
+    return obj;
 }
 
 static VALUE
@@ -107,7 +138,7 @@ fsdbm_fetch(obj, keystr, ifnone)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
@@ -135,10 +166,14 @@ fsdbm_fetch_m(argc, argv, obj)
     VALUE *argv;
     VALUE obj;
 {
-    VALUE keystr, ifnone;
+    VALUE keystr, valstr, ifnone;
 
     rb_scan_args(argc, argv, "11", &keystr, &ifnone);
-    return fsdbm_fetch(obj, keystr, ifnone);
+    valstr = fsdbm_fetch(obj, keystr, ifnone);
+    if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
+	rb_raise(rb_eIndexError, "key not found");
+
+    return valstr;
 }
 
 static VALUE
@@ -149,7 +184,7 @@ fsdbm_index(obj, valstr)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(valstr, T_STRING);
+    valstr = rb_str_to_str(valstr);
     val.dptr = RSTRING(valstr)->ptr;
     val.dsize = RSTRING(valstr)->len;
 
@@ -190,12 +225,13 @@ fsdbm_delete(obj, keystr)
     DBM *dbm;
 
     rb_secure(4);
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
+    dbmp->di_size = -1;
 
     value = sdbm_fetch(dbm, key);
     if (value.dptr == 0) {
@@ -229,10 +265,13 @@ fsdbm_shift(obj)
     key = sdbm_firstkey(dbm); 
     if (!key.dptr) return Qnil;
     val = sdbm_fetch(dbm, key);
-    sdbm_delete(dbm, key);
-
     keystr = rb_tainted_str_new(key.dptr, key.dsize);
     valstr = rb_tainted_str_new(val.dptr, val.dsize);
+    sdbm_delete(dbm, key);
+    if (dbmp->di_size >= 0) {
+	dbmp->di_size--;
+    }
+
     return rb_assoc_new(keystr, valstr);
 }
 
@@ -244,20 +283,34 @@ fsdbm_delete_if(obj)
     struct dbmdata *dbmp;
     DBM *dbm;
     VALUE keystr, valstr;
+    VALUE ret, ary = rb_ary_new();
+    int i, status = 0, n;
 
     rb_secure(4);
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
+    n = dbmp->di_size;
+    dbmp->di_size = -1;
     for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
 	val = sdbm_fetch(dbm, key);
 	keystr = rb_tainted_str_new(key.dptr, key.dsize);
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
-	if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) {
-	    if (sdbm_delete(dbm, key)) {
-		rb_raise(rb_eRuntimeError, "sdbm_delete failed");
-	    }
+        ret = rb_protect(rb_yield, rb_assoc_new(rb_str_dup(keystr), valstr), &status);
+        if (status != 0) goto delete;
+	if (RTEST(ret)) rb_ary_push(ary, keystr);
+    }
+ delete:
+    for (i = 0; i < RARRAY(ary)->len; i++) {
+	keystr = RARRAY(ary)->ptr[i];
+	key.dptr = RSTRING(keystr)->ptr;
+	key.dsize = RSTRING(keystr)->len;
+	if (sdbm_delete(dbm, key)) {
+	    rb_raise(rb_eRuntimeError, "sdbm_delete failed");
 	}
     }
+    if (status) rb_jump_tag(status);
+    if (n > 0) dbmp->di_size = n - RARRAY(ary)->len;
+
     return obj;
 }
 
@@ -273,11 +326,16 @@ fsdbm_clear(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     dbmp->di_size = -1;
-    for (key = sdbm_firstkey(dbm); key.dptr; key = sdbm_nextkey(dbm)) {
-	if (sdbm_delete(dbm, key)) {
-	    rb_raise(rb_eRuntimeError, "sdbm_delete failed");
-	}
+    while (key = sdbm_firstkey(dbm), key.dptr) {
+        do {
+	    if (sdbm_delete(dbm, key)) {
+		rb_raise(rb_eRuntimeError, "sdbm_delete failed");
+	    }
+	    key = sdbm_nextkey(dbm);
+	} while (key.dptr);
     }
+    dbmp->di_size = 0;
+
     return obj;
 }
 
@@ -299,7 +357,7 @@ fsdbm_invert(obj)
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
 	rb_hash_aset(hash, valstr, keystr);
     }
-    return obj;
+    return hash;
 }
 
 static VALUE
@@ -528,7 +586,7 @@ fsdbm_has_key(obj, keystr)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(keystr, T_STRING);
+    keystr = rb_str_to_str(keystr);
     key.dptr = RSTRING(keystr)->ptr;
     key.dsize = RSTRING(keystr)->len;
 
@@ -547,7 +605,7 @@ fsdbm_has_value(obj, valstr)
     struct dbmdata *dbmp;
     DBM *dbm;
 
-    Check_Type(valstr, T_STRING);
+    valstr = rb_str_to_str(valstr);
     val.dptr = RSTRING(valstr)->ptr;
     val.dsize = RSTRING(valstr)->len;
 
@@ -620,7 +678,8 @@ Init_sdbm()
     rb_include_module(cSDBM, rb_mEnumerable);
 
     rb_define_singleton_method(cSDBM, "open", fsdbm_s_open, -1);
-    rb_define_singleton_method(cSDBM, "new", fsdbm_s_open, -1);
+    rb_define_singleton_method(cSDBM, "new", fsdbm_s_new, -1);
+    rb_define_method(cSDBM, "initialize", fsdbm_initialize, -1);
     rb_define_method(cSDBM, "close", fsdbm_close, 0);
     rb_define_method(cSDBM, "[]", fsdbm_aref, 1);
     rb_define_method(cSDBM, "fetch", fsdbm_fetch_m, -1);
@@ -638,7 +697,7 @@ Init_sdbm()
     rb_define_method(cSDBM, "each_pair", fsdbm_each_pair, 0);
     rb_define_method(cSDBM, "keys", fsdbm_keys, 0);
     rb_define_method(cSDBM, "values", fsdbm_values, 0);
-    rb_define_method(cSDBM, "shift", fsdbm_shift, 1);
+    rb_define_method(cSDBM, "shift", fsdbm_shift, 0);
     rb_define_method(cSDBM, "delete", fsdbm_delete, 1);
     rb_define_method(cSDBM, "delete_if", fsdbm_delete_if, 0);
     rb_define_method(cSDBM, "reject!", fsdbm_delete_if, 0);
diff --git a/ext/socket/.cvsignore b/ext/socket/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/socket/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index 3582c21c41..7dadd70078 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -338,9 +338,9 @@ if have_func(test_func)
   end
   if ENV["SOCKS_SERVER"] or enable_config("socks", false)
     if have_library("socks5", "SOCKSinit")
-      $CFLAGS="-DSOCKS5 -DSOCKS"
+      $CFLAGS+=" -DSOCKS5 -DSOCKS"
     elsif have_library("socks", "Rconnect")
-      $CFLAGS="-DSOCKS"
+      $CFLAGS+=" -DSOCKS"
     end
   end
   create_makefile("socket")
diff --git a/ext/tcltklib/.cvsignore b/ext/tcltklib/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/tcltklib/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/tcltklib/extconf.rb b/ext/tcltklib/extconf.rb
index c9082e0a7f..f732c165dc 100644
--- a/ext/tcltklib/extconf.rb
+++ b/ext/tcltklib/extconf.rb
@@ -67,5 +67,6 @@ if have_header("tcl.h") && have_header("tk.h") &&
     find_tcl(tcllib, stubs) &&
     find_tk(tklib, stubs)
   $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs
+  $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM
   create_makefile("tcltklib")
 end
diff --git a/ext/tcltklib/stubs.c b/ext/tcltklib/stubs.c
index 537ca74d37..faf5b4bb4b 100644
--- a/ext/tcltklib/stubs.c
+++ b/ext/tcltklib/stubs.c
@@ -3,7 +3,7 @@
 #include 
 #include "ruby.h"
 
-#if defined _WIN32
+#if defined _WIN32 || defined __CYGWIN__
 # include 
   typedef HINSTANCE DL_HANDLE;
 # define DL_OPEN LoadLibrary
diff --git a/ext/tk/.cvsignore b/ext/tk/.cvsignore
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/ext/tk/.cvsignore
@@ -0,0 +1 @@
+Makefile
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index a088d5c493..7bbba06151 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -1,5 +1,5 @@
 #
-#		tk.rb - Tk interface modue using tcltklib
+#		tk.rb - Tk interface module using tcltklib
 #			$Date$
 #			by Yukihiro Matsumoto 
 
@@ -351,7 +351,7 @@ module TkComm
     end
     if context.kind_of? Array
       context = context.collect{|ev|
-	if context.kind_of? TkVirtualEvent
+	if ev.kind_of? TkVirtualEvent
 	  ev.path
 	else
 	  ev
@@ -397,8 +397,18 @@ module TkComm
 	end
       }
     else
-      tk_split_list(tk_call(*what)).collect{|seq|
-	seq[1..-2].gsub(/>]+>*/).collect!{|subseq|
+	  case (subseq)
+	  when /^<<[^<>]+>>$/
+	    TkVirtualEvent.getobj(subseq[1..-2])
+	  when /^<[^<>]+>$/
+	    subseq[1..-2]
+	  else
+	    subseq.split('')
+	  end
+	}.flatten
+	(l.size == 1) ? l[0] : l
       }
     end
   end
@@ -651,12 +661,77 @@ module TkCore
   end
 end
 
+module TkPackage
+  include TkCore
+  extend TkPackage
+
+  def add_path(path)
+    Tk::AUTO_PATH.value = Tk::AUTO_PATH.to_a << path
+  end
+
+  def forget(package)
+    tk_call('package', 'forget', package)
+    nil
+  end
+
+  def names
+    tk_split_simplelist(tk_call('package', 'names'))
+  end
+
+  def provide(package, version=nil)
+    if version
+      tk_call('package', 'provide', package, version)
+      nil
+    else
+      tk_call('package', 'provide', package)
+    end
+  end
+
+  def present(package, version=None)
+    tk_call('package', 'present', package, version)
+  end
+
+  def present_exact(package, version)
+    tk_call('package', 'present', '-exact', package, version)
+  end
+
+  def require(package, version=None)
+    tk_call('package', 'require', package, version)
+  end
+
+  def require_exact(package, version)
+    tk_call('package', 'require', '-exact', package, version)
+  end
+
+  def versions(package)
+    tk_split_simplelist(tk_call('package', 'versions', package))
+  end
+
+  def vcompare(version1, version2)
+    Integer(tk_call('package', 'vcompare', version1, version2))
+  end
+
+  def vsatisfies(version1, version2)
+    bool(tk_call('package', 'vsatisfies', version1, version2))
+  end
+end
+
 module Tk
   include TkCore
   extend Tk
 
   TCL_VERSION = INTERP._invoke("info", "tclversion")
   TK_VERSION  = INTERP._invoke("set", "tk_version")
+
+  TCL_PATCHLEVEL = INTERP._invoke("info", "patchlevel")
+  TK_PATCHLEVEL  = INTERP._invoke("set", "tk_patchLevel")
+
+  TCL_LIBRARY = INTERP._invoke("set", "tcl_library")
+  TK_LIBRARY  = INTERP._invoke("set", "tk_library")
+  LIBRARY     = INTERP._invoke("info", "library")
+
+  PLATFORM = Hash[*tk_split_simplelist(INTERP._eval('array get tcl_platform'))]
+
   JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "")
 
   def root
@@ -680,6 +755,10 @@ module Tk
     tk_tcl2ruby(tk_call('focus', '-lastfor', win))
   end
 
+  def Tk.strictMotif(bool=None)
+    bool(tk_call('set', 'tk_strictMotif', bool))
+  end
+
   def Tk.show_kinsoku(mode='both')
     begin
       if /^8\.*/ === TK_VERSION  && JAPANIZED_TK
@@ -710,11 +789,11 @@ module Tk
     end
   end
 
-  def toUTF8(str,encoding)
+  def Tk.toUTF8(str,encoding)
     INTERP._toUTF8(str,encoding)
   end
   
-  def fromUTF8(str,encoding)
+  def Tk.fromUTF8(str,encoding)
     INTERP._fromUTF8(str,encoding)
   end
 
@@ -978,6 +1057,12 @@ class TkBindTag
     BTagID_TBL[id]? BTagID_TBL[id]: id
   end
 
+  ALL = self.new
+  ALL.instance_eval {
+    @id = 'all'
+    BTagID_TBL[@id] = self
+  }
+
   def initialize(*args)
     @id = Tk_BINDTAG_ID[0]
     Tk_BINDTAG_ID[0] = Tk_BINDTAG_ID[0].succ
@@ -995,20 +1080,11 @@ class TkBindTag
 end
 
 class TkBindTagAll")
+	PreDefVirtEvent.new(event)
+      else
+	fail ArgumentError, "undefined virtual event '<#{event}>'"
+      end
+    end
   end
 
   def TkVirtualEvent.info
@@ -22,8 +37,8 @@ class TkVirtualEvent", TkVirturlEventID[0])
-    TkVirturlEventID[0] += 1
+    @path = @id = format("", TkVirtualEventID[0])
+    TkVirtualEventID[0] += 1
     add(*sequences)
   end
 
@@ -31,7 +46,7 @@ class TkVirtualEvent", 
 	      *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) )
-      TkVirturlEventTBL[@id] = self
+      TkVirtualEventTBL[@id] = self
     end
     self
   end
@@ -39,11 +54,11 @@ class TkVirtualEvent")
-      TkVirturlEventTBL[@id] = nil
+      TkVirtualEventTBL[@id] = nil
     else
       tk_call('event', 'delete', "<#{@id}>", 
 	      *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) )
-      TkVirturlEventTBL[@id] = nil if info == []
+      TkVirtualEventTBL[@id] = nil if info == []
     end
     self
   end
diff --git a/file.c b/file.c
index 98098f9047..b246762a8c 100644
--- a/file.c
+++ b/file.c
@@ -67,7 +67,7 @@ char *strrchr _((const char*,const char));
 #include 
 
 #ifndef HAVE_LSTAT
-#define lstat stat
+#define lstat rb_sys_stat
 #endif
  
 VALUE rb_cFile;
@@ -113,7 +113,8 @@ rb_file_path(obj)
 #endif
 
 static VALUE
-stat_new(st)
+stat_new_0(klass, st)
+    VALUE klass;
     struct stat *st;
 {
     struct stat *nst;
@@ -121,7 +122,14 @@ stat_new(st)
 
     nst = ALLOC(struct stat);
     *nst = *st;
-    return Data_Wrap_Struct(rb_cStat, NULL, free, nst);
+    return Data_Wrap_Struct(klass, NULL, free, nst);
+}
+
+static VALUE
+stat_new(st)
+    struct stat *st;
+{
+    return stat_new_0(rb_cStat, st);
 }
 
 static struct stat*
@@ -152,42 +160,42 @@ static VALUE
 rb_stat_dev(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_dev);
+    return INT2NUM(get_stat(self)->st_dev);
 }
 
 static VALUE
 rb_stat_ino(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_ino);
+    return UINT2NUM(get_stat(self)->st_ino);
 }
 
 static VALUE
 rb_stat_mode(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_mode);
+    return UINT2NUM(get_stat(self)->st_mode);
 }
 
 static VALUE
 rb_stat_nlink(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_nlink);
+    return UINT2NUM(get_stat(self)->st_nlink);
 }
 
 static VALUE
 rb_stat_uid(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_uid);
+    return UINT2NUM(get_stat(self)->st_uid);
 }
 
 static VALUE
 rb_stat_gid(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_gid);
+    return UINT2NUM(get_stat(self)->st_gid);
 }
 
 static VALUE
@@ -195,7 +203,7 @@ rb_stat_rdev(self)
     VALUE self;
 {
 #ifdef HAVE_ST_RDEV
-    return INT2FIX((int)get_stat(self)->st_rdev);
+    return INT2NUM(get_stat(self)->st_rdev);
 #else
     return INT2FIX(0);
 #endif
@@ -205,7 +213,7 @@ static VALUE
 rb_stat_size(self)
     VALUE self;
 {
-    return INT2FIX((int)get_stat(self)->st_size);
+    return INT2NUM(get_stat(self)->st_size);
 }
 
 static VALUE
@@ -213,7 +221,7 @@ rb_stat_blksize(self)
     VALUE self;
 {
 #ifdef HAVE_ST_BLKSIZE
-    return INT2FIX((int)get_stat(self)->st_blksize);
+    return UINT2NUM(get_stat(self)->st_blksize);
 #else
     return INT2FIX(0);
 #endif
@@ -224,7 +232,7 @@ rb_stat_blocks(self)
     VALUE self;
 {
 #ifdef HAVE_ST_BLOCKS
-    return INT2FIX((int)get_stat(self)->st_blocks);
+    return UINT2NUM(get_stat(self)->st_blocks);
 #else
     return INT2FIX(0);
 #endif
@@ -314,17 +322,17 @@ rb_stat(file, st)
 #if defined DJGPP
     if (RSTRING(file)->len == 0) return -1;
 #endif
-    return stat(RSTRING(file)->ptr, st);
+    return rb_sys_stat(RSTRING(file)->ptr, st);
 }
 
 static VALUE
-rb_file_s_stat(obj, fname)
-    VALUE obj, fname;
+rb_file_s_stat(klass, fname)
+    VALUE klass, fname;
 {
     struct stat st;
 
     Check_SafeStr(fname);
-    if (stat(RSTRING(fname)->ptr, &st) == -1) {
+    if (rb_sys_stat(RSTRING(fname)->ptr, &st) == -1) {
 	rb_sys_fail(RSTRING(fname)->ptr);
     }
     return stat_new(&st);
@@ -345,8 +353,8 @@ rb_io_stat(obj)
 }
 
 static VALUE
-rb_file_s_lstat(obj, fname)
-    VALUE obj, fname;
+rb_file_s_lstat(klass, fname)
+    VALUE klass, fname;
 {
 #ifdef HAVE_LSTAT
     struct stat st;
@@ -357,7 +365,7 @@ rb_file_s_lstat(obj, fname)
     }
     return stat_new(&st);
 #else
-    return rb_file_s_stat(obj, fname);
+    return rb_file_s_stat(klass, fname);
 #endif
 }
 
@@ -420,7 +428,7 @@ eaccess(path, mode)
   struct stat st;
   static int euid = -1;
 
-  if (stat(path, &st) < 0) return (-1);
+  if (rb_sys_stat(path, &st) < 0) return (-1);
 
   if (euid == -1)
     euid = geteuid ();
@@ -722,7 +730,7 @@ check3rdbyte(file, mode)
 {
     struct stat st;
 
-    if (stat(file, &st) < 0) return Qfalse;
+    if (rb_sys_stat(file, &st) < 0) return Qfalse;
     if (st.st_mode & mode) return Qtrue;
     return Qfalse;
 }
@@ -757,15 +765,16 @@ test_sticky(obj, fname)
     VALUE obj, fname;
 {
 #ifdef S_ISVTX
-    return check3rdbyte(STR2CSTR(fname), S_ISVTX);
+    Check_SafeStr(fname);
+    return check3rdbyte(RSTRING(fname)->ptr, S_ISVTX);
 #else
     return Qnil;
 #endif
 }
 
 static VALUE
-rb_file_s_size(obj, fname)
-    VALUE obj, fname;
+rb_file_s_size(klass, fname)
+    VALUE klass, fname;
 {
     struct stat st;
 
@@ -815,8 +824,8 @@ rb_file_ftype(st)
 }
 
 static VALUE
-rb_file_s_ftype(obj, fname)
-    VALUE obj, fname;
+rb_file_s_ftype(klass, fname)
+    VALUE klass, fname;
 {
     struct stat st;
 
@@ -829,8 +838,8 @@ rb_file_s_ftype(obj, fname)
 }
 
 static VALUE
-rb_file_s_atime(obj, fname)
-    VALUE obj, fname;
+rb_file_s_atime(klass, fname)
+    VALUE klass, fname;
 {
     struct stat st;
 
@@ -854,8 +863,8 @@ rb_file_atime(obj)
 }
 
 static VALUE
-rb_file_s_mtime(obj, fname)
-    VALUE obj, fname;
+rb_file_s_mtime(klass, fname)
+    VALUE klass, fname;
 {
     struct stat st;
 
@@ -879,8 +888,8 @@ rb_file_mtime(obj)
 }
 
 static VALUE
-rb_file_s_ctime(obj, fname)
-    VALUE obj, fname;
+rb_file_s_ctime(klass, fname)
+    VALUE klass, fname;
 {
     struct stat st;
 
@@ -1097,8 +1106,8 @@ rb_file_s_utime(argc, argv)
 #endif
 
 static VALUE
-rb_file_s_link(obj, from, to)
-    VALUE obj, from, to;
+rb_file_s_link(klass, from, to)
+    VALUE klass, from, to;
 {
     Check_SafeStr(from);
     Check_SafeStr(to);
@@ -1109,8 +1118,8 @@ rb_file_s_link(obj, from, to)
 }
 
 static VALUE
-rb_file_s_symlink(obj, from, to)
-    VALUE obj, from, to;
+rb_file_s_symlink(klass, from, to)
+    VALUE klass, from, to;
 {
 #ifdef HAVE_SYMLINK
     Check_SafeStr(from);
@@ -1126,8 +1135,8 @@ rb_file_s_symlink(obj, from, to)
 }
 
 static VALUE
-rb_file_s_readlink(obj, path)
-    VALUE obj, path;
+rb_file_s_readlink(klass, path)
+    VALUE klass, path;
 {
 #ifdef HAVE_READLINK
     char buf[MAXPATHLEN];
@@ -1154,24 +1163,30 @@ unlink_internal(path)
 }
 
 static VALUE
-rb_file_s_unlink(obj, args)
-    VALUE obj, args;
+rb_file_s_unlink(klass, args)
+    VALUE klass, args;
 {
     int n;
 
+    rb_secure(2);
     n = apply2files(unlink_internal, args, 0);
     return INT2FIX(n);
 }
 
 static VALUE
-rb_file_s_rename(obj, from, to)
-    VALUE obj, from, to;
+rb_file_s_rename(klass, from, to)
+    VALUE klass, from, to;
 {
     Check_SafeStr(from);
     Check_SafeStr(to);
 
-    if (rename(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0)
+    if (rename(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0) {
+#if defined __CYGWIN__
+	extern unsigned long __attribute__((stdcall)) GetLastError();
+	errno = GetLastError(); /* This is a Cygwin bug */
+#endif
 	rb_sys_fail(RSTRING(from)->ptr);
+    }
 
     return INT2FIX(0);
 }
@@ -1253,7 +1268,7 @@ rb_file_s_expand_path(argc, argv)
     }
 #if defined DOSISH
     /* skip drive letter */
-    else if (isalpha(s[0]) && s[1] == ':' && isdirsep(s[2])) {
+    else if (ISALPHA(s[0]) && s[1] == ':' && isdirsep(s[2])) {
 	while (*s && !isdirsep(*s)) {
 	    *p++ = *s++;
 	}
@@ -1388,8 +1403,8 @@ rb_file_s_basename(argc, argv)
 }
 
 static VALUE
-rb_file_s_dirname(obj, fname)
-    VALUE obj, fname;
+rb_file_s_dirname(klass, fname)
+    VALUE klass, fname;
 {
     char *name, *p;
     VALUE dirname;
@@ -1407,8 +1422,8 @@ rb_file_s_dirname(obj, fname)
 }
 
 static VALUE
-rb_file_s_split(obj, path)
-    VALUE obj, path;
+rb_file_s_split(klass, path)
+    VALUE klass, path;
 {
     return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path));
 }
@@ -1416,15 +1431,15 @@ rb_file_s_split(obj, path)
 static VALUE separator;
 
 static VALUE
-rb_file_s_join(obj, args)
-    VALUE obj, args;
+rb_file_s_join(klass, args)
+    VALUE klass, args;
 {
     return rb_ary_join(args, separator);
 }
 
 static VALUE
-rb_file_s_truncate(obj, path, len)
-    VALUE obj, path, len;
+rb_file_s_truncate(klass, path, len)
+    VALUE klass, path, len;
 {
     rb_secure(2);
     Check_SafeStr(path);
@@ -1509,11 +1524,14 @@ rb_thread_flock(fd, op, fptr)
     op |= LOCK_NB;
     while (flock(fd, op) < 0) {
 	switch (errno) {
-	  case EINTR:			/* can be happen? */
+          case EAGAIN:
+          case EACCES:
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
 	  case EWOULDBLOCK:
+#endif
 	    rb_thread_polling();	/* busy wait */
 	    rb_io_check_closed(fptr);
-	    break;
+            continue;
 	  default:
 	    return -1;
 	}
@@ -1542,11 +1560,14 @@ rb_file_flock(obj, operation)
     ret = flock(fileno(fptr->f), NUM2INT(operation));
     TRAP_END;
     if (ret < 0) {
-#ifdef EWOULDBLOCK
-	if (errno == EWOULDBLOCK) {
-	    return Qfalse;
-	}
+        switch (errno) {
+          case EAGAIN:
+          case EACCES:
+#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
+          case EWOULDBLOCK:
 #endif
+              return Qfalse;
+        }
 	rb_sys_fail(fptr->path);
     }
 #endif
@@ -1715,6 +1736,30 @@ rb_f_test(argc, argv)
     return Qnil;		/* not reached */
 }
 
+static VALUE
+rb_stat_s_new(klass, fname)
+    VALUE klass, fname;
+{
+    VALUE s;
+    struct stat st;
+
+    Check_SafeStr(fname);
+    if (rb_sys_stat(RSTRING(fname)->ptr, &st) == -1) {
+	rb_sys_fail(RSTRING(fname)->ptr);
+    }
+    s = stat_new_0(klass, &st);
+    rb_obj_call_init(s, 1, &fname);
+    return s;
+}
+
+static VALUE
+rb_stat_init(klass, fname)
+    VALUE klass, fname;
+{
+    /* do nothing */
+    return Qnil;
+}
+
 static VALUE
 rb_stat_ftype(obj)
     VALUE obj;
@@ -2029,6 +2074,7 @@ path_check_1(path)
     }
     for (;;) {
 	if (stat(path, &st) == 0 && (st.st_mode & 002)) {
+           if (p) *p = '/';
 	    return 0;
 	}
 	s = strrchr(path, '/');
@@ -2056,7 +2102,10 @@ rb_path_check(path)
 
 	if (pend) *pend = '\0';
 	safe = path_check_1(p);
-	if (!safe) return 0;
+       if (!safe) {
+           if (pend) *pend = sep;
+           return 0;
+       }
 	if (!pend) break;
 	*pend = sep;
 	p = pend + 1;
@@ -2089,7 +2138,7 @@ rb_find_file(file)
     if (is_macos_native_path(file)) {
 	FILE *f;
 
-	if (safe_level >= 2 && !rb_path_check(file)) {
+	if (rb_safe_level() >= 2 && !rb_path_check(file)) {
 	    rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
 	}
 	f= fopen(file, "r");
@@ -2159,6 +2208,7 @@ define_filetest_function(name, func, argc)
     rb_define_singleton_method(rb_cFile, name, func, argc);
 }
 
+void
 Init_File()
 {
     rb_mFileTest = rb_define_module("FileTest");
@@ -2254,6 +2304,8 @@ Init_File()
     rb_define_global_function("test", rb_f_test, -1);
 
     rb_cStat = rb_define_class_under(rb_cFile, "Stat", rb_cObject);
+    rb_define_singleton_method(rb_cStat, "new",  rb_stat_s_new, 1);
+    rb_define_method(rb_cStat, "initialize", rb_stat_init, 1);
 
     rb_include_module(rb_cStat, rb_mComparable);
 
diff --git a/gc.c b/gc.c
index a3578aef2f..1df6d8ede8 100644
--- a/gc.c
+++ b/gc.c
@@ -31,10 +31,23 @@ void rb_io_fptr_finalize _((struct OpenFile*));
 #endif
 #endif
 
-#ifdef C_ALLOCA
-#ifndef alloca
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+# ifndef atarist
+#  ifndef alloca
+#   define alloca __builtin_alloca
+#  endif
+# endif /* atarist */
+#else
+# if defined(HAVE_ALLOCA_H)
+#  include 
+# elif !defined(alloca)
 void *alloca();
-#endif
+# endif
+#endif /* __GNUC__ */
+
+#ifdef _AIX
+#pragma alloca
 #endif
 
 static void run_final();
@@ -53,10 +66,17 @@ static void
 mem_error(mesg)
     char *mesg;
 {
+    static int recurse = 0;
+
     if (rb_safe_level() >= 4) {
 	rb_raise(rb_eNoMemError, mesg);
     }
-    rb_fatal(mesg);
+    if (recurse == 0) {
+	recurse++;
+	rb_fatal(mesg);
+    }
+    fprintf(stderr, "[FATAL] failed to allocate memory\n");
+    exit(1);
 }
 
 void *
@@ -308,10 +328,7 @@ rb_data_object_alloc(klass, datap, dmark, dfree)
 extern st_table *rb_class_tbl;
 VALUE *rb_gc_stack_start = 0;
 
-#if defined(__GNUC__) && __GNUC__ >= 2
-__inline__
-#endif
-static int
+static inline int
 is_pointer_to_heap(ptr)
     void *ptr;
 {
@@ -606,6 +623,7 @@ rb_gc_mark(ptr)
       case T_REGEXP:
       case T_FLOAT:
       case T_BIGNUM:
+      case T_BLKTAG:
 	break;
 
       case T_MATCH:
@@ -712,7 +730,7 @@ gc_sweep()
     during_gc = 0;
 
     /* clear finalization list */
-    if (need_call_final && final_list) {
+    if (final_list) {
 	RVALUE *tmp;
 
 	if (rb_prohibit_interrupt || ruby_in_compile) {
@@ -822,6 +840,7 @@ obj_free(obj)
 
       case T_FLOAT:
       case T_VARMAP:
+      case T_BLKTAG:
 	break;
 
       case T_BIGNUM:
@@ -924,7 +943,7 @@ rb_gc()
     alloca(0);
 # define STACK_END (&stack_end)
 #else
-# if defined(__GNUC__) && !defined(__alpha__) && !defined(__APPLE__)
+# if defined(__GNUC__) && (defined(__i386__) || defined(__m68k__))
     VALUE *stack_end = __builtin_frame_address(0);
 # else
     VALUE *stack_end = alloca(1);
@@ -1004,7 +1023,7 @@ Init_stack(addr)
 #if defined(__human68k__)
     extern void *_SEND;
     rb_gc_stack_start = _SEND;
-#elif defined(__GNUC__) && !defined(__alpha__) && !defined(__APPLE__)
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__m68k__))
     rb_gc_stack_start = __builtin_frame_address(2);
 #else
     VALUE start;
@@ -1044,6 +1063,7 @@ os_live_obj()
 		  case T_CLASS:
 		    if (FL_TEST(p, FL_SINGLETON)) continue;
 		  default:
+		    if (!p->as.basic.klass) continue;
 		    rb_yield((VALUE)p);
 		    n++;
 		}
@@ -1076,6 +1096,7 @@ os_obj_of(of)
 		  case T_CLASS:
 		    if (FL_TEST(p, FL_SINGLETON)) continue;
 		  default:
+		    if (!p->as.basic.klass) continue;
 		    if (rb_obj_is_kind_of((VALUE)p, of)) {
 			rb_yield((VALUE)p);
 			n++;
@@ -1130,7 +1151,7 @@ rm_final(os, proc)
 static VALUE
 finals()
 {
-    rb_warn("ObjectSpace::finals is deprecated");
+    rb_warn("ObjectSpace::finalizers is deprecated");
     return finalizers;
 }
 
@@ -1207,8 +1228,7 @@ run_final(obj)
 	args[0] = RARRAY(finalizers)->ptr[i];
 	rb_protect(run_single_final, (VALUE)args, &status);
     }
-    if (finalizer_table && st_lookup(finalizer_table, obj, &table)) {
-	st_delete(finalizer_table, &obj, 0);
+    if (finalizer_table && st_delete(finalizer_table, &obj, &table)) {
 	for (i=0; ilen; i++) {
 	    args[0] = RARRAY(table)->ptr[i];
 	    rb_protect(run_single_final, (VALUE)args, &status);
@@ -1223,14 +1243,25 @@ rb_gc_call_finalizer_at_exit()
     int i;
 
     /* run finalizers */
-    for (i = 0; i < heaps_used; i++) {
-	p = heaps[i]; pend = p + HEAP_SLOTS;
-	while (p < pend) {
-	    if (FL_TEST(p, FL_FINALIZE)) {
-		p->as.free.flag = 0;
-		run_final((VALUE)p);
+    if (need_call_final) {
+	if (deferred_final_list) {
+	    p = deferred_final_list;
+	    while (p) {
+		RVALUE *tmp = p;
+		p = p->as.free.next;
+		run_final((VALUE)tmp);
+	    }
+	}
+	for (i = 0; i < heaps_used; i++) {
+	    p = heaps[i]; pend = p + HEAP_SLOTS;
+	    while (p < pend) {
+		if (FL_TEST(p, FL_FINALIZE)) {
+		    FL_UNSET(p, FL_FINALIZE);
+		    p->as.basic.klass = 0;
+		    run_final((VALUE)p);
+		}
+		p++;
 	    }
-	    p++;
 	}
     }
     /* run data object's finaliers */
@@ -1255,21 +1286,24 @@ static VALUE
 id2ref(obj, id)
     VALUE obj, id;
 {
-    unsigned long ptr;
+    unsigned long ptr, p0;
 
     rb_secure(4);
-    ptr = NUM2UINT(id);
-    if (FIXNUM_P(ptr)) return (VALUE)ptr;
+    p0 = ptr = NUM2ULONG(id);
     if (ptr == Qtrue) return Qtrue;
     if (ptr == Qfalse) return Qfalse;
     if (ptr == Qnil) return Qnil;
+    if (FIXNUM_P(ptr)) return (VALUE)ptr;
+    if (SYMBOL_P(ptr) && rb_id2name(SYM2ID((VALUE)ptr)) != 0) {
+	return (VALUE)ptr;
+    }
 
     ptr = id ^ FIXNUM_FLAG;	/* unset FIXNUM_FLAG */
     if (!is_pointer_to_heap(ptr)) {
-	rb_raise(rb_eRangeError, "0x%x is not id value", ptr);
+	rb_raise(rb_eRangeError, "0x%x is not id value", p0);
     }
     if (BUILTIN_TYPE(ptr) == 0) {
-	rb_raise(rb_eRangeError, "0x%x is recycled object", ptr);
+	rb_raise(rb_eRangeError, "0x%x is recycled object", p0);
     }
     return (VALUE)ptr;
 }
@@ -1303,37 +1337,3 @@ Init_GC()
     rb_gc_unregister_address(&rb_mObSpace);
     finalizers = rb_ary_new();
 }
-
-#undef xmalloc
-#undef xcalloc
-#undef xrealloc
-#undef xfree
-
-void*
-xmalloc(size)
-    long size;
-{
-    return ruby_xmalloc(size);
-}
-
-void*
-xcalloc(n,size)
-    long n,size;
-{
-    return ruby_xcalloc(n, size);
-}
-
-void*
-xrealloc(ptr,size)
-    void *ptr;
-    long size;
-{
-    return ruby_xrealloc(ptr, size);
-}
-
-void
-xfree(ptr)
-    void *ptr;
-{
-    ruby_xfree(ptr);
-}
diff --git a/hash.c b/hash.c
index 2a5803c96e..1b007526da 100644
--- a/hash.c
+++ b/hash.c
@@ -79,16 +79,16 @@ static int
 rb_any_hash(a)
     VALUE a;
 {
-    unsigned int hval;
+    VALUE hval;
 
     switch (TYPE(a)) {
       case T_FIXNUM:
       case T_SYMBOL:
-	hval = a;
+	return (int)a;
 	break;
 
       case T_STRING:
-	hval = rb_str_hash(a);
+	return rb_str_hash(a);
 	break;
 
       default:
@@ -98,9 +98,8 @@ rb_any_hash(a)
 	    hval = rb_funcall(hval, '%', 1, INT2FIX(65439));
 	}
 	ENABLE_INTS;
-	hval = FIX2LONG(hval);
+	return (int)FIX2LONG(hval);
     }
-    return  hval;
 }
 
 static struct st_hash_type objhash = {
@@ -511,7 +510,10 @@ static int
 replace_i(key, val, hash)
     VALUE key, val, hash;
 {
-    rb_hash_aset(hash, key, val);
+    if (key != Qundef) {
+	rb_hash_aset(hash, key, val);
+    }
+
     return ST_CONTINUE;
 }
 
diff --git a/instruby.rb b/instruby.rb
index 265b854eb4..7818455dec 100644
--- a/instruby.rb
+++ b/instruby.rb
@@ -79,7 +79,7 @@ Dir.chdir CONFIG["srcdir"]
 File.install "sample/irb.rb", "#{bindir}/irb", 0755, true
 
 Find.find("lib") do |f|
-  next unless /\.rb$/ =~ f
+  next unless /\.rb$/ =~ f || /help-message$/ =~ f
   dir = rubylibdir+"/"+File.dirname(f[4..-1])
   File.makedirs dir, true unless File.directory? dir
   File.install f, dir, 0644, true
diff --git a/intern.h b/intern.h
index 7d8b0de130..fd0027830c 100644
--- a/intern.h
+++ b/intern.h
@@ -41,6 +41,7 @@ VALUE rb_ary_sort _((VALUE));
 VALUE rb_ary_sort_bang _((VALUE));
 VALUE rb_ary_delete _((VALUE, VALUE));
 VALUE rb_ary_delete_at _((VALUE, long));
+VALUE rb_ary_clear _((VALUE));
 VALUE rb_ary_plus _((VALUE, VALUE));
 VALUE rb_ary_concat _((VALUE, VALUE));
 VALUE rb_ary_assoc _((VALUE, VALUE));
@@ -77,6 +78,8 @@ VALUE rb_big_lshift _((VALUE, VALUE));
 VALUE rb_big_rand _((VALUE, double));
 /* class.c */
 VALUE rb_class_new _((VALUE));
+VALUE rb_mod_clone _((VALUE));
+VALUE rb_mod_dup _((VALUE));
 VALUE rb_singleton_class_new _((VALUE));
 VALUE rb_singleton_class_clone _((VALUE));
 void rb_singleton_class_attached _((VALUE,VALUE));
@@ -107,7 +110,8 @@ VALUE rb_exc_new3 _((VALUE, VALUE));
 void rb_loaderror __((const char*, ...)) NORETURN;
 void rb_compile_error __((const char*, ...));
 void rb_compile_error_append __((const char*, ...));
-void rb_error_frozen _((char*));
+void rb_load_fail _((char*)) NORETURN;
+void rb_error_frozen _((char*)) NORETURN;
 /* eval.c */
 void rb_exc_raise _((VALUE)) NORETURN;
 void rb_exc_fatal _((VALUE)) NORETURN;
@@ -293,7 +297,7 @@ VALUE rb_f_kill _((int, VALUE*));
 void rb_gc_mark_trap_list _((void));
 #ifdef POSIX_SIGNAL
 #define posix_signal ruby_posix_signal
-void posix_signal _((int, void (*)()));
+void posix_signal _((int, RETSIGTYPE (*)()));
 #endif
 void rb_trap_exit _((void));
 void rb_trap_exec _((void));
diff --git a/io.c b/io.c
index a422cc0869..79118b073a 100644
--- a/io.c
+++ b/io.c
@@ -27,6 +27,10 @@
 # define NO_LONG_FNAME
 #endif
 
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(sun)
+# define USE_SETVBUF
+#endif
+
 #include 
 #if !defined(DJGPP) && !defined(NT) && !defined(__human68k__)
 #include 
@@ -1362,6 +1366,10 @@ rb_fopen(fname, mode)
 	    rb_sys_fail(fname);
 	}
     }
+#ifdef USE_SETVBUF
+    if (setvbuf(file, NULL, _IOFBF, 0) != 0)
+	rb_warn("setvbuf() can't be honered for %s", fname);
+#endif
 #ifdef __human68k__
     fmode(file, _IOTEXT);
 #endif
@@ -1385,6 +1393,11 @@ rb_fdopen(fd, mode)
 	    rb_sys_fail(0);
 	}
     }
+#ifdef USE_SETVBUF
+    if (setvbuf(file, NULL, _IOFBF, 0) != 0)
+	rb_warn("setvbuf() can't be honered (fd=%d)", fd);
+#endif
+
     return file;
 }
 
@@ -1902,12 +1915,18 @@ rb_io_reopen(argc, argv, file)
 	    fclose(fptr->f2);
 	    fptr->f2 = 0;
 	}
+
 	return file;
     }
 
     if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == 0) {
 	rb_sys_fail(fptr->path);
     }
+#ifdef USE_SETVBUF
+    if (setvbuf(fptr->f, NULL, _IOFBF, 0) != 0)
+	rb_warn("setvbuf() can't be honered for %s", RSTRING(fname)->ptr);
+#endif
+
     if (fptr->f2) {
 	if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == 0) {
 	    rb_sys_fail(fptr->path);
@@ -2156,7 +2175,9 @@ rb_f_p(argc, argv)
     for (i=0; i'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
 
   HTTP_STATUS = {
@@ -350,11 +351,11 @@ class CGI
 =begin
 === MAKE RFC1123 DATE STRING
   CGI::rfc1123_date(Time.now)
-    # Sat, 1 Jan 2000 00:00:00 GMT
+    # Sat, 01 Jan 2000 00:00:00 GMT
 =end
   def CGI::rfc1123_date(time)
     t = time.clone.gmtime
-    return format("%s, %d %s %d %.2d:%.2d:%.2d GMT",
+    return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
                 RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
                 t.hour, t.min, t.sec)
   end
@@ -423,7 +424,8 @@ status:
       options["type"].concat( options.delete("charset") )
     end
 
-    if options.delete("nph") or (/IIS/n === env_table['SERVER_SOFTWARE'])
+    options.delete("nph") if defined?(MOD_RUBY)
+    if options.delete("nph") or /IIS/n.match(env_table['SERVER_SOFTWARE'])
       buf.concat( (env_table["SERVER_PROTOCOL"] or "HTTP/1.0")  + " " )
       buf.concat( (HTTP_STATUS[options["status"]] or
                       options["status"] or
@@ -446,7 +448,9 @@ status:
     end
 
     if options.has_key?("status")
-      buf.concat("Status: " + options.delete("status") + EOL)
+      status = (HTTP_STATUS[options["status"]] or options["status"])
+      buf.concat("Status: " + status + EOL)
+      options.delete("status")
     end
 
     if options.has_key?("server")
@@ -496,8 +500,21 @@ status:
     }
 
     if defined?(MOD_RUBY)
-      buf.scan(/([^:]+): (.+)#{EOL}/n){
-        Apache::request[$1] = $2
+      table = Apache::request.headers_out
+      buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value|
+        $stderr.printf("name:%s value:%s\n", name, value) if $DEBUG
+        case name
+        when 'Set-Cookie'
+          table.add($1, $2)
+        when /^status$/ni
+          Apache::request.status_line = value
+        when /^content-type$/ni
+          Apache::request.content_type = value
+        when /^content-encoding$/ni
+          Apache::request.content_encoding = value
+        else
+          Apache::request.headers_out[name] = value
+        end
       }
       Apache::request.send_http_header
       ''
@@ -626,13 +643,9 @@ convert string charset, and set language to "ja".
       # simple support for IE
       if options["path"]
         @path = options["path"]
-      elsif ENV["REQUEST_URI"]
-        @path = ENV["REQUEST_URI"].sub(/\?.*/n,'')
-        if ENV["PATH_INFO"]
-          @path = @path[0...@path.rindex(ENV["PATH_INFO"])]
-        end
       else
-        @path = (ENV["SCRIPT_NAME"] or "")
+        %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
+        @path = ($1 or "")
       end
       @domain = options["domain"]
       @expires = options["expires"]
@@ -793,9 +806,9 @@ convert string charset, and set language to "ja".
         body = Tempfile.new("CGI")
         body.binmode
 
-        until head and (/#{boundary}(?:#{EOL}|--)/n === buf)
+        until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
 
-          if (not head) and (/#{EOL}#{EOL}/n === buf)
+          if (not head) and /#{EOL}#{EOL}/n.match(buf)
             buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
               head = $1.dup
               ""
@@ -834,14 +847,14 @@ convert string charset, and set language to "ja".
           end
         END
 
-        /Content-Disposition:.* filename="?([^\";]*)"?/ni === head
+        /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(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'])
+              if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
+                 /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
+                 (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
                 CGI::unescape(filename)
               else
                 filename
@@ -850,14 +863,14 @@ convert string charset, and set language to "ja".
           end
         END
 
-        /Content-Type: (.*)/ni === head
+        /Content-Type: (.*)/ni.match(head)
         eval <<-END
           def body.content_type
             #{($1 or "").dump.untaint}.taint
           end
         END
 
-        /Content-Disposition:.* name="?([^\";]*)"?/ni === head
+        /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
         name = $1.dup
 
         if params.has_key?(name)
@@ -889,7 +902,7 @@ convert string charset, and set language to "ja".
 
       words = Shellwords.shellwords(string)
 
-      if words.find{|x| /=/n === x }
+      if words.find{|x| /=/n.match(x) }
         words.join('&')
       else
         words.join('+')
@@ -899,8 +912,7 @@ convert string charset, and set language to "ja".
 
     def initialize_query()
       if ("POST" == env_table['REQUEST_METHOD']) and
-         (%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n ===
-           env_table['CONTENT_TYPE'])
+         %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE'])
         boundary = $1.dup
         @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
       else
@@ -975,8 +987,8 @@ convert string charset, and set language to "ja".
   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" }
+  cgi.element({ "ATTRIBUTE1" => "value1", "ATTRIBUTE2" => "value2" })
+  cgi.element({ "ATTRIBUTE1" => "value1", "ATTRIBUTE2" => "value2" }){ "string" }
 
   # add HTML generation methods
   CGI.new("html3")    # html3.2
@@ -1235,8 +1247,10 @@ convert string charset, and set language to "ja".
   form("get", "url"){ "string" }
     # 
string
- form({"METHOD" => "post", ENCTYPE => "enctype"}){ "string" } + form({"METHOD" => "post", "ENCTYPE" => "enctype"}){ "string" } #
string
+ +The hash keys are case sensitive. Ask the samples. =end def form(method = "post", action = nil, enctype = "application/x-www-form-urlencoded") attributes = if method.kind_of?(String) @@ -1244,7 +1258,7 @@ convert string charset, and set language to "ja". "ENCTYPE" => enctype } else unless method.has_key?("METHOD") - method["METHOD"] = method + method["METHOD"] = "post" end unless method.has_key?("ENCTYPE") method["ENCTYPE"] = enctype @@ -1935,161 +1949,7 @@ end == HISTORY -* Mon Dec 25 05:02:27 JST 2000 - wakou - * version 2.1.2 - * bug fix: CGI::escapeElement(): didn't accept empty element. - * bug fix: CGI::unescapeElement(): ditto. - * bug fix: CGI::unescapeHTML(): support for "©, ♥, ..." - thanks to YANAGAWA Kazuhisa - * bug fix: CGI::unescapeHTML(): support for " " - thanks to OHSHIMA Ryunosuke - * Regexp::last_match[0] --> $& - * Regexp::last_match[1] --> $1 - * Regexp::last_match[2] --> $2 - * add: CGI#param(): test implement. undocumented. - -* Mon Dec 11 00:16:51 JST 2000 - wakou - * version 2.1.1 - * support -T1 on ruby 1.6.2 - * body.original_filename: eval(str.dump.untaint).taint - * body.content_type: eval(str.dump.untaint).taint - * $& --> Regexp::last_match[0] - * $1 --> Regexp::last_match[1] - * $2 --> Regexp::last_match[2] - -* Thu Oct 12 01:16:59 JST 2000 - wakou - * version 2.1.0 - * bug fix: CGI::html(): PRETTY option didn't work. - thanks to akira yamada - -* Wed Sep 13 06:09:26 JST 2000 - wakou - * version 2.0.1 - * bug fix: CGI::header(): output status header. - thanks to Yasuhiro Fukuma - -* Tue Sep 12 06:56:51 JST 2000 - wakou - * version 2.0.0 - * require ruby1.5.4 or later. (ruby1.4 doesn't have block_given? method.) - * improvement: CGI::escape(), CGI::unescape(). - thanks to WATANABE Hirofumi - * bug fix: CGI::escapeElement(). - * improvement: CGI::unescapeHTML(). - thanks to Kazuhiro NISHIYAMA - -* 2000/08/09 04:32:22 - matz - * improvement: CGI::pretty() - -* 2000/06/23 07:01:34 - matz - * change: iterator? --> block_given? - -* Sun Jun 18 23:31:44 JST 2000 - wakou - * version 1.7.0 - * change: version syntax. old: x.yz, now: x.y.z - -* 2000/06/13 15:49:27 - wakou - * version 1.61 - * read_multipart(): if no content body then raise EOFError. - -* 2000/06/03 18:16:17 - wakou - * version 1.60 - * improve: CGI::pretty() - -* 2000/05/30 19:04:08 - wakou - * version 1.50 - * CGI#out(): if "HEAD" == REQUEST_METHOD then output only HTTP header. - -* 2000/05/24 06:58:51 - wakou - * version 1.40 - * typo: CGI::Cookie::new() - * bug fix: CGI::escape(): bad: " " --> "%2B"; true: " " --> "+"; - thanks to Ryunosuke Ohshima - -* 2000/05/08 21:51:30 - wakou - * version 1.31 - * improvement of time forming new CGI object accompanied with HTML generation methods. - -* 2000/05/07 21:51:14 - wakou - * version 1.30 - * require English.rb - * improvement of load time. - -* 2000/05/02 21:44:12 - wakou - * version 1.21 - * support for ruby 1.5.3 (2000-05-01) (Array#filter --> Array#collect!) - -* 2000/04/03 18:31:42 - wakou - * version 1.20 - * bug fix: CGI#image_button() can't get Hash option. - thanks to Takashi Ikeda - * CGI::unescapeHTML(): simple support for "〹" - * CGI::Cookie::new(): simple support for IE - * CGI::escape(): ' ' replaced by '+' - -* 1999/12/06 20:16:34 - wakou - * version 1.10 - * can make many CGI objects. - * if use mod_ruby, then require ruby1.4.3 or later. - -* 1999/11/29 21:35:58 - wakou - * version 1.01 - * support for ruby 1.5.0 (1999-11-20) - -* 1999/09/13 23:00:58 - wakou - * version 1.00 - * 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 []. - -* 1999/08/05 18:04:59 - wakou - * version 0.41 - * typo. thanks to MJ Ray - HTTP_STATUS["NOT_INPLEMENTED"] --> HTTP_STATUS["NOT_IMPLEMENTED"] - -* 1999/07/20 20:44:31 - wakou - * version 0.40 - * 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 - -* 1999/06/29 06:50:21 - wakou - * version 0.30 - * COUTION! incompatible change. - query = CGI.new - cookies = query.cookies # old: query.cookie - values = query.cookies[name] # old: query.cookie[name] - -* 1999/06/21 21:05:57 - wakou - * version 0.24 - * CGI::Cookie::parse() return { name => CGI::Cookie object } pairs. - -* 1999/06/20 23:29:12 - wakou - * version 0.23 - * modified a bit to clear module separation. - -* Mon Jun 14 17:49:32 JST 1999 - matz - * version 0.22 - * Cookies are now CGI::Cookie objects. - * Cookie modeled after CGI::Cookie.pm. - -* Fri Jun 11 11:19:11 JST 1999 - matz - * version 0.21 - * modified a bit to clear module separation. - -* 1999/06/03 06:48:15 - wakou - * version 0.20 - * support for multipart form. - -* 1999/05/24 07:05:41 - wakou - * version 0.10 - * first release. - -$Date$ +delete. see cvs log. + + =end diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb index 48f3496939..9187dbf82d 100644 --- a/lib/cgi/session.rb +++ b/lib/cgi/session.rb @@ -1,3 +1,4 @@ +# Copyright (C) 2001 Yukihiro "Matz" Matsumoto # Copyright (C) 2000 Network Applied Communication Laboratory, Inc. # Copyright (C) 2000 Information-technology Promotion Agency, Japan @@ -15,23 +16,22 @@ class CGI } end - def create_new_id + def Session::create_new_id require 'md5' md5 = MD5::new md5.update(String(Time::now)) md5.update(String(rand(0))) md5.update(String($$)) md5.update('foobar') - @session_id = md5.hexdigest[0,16] + md5.hexdigest[0,16] end - private :create_new_id def initialize(request, option={}) session_key = option['session_key'] || '_session_id' id, = option['session_id'] unless id if option['new_session'] - id = create_new_id + id = Session::create_new_id end end unless id @@ -43,7 +43,7 @@ class CGI if option.key?('new_session') and not option['new_session'] raise ArgumentError, "session_key `%s' should be supplied"%session_key end - id = create_new_id + id = Session::create_new_id end end @session_id = id @@ -54,7 +54,9 @@ class CGI @output_cookies = [ Cookie::new("name" => session_key, "value" => id, - "path" => if ENV["SCRIPT_NAME"] then + "path" => if option['session_path'] then + option['session_path'] + elsif ENV["SCRIPT_NAME"] then File::dirname(ENV["SCRIPT_NAME"]) else "" @@ -94,10 +96,18 @@ class CGI end class FileStore + def check_id(id) + /[^0-9a-zA-Z]/ =~ id.to_s ? false : true + end + def initialize(session, option={}) dir = option['tmpdir'] || ENV['TMP'] || '/tmp' prefix = option['prefix'] || '' - path = dir+"/"+prefix+session.session_id + id = session.session_id + unless check_id(id) + raise ArgumentError, "session_id `%s' is invalid" % id + end + path = dir+"/"+prefix+id path.untaint unless File::exist? path @hash = {} @@ -132,6 +142,7 @@ class CGI end def close + return if @f.closed? update @f.close end @@ -146,9 +157,9 @@ class CGI class MemoryStore GLOBAL_HASH_TABLE = {} - def initialize(session, option={}) + def initialize(session, option=nil) @session_id = session.session_id - GLOBAL_HASH_TABLE[@session_id] = {} + GLOBAL_HASH_TABLE[@session_id] ||= {} end def restore @@ -164,7 +175,7 @@ class CGI end def delete - GLOBAL_HASH_TABLE[@session_id] = nil + GLOBAL_HASH_TABLE.delete(@session_id) end end end diff --git a/lib/date.rb b/lib/date.rb index 58179a7153..3422121298 100644 --- a/lib/date.rb +++ b/lib/date.rb @@ -1,5 +1,5 @@ -# date.rb: Written by Tadayoshi Funaba 1998-2000 -# $Id: date.rb,v 1.22 2000-07-16 10:23:40+09 tadf Exp $ +# date2.rb: Written by Tadayoshi Funaba 1998-2001 +# $Id: date2.rb,v 1.23 2001-01-18 12:09:47+09 tadf Exp $ class Date @@ -128,16 +128,15 @@ class Date end if d < 0 ny, nm = clfloor(y * 12 + m, 12) - nm, = clfloor(m + 1, 1) - la = nil - 31.downto 1 do |z| - break if la = exist3?(y, m, z, sg) - end - ns = ns?(la, sg) - d = jd_to_civil(civil_to_jd(ny, nm, 1, ns) + d, ns)[-1] + nm, = clfloor(nm + 1, 1) + jd = civil_to_jd(ny, nm, d + 1, sg) + ns = ns?(jd, sg) + return unless [y, m] == jd_to_civil(jd, sg)[0..1] + return unless [ny, nm, 1] == jd_to_civil(jd - d, ns) + else + jd = civil_to_jd(y, m, d, sg) + return unless [y, m, d] == jd_to_civil(jd, sg) end - jd = civil_to_jd(y, m, d, sg) - return unless [y, m, d] == jd_to_civil(jd, sg) jd end @@ -154,16 +153,15 @@ class Date def exist2? (y, d, sg=ITALY) if d < 0 - ny = y + 1 - la = nil - 366.downto 1 do |z| - break if la = exist2?(y, z, sg) - end - ns = ns?(la, sg) - d = jd_to_ordinal(ordinal_to_jd(ny, 1, ns) + d, ns)[-1] + ny, = clfloor(y + 1, 1) + jd = ordinal_to_jd(ny, d + 1, sg) + ns = ns?(jd, sg) + return unless [y] == jd_to_ordinal(jd, sg)[0..0] + return unless [ny, 1] == jd_to_ordinal(jd - d, ns) + else + jd = ordinal_to_jd(y, d, sg) + return unless [y, d] == jd_to_ordinal(jd, sg) end - jd = ordinal_to_jd(y, d, sg) - return unless [y, d] == jd_to_ordinal(jd, sg) jd end diff --git a/lib/debug.rb b/lib/debug.rb index b6968cc338..220b68d2c9 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -91,22 +91,70 @@ class DEBUGGER__ @finish_pos = 0 @trace = false @catch = "StandardError" + @suspend_next = false end def stop_next(n=1) @stop_next = n end + def set_suspend + @suspend_next = true + end + + def clear_suspend + @suspend_next = false + end + + def suspend_all + DEBUGGER__.suspend + end + + def resume_all + DEBUGGER__.resume + end + + def check_suspend + while (Thread.critical = true; @suspend_next) + DEBUGGER__.waiting.push Thread.current + @suspend_next = false + Thread.stop + end + Thread.critical = false + end + + def trace? + @trace + end + + def set_trace(arg) + @trace = arg + end + def stdout DEBUGGER__.stdout end + def break_points DEBUGGER__.break_points end + def display DEBUGGER__.display end + def context(th) + DEBUGGER__.context(th) + end + + def set_trace_all(arg) + DEBUGGER__.set_trace(arg) + end + + def set_last_thread(th) + DEBUGGER__.set_last_thread(th) + end + def debug_eval(str, binding) begin val = eval(str, binding) @@ -205,7 +253,7 @@ class DEBUGGER__ def debug_command(file, line, id, binding) MUTEX.lock - DEBUGGER__.set_last_thread(Thread.current) + set_last_thread(Thread.current) frame_pos = 0 binding_file = file binding_line = line @@ -218,7 +266,8 @@ class DEBUGGER__ end @frames[0] = [binding, file, line, id] display_expressions(binding) - while input = readline("(rdb:%d) "%thnum(), true) + prompt = true + while prompt and input = readline("(rdb:%d) "%thnum(), true) catch(:debug_error) do if input == "" input = DEBUG_LAST_CMD[0] @@ -228,18 +277,24 @@ class DEBUGGER__ end case input - when /^\s*tr(?:ace)?(?:\s+(on|off))?$/ - if defined?( $1 ) + when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/ + if defined?( $2 ) if $1 == 'on' - @trace = true + set_trace_all true else - @trace = false + set_trace_all false + end + elsif defined?( $1 ) + if $1 == 'on' + set_trace true + else + set_trace false end end - if @trace - stdout.print "Trace on\n" + if trace? + stdout.print "Trace on.\n" else - stdout.print "Trace off\n" + stdout.print "Trace off.\n" end when /^\s*b(?:reak)?\s+((?:.*?+:)?.+)$/ @@ -336,8 +391,7 @@ class DEBUGGER__ end when /^\s*c(?:ont)?$/ - MUTEX.unlock - return + prompt = false when /^\s*s(?:tep)?(?:\s+(\d+))?$/ if $1 @@ -346,7 +400,7 @@ class DEBUGGER__ lev = 1 end @stop_next = lev - return + prompt = false when /^\s*n(?:ext)?(?:\s+(\d+))?$/ if $1 @@ -356,7 +410,7 @@ class DEBUGGER__ end @stop_next = lev @no_step = @frames.size - frame_pos - return + prompt = false when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ display_frames(frame_pos) @@ -417,8 +471,7 @@ class DEBUGGER__ else @finish_pos = @frames.size - frame_pos frame_pos = 0 - MUTEX.unlock - return + prompt = false end when /^\s*cat(?:ch)?(?:\s+(.+))?$/ @@ -440,8 +493,10 @@ class DEBUGGER__ end when /^\s*q(?:uit)?$/ - input = readline("really quit? (y/n) ", false) - exit if input == "y" + input = readline("Really quit? (y/n) ", false) + if input == "y" + exit! # exit -> exit!: No graceful way to stop threads... + end when /^\s*v(?:ar)?\s+/ debug_variable_info($', binding) @@ -451,8 +506,7 @@ class DEBUGGER__ when /^\s*th(?:read)?\s+/ if DEBUGGER__.debug_thread_info($', binding) == :cont - MUTEX.unlock - return + prompt = false end when /^\s*p\s+/ @@ -467,6 +521,8 @@ class DEBUGGER__ end end end + MUTEX.unlock + resume_all end def debug_print_help @@ -492,7 +548,8 @@ Commands up[ nn] move to higher frame down[ nn] move to lower frame fin[ish] return to outer frame - tr[ace][ (on|off)] set trace mode + tr[ace] (on|off) set trace mode of current thread + tr[ace] (on|off) all set trace mode of all threads q[uit] exit from debugger v[ar] g[lobal] show global variables v[ar] l[ocal] show local variables @@ -501,11 +558,10 @@ Commands m[ethod] i[nstance] show methods of object m[ethod] show instance methods of class or module th[read] l[ist] list all threads - th[read] c[ur[rent]] show current threads - th[read] stop thread nnn - th[read] stop alias for th[read] - th[read] c[ur[rent]] alias for th[read] - th[read] resume run thread nnn + th[read] c[ur[rent]] show current thread + th[read] [sw[itch]] switch thread context to nnn + th[read] stop stop thread nnn + th[read] resume resume thread nnn p expression evaluate expression and print its value h[elp] print this help evaluate @@ -587,7 +643,7 @@ EOHELP end def check_break_points(file, pos, binding, id) - MUTEX.lock # Stop all threads before 'line' and 'call'. + return false if break_points.empty? file = File.basename(file) n = 1 for b in break_points @@ -604,7 +660,6 @@ EOHELP end n += 1 end - MUTEX.unlock return false end @@ -616,7 +671,6 @@ EOHELP end if @catch and ($!.type.ancestors.find { |e| e.to_s == @catch }) - MUTEX.lock fs = @frames.size tb = caller(0)[-fs..-1] if tb @@ -624,12 +678,14 @@ EOHELP stdout.printf "\tfrom %s\n", i end end + suspend_all debug_command(file, line, id, binding) end end def trace_func(event, file, line, id, binding, klass) - Tracer.trace_func(event, file, line, id, binding) if @trace + Tracer.trace_func(event, file, line, id, binding, klass) if trace? + context(Thread.current).check_suspend @file = file @line = line case event @@ -647,6 +703,7 @@ EOHELP @stop_next = 1 else @no_step = nil + suspend_all debug_command(file, line, id, binding) @last = [file, line] end @@ -656,6 +713,7 @@ EOHELP @frames.unshift [binding, file, line, id] if check_break_points(file, id.id2name, binding, id) or check_break_points(klass.to_s, id.id2name, binding, id) + suspend_all debug_command(file, line, id, binding) end @@ -668,6 +726,7 @@ EOHELP when 'return', 'end' if @frames.size == @finish_pos @stop_next = 1 + @finish_pos = 0 end @frames.shift @@ -682,19 +741,20 @@ EOHELP end end - trap("INT") { DEBUGGER__.interrupt } -# $DEBUG = true + trap("INT") { DEBUGGER__.interrupt } @last_thread = Thread::main @max_thread = 1 @thread_list = {Thread::main => 1} @break_points = [] @display = [] + @waiting = [] @stdout = STDOUT class < true +# foo.hash == foo2.hash # => false # # Foo = DelegateClass(Array) # diff --git a/lib/forwardable.rb b/lib/forwardable.rb new file mode 100644 index 0000000000..7f57f77f53 --- /dev/null +++ b/lib/forwardable.rb @@ -0,0 +1,94 @@ +# +# forwardable.rb - +# $Release Version: 1.1$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# original definition by delegator.rb +# -- +# Usage: +# +# class Foo +# extend Forwardable +# +# def_delegators("@out", "printf", "print") +# def_delegators(:@in, :gets) +# def_delegator(:@contents, :[], "content_at") +# end +# f = Foo.new +# f.printf ... +# f.gets +# f.content_at(1) +# +# g = Goo.new +# g.extend SingleForwardable +# g.def_delegator("@out", :puts) +# g.puts ... +# +# + +module Forwardable + + @debug = nil + class< 0 + end + end + end + + @scanner.each_top_level_statement do + |line, line_no| + signal_status(:IN_EVAL) do + begin + trace_in do + @context._ = @context.workspace.evaluate(line, + @context.irb_path, + line_no) +# @context._ = irb_eval(line, @context.bind, @context.irb_path, line_no) + end + + if @context.inspect? + printf @context.return_format, @context._.inspect + else + printf @context.return_format, @context._ + end + rescue StandardError, ScriptError, Abort + $! = RuntimeError.new("unknown exception raised") unless $! + print $!.type, ": ", $!, "\n" + if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.type.to_s !~ /^IRB/ + irb_bug = true + else + irb_bug = false + end + + messages = [] + lasts = [] + levels = 0 + for m in $@ + m = @context.workspace.filter_backtrace(m) unless irb_bug + if m + if messages.size < @context.back_trace_limit + messages.push "\tfrom "+m + else + lasts.push "\tfrom "+m + if lasts.size > @context.back_trace_limit + lasts.shift + levels += 1 + end + end + end + end + print messages.join("\n"), "\n" + unless lasts.empty? + printf "... %d levels...\n", levels if levels > 0 + print lasts.join("\n") + end + print "Maybe IRB bug!!\n" if irb_bug + end + end + end + end + +# def irb_eval(line, bind, path, line_no) +# id, str = catch(:IRB_TOPLEVEL_EVAL){ +# return eval(line, bind, path, line_no) +# } +# case id +# when :EVAL_TOPLEVEL +# eval(str, bind, "(irb_internal)", 1) +# when :EVAL_CONTEXT +# @context.instance_eval(str) +# else +# IRB.fail IllegalParameter +# end +# end + + def signal_handle + unless @context.ignore_sigint? + print "\nabort!!\n" if @context.verbose? + exit + end + + case @signal_status + when :IN_INPUT + print "^C\n" + raise RubyLex::TerminateLineInput + when :IN_EVAL + IRB.irb_abort(self) + when :IN_LOAD + IRB.irb_abort(self, LoadAbort) + when :IN_IRB + # ignore + else + # ignore other cases as well + end + end + + def signal_status(status) + return yield if @signal_status == :IN_LOAD + + signal_status_back = @signal_status + @signal_status = status + begin + yield + ensure + @signal_status = signal_status_back + end + end + + def trace_in + Tracer.on if @context.use_tracer? + begin + yield + ensure + Tracer.off if @context.use_tracer? + end + end + + def prompt(prompt, ltype, indent, line_no) + p = prompt.dup + p.gsub!(/%([0-9]+)?([a-zA-Z])/) do + case $2 + when "N" + @context.irb_name + when "m" + @context.main.to_s + when "M" + @context.main.inspect + when "l" + ltype + when "i" + if $1 + format("%" + $1 + "d", indent) + else + indent.to_s + end + when "n" + if $1 + format("%" + $1 + "d", line_no) + else + line_no.to_s + end + when "%" + "%" + end + end + p + end + + def inspect + ary = [] + for iv in instance_variables + case iv + when "@signal_status" + ary.push format("%s=:%s", iv, @signal_status.id2name) + when "@context" + ary.push format("%s=%s", iv, eval(iv).__to_s__) + else + ary.push format("%s=%s", iv, eval(iv)) + end + end + format("#<%s: %s>", type, ary.join(", ")) + end + end + + # Singleton method + def @CONF.inspect + IRB.version unless self[:VERSION] + + array = [] + for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} + case k + when :MAIN_CONTEXT + next + when :PROMPT + s = v.collect{ + |kk, vv| + ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} + format(":%s=>{%s}", kk.id2name, ss.join(", ")) + } + array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) + else + array.push format("CONF[:%s]=%s", k.id2name, v.inspect) + end + end + array.join("\n") + end +end diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index cbd4012773..01dcbd2219 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -1,8 +1,19 @@ +# +# irb/completor.rb - +# $Release Version: 0.7.1$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# From Original Idea of shugo@ruby-lang.org +# require "readline" module IRB - module InputCompletion + module InputCompletor + + @RCS_ID='-$Id$-' + ReservedWords = [ "BEGIN", "END", "alias", "and", @@ -20,28 +31,147 @@ module IRB "then", "true", "undef", "unless", "until", "when", "while", - "yield" + "yield", ] CompletionProc = proc { |input| + bind = IRB.conf[:MAIN_CONTEXT].workspace.binding case input - when /^([^.]+)\.([^.]*)$/ + when /^(\/[^\/]*\/)\.([^.]*)$/ + # Regexp + receiver = $1 + message = Regexp.quote($2) + + candidates = Regexp.instance_methods(true) + select_message(receiver, message, candidates) + + when /^([^\]]*\])\.([^.]*)$/ + # Array receiver = $1 - message = $2 - if eval("(local_variables|#{receiver}.type.constants).include?('#{receiver}')", - IRB.conf[:MAIN_CONTEXT].bind) - candidates = eval("#{receiver}.methods", IRB.conf[:MAIN_CONTEXT].bind) + message = Regexp.quote($2) + + candidates = Array.instance_methods(true) + select_message(receiver, message, candidates) + + when /^([^\}]*\})\.([^.]*)$/ + # Proc or Hash + receiver = $1 + message = Regexp.quote($2) + + candidates = Proc.instance_methods(true) | Hash.instance_methods(true) + select_message(receiver, message, candidates) + + when /^(:[^:]*)$/ + # Symbol + if Symbol.respond_to?(:all_symbols) + sym = $1 + candidates = Symbol.all_symbols.collect{|s| s.id2name} + candidates.grep(/^#{sym}/) else + [] + end + + when /^::([A-Z][^:\.\(]*)$/ + # Absolute Constant or class methods + receiver = $1 + candidates = Object.constants + candidates.grep(/^#{receiver}/).collect{|e| "::" + e} + + when /^(((::)?[A-Z][^:.\(]*)+)::?([^:.]*)$/ + # Constant or class methods + receiver = $1 + message = Regexp.quote($4) + begin + candidates = eval("#{receiver}.constants | #{receiver}.methods", bind) + rescue Exception candidates = [] end - candidates.grep(/^#{Regexp.quote(message)}/).collect{|e| receiver + "." + e} + candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e} + + when /^(:[^.]+)\.([^.]*)$/ + # Symbol + receiver = $1 + message = Regexp.quote($2) + + candidates = Symbol.instance_methods(true) + select_message(receiver, message, candidates) + + when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ + # Numeric + receiver = $1 + message = Regexp.quote($4) + + begin + candidates = eval(receiver, bind).methods + rescue Exception + candidates + end + select_message(receiver, message, candidates) + +# when /^(\$?(\.?[^.]+)+)\.([^.]*)$/ + when /^((\.?[^.]+)+)\.([^.]*)$/ + # variable + receiver = $1 + message = Regexp.quote($3) + + gv = eval "global_variables", bind + lv = eval "local_variables", bind + cv = eval "type.constants", bind + + if (gv | lv | cv).include?(receiver) + # foo.func and foo is local var. + candidates = eval("#{receiver}.methods", bind) + elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver + # Foo::Bar.func + begin + candidates = eval("#{receiver}.methods", bind) + rescue Exception + candidates = [] + end + else + # func1.func2 + candidates = [] + ObjectSpace.each_object(Module){|m| + next if /^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name + candidates.concat m.instance_methods + } + candidates.sort! + candidates.uniq! + end + select_message(receiver, message, candidates) + + when /^\.([^.]*)$/ + # unknown(maybe String) + + receiver = "" + message = Regexp.quote($1) + + candidates = String.instance_methods(true) + select_message(receiver, message, candidates) + else - candidates = eval("methods | private_methods | local_variables | type.constants", - IRB.conf[:MAIN_CONTEXT].bind) + candidates = eval("methods | private_methods | local_variables | type.constants", bind) + (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/) end } + + Operators = ["%", "&", "*", "**", "+", "-", "/", + "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>", + "[]", "[]=", "^",] + + def self.select_message(receiver, message, candidates) + candidates.grep(/^#{message}/).collect do |e| + case e + when /^[a-zA-Z_]/ + receiver + "." + e + when /^[0-9]/ + when *Operators + #receiver + " " + e + end + end + end end end -Readline.completion_proc = IRB::InputCompletion::CompletionProc +Readline.completion_proc = IRB::InputCompletor::CompletionProc diff --git a/lib/irb/context.rb b/lib/irb/context.rb new file mode 100644 index 0000000000..ffc77de875 --- /dev/null +++ b/lib/irb/context.rb @@ -0,0 +1,289 @@ +# +# irb/context.rb - irb context +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +module IRB + class Context + # + # Arguments: + # input_method: nil -- stdin or readline + # String -- File + # other -- using this as InputMethod + # + def initialize(irb, workspace = nil, input_method = nil) + @irb = irb + if workspace + @workspace = workspace + else + @workspace = WorkSpace.new unless workspace + end + @thread = Thread.current if defined? Thread + @irb_level = 0 + + # copy of default configuration + @ap_name = IRB.conf[:AP_NAME] + @rc = IRB.conf[:RC] + @load_modules = IRB.conf[:LOAD_MODULES] + + self.math_mode = IRB.conf[:MATH_MODE] + @use_readline = IRB.conf[:USE_READLINE] + @inspect_mode = IRB.conf[:INSPECT_MODE] + self.use_tracer = IRB.conf[:USE_TRACER] +# @use_loader = IRB.conf[:USE_LOADER] + + self.prompt_mode = IRB.conf[:PROMPT_MODE] + + @ignore_sigint = IRB.conf[:IGNORE_SIGINT] + @ignore_eof = IRB.conf[:IGNORE_EOF] + + @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT] + + debug_level = IRB.conf[:DEBUG_LEVEL] + @verbose = IRB.conf[:VERBOSE] + + @tracer_initialized = false + + if IRB.conf[:SINGLE_IRB] or !defined?(JobManager) + @irb_name = IRB.conf[:IRB_NAME] + else + @irb_name = "irb#"+IRB.JobManager.n_jobs.to_s + end + @irb_path = "(" + @irb_name + ")" + + case input_method + when nil + if (use_readline.nil? && IRB.conf[:PROMPT_MODE] != :INF_RUBY || + use_readline?) + @io = ReadlineInputMethod.new + else + @io = StdioInputMethod.new + end + when String + @io = FileInputMethod.new(input_method) + @irb_name = File.basename(input_method) + @irb_path = input_method + else + @io = input_method + end + end + + def main + @workspace.main + end + + attr_accessor :workspace + attr_reader :thread + attr_accessor :io + + attr_reader :_ + + attr_accessor :irb + attr_accessor :ap_name + attr_accessor :rc + attr_accessor :load_modules + attr_accessor :irb_name + attr_accessor :irb_path + + attr_accessor :math_mode + attr_accessor :use_readline + attr_reader :inspect_mode + attr_reader :use_tracer +# attr :use_loader + + attr_reader :debug_level + attr_accessor :verbose + + attr_reader :prompt_mode + attr_accessor :prompt_i + attr_accessor :prompt_s + attr_accessor :prompt_c + attr_accessor :auto_indent_mode + attr_accessor :return_format + + attr_accessor :ignore_sigint + attr_accessor :ignore_eof + + attr_accessor :back_trace_limit + +# alias use_loader? use_loader + alias use_tracer? use_tracer + alias use_readline? use_readline + alias rc? rc + alias math? math_mode + alias verbose? verbose + alias ignore_sigint? ignore_sigint + alias ignore_eof? ignore_eof + + def _=(value) + @_ = value + @workspace.evaluate "_ = IRB.conf[:MAIN_CONTEXT]._" + end + + def irb_name + if @irb_level == 0 + @irb_name + elsif @irb_name =~ /#[0-9]*$/ + @irb_name + "." + @irb_level.to_s + else + @irb_name + "#0." + @irb_level.to_s + end + end + + def prompt_mode=(mode) + @prompt_mode = mode + pconf = IRB.conf[:PROMPT][mode] + @prompt_i = pconf[:PROMPT_I] + @prompt_s = pconf[:PROMPT_S] + @prompt_c = pconf[:PROMPT_C] + @return_format = pconf[:RETURN] + if ai = pconf.include?(:AUTO_INDENT) + @auto_indent_mode = ai + else + @auto_indent_mode = IRB.conf[:AUTO_INDENT] + end + end + + def inspect? + @inspect_mode.nil? && !@math_mode or @inspect_mode + end + + def file_input? + @io.type == FileInputMethod + end + + def use_tracer=(opt) + if opt + IRB.initialize_tracer + unless @tracer_initialized + Tracer.set_get_line_procs(@irb_path) { + |line_no| + @io.line(line_no) + } + @tracer_initialized = true + end + elsif !opt && @use_tracer + Tracer.off + end + @use_tracer=opt + end + + def use_loader + IRB.conf[:USE_LOADER] + end + + def use_loader=(opt) + IRB.conf[:USE_LOADER] = opt + if opt + IRB.initialize_loader + end + print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? + opt + end + + def inspect_mode=(opt) + if opt + @inspect_mode = opt + else + @inspect_mode = !@inspect_mode + end + print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose? + @inspect_mode + end + + def math_mode=(opt) + if @math_mode == true && opt == false + IRB.fail CantRetuenNormalMode + return + end + + @math_mode = opt + if math_mode + IRB.initialize_mathn + main.instance_eval("include Math") + print "start math mode\n" if verbose? + end + end + + def use_readline=(opt) + @use_readline = opt + print "use readline module\n" if @use_readline + end + + def debug_level=(value) + @debug_level = value + RubyLex.debug_level = value + SLex.debug_level = value + end + + def debug? + @debug_level > 0 + end + + def change_binding(*_main) + back = @workspace + @workspace = WorkSpace.new(*_main) + unless _main.empty? + begin + main.extend ExtendCommand + rescue + print "can't change binding to: ", main.inspect, "\n" + @workspace = back + return nil + end + end + @irb_level += 1 + begin + catch(:SU_EXIT) do + @irb.eval_input + end + ensure + @irb_level -= 1 + @workspace = back + end + end + alias change_workspace change_binding + + + alias __exit__ exit + def exit(ret = 0) + if @irb_level == 0 + IRB.irb_exit(@irb, ret) + else + throw :SU_EXIT, ret + end + end + + NOPRINTING_IVARS = ["@_"] + NO_INSPECTING_IVARS = ["@irb", "@io"] + IDNAME_IVARS = ["@prompt_mode"] + + alias __inspect__ inspect + def inspect + array = [] + for ivar in instance_variables.sort{|e1, e2| e1 <=> e2} + name = ivar.sub(/^@(.*)$/){$1} + val = instance_eval(ivar) + case ivar + when *NOPRINTING_IVARS + next + when *NO_INSPECTING_IVARS + array.push format("conf.%s=%s", name, val.to_s) + when *IDNAME_IVARS + array.push format("conf.%s=:%s", name, val.id2name) + else + array.push format("conf.%s=%s", name, val.inspect) + end + end + array.join("\n") + end + alias __to_s__ to_s + alias to_s inspect + end +end diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb new file mode 100644 index 0000000000..3f92707d01 --- /dev/null +++ b/lib/irb/extend-command.rb @@ -0,0 +1,126 @@ +# +# irb/extend-command.rb - irb command extend +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +module IRB + # + # IRB extended command + # + module ExtendCommand +# include Loader + + def irb_exit(ret = 0) + irb_context.exit(ret) + end + alias irb_quit irb_exit + + def irb_fork(&block) + pid = send ExtendCommand.irb_original_method_name("fork") + unless pid + class< { + :PROMPT_I => nil, + :PROMPT_S => nil, + :PROMPT_C => nil, + :RETURN => "%s\n" + }, + :DEFAULT => { + :PROMPT_I => "%N(%m):%03n:%i> ", + :PROMPT_S => "%N(%m):%03n:%i%l ", + :PROMPT_C => "%N(%m):%03n:%i* ", + :RETURN => "%s\n" + }, + :SIMPLE => { + :PROMPT_I => ">> ", + :PROMPT_S => nil, + :PROMPT_C => "?> ", + :RETURN => "=> %s\n" + }, + :INF_RUBY => { + :PROMPT_I => "%N(%m):%03n:%i> ", + :PROMPT_S => nil, + :PROMPT_C => nil, + :RETURN => "%s\n", + :AUTO_INDENT => true + }, + :XMP => { + :PROMPT_I => nil, + :PROMPT_S => nil, + :PROMPT_C => nil, + :RETURN => " ==>%s\n" + } + } + + @CONF[:PROMPT_MODE] = :DEFAULT + @CONF[:AUTO_INDENT] = false + + @CONF[:CONTEXT_MODE] = 3 # use binding in function on TOPLEVEL_BINDING + @CONF[:SINGLE_IRB] = false + +# @CONF[:LC_MESSAGES] = "en" + @CONF[:LC_MESSAGES] = Locale.new + + @CONF[:DEBUG_LEVEL] = 1 + @CONF[:VERBOSE] = true + end + + def IRB.init_error + @CONF[:LC_MESSAGES].load("irb/error.rb") + end + + # option analyzing + def IRB.parse_opts + while opt = ARGV.shift + case opt + when "-f" + opt = ARGV.shift + @CONF[:RC] = false + when "-m" + @CONF[:MATH_MODE] = true + when "-d" + $DEBUG = true + when "-r" + opt = ARGV.shift + @CONF[:LOAD_MODULES].push opt if opt + when "--inspect" + @CONF[:INSPECT_MODE] = true + when "--noinspect" + @CONF[:INSPECT_MODE] = false + when "--readline" + @CONF[:USE_READLINE] = true + when "--noreadline" + @CONF[:USE_READLINE] = false + + when "--prompt-mode", "--prompt" + prompt_mode = ARGV.shift.upcase.tr("-", "_").intern + IRB.fail(UndefinedPromptMode, + prompt_mode.id2name) unless @CONF[:PROMPT][prompt_mode] + @CONF[:PROMPT_MODE] = prompt_mode + when "--noprompt" + @CONF[:PROMPT_MODE] = :NULL + when "--inf-ruby-mode" + @CONF[:PROMPT_MODE] = :INF_RUBY + when "--sample-book-mode", "--simple-prompt" + @CONF[:PROMPT_MODE] = :SIMPLE + + when "--tracer" + @CONF[:USE_TRACER] = true + when "--back-trace-limit" + @CONF[:BACK_TRACE_LIMIT] = ARGV.shift.to_i + when "--context-mode" + @CONF[:CONTEXT_MODE] = ARGV.shift.to_i + when "--single-irb" + @CONF[:SINGLE_IRB] = true + when "--irb_debug" + @CONF[:DEBUG_LEVEL] = ARGV.shift.to_i + when "-v", "--version" + print IRB.version, "\n" + exit 0 + when "-h", "--help" + require "irb/help" + IRB.print_usage + exit 0 + when /^-/ + IRB.fail UnrecognizedSwitch, opt + else + @CONF[:USE_READLINE] = false + @CONF[:SCRIPT] = opt + $0 = opt + break + end + end + end + + # running config + def IRB.run_config + if @CONF[:RC] + rcs = [] + rcs.push File.expand_path("~/.irbrc") if ENV.key?("HOME") + rcs.push ".irbrc" + rcs.push "irb.rc" + rcs.push "_irbrc" + rcs.push "$irbrc" + catch(:EXIT) do + for rc in rcs + begin + load rc + throw :EXIT + rescue LoadError, Errno::ENOENT + rescue + print "load error: #{rc}\n" + print $!.type, ": ", $!, "\n" + for err in $@[0, $@.size - 2] + print "\t", err, "\n" + end + throw :EXIT + end + end + end + end + end + + # loading modules + def IRB.load_modules + for m in @CONF[:LOAD_MODULES] + begin + require m + rescue + print $@[0], ":", $!.type, ": ", $!, "\n" + end + end + end + + # initialize tracing function + def IRB.initialize_tracer + unless @TRACER_INITIALIZED + require("tracer") + Tracer.verbose = false + Tracer.add_filter { + |event, file, line, id, binding| + File::dirname(file) != @CONF[:IRB_LIB_PATH] + } + @TRACER_INITIALIZED = true + end + end + + # initialize mathn function + def IRB.initialize_mathn + unless @MATHN_INITIALIZED + require "mathn" + @MATHN_INITIALIZED = true + end + end + + # initialize loader function + def IRB.initialize_loader + unless @LOADER_INITIALIZED + require "irb/loader" + @LOADER_INITIALIZED = true + end + end +end diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index 19df0eb073..ffbc6d9edc 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -1,9 +1,9 @@ # -# input-method.rb - input methods using irb -# $Release Version: 0.6$ +# irb/input-method.rb - input methods using irb +# $Release Version: 0.7.3$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # @@ -23,9 +23,9 @@ module IRB def initialize(file = STDIN_FILE_NAME) @file_name = file end - attr :file_name + attr_reader :file_name - attr :prompt, true + attr_accessor :prompt def gets IRB.fail NotImplementError, "gets" @@ -67,7 +67,7 @@ module IRB super @io = open(file) end - attr :file_name + attr_reader :file_name def eof? @io.eof? diff --git a/lib/irb/lc/error.rb b/lib/irb/lc/error.rb new file mode 100644 index 0000000000..de38f29978 --- /dev/null +++ b/lib/irb/lc/error.rb @@ -0,0 +1,30 @@ +# +# irb/lc/error.rb - +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +require "e2mmap" + +module IRB + + # exceptions + extend Exception2MessageMapper + def_exception :UnrecognizedSwitch, "Unrecognized switch: %s" + def_exception :NotImplementError, "Need to define `%s'" + def_exception :CantRetuenNormalMode, "Can't return normal mode." + def_exception :IllegalParameter, "Illegal parameter(%s)." + def_exception :IrbAlreadyDead, "Irb is already dead." + def_exception :IrbSwitchToCurrentThread, "Change to current thread." + def_exception :NoSuchJob, "No such job(%s)." + def_exception :CanNotGoMultiIrbMode, "Can't go multi irb mode." + def_exception :CanNotChangeBinding, "Can't change binding to (%s)." + def_exception :UndefinedPromptMode, "Undefined prompt mode(%s)." + +end + diff --git a/lib/irb/lc/help-message b/lib/irb/lc/help-message new file mode 100644 index 0000000000..daede5ec21 --- /dev/null +++ b/lib/irb/lc/help-message @@ -0,0 +1,34 @@ +# +# irb/lc/help-message.rb - +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +Usage: irb.rb [options] [programfile] [arguments] + -f suppress read ~/.irbrc + -m bc mode (load mathn, fraction or matrix are available) + -d set $DEBUG to true (same as `ruby -d') + -r load-module same as `ruby -r' + --inspect uses `inspect' for output (the default except bc mode) + --noinspect doesn't uses inspect for output + --readline uses Readline extension module + --noreadline doesn't use Readline extension module + --prompt prompt-mode + --prompt-mode prompt-mode + switches prompt mode. Pre-defined prompt modes are + `default', `simple', `xmp' and `inf-ruby' + --inf-ruby-mode uses prompt appreciate for inf-ruby-mode on emacs. + Suppresses --readline. + --simple-prompt simple prompt mode + --noprompt no prompt + --tracer display trace for each execution of commands. + --back-trace-limit n + displayes backtrace top n and tail n. The default + value is 16. + --irb_debug n sets internal debug level to n (It shouldn't be used) + -v, --version prints the version of irb diff --git a/lib/irb/lc/ja/error.rb b/lib/irb/lc/ja/error.rb new file mode 100644 index 0000000000..d5aef0a7c8 --- /dev/null +++ b/lib/irb/lc/ja/error.rb @@ -0,0 +1,29 @@ +# +# irb/lc/ja/error.rb - +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +require "e2mmap" + +module IRB + # exceptions + extend Exception2MessageMapper + def_exception :UnrecognizedSwitch, '$B%9%$%C%A(B(%s)$B$,J,$j$^$;$s(B' + def_exception :NotImplementError, '`%s\'$B$NDj5A$,I,MW$G$9(B' + def_exception :CantRetuenNormalMode, 'Normal$B%b!<%I$KLa$l$^$;$s(B.' + def_exception :IllegalParameter, '$B%Q%i%a!<%?(B(%s)$B$,4V0c$C$F$$$^$9(B.' + def_exception :IrbAlreadyDead, 'Irb$B$O4{$K;`$s$G$$$^$9(B.' + def_exception :IrbSwitchToCurrentThread, 'Change to current thread.' + def_exception :NoSuchJob, '$B$=$N$h$&$J%8%g%V(B(%s)$B$O$"$j$^$;$s(B.' + def_exception :CanNotGoMultiIrbMode, 'multi-irb mode$B$K0\$l$^$;$s(B.' + def_exception :CanNotChangeBinding, '$B%P%$%s%G%#%s%0(B(%s)$B$KJQ99$G$-$^$;$s(B.' + def_exception :UndefinedPromptMode, '$B%W%m%s%W%H%b!<%I(B(%s)$B$ODj5A$5$l$F$$$^$;$s(B.' +end + + diff --git a/lib/irb/lc/ja/help-message b/lib/irb/lc/ja/help-message new file mode 100644 index 0000000000..9fa3952a0b --- /dev/null +++ b/lib/irb/lc/ja/help-message @@ -0,0 +1,35 @@ +# +# irb/lc/ja/help-message.rb - +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +Usage: irb.rb [options] [programfile] [arguments] + -f ~/.irbrc $B$rFI$_9~$^$J$$(B. + -m bc$B%b!<%I(B($BJ,?t(B, $B9TNs$N7W;;$,$G$-$k(B) + -d $DEBUG $B$r(Btrue$B$K$9$k(B(ruby -d $B$HF1$8(B) + -r load-module ruby -r $B$HF1$8(B. + --inspect $B7k2L=PNO$K(Binspect$B$rMQ$$$k(B(bc$B%b!<%I0J30$O%G%U%)%k%H(B). + --noinspect $B7k2L=PNO$K(Binspect$B$rMQ$$$J$$(B. + --readline readline$B%i%$%V%i%j$rMxMQ$9$k(B. + --noreadline readline$B%i%$%V%i%j$rMxMQ$7$J$$(B. + --prompt prompt-mode/--prompt-mode prompt-mode + $B%W%m%s%W%H%b!<%I$r@ZBX$($^$9(B. $B8=:_Dj5A$5$l$F$$$k%W(B + $B%m%s%W%H%b!<%I$O(B, default, simple, xmp, inf-ruby$B$,(B + $BMQ0U$5$l$F$$$^$9(B. + --inf-ruby-mode emacs$B$N(Binf-ruby-mode$BMQ$N%W%m%s%W%HI=<($r9T$J$&(B. $BFC(B + $B$K;XDj$,$J$$8B$j(B, readline$B%i%$%V%i%j$O;H$o$J$/$J$k(B. + --simple-prompt $BHs>o$K%7%s%W%k$J%W%m%s%W%H$rMQ$$$k%b!<%I$G$9(B. + --noprompt $B%W%m%s%W%HI=<($r9T$J$o$J$$(B. + --tracer $B%3%^%s%I Kconv::JIS, +# "ja_JP" => Kconv::JIS, + "ja_JP.ujis" => Kconv::EUC, + "ja_JP.euc" => Kconv::EUC, + "ja_JP.eucJP" => Kconv::EUC, + "ja_JP.sjis" => Kconv::SJIS, + "ja_JP.SJIS" => Kconv::SJIS, + } + + def initialize(locale = nil) + @lang = locale || ENV["IRB_LANG"] || ENV["LC_MESSAGES"] || ENV["LC_ALL"] || ENV["LANG"] + @lang = "C" unless @lang + end + + attr_reader :lang + + def String(mes) + mes = super(mes) + case @lang + when /^ja/ + mes = Kconv::kconv(mes, LC2KCONV[@lang]) + else + mes + end + mes + end + + def format(*opts) + String(super(*opts)) + end + + def gets(*rs) + String(super(*rs)) + end + + def readline(*rs) + String(super(*rs)) + end + + def print(*opts) + ary = opts.collect{|opt| String(opt)} + super *ary + end + + def printf(*opts) + s = format(*opts) + print s + end + + def puts(*opts) + ary = opts.collect{|opt| String(opts)} + super *ary + end + + autoload :Tempfile, "tempfile" + + def require(file, priv = nil) + rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?") + return false if $".find{|f| f =~ rex} + + case file + when /\.rb$/ + begin + load(file, priv) + $".push file + return true + rescue LoadError + end + when /\.(so|o|sl)$/ + return super + end + + begin + load(f = file + ".rb") + $".push f #" + return true + rescue LoadError + return ruby_require(file) + end + end + + alias toplevel_load load + + def load(file, priv=nil) + dir = File.dirname(file) + dir = "" if dir == "." + base = File.basename(file) + + if /^ja(_JP)?$/ =~ @lang + back, @lang = @lang, "C" + end + begin + if dir[0] == ?/ #/ + lc_path = search_file(dir, base) + return real_load(lc_path, priv) if lc_path + end + + for path in $: + lc_path = search_file(path + "/" + dir, base) + return real_load(lc_path, priv) if lc_path + end + ensure + @lang = back if back + end + raise LoadError, "No such file to load -- #{file}" + end + + def real_load(path, priv) + tmp_base = path.tr("./:", "___") + lc_file = Tempfile.new(tmp_base) + File.foreach(path) do |line| + line = self.String(line) + lc_file.print(line) + end + lc_file.close + toplevel_load lc_file.path, priv + end + private :real_load + + def find(file , paths = $:) + dir = File.dirname(file) + dir = "" if dir == "." + base = File.basename(file) + if dir[0] == ?/ #/ + return lc_path = search_file(dir, base) + else + for path in $: + if lc_path = search_file(path + "/" + dir, base) + return lc_path + end + end + end + nil + end + + def search_file(path, file) + if File.exists?(p1 = path + lc_path(file, "C")) + if File.exists?(p2 = path + lc_path(file)) + return p2 + else + end + return p1 + else + end + nil + end + private :search_file + + def lc_path(file = "", lc = @lang) + case lc + when "C" + LOCALE_DIR + file + when /^ja/ + LOCALE_DIR + "ja/" + file + else + LOCALE_DIR + @lang + "/" + file + end + end + private :lc_path + end +end + + + + diff --git a/lib/irb/main.rb b/lib/irb/main.rb deleted file mode 100644 index 4c7dac240b..0000000000 --- a/lib/irb/main.rb +++ /dev/null @@ -1,867 +0,0 @@ -# -# main.rb - irb main module -# $Release Version: 0.6 $ -# $Revision$ -# $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) -# -# -- -# -# -# -require "e2mmap" -require "irb/ruby-lex" -require "irb/input-method" -require "irb/workspace-binding" - -STDOUT.sync = true - -module IRB - @RCS_ID='-$Id$-' - - # exceptions - extend Exception2MessageMapper - def_exception :UnrecognizedSwitch, "Unrecognized switch: %s" - def_exception :NotImplementError, "Need to define `%s'" - def_exception :CantRetuenNormalMode, "Can't return normal mode." - def_exception :IllegalParameter, "Illegal parameter(%s)." - def_exception :IrbAlreadyDead, "Irb is already dead." - def_exception :IrbSwitchToCurrentThread, "Change to current thread." - def_exception :NoSuchJob, "No such job(%s)." - def_exception :CanNotGoMultiIrbMode, "Can't go multi irb mode." - def_exception :CanNotChangeBinding, "Can't change binding to (%s)." - def_exception :UndefinedPromptMode, "Undefined prompt mode(%s)." - - class Abort < Exception;end - - # initialize IRB and start TOP_LEVEL irb - def IRB.start(ap_path = nil) - $0 = File::basename(ap_path, ".rb") if ap_path - - IRB.initialize(ap_path) - IRB.parse_opts - IRB.load_modules - - bind = workspace_binding - main = eval("self", bind) - - if @CONF[:SCRIPT] - irb = Irb.new(main, bind, @CONF[:SCRIPT]) - else - irb = Irb.new(main, bind) - end - - @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] - @CONF[:MAIN_CONTEXT] = irb.context - - trap("SIGINT") do - irb.signal_handle - end - - catch(:IRB_EXIT) do - irb.eval_input - end - print "\n" - end - - # initialize config - def IRB.initialize(ap_path) - IRB.init_config(ap_path) - IRB.run_config - end - - # - # @CONF functions - # - @CONF = {} - # @CONF default setting - def IRB.init_config(ap_path) - # class instance variables - @TRACER_INITIALIZED = false - @MATHN_INITIALIZED = false - - # default configurations - unless ap_path and @CONF[:AP_NAME] - ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb") - end - @CONF[:AP_NAME] = File::basename(ap_path, ".rb") - - @CONF[:IRB_NAME] = "irb" - @CONF[:IRB_LIB_PATH] = File.dirname(__FILE__) - - @CONF[:RC] = true - @CONF[:LOAD_MODULES] = [] - @CONF[:IRB_RC] = nil - - @CONF[:MATH_MODE] = false - @CONF[:USE_READLINE] = false unless defined?(ReadlineInputMethod) - @CONF[:INSPECT_MODE] = nil - @CONF[:USE_TRACER] = false - @CONF[:USE_LOADER] = false - @CONF[:IGNORE_SIGINT] = true - @CONF[:IGNORE_EOF] = false - - @CONF[:BACK_TRACE_LIMIT] = 16 - - @CONF[:PROMPT] = { - :NULL => { - :PROMPT_I => nil, - :PROMPT_S => nil, - :PROMPT_C => nil, - :RETURN => "%s\n" - }, - :DEFAULT => { - :PROMPT_I => "%N(%m):%03n:%i> ", - :PROMPT_S => "%N(%m):%03n:%i%l ", - :PROMPT_C => "%N(%m):%03n:%i* ", - :RETURN => "%s\n" - }, - :SIMPLE => { - :PROMPT_I => ">> ", - :PROMPT_S => nil, - :PROMPT_C => "?> ", - :RETURN => "=> %s\n" - }, - :INF_RUBY => { - :PROMPT_I => "%N(%m):%03n:%i> ", - :PROMPT_S => nil, - :PROMPT_C => nil, - :RETURN => "%s\n", - :AUTO_INDENT => true - }, - :XMP => { - :PROMPT_I => nil, - :PROMPT_S => nil, - :PROMPT_C => nil, - :RETURN => " ==>%s\n" - } - } - - @CONF[:PROMPT_MODE] = :DEFAULT - @CONF[:AUTO_INDENT] = false - - @CONF[:CONTEXT_MODE] = 3 - @CONF[:SINGLE_IRB] = false - - @CONF[:DEBUG_LEVEL] = 1 - @CONF[:VERBOSE] = true - end - - # IRB version method - def IRB.version - if v = @CONF[:VERSION] then return v end - - require "irb/version" - rv = @RELEASE_VERSION.sub(/\.0/, "") - @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE) - end - - def IRB.conf - @CONF - end - - # option analyzing - def IRB.parse_opts - while opt = ARGV.shift - case opt - when "-f" - opt = ARGV.shift - @CONF[:RC] = false - when "-m" - @CONF[:MATH_MODE] = true - when "-d" - $DEBUG = true - when "-r" - opt = ARGV.shift - @CONF[:LOAD_MODULES].push opt if opt - when "--inspect" - @CONF[:INSPECT_MODE] = true - when "--noinspect" - @CONF[:INSPECT_MODE] = false - when "--readline" - @CONF[:USE_READLINE] = true - when "--noreadline" - @CONF[:USE_READLINE] = false - when "--prompt-mode", "--prompt" - prompt_mode = ARGV.shift.upcase.tr("-", "_").intern - IRB.fail(UndefinedPromptMode, - prompt_mode.id2name) unless @CONF[:PROMPT][prompt_mode] - @CONF[:PROMPT_MODE] = prompt_mode - when "--noprompt" - @CONF[:PROMPT_MODE] = :NULL - when "--inf-ruby-mode" - @CONF[:PROMPT_MODE] = :INF_RUBY - when "--sample-book-mode", "--simple-prompt" - @CONF[:PROMPT_MODE] = :SIMPLE - when "--tracer" - @CONF[:USE_TRACER] = true - when "--back-trace-limit" - @CONF[:BACK_TRACE_LIMIT] = ARGV.shift.to_i - when "--context-mode" - @CONF[:CONTEXT_MODE] = ARGV.shift.to_i - when "--single-irb" - @CONF[:SINGLE_IRB] = true - when "--irb_debug" - @CONF[:DEBUG_LEVEL] = ARGV.shift.to_i - when "-v", "--version" - print IRB.version, "\n" - exit(0) - when /^-/ - IRB.fail UnrecognizedSwitch, opt - else - @CONF[:USE_READLINE] = false - @CONF[:SCRIPT] = opt - $0 = opt - break - end - end - end - - # running config - def IRB.run_config - if @CONF[:RC] - rcs = [] - rcs.push File.expand_path("~/.irbrc") if ENV.key?("HOME") - rcs.push ".irbrc" - rcs.push "irb.rc" - rcs.push "_irbrc" - rcs.push "$irbrc" - catch(:EXIT) do - for rc in rcs - begin - load rc - throw :EXIT - rescue LoadError, Errno::ENOENT - rescue - print "load error: #{rc}\n" - print $!.type, ": ", $!, "\n" - for err in $@[0, $@.size - 2] - print "\t", err, "\n" - end - throw :EXIT - end - end - end - end - end - - # loading modules - def IRB.load_modules - for m in @CONF[:LOAD_MODULES] - begin - require m - rescue - print $@[0], ":", $!.type, ": ", $!, "\n" - end - end - end - - # initialize tracing function - def IRB.initialize_tracer - unless @TRACER_INITIALIZED - require("tracer") - Tracer.verbose = false - Tracer.add_filter { - |event, file, line, id, binding| - File::dirname(file) != @CONF[:IRB_LIB_PATH] - } - @TRACER_INITIALIZED = true - end - end - - # initialize mathn function - def IRB.initialize_mathn - unless @MATHN_INITIALIZED - require "mathn" - @MATHN_INITIALIZED = true - end - end - - # initialize loader function - def IRB.initialize_loader - unless @LOADER_INITIALIZED - require "irb/loader" - @LOADER_INITIALIZED = true - end - end - - def IRB.irb_exit(irb, ret) - throw :IRB_EXIT, ret - end - - def IRB.irb_abort(irb, exception = Abort) - if defined? Thread - irb.context.thread.raise exception, "abort then interrupt!!" - else - raise exception, "abort then interrupt!!" - end - end - - # - # irb interpriter main routine - # - class Irb - def initialize(main, bind, input_method = nil) - @context = Context.new(self, main, bind, input_method) - main.extend ExtendCommand - @signal_status = :IN_IRB - - @scanner = RubyLex.new - @scanner.exception_on_syntax_error = false - end - attr :context - attr :scanner, true - - def eval_input -# @scanner = RubyLex.new - @scanner.set_input(@context.io) do - signal_status(:IN_INPUT) do - unless l = @context.io.gets - if @context.ignore_eof? and @context.io.readable_atfer_eof? - l = "\n" - if @context.verbose? - printf "Use \"exit\" to leave %s\n", @context.ap_name - end - end - end - l - end - end - - @scanner.set_prompt do - |ltype, indent, continue, line_no| - if ltype - f = @context.prompt_s - elsif continue - f = @context.prompt_c - else @context.prompt_i - f = @context.prompt_i - end - f = "" unless f - @context.io.prompt = p = prompt(f, ltype, indent, line_no) - if @context.auto_indent_mode - unless ltype - ind = prompt(@context.prompt_i, ltype, indent, line_no).size + - indent * 2 - p.size - ind += 2 if continue - @context.io.prompt = p + " " * ind if ind > 0 - end - end - end - - @scanner.each_top_level_statement do - |line, line_no| - signal_status(:IN_EVAL) do - begin - trace_in do - @context._ = eval(line, @context.bind, @context.irb_path, line_no) -# @context._ = irb_eval(line, @context.bind, @context.irb_path, line_no) - end - - if @context.inspect? - printf @context.return_format, @context._.inspect - else - printf @context.return_format, @context._ - end - rescue StandardError, ScriptError, Abort - $! = RuntimeError.new("unknown exception raised") unless $! - print $!.type, ": ", $!, "\n" - if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.type.to_s !~ /^IRB/ - irb_bug = true - else - irb_bug = false - end - - messages = [] - lasts = [] - levels = 0 - for m in $@ - if m !~ /irb2?(\/.*|-.*|\.rb)?:/ or irb_bug - if messages.size < @context.back_trace_limit - messages.push m - else - lasts.push m - if lasts.size > @context.back_trace_limit - lasts.shift - levels += 1 - end - end - end - end - print messages.join("\n"), "\n" - unless lasts.empty? - printf "... %d levels...\n", levels if levels > 0 - print lasts.join("\n") - end - print "Maybe IRB bug!!\n" if irb_bug - end - end - end - end - -# def irb_eval(line, bind, path, line_no) -# id, str = catch(:IRB_TOPLEVEL_EVAL){ -# return eval(line, bind, path, line_no) -# } -# case id -# when :EVAL_TOPLEVEL -# eval(str, bind, "(irb_internal)", 1) -# when :EVAL_CONTEXT -# @context.instance_eval(str) -# else -# IRB.fail IllegalParameter -# end -# end - - def signal_handle - unless @context.ignore_sigint? - print "\nabort!!\n" if @context.verbose? - exit - end - - case @signal_status - when :IN_INPUT - print "^C\n" - @scanner.initialize_input - print @context.io.prompt - when :IN_EVAL - IRB.irb_abort(self) - when :IN_LOAD - IRB.irb_abort(self, LoadAbort) - when :IN_IRB - # ignore - else - # ignore - end - end - - def signal_status(status) - return yield if @signal_status == :IN_LOAD - - signal_status_back = @signal_status - @signal_status = status - begin - yield - ensure - @signal_status = signal_status_back - end - end - - def trace_in - Tracer.on if @context.use_tracer? - begin - yield - ensure - Tracer.off if @context.use_tracer? - end - end - - def prompt(prompt, ltype, indent, line_no) - p = prompt.dup - p.gsub!(/%([0-9]+)?([a-zA-Z])/) do - case $2 - when "N" - @context.irb_name - when "m" - @context.main.to_s - when "M" - @context.main.inspect - when "l" - ltype - when "i" - if $1 - format("%" + $1 + "d", indent) - else - indent.to_s - end - when "n" - if $1 - format("%" + $1 + "d", line_no) - else - line_no.to_s - end - when "%" - "%" - end - end - p - end - - def inspect - ary = [] - for iv in instance_variables - case iv - when "@signal_status" - ary.push format("%s=:%s", iv, @signal_status.id2name) - when "@context" - ary.push format("%s=%s", iv, eval(iv).__to_s__) - else - ary.push format("%s=%s", iv, eval(iv)) - end - end - format("#<%s: %s>", type, ary.join(", ")) - end - end - - # - # irb context - # - class Context - # - # Arguments: - # input_method: nil -- stdin or readline - # String -- File - # other -- using this as InputMethod - # - def initialize(irb, main, bind, input_method = nil) - @irb = irb - @main = main - @bind = bind - @thread = Thread.current if defined? Thread - @irb_level = 0 - - # copy of default configuration - @ap_name = IRB.conf[:AP_NAME] - @rc = IRB.conf[:RC] - @load_modules = IRB.conf[:LOAD_MODULES] - - self.math_mode = IRB.conf[:MATH_MODE] - @use_readline = IRB.conf[:USE_READLINE] - @inspect_mode = IRB.conf[:INSPECT_MODE] - @use_tracer = IRB.conf[:USE_TRACER] -# @use_loader = IRB.conf[:USE_LOADER] - - self.prompt_mode = IRB.conf[:PROMPT_MODE] - - @ignore_sigint = IRB.conf[:IGNORE_SIGINT] - @ignore_eof = IRB.conf[:IGNORE_EOF] - - @back_trace_limit = IRB.conf[:BACK_TRACE_LIMIT] - - debug_level = IRB.conf[:DEBUG_LEVEL] - @verbose = IRB.conf[:VERBOSE] - - @tracer_initialized = false - - if IRB.conf[:SINGLE_IRB] or !defined?(JobManager) - @irb_name = IRB.conf[:IRB_NAME] - else - @irb_name = "irb#"+IRB.JobManager.n_jobs.to_s - end - @irb_path = "(" + @irb_name + ")" - - case input_method - when nil - if (use_readline.nil? && IRB.conf[:PROMPT_MODE] != :INF_RUBY || - use_readline?) - @io = ReadlineInputMethod.new - else - @io = StdioInputMethod.new - end - when String - @io = FileInputMethod.new(input_method) - @irb_name = File.basename(input_method) - @irb_path = input_method - else - @io = input_method - end - end - - attr :bind, true - attr :main, true - attr :thread - attr :io, true - - attr :_ - - attr :irb - attr :ap_name - attr :rc - attr :load_modules - attr :irb_name - attr :irb_path - - attr :math_mode, true - attr :use_readline, true - attr :inspect_mode - attr :use_tracer -# attr :use_loader - - attr :debug_level - attr :verbose, true - - attr :prompt_mode - attr :prompt_i, true - attr :prompt_s, true - attr :prompt_c, true - attr :auto_indent_mode, true - attr :return_format, true - - attr :ignore_sigint, true - attr :ignore_eof, true - - attr :back_trace_limit - -# alias use_loader? use_loader - alias use_tracer? use_tracer - alias use_readline? use_readline - alias rc? rc - alias math? math_mode - alias verbose? verbose - alias ignore_sigint? ignore_sigint - alias ignore_eof? ignore_eof - - def _=(value) - @_ = value - eval "_ = IRB.conf[:MAIN_CONTEXT]._", @bind - end - - def irb_name - if @irb_level == 0 - @irb_name - elsif @irb_name =~ /#[0-9]*$/ - @irb_name + "." + @irb_level.to_s - else - @irb_name + "#0." + @irb_level.to_s - end - end - - def prompt_mode=(mode) - @prompt_mode = mode - pconf = IRB.conf[:PROMPT][mode] - @prompt_i = pconf[:PROMPT_I] - @prompt_s = pconf[:PROMPT_S] - @prompt_c = pconf[:PROMPT_C] - @return_format = pconf[:RETURN] - if ai = pconf.include?(:AUTO_INDENT) - @auto_indent_mode = ai - else - @auto_indent_mode = IRB.conf[:AUTO_INDENT] - end - end - - def inspect? - @inspect_mode.nil? && !@math_mode or @inspect_mode - end - - def file_input? - @io.type == FileInputMethod - end - - def use_tracer=(opt) - if opt - IRB.initialize_tracer - unless @tracer_initialized - Tracer.set_get_line_procs(@irb_path) { - |line_no| - @io.line(line_no) - } - @tracer_initialized = true - end - elsif !opt && @use_tracer - Tracer.off - end - @use_tracer=opt - end - - def use_loader - IRB.conf[:USE_LOADER] - end - - def use_loader=(opt) - IRB.conf[:USE_LOADER] = opt - if opt - IRB.initialize_loader - end - print "Switch to load/require#{unless use_loader; ' non';end} trace mode.\n" if verbose? - opt - end - - def inspect_mode=(opt) - if opt - @inspect_mode = opt - else - @inspect_mode = !@inspect_mode - end - print "Switch to#{unless @inspect_mode; ' non';end} inspect mode.\n" if verbose? - @inspect_mode - end - - def math_mode=(opt) - if @math_mode == true && opt == false - IRB.fail CantRetuenNormalMode - return - end - - @math_mode = opt - if math_mode - IRB.initialize_mathn - @main.instance_eval("include Math") - print "start math mode\n" if verbose? - end - end - - def use_readline=(opt) - @use_readline = opt - print "use readline module\n" if @use_readline - end - - def debug_level=(value) - @debug_level = value - RubyLex.debug_level = value - SLex.debug_level = value - end - - def debug? - @debug_level > 0 - end - - def change_binding(*main) - back = [@bind, @main] - @bind = IRB.workspace_binding(*main) - unless main.empty? - @main = eval("self", @bind) - begin - @main.extend ExtendCommand - rescue - print "can't change binding to: ", @main.inspect, "\n" - @bind, @main = back - return nil - end - end - @irb_level += 1 - begin - catch(:SU_EXIT) do - @irb.eval_input - end - ensure - @irb_level -= 1 - @bind, @main = back - end - end - - alias __exit__ exit - def exit(ret = 0) - if @irb_level == 0 - IRB.irb_exit(@irb, ret) - else - throw :SU_EXIT, ret - end - end - - NOPRINTING_IVARS = ["@_"] - NO_INSPECTING_IVARS = ["@irb", "@io"] - IDNAME_IVARS = ["@prompt_mode"] - - alias __inspect__ inspect - def inspect - array = [] - for ivar in instance_variables.sort{|e1, e2| e1 <=> e2} - name = ivar.sub(/^@(.*)$/){$1} - val = instance_eval(ivar) - case ivar - when *NOPRINTING_IVARS - next - when *NO_INSPECTING_IVARS - array.push format("conf.%s=%s", name, val.to_s) - when *IDNAME_IVARS - array.push format("conf.%s=:%s", name, val.id2name) - else - array.push format("conf.%s=%s", name, val.inspect) - end - end - array.join("\n") - end - alias __to_s__ to_s - alias to_s inspect - - end - - # - # IRB extended command - # - module Loader; end - module ExtendCommand - include Loader - - alias irb_exit_org exit - def irb_exit(ret = 0) - irb_context.exit(ret) - end - alias exit irb_exit - alias quit irb_exit - - alias irb_fork fork - def fork(&block) - unless irb_fork - eval "alias exit irb_exit_org" - instance_eval "alias exit irb_exit_org" - if iterator? - yield - exit - end - end - end - - def irb_change_binding(*main) - irb_context.change_binding(*main) - end - alias cb irb_change_binding - - def irb_source(file) - irb_context.source(file) - end - alias source irb_source - - def irb(*obj) - require "irb/multi-irb" - IRB.irb(nil, *obj) - end - - def irb_context - IRB.conf[:MAIN_CONTEXT] - end - alias conf irb_context - - def irb_jobs - require "irb/multi-irb" - IRB.JobManager - end - alias jobs irb_jobs - - def irb_fg(key) - require "irb/multi-irb" - IRB.JobManager.switch(key) - end - alias fg irb_fg - - def irb_kill(*keys) - require "irb/multi-irb" - IRB.JobManager.kill(*keys) - end - alias kill irb_kill - end - - # Singleton method - def @CONF.inspect - IRB.version unless self[:VERSION] - - array = [] - for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name} - case k - when :MAIN_CONTEXT - next - when :PROMPT - s = v.collect{ - |kk, vv| - ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"} - format(":%s=>{%s}", kk.id2name, ss.join(", ")) - } - array.push format("CONF[:%s]={%s}", k.id2name, s.join(", ")) - else - array.push format("CONF[:%s]=%s", k.id2name, v.inspect) - end - end - array.join("\n") - end -end diff --git a/lib/irb/multi-irb.rb b/lib/irb/multi-irb.rb index 39dbcbae3c..6e97512e27 100644 --- a/lib/irb/multi-irb.rb +++ b/lib/irb/multi-irb.rb @@ -1,9 +1,9 @@ # -# multi-irb.rb - multiple irb module -# $Release Version: 0.6$ +# irb/multi-irb.rb - multiple irb module +# $Release Version: 0.7.3$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # @@ -23,7 +23,7 @@ module IRB @current_job = nil end - attr :current_job, true + attr_accessor :current_job def n_jobs @jobs.size @@ -31,7 +31,7 @@ module IRB def thread(key) th, irb = search(key) - irb + th end def irb(key) @@ -74,7 +74,7 @@ module IRB when Integer @jobs[key] when Irb - @jobs.find{|k, v| v.equal?(irb)} + @jobs.find{|k, v| v.equal?(key)} when Thread @jobs.assoc(key) else @@ -140,20 +140,15 @@ module IRB @JobManager end - # invoke multiple irb + # invoke multi-irb def IRB.irb(file = nil, *main) - workspace = IRB.workspace_binding(*main) - if main.empty? - main = eval("self", workspace) - else - main = main[0] - end + workspace = WorkSpace.new(*main) parent_thread = Thread.current Thread.start do begin - irb = Irb.new(main, workspace, file) + irb = Irb.new(workspace, file) rescue - print "Subirb can't start with context(self): ", main.inspect, "\n" + print "Subirb can't start with context(self): ", workspace.main.inspect, "\n" print "return to main irb\n" Thread.pass Thread.main.wakeup @@ -161,6 +156,7 @@ module IRB end @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @JobManager.insert(irb) + @JobManager.current_job = irb begin system_exit = false catch(:IRB_EXIT) do @@ -190,7 +186,7 @@ module IRB class Context def _=(value) @_ = value - eval "_ = IRB.JobManager.irb(Thread.current).context._", @bind + @workspace.evaluate "_ = IRB.JobManager.irb(Thread.current).context._" end end @@ -198,15 +194,39 @@ module IRB def irb_context IRB.JobManager.irb(Thread.current).context end - alias conf irb_context +# alias conf irb_context end @CONF[:SINGLE_IRB_MODE] = false @JobManager.insert(@CONF[:MAIN_CONTEXT].irb) @JobManager.current_job = @CONF[:MAIN_CONTEXT].irb + class Irb + def signal_handle + unless @context.ignore_sigint? + print "\nabort!!\n" if @context.verbose? + exit + end + + case @signal_status + when :IN_INPUT + print "^C\n" + IRB.JobManager.thread(self).raise RubyLex::TerminateLineInput + when :IN_EVAL + IRB.irb_abort(self) + when :IN_LOAD + IRB.irb_abort(self, LoadAbort) + when :IN_IRB + # ignore + else + # ignore + end + end + end + trap("SIGINT") do @JobManager.current_job.signal_handle + Thread.stop end end diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index 4c7a3b1002..3a862002a6 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -1,9 +1,9 @@ # -# ruby-lex.rb - ruby lexcal analizer -# $Release Version: 0.6$ +# irb/ruby-lex.rb - ruby lexcal analizer +# $Release Version: 0.7.3$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # @@ -24,11 +24,13 @@ class RubyLex def_exception(:TkReading2TokenDuplicateError, "key duplicate(token_n='%s', key='%s')") def_exception(:SyntaxError, "%s") + + def_exception(:TerminateLineInput, "Terminate Line Input") include RubyToken class << self - attr :debug_level, TRUE + attr_accessor :debug_level def debug? @debug_level > 0 end @@ -54,14 +56,14 @@ class RubyLex @exception_on_syntax_error = true end - attr :skip_space, true - attr :readed_auto_clean_up, true - attr :exception_on_syntax_error, true + attr_accessor :skip_space + attr_accessor :readed_auto_clean_up + attr_accessor :exception_on_syntax_error - attr :seek - attr :char_no - attr :line_no - attr :indent + attr_reader :seek + attr_reader :char_no + attr_reader :line_no + attr_reader :indent # io functions def set_input(io, p = nil) @@ -202,8 +204,8 @@ class RubyLex @space_seen = false @here_header = false + @continue = false prompt - @continue = FALSE @line = "" @exp_line_no = @line_no @@ -211,27 +213,35 @@ class RubyLex def each_top_level_statement initialize_input - loop do - @continue = FALSE - prompt - unless l = lex - break if @line == '' - else - # p l - @line.concat l - if @ltype or @continue or @indent > 0 - next + catch(:TERM_INPUT) do + loop do + begin + @continue = false + prompt + unless l = lex + throw :TERM_INPUT if @line == '' + else + #p l + @line.concat l + if @ltype or @continue or @indent > 0 + next + end + end + if @line != "\n" + yield @line, @exp_line_no + end + break unless l + @line = '' + @exp_line_no = @line_no + + @indent = 0 + prompt + rescue TerminateLineInput + initialize_input + prompt + get_readed end end - if @line != "\n" - yield @line, @exp_line_no - end - break unless l - @line = '' - @exp_line_no = @line_no - - @indent = 0 - prompt end end @@ -239,8 +249,8 @@ class RubyLex until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && !@continue or tk.nil?) - # p tk - # p self + #p tk + #p self end line = get_readed # print self.inspect @@ -315,7 +325,7 @@ class RubyLex end @OP.def_rules(" ", "\t", "\f", "\r", "\13") do - @space_seen = TRUE + @space_seen = true while getc =~ /[ \t\f\r\13]/; end ungetc Token(TkSPACE) @@ -333,7 +343,7 @@ class RubyLex until peek_equal?("=end") && peek(4) =~ /\s/ until getc == "\n"; end end - getc; getc; getc; getc + gets @ltype = nil Token(TkRD_COMMENT) end @@ -342,9 +352,9 @@ class RubyLex print "\\n\n" if RubyLex.debug? case @lex_state when EXPR_BEG, EXPR_FNAME, EXPR_DOT - @continue = TRUE + @continue = true else - @continue = FALSE + @continue = false @lex_state = EXPR_BEG end @here_header = false @@ -458,7 +468,7 @@ class RubyLex ungetc identify_number else - # for obj.if + # for "obj.if" etc. @lex_state = EXPR_DOT Token(TkDOT) end @@ -608,7 +618,7 @@ class RubyLex identify_quotation elsif peek(0) == '=' getc - Token(OP_ASGIN, "%") + Token(TkOPASGN, :%) elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_quotation else @@ -691,7 +701,7 @@ class RubyLex if ch == "!" or ch == "?" token.concat getc end - # fix token + # almost fix token case token when /^\$/ @@ -752,6 +762,7 @@ class RubyLex def identify_here_document ch = getc +# if lt = PERCENT_LTYPE[ch] if ch == "-" ch = getc indent = true @@ -835,8 +846,8 @@ class RubyLex end type = TkINTEGER - allow_point = TRUE - allow_e = TRUE + allow_point = true + allow_e = true while ch = getc case ch when /[0-9_]/ @@ -954,7 +965,7 @@ class RubyLex read_escape(chrs) end else - # other characters + # other characters end end end diff --git a/lib/irb/ruby-token.rb b/lib/irb/ruby-token.rb index 1532dc78eb..2e5715c9f7 100644 --- a/lib/irb/ruby-token.rb +++ b/lib/irb/ruby-token.rb @@ -1,9 +1,9 @@ # -# ruby-token.rb - ruby tokens -# $Release Version: 0.6$ +# irb/ruby-token.rb - ruby tokens +# $Release Version: 0.7.3$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # @@ -17,6 +17,11 @@ module RubyToken EXPR_FNAME = :EXPR_FNAME EXPR_DOT = :EXPR_DOT EXPR_CLASS = :EXPR_CLASS + + # for ruby 1.4X + if !defined?(Symbol) + Symbol = Integer + end class Token def initialize(seek, line_no, char_no) @@ -241,7 +246,7 @@ module RubyToken TkSymbol2Token = {} def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts) - token_n = token_n.id2name unless token_n.kind_of?(String) + token_n = token_n.id2name if token_n.kind_of?(Symbol) if RubyToken.const_defined?(token_n) IRB.fail AlreadyDefinedToken, token_n end diff --git a/lib/irb/slex.rb b/lib/irb/slex.rb index 85aa92bd73..26008906e5 100644 --- a/lib/irb/slex.rb +++ b/lib/irb/slex.rb @@ -1,9 +1,9 @@ # -# irb-slex.rb - symple lex analizer -# $Release Version: 0.6$ +# irb/slex.rb - symple lex analizer +# $Release Version: 0.7.3$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# by Keiju ISHITSUKA(keiju@ishituska.com) # # -- # @@ -20,7 +20,7 @@ class SLex def_exception :ErrNodeAlreadyExists, "node already exists" class << self - attr :debug_level, TRUE + attr_accessor :debug_level def debug? debug_level > 0 end @@ -88,16 +88,16 @@ class SLex # #---------------------------------------------------------------------- class Node - # if postproc no exist, this node is abstract node. - # if postproc isn't nil, this node is real node. + # if postproc is nil, this node is an abstract node. + # if postproc is non-nil, this node is a real node. def initialize(preproc = nil, postproc = nil) @Tree = {} @preproc = preproc @postproc = postproc end - attr :preproc, TRUE - attr :postproc, TRUE + attr_accessor :preproc + attr_accessor :postproc def search(chrs, opt = nil) return self if chrs.empty? @@ -159,8 +159,8 @@ class SLex # # chrs: String # character array - # io It must have getc()/ungetc(), and ungetc() can be - # called any number of times. + # io must have getc()/ungetc(); and ungetc() must be + # able to be called arbitrary number of times. # def match(chrs, op = "") print "match>: ", chrs, "op:", op, "\n" if SLex.debug? @@ -265,7 +265,7 @@ if $0 == __FILE__ print "0: ", tr.inspect, "\n" tr.def_rule("=") {print "=\n"} print "1: ", tr.inspect, "\n" - tr.def_rule("==", proc{FALSE}) {print "==\n"} + tr.def_rule("==", proc{false}) {print "==\n"} print "2: ", tr.inspect, "\n" print "case 1:\n" diff --git a/lib/irb/version.rb b/lib/irb/version.rb index 7179d1c163..367cc21046 100644 --- a/lib/irb/version.rb +++ b/lib/irb/version.rb @@ -1,9 +1,9 @@ # -# version.rb - irb version definition file -# $Release Version: 0.6.1$ +# irb/version.rb - irb version definition file +# $Release Version: 0.7.4$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # @@ -11,6 +11,6 @@ # module IRB - @RELEASE_VERSION = "0.6.1" - @LAST_UPDATE_DATE = "99/09/16" + @RELEASE_VERSION = "0.7.4" + @LAST_UPDATE_DATE = "01/05/08" end diff --git a/lib/irb/workspace-binding-2.rb b/lib/irb/workspace-binding-2.rb deleted file mode 100644 index d005296f6e..0000000000 --- a/lib/irb/workspace-binding-2.rb +++ /dev/null @@ -1,15 +0,0 @@ -# -# bind.rb - -# $Release Version: $ -# $Revision$ -# $Date$ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) -# -# -- -# -# -# - -while true - IRB::BINDING_QUEUE.push b = binding -end diff --git a/lib/irb/workspace-binding.rb b/lib/irb/workspace-binding.rb deleted file mode 100644 index d58088d9dd..0000000000 --- a/lib/irb/workspace-binding.rb +++ /dev/null @@ -1,77 +0,0 @@ -# -# workspace-binding.rb - -# $Release Version: $ -# $Revision$ -# $Date$ -# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) -# -# -- -# -# -# - - -module IRB - # create new workspace. - def IRB.workspace_binding(*main) - if @CONF[:SINGLE_IRB] - bind = TOPLEVEL_BINDING - else - case @CONF[:CONTEXT_MODE] - when 0 - bind = eval("proc{binding}.call", - TOPLEVEL_BINDING, - "(irb_local_binding)", - 1) - when 1 - require "tempfile" - f = Tempfile.open("irb-binding") - f.print < -Version: 1.2.1 += monitor.rb -USAGE: +Copyright (C) 2001 Shugo Maeda - foo = Foo.new - foo.extend(MonitorMixin) - cond = foo.new_cond +This library is distributed under the terms of the Ruby license. +You can freely distribute/modify this library. - thread1: - foo.synchronize { - ... - cond.wait_until { foo.done? } - ... - } +== example - thread2: - foo.synchronize { - foo.do_something - cond.signal - } +This is a simple example. + + require 'monitor.rb' + + buf = [] + buf.extend(MonitorMixin) + empty_cond = buf.new_cond + + # consumer + Thread.start do + loop do + buf.synchronize do + empty_cond.wait_while { buf.empty? } + print buf.shift + end + end + end + + # producer + while line = ARGF.gets + buf.synchronize do + buf.push(line) + empty_cond.signal + end + end + +The consumer thread waits for the producer thread to push a line +to buf while buf.empty?, and the producer thread (main thread) +reads a line from ARGF and push it to buf, then call +empty_cond.signal. =end @@ -52,6 +69,15 @@ module MonitorMixin raise ThreadError, "current thread not owner" end + if timeout + ct = Thread.current + timeout_thread = Thread.start { + Thread.pass + sleep(timeout) + ct.raise(Timeout.new) + } + end + Thread.critical = true count = @monitor.mon_count @monitor.mon_count = 0 @@ -63,34 +89,28 @@ module MonitorMixin end t.wakeup if t @waiters.push(Thread.current) - - if timeout - t = Thread.current - timeout_thread = Thread.start { - sleep(timeout) - t.raise(Timeout.new) - } - end + begin Thread.stop rescue Timeout - @waiters.delete(Thread.current) ensure + Thread.critical = true if timeout && timeout_thread.alive? Thread.kill(timeout_thread) end + if @waiters.include?(Thread.current) # interrupted? + @waiters.delete(Thread.current) + end + while @monitor.mon_owner && + @monitor.mon_owner != Thread.current + @monitor.mon_waiting_queue.push(Thread.current) + Thread.stop + Thread.critical = true + end + @monitor.mon_owner = Thread.current + @monitor.mon_count = count + Thread.critical = false end - - Thread.critical = true - while @monitor.mon_owner && - @monitor.mon_owner != Thread.current - @monitor.mon_waiting_queue.push(Thread.current) - Thread.stop - Thread.critical = true - end - @monitor.mon_owner = Thread.current - @monitor.mon_count = count - Thread.critical = false end def wait_while diff --git a/lib/net/http.rb b/lib/net/http.rb index 3900ed6c68..26e5285525 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -1,8 +1,9 @@ =begin -= net/http.rb version 1.1.32 += net/http.rb version 1.1.34 + +written by Minero Aoki -maintained by Minero Aoki This file is derived from "http-access.rb". This program is free software. @@ -14,9 +15,34 @@ You can get it from RAA (Ruby Application Archive: http://www.ruby-lang.org/en/raa.html). -= class HTTP +== http.rb version 1.2 features + +You can use 1.2 features by calling HTTP.version_1_2. And +calling Net::HTTP.version_1_1 allows to use 1.1 features. + + # example + HTTP.start {|http1| ...(http1 has 1.1 features)... } + + HTTP.version_1_2 + HTTP.start {|http2| ...(http2 has 1.2 features)... } + + HTTP.version_1_1 + HTTP.start {|http3| ...(http3 has 1.1 features)... } + +Changes are: -== Class Methods + * HTTP#get, head, post does not raise ProtocolError + * HTTP#get, head, post returns only one object, a HTTPResponse object + * HTTPResponseReceiver is joined into HTTPResponse + * request object: HTTP::Get, Head, Post; and HTTP#request(req) + +WARNING: These features are not definite yet. +They will change without notice! + + +== class HTTP + +=== Class Methods : new( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil ) creates a new Net::HTTP object. @@ -49,7 +75,7 @@ You can get it from RAA HTTP default port (80). -== Methods +=== Methods : start : start {|http| .... } @@ -72,7 +98,7 @@ You can get it from RAA get data from "path" on connecting host. "header" must be a Hash like { 'Accept' => '*/*', ... }. Data is written to "dest" by using "<<" method. - This method returns Net::HTTPResponse object, and "dest". + This method returns HTTPResponse object, and "dest". # example response, body = http.get( '/index.html' ) @@ -95,7 +121,7 @@ You can get it from RAA : head( path, header = nil ) gets only header from "path" on connecting host. "header" is a Hash like { 'Accept' => '*/*', ... }. - This method returns a Net::HTTPResponse object. + This method returns a HTTPResponse object. You can http header from this object like: response['content-length'] #-> '2554' @@ -109,7 +135,7 @@ You can get it from RAA If the body exists, also gets entity body. Data is written to "dest" by using "<<" method. "header" must be a Hash like { 'Accept' => '*/*', ... }. - This method returns Net::HTTPResponse object and "dest". + This method returns HTTPResponse object and "dest". If called with block, gives a part of entity body string. @@ -181,21 +207,21 @@ You can get it from RAA response.body -= class HTTPResponse +== class HTTPResponse HTTP response object. All "key" is case-insensitive. -== Methods +=== Methods : body - the entity body. ("dest" argument for HTTP#get, post, put) + the entity body (String). : self[ key ] returns header field for "key". for HTTP, value is a string like 'text/plain'(for Content-Type), - '2045'(for Content-Length), 'bytes 0-1024/10024'(for Content-Range). - Multiple header had be joined by HTTP1.1 scheme. + '2045'(for Content-Length), 'bytes 0-1023/10024'(for Content-Range). + If there's some fields which has same name, they are joined with ','. : self[ key ] = val set field value for "key". @@ -204,88 +230,92 @@ All "key" is case-insensitive. true if key exists : each {|name,value| .... } - iterates for each field name and value pair + iterates for each field name and value pair. : code - HTTP result code string. For example, '302' + HTTP result code string. For example, '302'. : message - HTTP result message. For example, 'Not Found' + HTTP result message. For example, 'Not Found'. -= class HTTPResponseReceiver +== class HTTPResponseReceiver -== Methods +=== Methods : header : response - Net::HTTPResponse object + HTTPResponse object -: body( dest = '' ) -: entity( dest = '' ) - entity body. A body is written to "dest" using "<<" method. +: read_body( dest = '' ) + reads entity body into DEST by calling "<<" method and + returns DEST. -: body {|str| ... } - gets entity body with block. - If this method is called twice, block is not executed and - returns first "dest". +: read_body {|string| ... } + reads entity body little by little and gives it to block + until entity ends. +: body +: entity + entity body. If #read_body is called already, returns its + argument DEST. Else returns entity body as String. -= http.rb version 1.2 features + Calling this method any times causes returning same + object (does not read entity again). -You can use 1.2 features by calling HTTP.version_1_2. And -calling Net::HTTP.version_1_1 allows to use 1.1 features. +=end - # example - HTTP.start {|http1| ...(http1 has 1.1 features)... } +require 'net/protocol' - HTTP.version_1_2 - HTTP.start {|http2| ...(http2 has 1.2 features)... } - HTTP.version_1_1 - HTTP.start {|http3| ...(http3 has 1.1 features)... } +module Net -== Method (only diff to 1.1) + class HTTPBadResponse < StandardError; end + class HTTPHeaderSyntaxError < StandardError; end -: get( path, u_header = nil ) -: get( path, u_header = nil ) {|str| .... } - gets document from "path". - returns HTTPResponse object. -: head( path, u_header = nil ) - gets only document header from "path". - returns HTTPResponse object. + class HTTP < Protocol -: post( path, data, u_header = nil ) -: post( path, data, u_header = nil ) {|str| .... } - posts "data" to "path" entity and gets document. - returns HTTPResponse object. + HTTPVersion = '1.1' -=end + # + # connection + # -require 'net/protocol' + protocol_param :port, '80' -module Net + def initialize( addr = nil, port = nil ) + super - class HTTPBadResponse < StandardError; end + @proxy_address = nil + @proxy_port = nil + @curr_http_version = HTTPVersion + @seems_1_0_server = false + end - class HTTP < Protocol - protocol_param :port, '80' - protocol_param :command_type, '::Net::NetPrivate::HTTPCommand' + private + def conn_command( sock ) + end + + def do_finish + end + + + # + # proxy + # + + public - ### - ### proxy - ### class << self def Proxy( p_addr, p_port = nil ) - ::Net::NetPrivate::HTTPProxy.create_proxy_class( - p_addr, p_port || self.port ) + ProxyMod.create_proxy_class( p_addr, p_port || self.port ) end alias orig_new new @@ -293,7 +323,7 @@ module Net def new( address = nil, port = nil, p_addr = nil, p_port = nil ) c = p_addr ? self::Proxy(p_addr, p_port) : self i = c.orig_new( address, port ) - setimplv i + setvar i i end @@ -332,385 +362,230 @@ module Net end - ### - ### 1.2 implementation - ### + module ProxyMod - @@newimpl = false + class << self - #class << self + def create_proxy_class( p_addr, p_port ) + mod = self + klass = Class.new( HTTP ) + klass.module_eval { + include mod + @proxy_address = p_addr + @proxy_port = p_port + } + def klass.proxy_class? + true + end - def self.version_1_2 - @@newimpl = true - end + def klass.proxy_address + @proxy_address + end - def self.version_1_1 - @@newimpl = false - end + def klass.proxy_port + @proxy_port + end - #private + klass + end - def self.setimplv( obj ) - f = @@newimpl - obj.instance_eval { @newimpl = f } end - #end - - - ### - ### http operations - ### - - def get( path, u_header = nil, dest = nil, &block ) - resp = get2( path, u_header ) {|f| f.body( dest, &block ) } - if @newimpl then - resp - else - resp.value - return resp, resp.body + def initialize( addr, port ) + super + @proxy_address = type.proxy_address + @proxy_port = type.proxy_port end - end - - def get2( path, u_header = nil, &block ) - common_oper( u_header, true, block ) {|uh| - @command.get edit_path(path), uh - } - end + + attr_reader :proxy_address, :proxy_port + alias proxyaddr proxy_address + alias proxyport proxy_port - def head( path, u_header = nil ) - resp = head2( path, u_header ) - unless @newimpl then - resp.value + def proxy? + true end - resp - end - - def head2( path, u_header = nil, &block ) - common_oper( u_header, false, block ) {|uh| - @command.head edit_path(path), uh - } - end - - - def post( path, data, u_header = nil, dest = nil, &block ) - resp = post2( path, data, u_header ) {|f| f.body( dest, &block ) } - if @newimpl then - resp - else - resp.value - return resp, resp.body + + private + + def conn_socket( addr, port ) + super @proxy_address, @proxy_port end - end - - def post2( path, data, u_header = nil, &block ) - common_oper( u_header, true, block ) {|uh| - @command.post edit_path(path), uh, data - } - end - - # not tested because I could not setup apache (__;;; - def put( path, src, u_header = nil ) - resp = put2( path, src, u_header ) {|f| f.body } - if @newimpl then - resp - else - resp.value - return resp, resp.body + def edit_path( path ) + 'http://' + addr_port + path end - end + + end # module ProxyMod - def put2( path, src, u_header = nil, &block ) - common_oper( u_header, true, block ) {|uh| - @command.put path, uh, src - } - end - - - private - - - def common_oper( u_header, body_exist, block ) - header = procheader( u_header ) - recv = err = nil - - connecting( header ) { - recv = HTTPResponseReceiver.new( @command, body_exist ) - yield header - begin - block.call recv if block - rescue Exception => err - ; - end - recv.terminate - - recv.response - } - raise err if err - recv.response - end + # + # for backward compatibility + # - def connecting( header ) - if not @socket then - header['Connection'] = 'close' - start - elsif @socket.closed? then - @socket.reopen - end + @@newimpl = false - resp = yield + class << self - unless keep_alive? header, resp then - @socket.close + def version_1_2 + @@newimpl = true end - end - def keep_alive?( header, resp ) - if resp.key? 'connection' then - if /keep-alive/i === resp['connection'] then - return true - end - elsif resp.key? 'proxy-connection' then - if /keep-alive/i === resp['proxy-connection'] then - return true - end - elsif header.key? 'Connection' then - if /keep-alive/i === header['Connection'] then - return true - end - else - if @command.http_version == '1.1' then - return true - end + def version_1_1 + @@newimpl = false end - false - end - - def procheader( h ) - ret = {} - ret[ 'Host' ] = address + - ((port == HTTP.port) ? '' : ":#{port}") - ret[ 'Connection' ] = 'Keep-Alive' - ret[ 'Accept' ] = '*/*' + private - return ret unless h - tmp = {} - h.each do |k,v| - key = k.split('-').collect {|i| i.capitalize }.join('-') - if tmp[key] then - $stderr.puts "'#{key}' http header appered twice" if $VERBOSE - end - tmp[key] = v + def setvar( obj ) + f = @@newimpl + obj.instance_eval { @newimpl = f } end - ret.update tmp - ret end - def do_finish - end + # + # http operations + # - end - - HTTPSession = HTTP - - - module NetPrivate - - module HTTPProxy - - class << self - - def create_proxy_class( p_addr, p_port ) - klass = Class.new( HTTP ) - klass.module_eval { - include HTTPProxy - @proxy_address = p_addr - @proxy_port = p_port - } - def klass.proxy_class? - true - end + public - def klass.proxy_address - @proxy_address + def self.def_http_method( nm, hasdest, hasdata ) + name = nm.id2name.downcase + cname = nm.id2name + lineno = __LINE__ + 2 + src = <<" ----" + + def #{name}( path, #{hasdata ? 'data,' : ''} + u_header = nil #{hasdest ? ',dest = nil, &block' : ''} ) + resp = nil + request( + #{cname}.new( path, u_header ) #{hasdata ? ',data' : ''} + ) do |resp| + resp.read_body( #{hasdest ? 'dest, &block' : ''} ) + end + if @newimpl then + resp + else + resp.value + #{hasdest ? 'return resp, resp.body' : 'resp'} + end end - def klass.proxy_port - @proxy_port + def #{name}2( path, #{hasdata ? 'data,' : ''} + u_header = nil, &block ) + request( #{cname}.new(path, u_header), + #{hasdata ? 'data,' : ''} &block ) end - - klass - end - - end - - - def initialize( addr, port ) - super - @proxy_address = type.proxy_address - @proxy_port = type.proxy_port + ---- + module_eval src, __FILE__, lineno end - attr_reader :proxy_address, :proxy_port + def_http_method :Get, true, false + def_http_method :Head, false, false + def_http_method :Post, true, true + def_http_method :Put, false, true - alias proxyaddr proxy_address - alias proxyport proxy_port - - def proxy? - true - end - - def connect( addr = nil, port = nil ) - super @proxy_address, @proxy_port - end - - def edit_path( path ) - 'http://' + address + (port == type.port ? '' : ":#{port}") + path + def request( req, *args ) + common_oper( req ) { + req.__send__( :exec, + @socket, @curr_http_version, edit_path(req.path), *args ) + yield req.response if block_given? + } + req.response end - - end - - end # net private + private - class HTTPResponseReceiver - - def initialize( command, body_exist ) - @command = command - @body_exist = body_exist - @header = @body = nil - end - - def inspect - "#<#{type}>" - end - def read_header - unless @header then - stream_check - @header = @command.get_response + def common_oper( req ) + req['connection'] ||= 'keep-alive' + if not @socket then + start + req['connection'] = 'close' + elsif @socket.closed? then + re_connect end - @header - end - - alias header read_header - alias response read_header - - def read_body( dest = nil, &block ) - unless @body then - read_header - - to = procdest( dest, block ) - stream_check - - if @body_exist and @header.code_type.body_exist? then - @command.get_body @header, to - @header.body = @body = to - else - @command.no_body - @header.body = nil - @body = 1 - end + if not req.body_exist? or @seems_1_0_server then + req['connection'] = 'close' end - @body == 1 ? nil : @body - end - - alias body read_body - alias entity read_body + req['host'] = addr_port - def terminate - read_header - read_body - @command = nil - end + yield req + req.response.__send__ :terminate + @curr_http_version = req.response.http_version - - private - - def stream_check - unless @command then - raise IOError, 'receiver was used out of block' - end - end - - def procdest( dest, block ) - if dest and block then - raise ArgumentError, - 'both of arg and block are given for HTTP method' - end - if block then - NetPrivate::ReadAdapter.new block + if not req.response.body then + @socket.close + elsif keep_alive? req, req.response then + D 'Conn keep-alive' + if @socket.closed? then # (only) read stream had been closed + D 'Conn (but seems 1.0 server)' + @seems_1_0_server = true + @socket.close + end else - dest or '' + D 'Conn close' + @socket.close end - end - - end - - HTTPReadAdapter = HTTPResponseReceiver - - class HTTPResponse < Response - - def initialize( code_type, code, msg ) - super - @data = {} - @body = nil + req.response end - attr_accessor :body + def keep_alive?( req, res ) + /close/i === req['connection'].to_s and return false + @seems_1_0_server and return false - def inspect - "#<#{type.name} #{code}>" - end + /keep-alive/i === res['connection'].to_s and return true + /close/i === res['connection'].to_s and return false + /keep-alive/i === res['proxy-connection'].to_s and return true + /close/i === res['proxy-connection'].to_s and return false - def []( key ) - @data[ key.downcase ] + @curr_http_version == '1.1' and return true + false end - def []=( key, val ) - @data[ key.downcase ] = val - end - def each( &block ) - @data.each( &block ) - end + # + # utils + # - def each_key( &block ) - @data.each_key( &block ) - end + public - def each_value( &block ) - @data.each_value( &block ) + def self.get( addr, path, port = nil ) + req = Get.new( path ) + resp = nil + new( addr, port || HTTP.port ).start {|http| + resp = http.request( req ) + } + resp.body end - def delete( key ) - @data.delete key.downcase + def self.get_print( addr, path, port = nil ) + print get( addr, path, port ) end - def key?( key ) - @data.key? key.downcase - end - def to_hash - @data.dup + private + + def addr_port + address + (port == HTTP.port ? '' : ":#{port}") end - def value - unless SuccessCode === self then - error! self + def D( msg ) + if @dout then + @dout << msg + @dout << "\n" end end end + HTTPSession = HTTP + + class Code @@ -776,101 +651,246 @@ module Net HTTPVersionNotSupported = HTTPServerErrorCode.http_mkchild - module NetPrivate + ### + ### header + ### - class HTTPCommand < Command + net_private { - HTTPVersion = '1.1' + module HTTPHeader - def initialize( sock ) - @http_version = HTTPVersion - super sock + def size + @header.size end - attr_reader :http_version + alias length size - def inspect - "#" + def []( key ) + @header[ key.downcase ] end + def []=( key, val ) + @header[ key.downcase ] = val + end - ### - ### request - ### + def each( &block ) + @header.each( &block ) + end - public + def each_key( &block ) + @header.each_key( &block ) + end - def get( path, u_header ) - return unless begin_critical - request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header + def each_value( &block ) + @header.each_value( &block ) end - - def head( path, u_header ) - return unless begin_critical - request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header + + def delete( key ) + @header.delete key.downcase + end + + def key?( key ) + @header.key? key.downcase + end + + def to_hash + @header.dup end - def post( path, u_header, data ) - return unless begin_critical - u_header[ 'Content-Length' ] = data.size.to_s - request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header - @socket.write data + def canonical_each + @header.each do |k,v| + yield canonical(k), v + end end - def put( path, u_header, src ) - return unless begin_critical - request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header - @socket.write_bin src + def canonical( k ) + k.split('-').collect {|i| i.capitalize }.join('-') end - # def delete + def range + s = @header['range'] + s or return nil - # def trace + arr = [] + s.split(',').each do |spec| + m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match( spec ) + m or raise HTTPHeaderSyntaxError, "wrong Range: #{spec}" - # def options + d1 = m[1].to_i + d2 = m[2].to_i + if m[1] and m[2] then arr.push (d1 .. d2) + elsif m[1] then arr.push (d1 .. -1) + elsif m[2] then arr.push (-d2 .. -1) + else + raise HTTPHeaderSyntaxError, 'range is not specified' + end + end - def quit + return *arr end + def range=( r, fin = nil ) + if fin then + r = r ... r+fin + end - private + case r + when Numeric + s = r > 0 ? "0-#{r - 1}" : "-#{-r}" + when Range + first = r.first + last = r.last + if r.exclude_end? then + last -= 1 + end - def request( req, u_header ) - @socket.writeline req - u_header.each do |n,v| - @socket.writeline n + ': ' + v + if last == -1 then + s = first > 0 ? "#{first}-" : "-#{-first}" + else + first >= 0 or raise HTTPHeaderSyntaxError, 'range.first is negative' + last > 0 or raise HTTPHeaderSyntaxError, 'range.last is negative' + first < last or raise HTTPHeaderSyntaxError, 'must be .first < .last' + s = "#{first}-#{last}" + end + else + raise TypeError, 'Range/Integer is required' end - @socket.writeline '' + + @header['range'] = "bytes=#{s}" + r end + alias set_range range= - ### - ### response line & header - ### + def content_length + s = @header['content-length'] + s or return nil - public + m = /\d+/.match(s) + m or raise HTTPHeaderSyntaxError, 'wrong Content-Length format' + m[0].to_i + end - def get_response - resp = get_resp0 - resp = get_resp0 while ContinueCode === resp - resp + def chunked? + s = @header['transfer-encoding'] + (s and /(?:\A|[^\-\w])chunked(?:[^\-\w]|\z)/i === s) ? true : false + end + + def content_range + s = @header['content-range'] + s or return nil + + m = %ri.match( s ) + m or raise HTTPHeaderSyntaxError, 'wrong Content-Range format' + + m[1].to_i .. m[2].to_i + 1 + end + + def range_length + r = content_range + r and r.length + end + + def basic_auth( acc, pass ) + @header['authorization'] = + 'Basic ' + ["#{acc}:#{pass}"].pack('m').gsub(/\s+/, '') + end + + end + + } + + + ### + ### request + ### + + net_private { + + class HTTPRequest + + include ::Net::NetPrivate::HTTPHeader + + def initialize( path, uhead = nil ) + @path = path + @header = tmp = {} + return unless uhead + uhead.each do |k,v| + key = k.downcase + if tmp.key? key then + $stderr.puts "WARNING: duplicated HTTP header: #{k}" if $VERBOSE + end + tmp[ key ] = v.strip + end + tmp['accept'] ||= '*/*' + + @socket = nil + @response = nil + end + + attr_reader :path + attr_reader :response + + def inspect + "\#<#{type}>" + end + + def body_exist? + type::HAS_BODY end private - def get_resp0 - resp = get_reply + # + # write + # + + def exec( sock, ver, path ) + ready( sock ) { + request ver, path + } + @response + end + + def ready( sock ) + @response = nil + @socket = sock + yield + @response = get_response + @socket = nil + end + + def request( ver, path ) + @socket.writeline sprintf('%s %s HTTP/%s', type::METHOD, path, ver) + canonical_each do |k,v| + @socket.writeline k + ': ' + v + end + @socket.writeline '' + end + + # + # read + # + + def get_response + begin + resp = read_response + end while ContinueCode === resp + resp + end + + def read_response + resp = get_resline while true do - line = @socket.readline + line = @socket.readuntil( "\n", true ) # ignore EOF + line.sub!( /\s+\z/, '' ) # don't use chop! break if line.empty? m = /\A([^:]+):\s*/.match( line ) - unless m then - raise HTTPBadResponse, 'wrong header line format' - end + m or raise HTTPBadResponse, 'wrong header line format' nm = m[1] line = m.post_match if resp.key? nm then @@ -883,23 +903,117 @@ module Net resp end - def get_reply + def get_resline str = @socket.readline - m = /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i.match( str ) - unless m then - raise HTTPBadResponse, "wrong status line: #{str}" - end - @http_version = m[1] + m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/i.match( str ) + m or raise HTTPBadResponse, "wrong status line: #{str}" + httpver = m[1] status = m[2] discrip = m[3] - code = HTTPCODE_TO_OBJ[status] || - HTTPCODE_CLASS_TO_OBJ[status[0,1]] || - UnknownCode - HTTPResponse.new( code, status, discrip ) + ::Net::NetPrivate::HTTPResponse.new( + status, discrip, @socket, type::HAS_BODY, httpver ) + end + + end + + + class HTTPRequestWithBody < HTTPRequest + + private + + def exec( sock, ver, path, str = nil ) + check_arg str, block_given? + + if block_given? then + ac = Accumulator.new + yield ac # must be yield, DO NOT USE block.call + data = ac.terminate + else + data = str + end + @header['content-length'] = data.size.to_s + @header.delete 'transfer-encoding' + + ready( sock ) { + request ver, path + @socket.write data + } + @response + end + + def check_arg( data, blkp ) + if data and blkp then + raise ArgumentError, 'both of data and block given' + end + unless data or blkp then + raise ArgumentError, 'str or block required' + end + end + + end + + + class Accumulator + + def initialize + @buf = '' + end + + def write( s ) + @buf.concat s + end + + alias << write + + def terminate + ret = @buf + @buf = nil + ret + end + + end + + } + + + class HTTP + + class Get < ::Net::NetPrivate::HTTPRequest + HAS_BODY = true + METHOD = 'GET' + end + + class Head < ::Net::NetPrivate::HTTPRequest + HAS_BODY = false + METHOD = 'HEAD' + end + + class Post < ::Net::NetPrivate::HTTPRequestWithBody + HAS_BODY = true + METHOD = 'POST' + end + + class Put < ::Net::NetPrivate::HTTPRequestWithBody + HAS_BODY = true + METHOD = 'PUT' end - HTTPCODE_CLASS_TO_OBJ = { + end + + + + ### + ### response + ### + + net_private { + + class HTTPResponse < Response + + include ::Net::NetPrivate::HTTPHeader + + CODE_CLASS_TO_OBJ = { '1' => HTTPInformationCode, '2' => HTTPSuccessCode, '3' => HTTPRedirectionCode, @@ -907,7 +1021,7 @@ module Net '5' => HTTPServerErrorCode } - HTTPCODE_TO_OBJ = { + CODE_TO_OBJ = { '100' => ContinueCode, '101' => HTTPSwitchProtocol, @@ -951,22 +1065,87 @@ module Net '505' => HTTPVersionNotSupported } + def initialize( stat, msg, sock, be, hv ) + code = CODE_TO_OBJ[stat] || + CODE_CLASS_TO_OBJ[stat[0,1]] || + UnknownCode + super code, stat, msg + @socket = sock + @body_exist = be + @http_version = hv - ### - ### body - ### + @header = {} + @body = nil + @read = false + end - public + attr_reader :http_version + + def inspect + "#<#{type} #{code}>" + end + + def value + SuccessCode === self or error! self + end - def get_body( resp, dest ) - if chunked? resp then + + # + # header (for backward compatibility) + # + + def read_header + self + end + + alias header read_header + alias response read_header + + # + # body + # + + def read_body( dest = nil, &block ) + if @read and (dest or block) then + raise IOError, "#{type}\#read_body called twice with argument" + end + + unless @read then + to = procdest( dest, block ) + stream_check + + if @body_exist and code_type.body_exist? then + read_body_0 to + @body = to + else + @body = nil + end + @read = true + end + + @body + end + + alias body read_body + alias entity read_body + + + private + + + def terminate + read_body + end + + def read_body_0( dest ) + if chunked? then read_chunked dest else - clen = content_length( resp ) + clen = content_length if clen then - @socket.read clen, dest + @socket.read clen, dest, true # ignore EOF else - clen = range_length( resp ) + clen = range_length if clen then @socket.read clen, dest else @@ -974,16 +1153,8 @@ module Net end end end - end_critical - end - - def no_body - end_critical end - - private - def read_chunked( dest ) len = nil total = 0 @@ -991,9 +1162,7 @@ module Net while true do line = @socket.readline m = /[0-9a-fA-F]+/.match( line ) - unless m then - raise HTTPBadResponse, "wrong chunk size line: #{line}" - end + m or raise HTTPBadResponse, "wrong chunk size line: #{line}" len = m[0].hex break if len == 0 @socket.read( len, dest ); total += len @@ -1004,44 +1173,27 @@ module Net end end - def content_length( resp ) - if resp.key? 'content-length' then - m = /\d+/.match( resp['content-length'] ) - unless m then - raise HTTPBadResponse, 'wrong Content-Length format' - end - m[0].to_i - else - nil - end + def stream_check + @socket.closed? and raise IOError, 'try to read body out of block' end - def chunked?( resp ) - tmp = resp['transfer-encoding'] - tmp and /(?:\A|\s+)chunked(?:\s+|\z)/i === tmp - end - - def range_length( resp ) - if resp.key? 'content-range' then - m = %r.match( resp['content-range'] ) - unless m then - raise HTTPBadResponse, 'wrong Content-Range format' - end - l = m[2].to_i - u = m[1].to_i - if l > u then - nil - else - u - l - end + def procdest( dest, block ) + if dest and block then + raise ArgumentError, 'both of arg and block are given for HTTP method' + end + if block then + ::Net::NetPrivate::ReadAdapter.new block else - nil + dest || '' end end end + } + - end # module Net::NetPrivate + HTTPResponse = NetPrivate::HTTPResponse + HTTPResponseReceiver = NetPrivate::HTTPResponse end # module Net diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 34d324ed12..ea064d2552 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -7,9 +7,10 @@ Copyright (C) 2000 Shugo Maeda This library is distributed under the terms of the Ruby license. You can freely distribute/modify this library. -== class Net::IMAP +== Net::IMAP Net::IMAP implements Internet Message Access Protocol (IMAP) clients. +(The protocol is described in ((<[IMAP]>)).) === Super Class @@ -102,21 +103,24 @@ Object : list(refname, mailbox) Sends a LIST command, and returns a subset of names from the complete set of all names available to the client. + The return value is an array of (()). ex). imap.create("foo/bar") imap.create("foo/baz") p imap.list("", "foo/%") - #=> [#, #, #] + #=> [#, #, #] : lsub(refname, mailbox) Sends a LSUB command, and returns a subset of names from the set of names that the user has declared as being "active" or "subscribed". + The return value is an array of (()). : status(mailbox, attr) Sends a STATUS command, and returns the status of the indicated mailbox. + The return value is a hash of attributes. ex). p imap.status("inbox", ["MESSAGES", "RECENT"]) @@ -166,6 +170,7 @@ Object in the mailbox. the set parameter is a number or an array of numbers or a Range object. the number is a message sequence number (fetch) or a unique identifier (uid_fetch). + The return value is an array of (()). ex). p imap.fetch(6..8, "UID") @@ -188,6 +193,7 @@ Object in the mailbox. the set parameter is a number or an array of numbers or a Range object. the number is a message sequence number (store) or a unique identifier (uid_store). + The return value is an array of (()). ex). p imap.store(6..8, "+FLAGS", [:Deleted]) @@ -210,6 +216,443 @@ Object p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII") #=> [6, 7, 8, 1] +== Net::IMAP::ContinuationRequest + +Net::IMAP::ContinuationRequest represents command continuation requests. + +The command continuation request response is indicated by a "+" token +instead of a tag. This form of response indicates that the server is +ready to accept the continuation of a command from the client. The +remainder of this response is a line of text. + + continue_req ::= "+" SPACE (resp_text / base64) + +=== Super Class + +Struct + +=== Methods + +: data + Returns the data (Net::IMAP::ResponseText). + +: raw_data + Returns the raw data string. + +== Net::IMAP::UntaggedResponse + +Net::IMAP::UntaggedResponse represents untagged responses. + +Data transmitted by the server to the client and status responses +that do not indicate command completion are prefixed with the token +"*", and are called untagged responses. + + response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye / + mailbox_data / message_data / capability_data) + +=== Super Class + +Struct + +=== Methods + +: name + Returns the name such as "FLAGS", "LIST", "FETCH".... + +: data + Returns the data such as an array of flag symbols, + a (()) object.... + +: raw_data + Returns the raw data string. + +== Net::IMAP::TaggedResponse + +Net::IMAP::TaggedResponse represents tagged responses. + +The server completion result response indicates the success or +failure of the operation. It is tagged with the same tag as the +client command which began the operation. + + response_tagged ::= tag SPACE resp_cond_state CRLF + + tag ::= 1* + + resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text + +=== Super Class + +Struct + +=== Methods + +: tag + Returns the tag. + +: name + Returns the name. the name is one of "OK", "NO", "BAD". + +: data + Returns the data. See (()). + +: raw_data + Returns the raw data string. + +== Net::IMAP::ResponseText + +Net::IMAP::ResponseText represents texts of responses. +The text may be prefixed by the response code. + + resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text) + ;; text SHOULD NOT begin with "[" or "=" + +=== Super Class + +Struct + +=== Methods + +: code + Returns the response code. See (()). + +: text + Returns the text. + +== Net::IMAP::ResponseCode + +Net::IMAP::ResponseCode represents response codes. + + resp_text_code ::= "ALERT" / "PARSE" / + "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" / + "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / + "UIDVALIDITY" SPACE nz_number / + "UNSEEN" SPACE nz_number / + atom [SPACE 1*] + +=== SuperClass + +Struct + +=== Methods + +: name + Returns the name such as "ALERT", "PERMANENTFLAGS", "UIDVALIDITY".... + +: data + Returns the data if it exists. + +== Net::IMAP::MailboxList + +Net::IMAP::MailboxList represents contents of the LIST response. + + mailbox_list ::= "(" #("\Marked" / "\Noinferiors" / + "\Noselect" / "\Unmarked" / flag_extension) ")" + SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox + +=== Super Class + +Struct + +=== Methods + +: attr + Returns the name attributes. Each name attribute is a symbol + capitalized by String#capitalize, such as :Noselect (not :NoSelect). + +: delim + Returns the hierarchy delimiter + +: name + Returns the mailbox name. + +== Net::IMAP::StatusData + +Net::IMAP::StatusData represents contents of the STATUS response. + +=== Super Class + +Object + +=== Methods + +: mailbox + Returns the mailbox name. + +: attr + Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT", + "UIDVALIDITY", "UNSEEN". Each value is a number. + +== Net::IMAP::FetchData + +Net::IMAP::FetchData represents contents of the FETCH response. + +=== Super Class + +Object + +=== Methods + +: seqno + Returns the message sequence number. + (Note: not the unique identifier, even for the UID command response.) + +: attr + Returns a hash. Each key is a data item name, and each value is + its value. + + The current data items are: + + : BODY + A form of BODYSTRUCTURE without extension data. + : BODY[
]<> + A string expressing the body contents of the specified section. + : BODYSTRUCTURE + An object that describes the ((<[MIME-IMB]>)) body structure of a message. + See (()), (()), + (()), (()). + : ENVELOPE + A (()) object that describes the envelope + structure of a message. + : FLAGS + A array of flag symbols that are set for this message. flag symbols + are capitalized by String#capitalize. + : INTERNALDATE + A string representing the internal date of the message. + : RFC822 + Equivalent to BODY[]. + : RFC822.HEADER + Equivalent to BODY.PEEK[HEADER]. + : RFC822.SIZE + A number expressing the ((<[RFC-822]>)) size of the message. + : RFC822.TEXT + Equivalent to BODY[TEXT]. + : UID + A number expressing the unique identifier of the message. + +== Net::IMAP::Envelope + +Net::IMAP::Envelope represents envelope structures of messages. + +=== Super Class + +Struct + +=== Methods + +: date + Retunns a string that represents the date. + +: subject + Retunns a string that represents the subject. + +: from + Retunns an array of (()) that represents the from. + +: sender + Retunns an array of (()) that represents the sender. + +: reply_to + Retunns an array of (()) that represents the reply-to. + +: to + Retunns an array of (()) that represents the to. + +: cc + Retunns an array of (()) that represents the cc. + +: bcc + Retunns an array of (()) that represents the bcc. + +: in_reply_to + Retunns a string that represents the in-reply-to. + +: message_id + Retunns a string that represents the message-id. + +== Net::IMAP::Address + +(()) represents electronic mail addresses. + +=== Super Class + +Struct + +=== Methods + +: name + Returns the phrase from ((<[RFC-822]>)) mailbox. + +: route + Returns the route from ((<[RFC-822]>)) route-addr. + +: mailbox + nil indicates end of ((<[RFC-822]>)) group. + If non-nil and host is nil, returns ((<[RFC-822]>)) group name. + Otherwise, returns ((<[RFC-822]>)) local-part + +: host + nil indicates ((<[RFC-822]>)) group syntax. + Otherwise, returns ((<[RFC-822]>)) domain name. + +== Net::IMAP::ContentDisposition + +Net::IMAP::ContentDisposition represents Content-Disposition fields. + +=== Super Class + +Struct + +=== Methods + +: dsp_type + Returns the disposition type. + +: param + Returns a hash that represents parameters of the Content-Disposition + field. + +== Net::IMAP::BodyTypeBasic + +Net::IMAP::BodyTypeBasic represents basic body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: media_type + Returns the content media type name as defined in ((<[MIME-IMB]>)). + +: subtype + Returns the content subtype name as defined in ((<[MIME-IMB]>)). + +: param + Returns a hash that represents parameters as defined in + ((<[MIME-IMB]>)). + +: content_id + Returns a string giving the content id as defined in ((<[MIME-IMB]>)). + +: description + Returns a string giving the content description as defined in + ((<[MIME-IMB]>)). + +: encoding + Returns a string giving the content transfer encoding as defined in + ((<[MIME-IMB]>)). + +: size + Returns a number giving the size of the body in octets. + +: md5 + Returns a string giving the body MD5 value as defined in ((<[MD5]>)). + +: disposition + Returns a (()) object giving + the content disposition. + +: language + Returns a string or an array of strings giving the body + language value as defined in [LANGUAGE-TAGS]. + +: extension + Returns extension data. + +: multipart? + Returns false. + +== Net::IMAP::BodyTypeText + +Net::IMAP::BodyTypeText represents TEXT body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: lines + Returns the size of the body in text lines. + +And Net::IMAP::BodyTypeText has all methods of (()). + +== Net::IMAP::BodyTypeMessage + +Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: envelope + Returns a (()) giving the envelope structure. + +: body + Returns an object giving the body structure. + +And Net::IMAP::BodyTypeMessage has all methods of (()). + +== Net::IMAP::BodyTypeText + +=== Super Class + +Struct + +=== Methods + +: media_type + Returns the content media type name as defined in ((<[MIME-IMB]>)). + +: subtype + Returns the content subtype name as defined in ((<[MIME-IMB]>)). + +: parts + Returns multiple parts. + +: param + Returns a hash that represents parameters as defined in + ((<[MIME-IMB]>)). + +: disposition + Returns a (()) object giving + the content disposition. + +: language + Returns a string or an array of strings giving the body + language value as defined in [LANGUAGE-TAGS]. + +: extension + Returns extension data. + +: multipart? + Returns true. + +== References + +: [IMAP] + M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", + RFC 2060, December 1996. + +: [LANGUAGE-TAGS] + Alvestrand, H., "Tags for the Identification of + Languages", RFC 1766, March 1995. + +: [MD5] + Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC + 1864, October 1995. + +: [MIME-IMB] + Freed, N., and N. Borenstein, "MIME (Multipurpose Internet + Mail Extensions) Part One: Format of Internet Message Bodies", RFC + 2045, November 1996. + +: [RFC-822] + Crocker, D., "Standard for the Format of ARPA Internet Text + Messages", STD 11, RFC 822, University of Delaware, August 1982. + =end require "socket" @@ -702,7 +1145,7 @@ module Net Address = Struct.new(:name, :route, :mailbox, :host) ContentDisposition = Struct.new(:dsp_type, :param) - class BodyTypeBasic < Struct.new(:media_type, :media_subtype, + class BodyTypeBasic < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :md5, :disposition, :language, @@ -710,9 +1153,15 @@ module Net def multipart? return false end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end - class BodyTypeText < Struct.new(:media_type, :media_subtype, + class BodyTypeText < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :lines, @@ -721,9 +1170,15 @@ module Net def multipart? return false end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end - class BodyTypeMessage < Struct.new(:media_type, :media_subtype, + class BodyTypeMessage < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :envelope, :body, :lines, @@ -732,15 +1187,27 @@ module Net def multipart? return false end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end - class BodyTypeMultipart < Struct.new(:media_type, :media_subtype, + class BodyTypeMultipart < Struct.new(:media_type, :subtype, :parts, :param, :disposition, :language, :extension) def multipart? return true end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end class ResponseParser @@ -1475,6 +1942,12 @@ module Net when /\A(?:UIDVALIDITY|UIDNEXT|UNSEEN)\z/n match(T_SPACE) result = ResponseCode.new(name, number) + else + match(T_SPACE) + @lex_state = EXPR_CTEXT + token = match(T_TEXT) + @lex_state = EXPR_BEG + result = ResponseCode.new(name, token.value) end match(T_RBRA) @lex_state = EXPR_RTEXT @@ -1579,7 +2052,7 @@ module Net if @str.index(/\(([^)]*)\)/ni, @pos) @pos = $~.end(0) return $1.scan(FLAG_REGEXP).collect { |flag, atom| - atom || flag.intern + atom || flag.capitalize.intern } else parse_error("invalid flag list") diff --git a/lib/net/pop.rb b/lib/net/pop.rb index 4f6eb930a4..8f3f978e8c 100644 --- a/lib/net/pop.rb +++ b/lib/net/pop.rb @@ -1,6 +1,6 @@ =begin -= net/pop.rb version 1.1.32 += net/pop.rb version 1.1.34 written by Minero Aoki @@ -184,6 +184,7 @@ module Net protocol_param :port, '110' protocol_param :command_type, '::Net::NetPrivate::POP3Command' + protocol_param :apop_command_type, '::Net::NetPrivate::APOPCommand' protocol_param :mail_type, '::Net::POPMail' @@ -206,9 +207,10 @@ module Net end - def initialize( addr = nil, port = nil ) - super + def initialize( addr = nil, port = nil, apop = false ) + super addr, port @mails = nil + @apop = false end attr :mails @@ -238,6 +240,11 @@ module Net private + def conn_command( sock ) + @command = + (@apop ? type.apop_command_type : type.command_type).new(sock) + end + def do_start( acnt, pwd ) @command.auth( acnt, pwd ) diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb index 161024cfe2..343721add3 100644 --- a/lib/net/protocol.rb +++ b/lib/net/protocol.rb @@ -1,6 +1,6 @@ =begin -= net/protocol.rb version 1.1.32 += net/protocol.rb version 1.1.34 written by Minero Aoki @@ -59,13 +59,22 @@ Object =end require 'socket' +require 'timeout' module Net + module NetPrivate + end + + def self.net_private( &block ) + ::Net::NetPrivate.module_eval( &block ) + end + + class Protocol - Version = '1.1.32' + Version = '1.1.34' class << self @@ -116,8 +125,12 @@ module Net @command = nil @socket = nil - @active = false - @pipe = nil + @active = false + + @open_timeout = nil + @read_timeout = nil + + @dout = nil end attr_reader :address @@ -126,10 +139,26 @@ module Net attr_reader :command attr_reader :socket + attr_accessor :open_timeout + attr_accessor :read_timeout + + def active? + @active + end + + def set_debug_output( arg ) # un-documented + @dout = arg + end + + alias set_pipe set_debug_output + def inspect "#<#{type} #{address}:#{port} open=#{active?}>" end + # + # open session + # def start( *args ) return false if active? @@ -146,45 +175,59 @@ module Net end end + private + def _start( args ) connect do_start( *args ) @active = true end - private :_start - - def finish - return false unless active? - do_finish unless @command.critical? - disconnect - @active = false - true + def connect + conn_socket @address, @port + conn_command @socket + on_connect end - def active? - @active + def re_connect + @socket.reopen @open_timeout + on_connect end - def set_pipe( arg ) # un-documented - @pipe = arg + def conn_socket( addr, port ) + @socket = type.socket_type.open( + addr, port, @open_timeout, @read_timeout, @dout ) end + def conn_command( sock ) + @command = type.command_type.new( sock ) + end - private - + def on_connect + end def do_start end - def do_finish - @command.quit + # + # close session + # + + public + + def finish + return false unless active? + + do_finish if @command and not @command.critical? + disconnect + @active = false + true end + private - def connect( addr = @address, port = @port ) - @socket = type.socket_type.open( addr, port, @pipe ) - @command = type.command_type.new( @socket ) + def do_finish + @command.quit end def disconnect @@ -192,7 +235,11 @@ module Net if @socket and not @socket.closed? then @socket.close end - @socket = nil + @socket = nil + on_disconnect + end + + def on_disconnect end end @@ -200,6 +247,7 @@ module Net Session = Protocol + net_private { class Response @@ -223,6 +271,8 @@ module Net end + } + class ProtocolError < StandardError; end class ProtoSyntaxError < ProtocolError; end @@ -294,8 +344,7 @@ module Net - module NetPrivate - + net_private { class WriteAdapter @@ -311,7 +360,11 @@ module Net def write( str ) @sock.__send__ @mid, str end - alias << write + + def <<( str ) + @sock.__send__ @mid, str + self + end end @@ -407,6 +460,7 @@ module Net @critical = false end + private def critical @@ -431,22 +485,30 @@ module Net class Socket - def initialize( addr, port, pipe = nil ) + def initialize( addr, port, otime = nil, rtime = nil, dout = nil ) @addr = addr @port = port - @pipe = pipe - @prepipe = nil - @closed = true - @ipaddr = '' + @read_timeout = rtime + + @debugout = dout + + @socket = nil @sending = '' @buffer = '' - @socket = TCPsocket.new( addr, port ) - @closed = false - @ipaddr = @socket.addr[3] + connect otime + D 'opened' end + def connect( otime ) + D "opening connection to #{@addr}..." + timeout( otime ) { + @socket = TCPsocket.new( @addr, @port ) + } + end + private :connect + attr :pipe, true class << self @@ -454,27 +516,31 @@ module Net end def inspect - "#<#{type} open=#{!@closed}>" + "#<#{type} #{closed? ? 'closed' : 'opened'}>" end - def reopen - unless closed? then - close - @buffer = '' - end - @socket = TCPsocket.new( @addr, @port ) - @closed = false + def reopen( otime = nil ) + D 'reopening...' + close + connect otime + D 'reopened' end attr :socket, true def close - @socket.close - @closed = true + if @socket then + @socket.close + D 'closed' + else + D 'close call for already closed socket' + end + @socket = nil + @buffer = '' end def closed? - @closed + not @socket end def address @@ -486,7 +552,8 @@ module Net attr_reader :port def ip_address - @ipaddr.dup + @socket or return '' + @socket.addr[3] end alias ipaddr ip_address @@ -494,57 +561,64 @@ module Net attr_reader :sending - ### - ### read - ### + # + # read + # + + public CRLF = "\r\n" - def read( len, dest = '' ) - @pipe << "reading #{len} bytes...\n" if @pipe; pipeoff + def read( len, dest = '', ignerr = false ) + D_off "reading #{len} bytes..." rsize = 0 - while rsize + @buffer.size < len do - rsize += writeinto( dest, @buffer.size ) - fill_rbuf + begin + while rsize + @buffer.size < len do + rsize += rbuf_moveto( dest, @buffer.size ) + rbuf_fill + end + rbuf_moveto dest, len - rsize + rescue EOFError + raise unless igneof end - writeinto( dest, len - rsize ) - @pipe << "read #{len} bytes\n" if pipeon + D_on "read #{len} bytes" dest end - def read_all( dest = '' ) - @pipe << "reading all...\n" if @pipe; pipeoff + D_off 'reading all...' rsize = 0 begin while true do - rsize += writeinto( dest, @buffer.size ) - fill_rbuf + rsize += rbuf_moveto( dest, @buffer.size ) + rbuf_fill end rescue EOFError ; end - @pipe << "read #{rsize} bytes\n" if pipeon + D_on "read #{rsize} bytes" dest end - - def readuntil( target ) - while true do - idx = @buffer.index( target ) - break if idx - fill_rbuf - end - + def readuntil( target, igneof = false ) dest = '' - writeinto( dest, idx + target.size ) + begin + while true do + idx = @buffer.index( target ) + break if idx + rbuf_fill + end + rbuf_moveto dest, idx + target.size + rescue EOFError + raise unless igneof + rbuf_moveto dest, @buffer.size + end dest end - def readline ret = readuntil( "\n" ) @@ -552,9 +626,8 @@ module Net ret end - def read_pendstr( dest ) - @pipe << "reading text...\n" if @pipe; pipeoff + D_off 'reading text...' rsize = 0 while (str = readuntil("\r\n")) != ".\r\n" do @@ -563,14 +636,13 @@ module Net dest << str end - @pipe << "read #{rsize} bytes\n" if pipeon + D_on "read #{rsize} bytes" dest end - # private use only (can not handle 'break') def read_pendlist - @pipe << "reading list...\n" if @pipe; pipeoff + D_off 'reading list...' str = nil i = 0 @@ -580,55 +652,59 @@ module Net yield str end - @pipe << "read #{i} items\n" if pipeon + D_on "read #{i} items" end private - READ_BLOCK = 1024 * 8 + READ_SIZE = 1024 * 4 - def fill_rbuf - @buffer << @socket.sysread( READ_BLOCK ) + def rbuf_fill + unless IO.select [@socket], nil, nil, @read_timeout then + on_read_timeout + end + @buffer << @socket.sysread( READ_SIZE ) end - def writeinto( dest, len ) + def on_read_timeout + raise TimeoutError, "socket read timeout (#{@read_timeout} sec)" + end + + def rbuf_moveto( dest, len ) bsi = @buffer.size - dest << @buffer[ 0, len ] + s = @buffer[ 0, len ] + dest << s @buffer = @buffer[ len, bsi - len ] - @pipe << %{read "#{Net.quote dest}"\n} if @pipe + @debugout << % if @debugout len end - ### - ### write - ### + # + # write interfece + # public - def write( str ) writing { do_write str } end - def writeline( str ) writing { - do_write str - do_write "\r\n" + do_write str + "\r\n" } end - def write_bin( src, block ) writing { if block then - block.call WriteAdapter.new( self, :do_write ) + block.call ::Net::NetPrivate::WriteAdapter.new( self, :do_write ) else src.each do |bin| do_write bin @@ -637,19 +713,18 @@ module Net } end - def write_pendstr( src, block ) - @pipe << "writing text from #{src.type}\n" if @pipe; pipeoff + D_off "writing text from #{src.type}" wsize = use_each_crlf_line { if block then - block.call WriteAdapter.new( self, :wpend_in ) + block.call ::Net::NetPrivate::WriteAdapter.new( self, :wpend_in ) else wpend_in src end } - @pipe << "wrote #{wsize} bytes text\n" if pipeon + D_on "wrote #{wsize} bytes text" wsize end @@ -696,17 +771,17 @@ module Net beg = 0 buf = @wbuf while buf.index( /\n|\r\n|\r/, beg ) do - m = $~ + m = Regexp.last_match if m.begin(0) == buf.size - 1 and buf[-1] == ?\r then # "...\r" : can follow "\n..." break end - str = buf[ beg, m.begin(0) - beg ] + str = buf[ beg ... m.begin(0) ] str.concat "\r\n" yield str beg = m.end(0) end - @wbuf = buf[ beg, buf.size - beg ] + @wbuf = buf[ beg ... buf.size ] end end @@ -736,6 +811,7 @@ module Net yield end end + yield unless @wbuf.empty? end end @@ -746,17 +822,17 @@ module Net yield - if @pipe then - @pipe << 'write "' - @pipe << @sending - @pipe << "\"\n" + if @debugout then + @debugout << 'write "' + @debugout << @sending + @debugout << "\"\n" end @socket.flush @writtensize end def do_write( arg ) - if @pipe or @sending.size < 128 then + if @debugout or @sending.size < 128 then @sending << Net.quote( arg ) else @sending << '...' unless @sending[-1] == ?. @@ -768,22 +844,25 @@ module Net end - def pipeoff - @prepipe = @pipe - @pipe = nil - @prepipe + def D_off( msg ) + D msg + @savedo, @debugout = @debugout, nil end - def pipeon - @pipe = @prepipe - @prepipe = nil - @pipe + def D_on( msg ) + @debugout = @savedo + D msg end - end + def D( msg ) + @debugout or return + @debugout << msg + @debugout << "\n" + end + end - end # module Net::NetPrivate + } def Net.quote( str ) diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb index 9679984e2c..befc1adf03 100644 --- a/lib/net/smtp.rb +++ b/lib/net/smtp.rb @@ -1,6 +1,6 @@ =begin -= net/smtp.rb version 1.1.32 += net/smtp.rb version 1.1.34 written by Minero Aoki @@ -30,10 +30,8 @@ Net::Protocol === Methods -: start( helo_domain = Socket.gethostname, \ - account = nil, password = nil, authtype = nil ) -: start( helo_domain = Socket.gethostname, \ - account = nil, password = nil, authtype = nil ) {|smtp| .... } +: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) +: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... } opens TCP connection and starts SMTP session. If protocol had been started, do nothing and return false. @@ -53,10 +51,10 @@ Net::Protocol to_addrs must be a String(s) or an Array of String. Exceptions which SMTP raises are: - * Net::ProtoSyntaxError: syntax error (errno.500) - * Net::ProtoFatalError: fatal error (errno.550) - * Net::ProtoUnknownError: unknown error - * Net::ProtoServerBusy: temporary error (errno.420/450) + * Net::ProtoSyntaxError: syntax error (errno.500) + * Net::ProtoFatalError: fatal error (errno.550) + * Net::ProtoUnknownError: unknown error + * Net::ProtoServerBusy: temporary error (errno.420/450) # usage example @@ -153,12 +151,15 @@ module Net end end - if user and secret then + if user or secret then + (user and secret) or + raise ArgumentError, 'both of account and password are required' + mid = 'auth_' + (authtype || 'cram_md5').to_s - unless @command.respond_to? mid then - raise ArgumentError, "wrong auth type #{authtype.to_s}" - end - @command.send mid, user, secret + @command.respond_to? mid or + raise ArgumentError, "wrong auth type #{authtype.to_s}" + + @command.__send__ mid, user, secret end end diff --git a/lib/net/telnet.rb b/lib/net/telnet.rb index 87790c0300..380e834bea 100644 --- a/lib/net/telnet.rb +++ b/lib/net/telnet.rb @@ -4,7 +4,7 @@ net/telnet.rb - simple telnet client library -Version 1.6.2 +Version 1.6.3 Wakou Aoyama @@ -239,10 +239,11 @@ module Net CR = "\015" LF = "\012" EOL = CR + LF - VERSION = "1.6.2" - RELEASE_DATE = "2000-12-25" - VERSION_CODE = 162 - RELEASE_CODE = 20001225 + VERSION = '1.6.3' + RELEASE_DATE = '2001-02-26' + VERSION_CODE = 163 + RELEASE_CODE = 20010226 + REVISION = '$Id$' def initialize(options) @options = options @@ -346,14 +347,13 @@ module Net attr :sock def telnetmode(mode = nil) - if mode - if (true == mode or false == mode) - @options["Telnetmode"] = mode - else - raise ArgumentError, "required true or false" - end - else + case mode + when nil @options["Telnetmode"] + when true, false + @options["Telnetmode"] = mode + else + raise ArgumentError, "required true or false" end end @@ -366,14 +366,13 @@ module Net end def binmode(mode = nil) - if mode - if (true == mode or false == mode) - @options["Binmode"] = mode - else - raise ArgumentError, "required true or false" - end - else + case mode + when nil @options["Binmode"] + when true, false + @options["Binmode"] = mode + else + raise ArgumentError, "required true or false" end end @@ -599,181 +598,7 @@ end == HISTORY -* Mon Dec 25 01:37:43 JST 2000 - wakou - * version 1.6.2 - * Regexp::last_match[1] --> $1 - -* Mon Dec 11 00:16:51 JST 2000 - wakou - * version 1.6.1 - * $1 --> Regexp::last_match[1] - -* 2000/09/12 05:37:35 - matz - * change: iterator? --> block_given? - -* Tue Sep 12 06:52:48 JST 2000 - wakou - * version 1.6.0 - * correct: document. - thanks to Kazuhiro NISHIYAMA - * add: Telnet#puts(). - -* Sun Jun 18 23:31:44 JST 2000 - wakou - * version 1.5.0 - * change: version syntax. old: x.yz, now: x.y.z - -* 2000/05/24 06:57:38 - wakou - * version 1.40 - * improve: binmode(), telnetmode() interface. - thanks to Dave Thomas - -* 2000/05/09 22:02:56 - wakou - * version 1.32 - * require English.rb - -* 2000/05/02 21:48:39 - wakou - * version 1.31 - * Proxy option: can receive IO object. - -* 2000/04/03 18:27:02 - wakou - * version 1.30 - * telnet.rb --> net/telnet.rb - -* 2000/01/24 17:02:57 - wakou - * version 1.20 - * respond to "IAC WILL x" with "IAC DONT x" - * respond to "IAC WONT x" with "IAC DONT x" - * better dumplog format. - thanks to WATANABE Hirofumi - -* 2000/01/18 17:47:31 - wakou - * version 1.10 - * bug fix: write method - * respond to "IAC WILL BINARY" with "IAC DO BINARY" - -* 1999/10/04 22:51:26 - wakou - * version 1.00 - * bug fix: waitfor(preprocess) method. - thanks to Shin-ichiro Hara - * add simple support for AO, DM, IP, NOP, SB, SE - * COUTION! TimeOut --> TimeoutError - -* 1999/09/21 21:24:07 - wakou - * version 0.50 - * add write method - -* 1999/09/17 17:41:41 - wakou - * version 0.40 - * bug fix: preprocess method - -* 1999/09/14 23:09:05 - wakou - * version 0.30 - * change prompt check order. - not IO::select([@sock], nil, nil, waittime) and prompt === line - --> prompt === line and not IO::select([@sock], nil, nil, waittime) - -* 1999/09/13 22:28:33 - wakou - * version 0.24 - * Telnet#login: if ommit password, then not require password prompt. - -* 1999/08/10 05:20:21 - wakou - * version 0.232 - * STATUS OUTPUT sample code typo. - thanks to Tadayoshi Funaba - host = Telnet.new({"Hosh" => "localhost"){|c| print c } - --> host = Telnet.new({"Host" => "localhost"){|c| print c } - -* 1999/07/16 13:39:42 - wakou - * version 0.231 - * TRUE --> true, FALSE --> false - -* 1999/07/15 22:32:09 - wakou - * version 0.23 - * waitfor: if end of file reached, then return nil. - -* 1999/06/29 09:08:51 - wakou - * version 0.22 - * new, waitfor, cmd: {"Timeout" => false} # ignore timeout - -* 1999/06/28 18:18:55 - wakou - * version 0.21 - * waitfor: not rescue (EOFError) - -* 1999/06/04 06:24:58 - wakou - * version 0.20 - * waitfor: support for divided telnet command - -* 1999/05/22 - wakou - * version 0.181 - * bug fix: print method - -* 1999/05/14 - wakou - * version 0.18 - * respond to "IAC WON'T SGA" with "IAC DON'T SGA" - * DON'T SGA : end of line --> CR + LF - * bug fix: preprocess method - -* 1999/04/30 - wakou - * version 0.17 - * bug fix: $! + "\n" --> $!.to_s + "\n" - -* 1999/04/11 - wakou - * version 0.163 - * STDOUT.write(message) --> yield(message) if iterator? - -* 1999/03/17 - wakou - * version 0.162 - * add "Proxy" option - * required timeout.rb - -* 1999/02/03 - wakou - * version 0.161 - * select --> IO::select - -* 1998/10/09 - wakou - * version 0.16 - * preprocess method change for the better - * add binmode method. - * change default Binmode. TRUE --> FALSE - -* 1998/10/04 - wakou - * version 0.15 - * add telnetmode method. - -* 1998/09/22 - wakou - * version 0.141 - * change default prompt. /[$%#>] $/ --> /[$%#>] \Z/ - -* 1998/09/01 - wakou - * version 0.14 - * IAC WILL SGA send EOL --> CR+NULL - * IAC WILL SGA IAC DO BIN send EOL --> CR - * NONE send EOL --> LF - * add Dump_log option. - -* 1998/08/25 - wakou - * version 0.13 - * add print method. - -* 1998/08/05 - wakou - * version 0.122 - * support for HP-UX 10.20. - thanks to WATANABE Tetsuya - * socket.<< --> socket.write - -* 1998/07/15 - wakou - * version 0.121 - * string.+= --> string.concat - -* 1998/06/01 - wakou - * version 0.12 - * add timeout, waittime. - -* 1998/04/21 - wakou - * version 0.11 - * add realtime output. - -* 1998/04/13 - wakou - * version 0.10 - * first release. - -$Date$ +delete. see cvs log. + + =end diff --git a/lib/observer.rb b/lib/observer.rb index 08e75f5125..e1b249e885 100644 --- a/lib/observer.rb +++ b/lib/observer.rb @@ -5,7 +5,7 @@ module Observable def add_observer(observer) @observer_peers = [] unless defined? @observer_peers - unless defined? observer.update + unless observer.respond_to? :update raise NameError, "observer needs to respond to `update'" end @observer_peers.push observer diff --git a/lib/open3.rb b/lib/open3.rb index 58de740393..33701bbfc0 100644 --- a/lib/open3.rb +++ b/lib/open3.rb @@ -32,6 +32,7 @@ module Open3 exec(*cmd) } + exit! } pw[0].close diff --git a/lib/parsedate.rb b/lib/parsedate.rb index eee114acb2..7fc75cf0c2 100644 --- a/lib/parsedate.rb +++ b/lib/parsedate.rb @@ -1,5 +1,5 @@ -# parsedate.rb: Written by Tadayoshi Funaba 2000 -# $Id: parsedate.rb,v 1.2 2000-04-01 12:16:56+09 tadf Exp $ +# parsedate3.rb: Written by Tadayoshi Funaba 2000, 2001 +# $Id: parsedate3.rb,v 1.3 2001-01-18 12:09:47+09 tadf Exp $ module ParseDate @@ -46,7 +46,12 @@ module ParseDate hour = $1.to_i min = $2.to_i sec = $3.to_i if $3 - hour += 12 if $4 and $4.downcase == 'p' + if $4 + hour %= 12 + if $4.downcase == 'p' + hour += 12 + end + end zone = $5 end diff --git a/lib/ping.rb b/lib/ping.rb index 48657818cc..d698dd0c52 100644 --- a/lib/ping.rb +++ b/lib/ping.rb @@ -47,6 +47,8 @@ module Ping s = TCPsocket.new(host, service) s.close end + rescue Errno::ECONNREFUSED + return true rescue return false end diff --git a/lib/pstore.rb b/lib/pstore.rb index b3e1df8284..d5334efda4 100644 --- a/lib/pstore.rb +++ b/lib/pstore.rb @@ -41,11 +41,10 @@ class PStore def [](name) in_transaction - value = @table[name] - if value == nil + unless @table.key? name raise PStore::Error, format("undefined root name `%s'", name) end - value + @table[name] end def []=(name, value) in_transaction @@ -69,10 +68,12 @@ class PStore end def commit + in_transaction @abort = false throw :pstore_abort_transaction end def abort + in_transaction @abort = true throw :pstore_abort_transaction end diff --git a/lib/shell.rb b/lib/shell.rb new file mode 100644 index 0000000000..1d28834213 --- /dev/null +++ b/lib/shell.rb @@ -0,0 +1,274 @@ +# +# shell.rb - +# $Release Version: 0.6.0 $ +# $Revision: 1.8 $ +# $Date: 2001/03/19 09:01:11 $ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# + +require "e2mmap" +require "thread" + +require "shell/error" +require "shell/command-processor" +require "shell/process-controller" + +class Shell + @RCS_ID='-$Id: shell.rb,v 1.8 2001/03/19 09:01:11 keiju Exp keiju $-' + + include Error + extend Exception2MessageMapper + +# @cascade = true + # debug: true -> normal debug + # debug: 1 -> eval definition debug + # debug: 2 -> detail inspect debug + @debug = false + @verbose = true + + class << Shell + attr :cascade, true + attr :debug, true + attr :verbose, true + +# alias cascade? cascade + alias debug? debug + alias verbose? verbose + @verbose = true + + def debug=(val) + @debug = val + @verbose = val if val + end + + def cd(path) + sh = new + sh.cd path + sh + end + + def default_system_path + if @default_system_path + @default_system_path + else + ENV["PATH"].split(":") + end + end + + def default_system_path=(path) + @default_system_path = path + end + + def default_record_separator + if @default_record_separator + @default_record_separator + else + $/ + end + end + + def default_record_separator=(rs) + @default_record_separator = rs + end + end + + def initialize + @cwd = Dir.pwd + @dir_stack = [] + @umask = nil + + @system_path = Shell.default_system_path + @record_separator = Shell.default_record_separator + + @command_processor = CommandProcessor.new(self) + @process_controller = ProcessController.new(self) + + @verbose = Shell.verbose + @debug = Shell.debug + end + + attr_reader :system_path + + def system_path=(path) + @system_path = path + rehash + end + + attr :umask, true + attr :record_separator, true + + attr :verbose, true + attr :debug, true + + def debug=(val) + @debug = val + @verbose = val if val + end + + alias verbose? verbose + alias debug? debug + + attr_reader :command_processor + attr_reader :process_controller + + def expand_path(path) + if /^\// =~ path + File.expand_path(path) + else + File.expand_path(File.join(@cwd, path)) + end + end + + # Most Shell commands are defined via CommandProcessor + + # + # Dir related methods + # + # Shell#cwd/dir/getwd/pwd + # Shell#chdir/cd + # Shell#pushdir/pushd + # Shell#popdir/popd + # Shell#mkdir + # Shell#rmdir + + attr :cwd + alias dir cwd + alias getwd cwd + alias pwd cwd + + attr :dir_stack + alias dirs dir_stack + + # If called as iterator, it restores the current directory when the + # block ends. + def chdir(path = nil) + if iterator? + cwd_old = @cwd + begin + chdir(path) + yield + ensure + chdir(cwd_old) + end + else + path = "~" unless path + @cwd = expand_path(path) + notify "current dir: #{@cwd}" + rehash + self + end + end + alias cd chdir + + def pushdir(path = nil) + if iterator? + pushdir(path) + begin + yield + ensure + popdir + end + elsif path + @dir_stack.push @cwd + chdir path + notify "dir stack: [#{@dir_stack.join ', '}]" + self + else + if pop = @dir_stack.pop + @dir_stack.push @cwd + chdir pop + notify "dir stack: [#{@dir_stack.join ', '}]" + self + else + Shell.Fail DirStackEmpty + end + end + end + alias pushd pushdir + + def popdir + if pop = @dir_stack.pop + chdir pop + notify "dir stack: [#{@dir_stack.join ', '}]" + self + else + Shell.Fail DirStackEmpty + end + end + alias popd popdir + + + # + # process management + # + def jobs + @process_controller.jobs + end + + def kill(sig, command) + @process_controller.kill_job(sig, command) + end + + # + # command definitions + # + def Shell.def_system_command(command, path = command) + CommandProcessor.def_system_command(command, path) + end + + def Shell.undef_system_command(command) + CommandProcessor.undef_system_command(command) + end + + def Shell.alias_command(ali, command, *opts, &block) + CommandProcessor.alias_command(ali, command, *opts, &block) + end + + def Shell.unalias_command(ali) + CommandProcessor.unalias_command(ali) + end + + def Shell.install_system_commands(pre = "sys_") + CommandProcessor.install_system_commands(pre) + end + + # + def inspect + if debug.kind_of?(Integer) && debug > 2 + super + else + to_s + end + end + + def self.notify(*opts, &block) + Thread.exclusive do + if opts[-1].kind_of?(String) + yorn = verbose? + else + yorn = opts.pop + end + return unless yorn + + _head = true + print *opts.collect{|mes| + mes = mes.dup + yield mes if iterator? + if _head + _head = false + "shell: " + mes + else + " " + mes + end + }.join("\n")+"\n" + end + end + + CommandProcessor.initialize + CommandProcessor.run_config +end + diff --git a/lib/shell/builtin-command.rb b/lib/shell/builtin-command.rb new file mode 100644 index 0000000000..db1adfa48b --- /dev/null +++ b/lib/shell/builtin-command.rb @@ -0,0 +1,154 @@ +# +# shell/builtin-command.rb - +# $Release Version: 0.6.0 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +require "shell/filter" + +class Shell + class BuiltInCommand + # + def expand_path(path) + @shell.expand_path(path) + end + + # + # File related commands + # Shell#foreach + # Shell#open + # Shell#unlink + # Shell#test + # + # - + # + # CommandProcessor#foreach(path, rs) + # path: String + # rs: String - record separator + # iterator + # Same as: + # File#foreach (when path is file) + # Dir#foreach (when path is directory) + # path is relative to pwd + # + def foreach(path = nil, *rs) + path = "." unless path + path = expand_path(path) + + if File.directory?(path) + Dir.foreach(path){|fn| yield fn} + else + IO.foreach(path, *rs){|l| yield l} + end + end + + # + # CommandProcessor#open(path, mode) + # path: String + # mode: String + # return: File or Dir + # Same as: + # File#open (when path is file) + # Dir#open (when path is directory) + # mode has an effect only when path is a file + # + def open(path, mode) + path = expand_path(path) + if File.directory?(path) + Dir.open(path) + else + effect_umask do + File.open(path, mode) + end + end + end + # public :open + + # + # CommandProcessor#unlink(path) + # same as: + # Dir#unlink (when path is directory) + # File#unlink (when path is file) + # + def unlink(path) + path = expand_path(path) + if File.directory?(path) + Dir.unlink(path) + else + IO.unlink(path) + end + end + + # + # CommandProcessor#test(command, file1, file2) + # CommandProcessor#[command, file1, file2] + # command: char or String or Symbol + # file1: String + # file2: String(optional) + # return: Boolean + # same as: + # test() (when command is char or length 1 string or sumbol) + # FileTest.command (others) + # example: + # sh[?e, "foo"] + # sh[:e, "foo"] + # sh["e", "foo"] + # sh[:exists?, "foo"] + # sh["exists?", "foo"] + # + def test(command, file1, file2=nil) + file1 = expand_path(file1) + file2 = expand_path(file2) if file2 + command = command.id2name if command.kind_of?(Symbol) + + case command + when Integer + top_level_test(command, file1, file2) + when String + if command.size == 1 + if file2 + top_level_test(command, file1, file2) + else + top_level_test(command, file1) + end + else + if file2 + FileTest.send(command, file1, file2) + else + FileTest.send(command, file1) + end + end + end + end + alias [] test + + # + # Dir related methods + # + # Shell#mkdir + # Shell#rmdir + # + #-- + # + # CommandProcessor#mkdir(*path) + # path: String + # same as Dir.mkdir() + # + def mkdir(*path) + for dir in path + Dir.mkdir(expand_path(dir)) + end + end + + # + # CommandProcessor#rmdir(*path) + # path: String + # same as Dir.rmdir() + # + def rmdir(*path) + for dir in path + Dir.rmdir(expand_path(path)) + end + end + + # + # CommandProcessor#system(command, *opts) + # command: String + # opts: String + # retuen: SystemCommand + # Same as system() function + # example: + # print sh.system("ls", "-l") + # sh.system("ls", "-l") | sh.head > STDOUT + # + def system(command, *opts) + SystemCommand.new(@shell, find_system_command(command), *opts) + end + + # + # ProcessCommand#rehash + # clear command hash table. + # + def rehash + @system_commands = {} + end + + # + # ProcessCommand#transact + # + def check_point + @shell.process_controller.wait_all_jobs_execution + end + alias finish_all_jobs check_point + + def transact(&block) + begin + @shell.instance_eval &block + ensure + check_point + end + end + + # + # internal commands + # + def out(dev = STDOUT, &block) + dev.print transact &block + end + + def echo(*strings) + Echo.new(@shell, *strings) + end + + def cat(*filenames) + Cat.new(@shell, *filenames) + end + + # def sort(*filenames) + # Sort.new(self, *filenames) + # end + + def glob(pattern) + Glob.new(@shell, pattern) + end + + def append(to, filter) + case to + when String + AppendFile.new(@shell, to, filter) + when IO + AppendIO.new(@shell, to, filter) + else + Shell.Fail CanNotMethodApply, "append", to.type + end + end + + def tee(file) + Tee.new(@shell, file) + end + + def concat(*jobs) + Concat.new(@shell, *jobs) + end + + # %pwd, %cwd -> @pwd + def notify(*opts, &block) + Thread.exclusive do + Shell.notify(*opts) {|mes| + yield mes if iterator? + + mes.gsub!("%pwd", "#{@cwd}") + mes.gsub!("%cwd", "#{@cwd}") + } + end + end + + # + # private functions + # + def effect_umask + if @shell.umask + Thread.critical = true + save = File.umask + begin + yield + ensure + File.umask save + Thread.critical = false + end + else + yield + end + end + private :effect_umask + + def find_system_command(command) + return command if /^\// =~ command + case path = @system_commands[command] + when String + if exists?(path) + return path + else + Shell.Fail CommandNotFound, command + end + when false + Shell.Fail CommandNotFound, command + end + + for p in @shell.system_path + path = join(p, command) + if FileTest.exists?(path) + @system_commands[command] = path + return path + end + end + @system_commands[command] = false + Shell.Fail CommandNotFound, command + end + + # + # CommandProcessor.def_system_command(command, path) + # command: String + # path: String + # define 'command()' method as method. + # + def self.def_system_command(command, path = command) + begin + eval ((d = %Q[def #{command}(*opts) + SystemCommand.new(@shell, '#{path}', *opts) + end]), nil, __FILE__, __LINE__ - 1) + rescue SyntaxError + Shell.notify "warn: Can't define #{command} path: #{path}." + end + Shell.notify "Define #{command} path: #{path}.", Shell.debug? + Shell.notify("Definition of #{command}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + end + + def self.undef_system_command(command) + command = command.id2name if command.kind_of?(Symbol) + remove_method(command) + Shell.module_eval{remove_method(command)} + Filter.module_eval{remove_method(command)} + self + end + + # define command alias + # ex) + # def_alias_command("ls_c", "ls", "-C", "-F") + # def_alias_command("ls_c", "ls"){|*opts| ["-C", "-F", *opts]} + # + @alias_map = {} + def self.alias_map + @alias_map + end + def self.alias_command(ali, command, *opts, &block) + ali = ali.id2name if ali.kind_of?(Symbol) + command = command.id2name if command.kind_of?(Symbol) + begin + if iterator? + @alias_map[ali.intern] = proc + + eval ((d = %Q[def #{ali}(*opts) + @shell.__send__(:#{command}, + *(CommandProcessor.alias_map[:#{ali}].call *opts)) + end]), nil, __FILE__, __LINE__ - 1) + + else + args = opts.collect{|opt| '"' + opt + '"'}.join "," + eval ((d = %Q[def #{ali}(*opts) + @shell.__send__(:#{command}, #{args}, *opts) + end]), nil, __FILE__, __LINE__ - 1) + end + rescue SyntaxError + Shell.notify "warn: Can't alias #{ali} command: #{command}." + Shell.notify("Definition of #{ali}: ", d) + raise + end + Shell.notify "Define #{ali} command: #{command}.", Shell.debug? + Shell.notify("Definition of #{ali}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + self + end + + def self.unalias_command(ali) + ali = ali.id2name if ali.kind_of?(Symbol) + @alias_map.delete ali.intern + undef_system_command(ali) + end + + # + # CommandProcessor.def_builtin_commands(delegation_class, command_specs) + # delegation_class: Class or Module + # command_specs: [[command_name, [argument,...]],...] + # command_name: String + # arguments: String + # FILENAME?? -> expand_path(filename??) + # *FILENAME?? -> filename??.collect{|f|expand_path(f)}.join(", ") + # define command_name(argument,...) as + # delegation_class.command_name(argument,...) + # + def self.def_builtin_commands(delegation_class, command_specs) + for meth, args in command_specs + arg_str = args.collect{|arg| arg.downcase}.join(", ") + call_arg_str = args.collect{ + |arg| + case arg + when /^(FILENAME.*)$/ + format("expand_path(%s)", $1.downcase) + when /^(\*FILENAME.*)$/ + # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ") + $1.downcase + '.collect{|fn| expand_path(fn)}' + else + arg + end + }.join(", ") + d = %Q[def #{meth}(#{arg_str}) + #{delegation_class}.#{meth}(#{call_arg_str}) + end] + Shell.notify "Define #{meth}(#{arg_str})", Shell.debug? + Shell.notify("Definition of #{meth}: ", d, + Shell.debug.kind_of?(Integer) && Shell.debug > 1) + eval d + end + end + + # + # CommandProcessor.install_system_commands(pre) + # pre: String - command name prefix + # defines every command which belongs in default_system_path via + # CommandProcessor.command(). It doesn't define already defined + # methods twice. By default, "pre_" is prefixes to each method + # name. Characters that may not be used in a method name are + # all converted to '_'. Definition errors are just ignored. + # + def self.install_system_commands(pre = "sys_") + defined_meth = {} + for m in Shell.methods + defined_meth[m] = true + end + sh = Shell.new + for path in Shell.default_system_path + next unless sh.directory? path + sh.cd path + sh.foreach do + |cn| + if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn) + command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1') + begin + def_system_command(command, sh.expand_path(cn)) + rescue + Shell.notify "warn: Can't define #{command} path: #{cn}" + end + defined_meth[command] = command + end + end + end + end + + #---------------------------------------------------------------------- + # + # class initializing methods - + # + #---------------------------------------------------------------------- + def self.add_delegate_command_to_shell(id) + id = id.intern if id.kind_of?(String) + name = id.id2name + if Shell.method_defined?(id) + Shell.notify "warn: override definnition of Shell##{name}." + Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n" + Shell.module_eval "alias #{name}_org #{name}" + end + Shell.notify "method added: Shell##{name}.", Shell.debug? + Shell.module_eval(%Q[def #{name}(*args, &block) + begin + @command_processor.__send__(:#{name}, *args, &block) + rescue Exception + $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` + $@.delete_if{|s| /^\\(eval\\):/ =~ s} + raise + end + end], __FILE__, __LINE__) + + if Shell::Filter.method_defined?(id) + Shell.notify "warn: override definnition of Shell::Filter##{name}." + Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org." + Filter.module_eval "alias #{name}_org #{name}" + end + Shell.notify "method added: Shell::Filter##{name}.", Shell.debug? + Filter.module_eval(%Q[def #{name}(*args, &block) + begin + self | @shell.__send__(:#{name}, *args, &block) + rescue Exception + $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #` + $@.delete_if{|s| /^\\(eval\\):/ =~ s} + raise + end + end], __FILE__, __LINE__) + end + + # + # define default builtin commands + # + def self.install_builtin_commands + # method related File. + # (exclude open/foreach/unlink) + normal_delegation_file_methods = [ + ["atime", ["FILENAME"]], + ["basename", ["fn", "*opts"]], + ["chmod", ["mode", "*FILENAMES"]], + ["chown", ["owner", "group", "*FILENAME"]], + ["ctime", ["FILENAMES"]], + ["delete", ["*FILENAMES"]], + ["dirname", ["FILENAME"]], + ["ftype", ["FILENAME"]], + ["join", ["*items"]], + ["link", ["FILENAME_O", "FILENAME_N"]], + ["lstat", ["FILENAME"]], + ["mtime", ["FILENAME"]], + ["readlink", ["FILENAME"]], + ["rename", ["FILENAME_FROM", "FILENAME_TO"]], + # ["size", ["FILENAME"]], + ["split", ["pathname"]], + ["stat", ["FILENAME"]], + ["symlink", ["FILENAME_O", "FILENAME_N"]], + ["truncate", ["FILENAME", "length"]], + ["utime", ["atime", "mtime", "*FILENAMES"]]] + + def_builtin_commands(File, normal_delegation_file_methods) + alias_method :rm, :delete + + # method related FileTest + def_builtin_commands(FileTest, + FileTest.singleton_methods.collect{|m| [m, ["FILENAME"]]}) + + # method related ftools + normal_delegation_ftools_methods = [ + ["syscopy", ["FILENAME_FROM", "FILENAME_TO"]], + ["copy", ["FILENAME_FROM", "FILENAME_TO"]], + ["move", ["FILENAME_FROM", "FILENAME_TO"]], + ["compare", ["FILENAME_FROM", "FILENAME_TO"]], + ["safe_unlink", ["*FILENAMES"]], + ["makedirs", ["*FILENAMES"]], + # ["chmod", ["mode", "*FILENAMES"]], + ["install", ["FILENAME_FROM", "FILENAME_TO", "mode"]], + ] + def_builtin_commands(File, + normal_delegation_ftools_methods) + alias_method :cmp, :compare + alias_method :mv, :move + alias_method :cp, :copy + alias_method :rm_f, :safe_unlink + alias_method :mkpath, :makedirs + end + + end +end diff --git a/lib/shell/error.rb b/lib/shell/error.rb new file mode 100644 index 0000000000..df5e669af6 --- /dev/null +++ b/lib/shell/error.rb @@ -0,0 +1,26 @@ +# +# shell/error.rb - +# $Release Version: 0.6.0 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +require "e2mmap" + +class Shell + module Error + extend Exception2MessageMapper + def_e2message TypeError, "wrong argument type %s (expected %s)" + + def_exception :DirStackEmpty, "Directory stack empty." + def_exception :CanNotDefine, "Can't define method(%s, %s)." + def_exception :CanNotMethodApply, "This method(%s) can't apply this type(%s)." + def_exception :CommandNotFound, "Command not found(%s)." + end +end + diff --git a/lib/shell/filter.rb b/lib/shell/filter.rb new file mode 100644 index 0000000000..441cded221 --- /dev/null +++ b/lib/shell/filter.rb @@ -0,0 +1,111 @@ +# +# shell/filter.rb - +# $Release Version: 0.6.0 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +class Shell + # + # Filter + # A method to require + # each() + # + class Filter + include Enumerable + include Error + + def initialize(sh) + @shell = sh # parent shell + @input = nil # input filter + end + + attr_reader :input + + def input=(filter) + @input = filter + end + + def each(rs = nil) + rs = @shell.record_separator unless rs + if @input + @input.each(rs){|l| yield l} + end + end + + def < (src) + case src + when String + cat = Cat.new(@shell, src) + cat | self + when IO + self.input = src + self + else + Filter.Fail CanNotMethodApply, "<", to.type + end + end + + def > (to) + case to + when String + dst = @shell.open(to, "w") + begin + each(){|l| dst << l} + ensure + dst.close + end + when IO + each(){|l| to << l} + else + Filter.Fail CanNotMethodApply, ">", to.type + end + self + end + + def >> (to) + begin + Shell.cd(@shell.pwd).append(to, self) + rescue CanNotMethodApply + Shell.Fail CanNotMethodApply, ">>", to.type + end + end + + def | (filter) + filter.input = self + if active? + @shell.process_controller.start_job filter + end + filter + end + + def + (filter) + Join.new(@shell, self, filter) + end + + def to_a + ary = [] + each(){|l| ary.push l} + ary + end + + def to_s + str = "" + each(){|l| str.concat l} + str + end + + def inspect + if @shell.debug.kind_of?(Integer) && @shell.debug > 2 + super + else + to_s + end + end + end +end diff --git a/lib/shell/process-controller.rb b/lib/shell/process-controller.rb new file mode 100644 index 0000000000..26fb1d9f08 --- /dev/null +++ b/lib/shell/process-controller.rb @@ -0,0 +1,258 @@ +# +# shell/process-controller.rb - +# $Release Version: 0.6.0 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +require "mutex_m" +require "monitor" +require "sync" + +class Shell + class ProcessController + + @ProcessControllers = {} + @ProcessControllers.extend Mutex_m + + class<= @max + if max <= @max @max = max Thread.critical = false else - diff = max - @max + diff = @max - max @max = max Thread.critical = false diff.times do @@ -253,6 +257,7 @@ class SizedQueuesign = (r_byte(arg) == '+'); len = r_long(arg); +#if SIZEOF_BDIGITS == SIZEOF_SHORT + big->len = len; +#else big->len = (len + 1) * sizeof(short) / sizeof(BDIGIT); +#endif big->digits = digits = ALLOC_N(BDIGIT, big->len); while (len > 0) { #if SIZEOF_BDIGITS > SIZEOF_SHORT @@ -1055,7 +1059,7 @@ marshal_load(argc, argv) \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); } - if (minor != MARSHAL_MINOR) { + if (ruby_verbose && minor != MARSHAL_MINOR) { rb_warn("incompatible marshal file format (can be read)\n\ \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); diff --git a/math.c b/math.c index ac87b9c8dc..2cac83e938 100644 --- a/math.c +++ b/math.c @@ -64,6 +64,11 @@ math_exp(obj, x) return rb_float_new(exp(RFLOAT(x)->value)); } +#if defined __CYGWIN__ +#define log(x) ((x) < 0.0 ? nan() : log(x)) +#define log10(x) ((x) < 0.0 ? nan() : log10(x)) +#endif + static VALUE math_log(obj, x) VALUE obj, x; diff --git a/misc/ruby-mode.el b/misc/ruby-mode.el index c0754efad4..7dd4708176 100644 --- a/misc/ruby-mode.el +++ b/misc/ruby-mode.el @@ -749,7 +749,7 @@ An end of a defun is found by moving forward from the beginning of one." '("^\\s *def\\s +\\([^( ]+\\)" 1 font-lock-function-name-face) ;; symbols - '("\\(^\\|[^:]\\)\\(:\\(\\w\\|_\\)+\\??\\)\\b" + '("\\(^\\|[^:]\\)\\(:\\([-+/%&|^~`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|\\[\\]\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b\\)\\)\\)" 2 font-lock-reference-face)) "*Additional expressions to highlight in ruby mode.")) diff --git a/missing/alloca.c b/missing/alloca.c index 6879618c8a..5746497371 100644 --- a/missing/alloca.c +++ b/missing/alloca.c @@ -2,7 +2,6 @@ last edit: 86/05/30 rms include config.h, since on VMS it renames some symbols. - Use xmalloc instead of malloc. This implementation of the PWB library alloca() function, which is used to allocate space off the run-time stack so @@ -53,7 +52,7 @@ typedef char *pointer; /* generic pointer type */ #define NULL 0 /* null pointer constant */ extern void free(); -extern pointer xmalloc(); +extern pointer malloc(); /* Define STACK_DIRECTION if you know the direction of stack @@ -173,7 +172,7 @@ alloca (size) /* returns pointer to storage */ /* Allocate combined header + user data storage. */ { - register pointer new = xmalloc (sizeof (header) + size); + register pointer new = malloc (sizeof (header) + size); /* address of header */ ((header *)new)->h.next = last_alloca_header; diff --git a/missing/dir.h b/missing/dir.h deleted file mode 100644 index 830239b3ea..0000000000 --- a/missing/dir.h +++ /dev/null @@ -1,65 +0,0 @@ -/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $ - * - * (C) Copyright 1987, 1990 Diomidis Spinellis. - * - * You may distribute under the terms of either the GNU General Public - * License or the Artistic License, as specified in the README file. - * - * $Log: dir.h,v $ - * Revision 4.0.1.1 91/06/07 11:22:10 lwall - * patch4: new copyright notice - * - * Revision 4.0 91/03/20 01:34:20 lwall - * 4.0 baseline. - * - * Revision 3.0.1.1 90/03/27 16:07:08 lwall - * patch16: MSDOS support - * - * Revision 1.1 90/03/18 20:32:29 dds - * Initial revision - * - * - */ - -/* - * defines the type returned by the directory(3) functions - */ - -#ifndef __DIR_INCLUDED -#define __DIR_INCLUDED - -#if !defined __MINGW32__ -/*Directory entry size */ -#ifdef DIRSIZ -#undef DIRSIZ -#endif -#define DIRSIZ(rp) (sizeof(struct direct)) - -/* - * Structure of a directory entry - */ -struct direct { - ino_t d_ino; /* inode number (not used by MS-DOS) */ - int d_namlen; /* Name length */ - char d_name[256]; /* file name */ -}; - -struct _dir_struc { /* Structure used by dir operations */ - char *start; /* Starting position */ - char *curr; /* Current position */ - long size; /* Size of string table */ - long nfiles; /* number if filenames in table */ - struct direct dirstr; /* Directory structure to return */ -}; - -typedef struct _dir_struc DIR; /* Type returned by dir operations */ - -DIR *cdecl opendir(char *filename); -struct direct *readdir(DIR *dirp); -long telldir(DIR *dirp); -void seekdir(DIR *dirp,long loc); -void rewinddir(DIR *dirp); -void closedir(DIR *dirp); - -#endif -#endif /* __DIR_INCLUDED */ diff --git a/missing/flock.c b/missing/flock.c index 78576d438c..c828fcc7ad 100644 --- a/missing/flock.c +++ b/missing/flock.c @@ -1,6 +1,55 @@ #include "config.h" -#if defined(HAVE_LOCKF) +#if defined HAVE_FCNTL && defined HAVE_FCNTL_H + +/* These are the flock() constants. Since this sytems doesn't have + flock(), the values of the constants are probably not available. +*/ +# ifndef LOCK_SH +# define LOCK_SH 1 +# endif +# ifndef LOCK_EX +# define LOCK_EX 2 +# endif +# ifndef LOCK_NB +# define LOCK_NB 4 +# endif +# ifndef LOCK_UN +# define LOCK_UN 8 +# endif + +#include +#include +#include + +int +flock(fd, operation) + int fd; + int operation; +{ + struct flock lock; + + switch (operation & ~LOCK_NB) { + case LOCK_SH: + lock.l_type = F_RDLCK; + break; + case LOCK_EX: + lock.l_type = F_WRLCK; + break; + case LOCK_UN: + lock.l_type = F_UNLCK; + break; + default: + errno = EINVAL; + return -1; + } + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + + return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); +} + +#elif defined(HAVE_LOCKF) #include #include @@ -45,86 +94,33 @@ flock(fd, operation) int fd; int operation; { - int i; switch (operation) { /* LOCK_SH - get a shared lock */ case LOCK_SH: + rb_notimplement(); + return -1; /* LOCK_EX - get an exclusive lock */ case LOCK_EX: - i = lockf (fd, F_LOCK, 0); - break; + return lockf (fd, F_LOCK, 0); /* LOCK_SH|LOCK_NB - get a non-blocking shared lock */ case LOCK_SH|LOCK_NB: + rb_notimplement(); + return -1; /* LOCK_EX|LOCK_NB - get a non-blocking exclusive lock */ case LOCK_EX|LOCK_NB: - i = lockf (fd, F_TLOCK, 0); - if (i == -1) - if ((errno == EAGAIN) || (errno == EACCES)) - errno = EWOULDBLOCK; - break; + return lockf (fd, F_TLOCK, 0); /* LOCK_UN - unlock */ case LOCK_UN: - i = lockf (fd, F_ULOCK, 0); - break; + return lockf (fd, F_ULOCK, 0); /* Default - can't decipher operation */ default: - i = -1; errno = EINVAL; - break; + return -1; } - return i; -} -#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H - -/* These are the flock() constants. Since this sytems doesn't have - flock(), the values of the constants are probably not available. -*/ -# ifndef LOCK_SH -# define LOCK_SH 1 -# endif -# ifndef LOCK_EX -# define LOCK_EX 2 -# endif -# ifndef LOCK_NB -# define LOCK_NB 4 -# endif -# ifndef LOCK_UN -# define LOCK_UN 8 -# endif - -#include -#include -#include - -int -flock(fd, operation) - int fd; - int operation; -{ - struct flock lock; - - switch (operation & ~LOCK_NB) { - case LOCK_SH: - lock.l_type = F_RDLCK; - break; - case LOCK_EX: - lock.l_type = F_WRLCK; - break; - case LOCK_UN: - lock.l_type = F_UNLCK; - break; - default: - errno = EINVAL; - return -1; - } - lock.l_whence = SEEK_SET; - lock.l_start = lock.l_len = 0L; - - return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); } #elif !defined NT int diff --git a/missing/hypot.c b/missing/hypot.c new file mode 100644 index 0000000000..aad5259e92 --- /dev/null +++ b/missing/hypot.c @@ -0,0 +1,17 @@ +/* public domain rewrite of hypot */ + +#include + +double hypot(x,y) + double x, y; +{ + if (x < 0) x = -x; + if (y < 0) y = -y; + if (x < y) { + double tmp = x; + x = y; y = tmp; + } + if (y == 0.0) return x; + y /= x; + return x * sqrt(1.0+y*y); +} diff --git a/missing/strftime.c b/missing/strftime.c index 6bce490249..3042649aeb 100644 --- a/missing/strftime.c +++ b/missing/strftime.c @@ -113,12 +113,6 @@ extern char *getenv(); extern char *strchr(); #endif -#ifdef __GNUC__ -#define inline __inline__ -#else -#define inline /**/ -#endif - #define range(low, item, hi) max(low, min(item, hi)) #if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) diff --git a/missing/vsnprintf.c b/missing/vsnprintf.c index d297209d06..489bf58361 100644 --- a/missing/vsnprintf.c +++ b/missing/vsnprintf.c @@ -108,9 +108,7 @@ #define __const #endif /* People who don't like const sys_error */ -#if defined NT && !defined __MINGW32__ -typedef long size_t; -#endif +#include #ifndef NULL #define NULL 0 @@ -1095,8 +1093,6 @@ vsnprintf(str, n, fmt, ap) static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ -#include - #if defined(__STDC__) # include #else diff --git a/mkconfig.rb b/mkconfig.rb index 175a4c3b15..57c4384983 100644 --- a/mkconfig.rb +++ b/mkconfig.rb @@ -6,7 +6,7 @@ rbconfig_rb = ARGV[0] || 'rbconfig.rb' srcdir = $srcdir if $srcdir File.makedirs(File.dirname(rbconfig_rb), true) -version = VERSION +version = RUBY_VERSION config = open(rbconfig_rb, "w") $stdout.reopen(config) @@ -14,8 +14,8 @@ fast = {'prefix'=>TRUE, 'ruby_install_name'=>TRUE, 'INSTALL'=>TRUE, 'EXEEXT'=>TR print %[ module Config - VERSION == "#{version}" or - raise "ruby lib version (#{version}) doesn't match executable version (\#{VERSION})" + RUBY_VERSION == "#{version}" or + raise "ruby lib version (#{version}) doesn't match executable version (\#{RUBY_VERSION})" # This file was created by configrb when ruby was built. Any changes # made to this file will be lost the next time ruby is built. @@ -28,11 +28,11 @@ has_srcdir = false has_version = false File.foreach "config.status" do |$_| next if /^#/ - if /^s%@program_transform_name@%s,(.*)%g$/ + if /^s[%,]@program_transform_name@[%,]s,(.*)[%,]/ next if $install_name ptn = $1.sub(/\$\$/, '$').split(/,/) #' v_fast << " CONFIG[\"ruby_install_name\"] = \"" + "ruby".sub(ptn[0],ptn[1]) + "\"\n" - elsif /^s%@(\w+)@%(.*)%g/ + elsif /^s[%,]@(\w+)@[%,](.*)[%,]/ name = $1 val = $2 || "" next if name =~ /^(INSTALL|DEFS|configure_input|srcdir|top_srcdir)$/ @@ -40,7 +40,7 @@ File.foreach "config.status" do |$_| next if $so_name and name =~ /^RUBY_SO_NAME$/ v = " CONFIG[\"" + name + "\"] = " + val.sub(/^\s*(.*)\s*$/, '"\1"').gsub(/\$\{?(\w+)\}?/) { - "\#{CONFIG[\\\"#{$1}\\\"]}" + "$(#{$1})" } + "\n" if fast[name] v_fast << v @@ -48,20 +48,7 @@ File.foreach "config.status" do |$_| v_others << v end has_version = true if name == "MAJOR" - if /DEFS/ - val.split(/\s*-D/).each do |i| - if i =~ /(.*)=(\\")?([^\\]*)(\\")?/ - key, val = $1, $3 - if val == '1' - val = "TRUE" - else - val.sub! /^\s*(.*)\s*$/, '"\1"' - end - print " CONFIG[\"#{key}\"] = #{val}\n" - end - end - end - elsif /^ac_given_srcdir=(.*)/ + elsif /^(?:ac_given_)?srcdir=(.*)/ v_fast << " CONFIG[\"srcdir\"] = \"" + File.expand_path($1) + "\"\n" has_srcdir = true elsif /^ac_given_INSTALL=(.*)/ @@ -71,11 +58,11 @@ File.foreach "config.status" do |$_| end if not has_srcdir - v_fast << " CONFIG[\"srcdir\"] = \"" + File.expand_path(srcdir) + "\"\n" + v_fast << " CONFIG[\"srcdir\"] = \"" + File.expand_path(srcdir || '.') + "\"\n" end if not has_version - VERSION.scan(/(\d+)\.(\d+)\.(\d+)/) { + RUBY_VERSION.scan(/(\d+)\.(\d+)\.(\d+)/) { print " CONFIG[\"MAJOR\"] = \"" + $1 + "\"\n" print " CONFIG[\"MINOR\"] = \"" + $2 + "\"\n" print " CONFIG[\"TEENY\"] = \"" + $3 + "\"\n" @@ -102,6 +89,11 @@ end print v_fast, v_others print <cbase)) -#define NEW_CREF() (cur_cref=rb_node_newnode(NODE_CREF,0,0,cur_cref)) -#define NEW_CBODY(b) (cur_cref->nd_body=NEW_SCOPE(b),cur_cref) +#define NEW_CREF(c) (rb_node_newnode(NODE_CREF,0,0,c)) #define NEW_DOT2(b,e) rb_node_newnode(NODE_DOT2,b,e,0) #define NEW_DOT3(b,e) rb_node_newnode(NODE_DOT3,b,e,0) #define NEW_ATTRSET(a) rb_node_newnode(NODE_ATTRSET,a,0,0) diff --git a/numeric.c b/numeric.c index 0dd86f0532..40e607b222 100644 --- a/numeric.c +++ b/numeric.c @@ -332,7 +332,7 @@ flodivmod(x, y, divp, modp) double z; modf(x/y, &z); - mod = x - z * x; + mod = x - z * y; } #endif div = (x - mod) / y; @@ -1295,12 +1295,14 @@ static VALUE fix_aref(fix, idx) VALUE fix, idx; { - unsigned long val = FIX2LONG(fix); + long val = FIX2LONG(fix); int i = NUM2INT(idx); - if (i < 0 || sizeof(VALUE)*CHAR_BIT-1 < i) + if (i < 0 || sizeof(VALUE)*CHAR_BIT-1 < i) { + if (val < 0) return INT2FIX(1); return INT2FIX(0); - if (val & (1<ptr[0] == '-') { /* first element */ RSTRING(str)->ptr[0] = '#'; + rb_str_cat2(str, " "); } else { rb_str_cat2(str, ", "); @@ -182,6 +183,7 @@ inspect_obj(obj, str) { st_foreach(ROBJECT(obj)->iv_tbl, inspect_i, str); rb_str_cat2(str, ">"); + RSTRING(str)->ptr[0] = '#'; OBJ_INFECT(str, obj); return str; @@ -227,12 +229,10 @@ rb_obj_is_instance_of(obj, c) return Qfalse; case T_FALSE: - if (obj) return Qfalse; - return Qtrue; + return RTEST(obj) ? Qfalse : Qtrue; case T_TRUE: - if (obj) return Qtrue; - return Qfalse; + return RTEST(obj) ? Qtrue : Qfalse; default: rb_raise(rb_eTypeError, "class or module required"); @@ -286,7 +286,12 @@ rb_obj_taint(obj) VALUE obj; { rb_secure(4); - OBJ_TAINT(obj); + if (!OBJ_TAINTED(obj)) { + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + OBJ_TAINT(obj); + } return obj; } @@ -295,7 +300,12 @@ rb_obj_untaint(obj) VALUE obj; { rb_secure(3); - FL_UNSET(obj, FL_TAINT); + if (OBJ_TAINTED(obj)) { + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + FL_UNSET(obj, FL_TAINT); + } return obj; } @@ -513,33 +523,6 @@ sym_to_s(sym) return rb_str_new2(rb_id2name(SYM2ID(sym))); } -static VALUE -rb_mod_clone(module) - VALUE module; -{ - NEWOBJ(clone, struct RClass); - CLONESETUP(clone, module); - - clone->super = RCLASS(module)->super; - if (RCLASS(module)->iv_tbl) { - clone->iv_tbl = st_copy(RCLASS(module)->iv_tbl); - } - if (RCLASS(module)->m_tbl) { - clone->m_tbl = st_copy(RCLASS(module)->m_tbl); - } - - return (VALUE)clone; -} - -static VALUE -rb_mod_dup(module) - VALUE module; -{ - VALUE dup = rb_mod_clone(module); - OBJSETUP(dup, RBASIC(module)->klass, BUILTIN_TYPE(module)); - return dup; -} - static VALUE rb_mod_to_s(klass) VALUE klass; @@ -776,14 +759,24 @@ static VALUE rb_mod_const_get(mod, name) VALUE mod, name; { - return rb_const_get(mod, rb_to_id(name)); + ID id = rb_to_id(name); + + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "wrong constant name %s", name); + } + return rb_const_get(mod, id); } static VALUE rb_mod_const_set(mod, name, value) VALUE mod, name, value; { - rb_const_set(mod, rb_to_id(name), value); + ID id = rb_to_id(name); + + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "wrong constant name %s", name); + } + rb_const_set(mod, id, value); return value; } @@ -791,7 +784,12 @@ static VALUE rb_mod_const_defined(mod, name) VALUE mod, name; { - return rb_const_defined_at(mod, rb_to_id(name)); + ID id = rb_to_id(name); + + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "wrong constant name %s", name); + } + return rb_const_defined_at(mod, id); } static VALUE @@ -1036,6 +1034,9 @@ rb_str2cstr(str, len) str = rb_str_to_str(str); } if (len) *len = RSTRING(str)->len; + else if (ruby_verbose && RSTRING(str)->len != strlen(RSTRING(str)->ptr)) { + rb_warn("string contains \\0 character"); + } return RSTRING(str)->ptr; } diff --git a/pack.c b/pack.c index 5538600449..9e05f46c5a 100644 --- a/pack.c +++ b/pack.c @@ -826,7 +826,7 @@ pack_pack(ary, fmt) case 'm': ptr = rb_str2cstr(NEXTFROM, &plen); - if (len <= 1) + if (len <= 2) len = 45; else len = len / 3 * 3; @@ -1026,11 +1026,7 @@ qpencode(str, from, len) } } -#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(RUBY_NO_INLINE) -static __inline__ int -#else -static int -#endif +static inline int hex2num(c) char c; { diff --git a/parse.y b/parse.y index d1f1a32321..f92da9a8ff 100644 --- a/parse.y +++ b/parse.y @@ -6,7 +6,7 @@ $Date$ created at: Fri May 28 18:02:42 JST 1993 - Copyright (C) 1993-2000 Yukihiro Matsumoto + Copyright (C) 1993-2001 Yukihiro Matsumoto **********************************************************************/ @@ -49,7 +49,6 @@ static int yyerror(); static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_END, /* newline significant, +/- is a operator. */ - EXPR_PAREN, /* almost like EXPR_END, `do' works as `{'. */ EXPR_ARG, /* newline significant, +/- is a operator. */ EXPR_MID, /* newline significant, +/- is a operator. */ EXPR_FNAME, /* ignore newline, no reserved words. */ @@ -57,8 +56,16 @@ static enum lex_state { EXPR_CLASS, /* immediate after `class', no here document. */ } lex_state; +#if SIZEOF_LONG_LONG > 0 +typedef unsigned long long stack_type; +#elif SIZEOF___INT64 > 0 +typedef unsigned __int64 stack_type; +#else +typedef unsigned long stack_type; +#endif + static int cond_nest = 0; -static unsigned long cond_stack = 0; +static stack_type cond_stack = 0; #define COND_PUSH do {\ cond_nest++;\ cond_stack = (cond_stack<<1)|1;\ @@ -67,10 +74,20 @@ static unsigned long cond_stack = 0; cond_nest--;\ cond_stack >>= 1;\ } while (0) -#define IN_COND (cond_nest > 0 && (cond_stack&1)) +#define COND_P() (cond_nest > 0 && (cond_stack&1)) + +static stack_type cmdarg_stack = 0; +#define CMDARG_PUSH do {\ + cmdarg_stack = (cmdarg_stack<<1)|1;\ +} while(0) +#define CMDARG_POP do {\ + cmdarg_stack >>= 1;\ +} while (0) +#define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1)) static int class_nest = 0; static int in_single = 0; +static int in_def = 0; static int compile_for_eval = 0; static ID cur_mid = 0; @@ -115,10 +132,6 @@ static struct RVarmap *dyna_push(); static void dyna_pop(); static int dyna_in_block(); -#define cref_push() NEW_CREF() -static void cref_pop(); -static NODE *cur_cref; - static void top_local_init(); static void top_local_setup(); %} @@ -155,7 +168,8 @@ static void top_local_setup(); kRETRY kIN kDO - kDO2 + kDO_COND + kDO_BLOCK kRETURN kYIELD kSUPER @@ -184,11 +198,11 @@ static void top_local_setup(); %type singleton string %type literal numeric -%type compstmt stmts stmt expr arg primary command_call method_call +%type compstmt stmts stmt expr arg primary command command_call method_call %type if_tail opt_else case_body cases rescue exc_list exc_var ensure -%type opt_call_args call_args ret_args args when_args -%type aref_args opt_block_arg block_arg stmt_rhs -%type mrhs mrhs_basic superclass generic_call block_call var_ref +%type args ret_args when_args call_args paren_args opt_paren_args +%type command_args aref_args opt_block_arg block_arg var_ref +%type mrhs mrhs_basic superclass block_call block_command %type f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg %type assoc_list assocs assoc undef_list backref %type block_var opt_block_var brace_block do_block lhs none @@ -251,7 +265,6 @@ program : { $$ = ruby_dyna_vars; lex_state = EXPR_BEG; top_local_init(); - NEW_CREF0(); /* initialize constant c-ref */ if ((VALUE)ruby_class == rb_cObject) class_nest = 0; else class_nest = 1; } @@ -270,7 +283,6 @@ program : { } ruby_eval_tree = block_append(ruby_eval_tree, $2); top_local_setup(); - cur_cref = 0; class_nest = 0; ruby_dyna_vars = $1; } @@ -295,16 +307,15 @@ stmts : none $$ = $2; } -stmt : block_call - | kALIAS fitem {lex_state = EXPR_FNAME;} fitem +stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("alias within method"); $$ = NEW_ALIAS($2, $4); } | kALIAS tGVAR tGVAR { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("alias within method"); $$ = NEW_VALIAS($2, $3); } @@ -312,7 +323,7 @@ stmt : block_call { char buf[3]; - if (cur_mid || in_single) + if (in_def || in_single) yyerror("alias within method"); sprintf(buf, "$%c", $3->nd_nth); $$ = NEW_VALIAS($2, rb_intern(buf)); @@ -324,7 +335,7 @@ stmt : block_call } | kUNDEF undef_list { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("undef within method"); $$ = $2; } @@ -343,31 +354,21 @@ stmt : block_call | stmt kWHILE_MOD expr { value_expr($3); - if ($1) { - if (nd_type($1) == NODE_BEGIN) { - $$ = NEW_WHILE(cond($3), $1->nd_body, 0); - } - else { - $$ = NEW_WHILE(cond($3), $1, 1); - } + if ($1 && nd_type($1) == NODE_BEGIN) { + $$ = NEW_WHILE(cond($3), $1->nd_body, 0); } else { - $$ = 0; + $$ = NEW_WHILE(cond($3), $1, 1); } } | stmt kUNTIL_MOD expr { value_expr($3); - if ($1) { - if (nd_type($1) == NODE_BEGIN) { - $$ = NEW_UNTIL(cond($3), $1->nd_body, 0); - } - else { - $$ = NEW_UNTIL(cond($3), $1, 1); - } + if ($1 && nd_type($1) == NODE_BEGIN) { + $$ = NEW_UNTIL(cond($3), $1->nd_body, 0); } else { - $$ = 0; + $$ = NEW_UNTIL(cond($3), $1, 1); } } | stmt kRESCUE_MOD stmt @@ -376,7 +377,7 @@ stmt : block_call } | klBEGIN { - if (cur_mid || in_single) { + if (in_def || in_single) { yyerror("BEGIN in method"); } local_push(); @@ -390,18 +391,18 @@ stmt : block_call } | klEND '{' compstmt '}' { - if (compile_for_eval && (cur_mid || in_single)) { + if (compile_for_eval && (in_def || in_single)) { yyerror("END in method; use at_exit"); } $$ = NEW_ITER(0, NEW_POSTEXE(), $3); } - | lhs '=' stmt_rhs + | lhs '=' command_call { value_expr($3); $$ = node_assign($1, $3); } - | mlhs '=' stmt_rhs + | mlhs '=' command_call { value_expr($3); $1->nd_value = $3; @@ -421,7 +422,7 @@ expr : mlhs '=' mrhs } | kRETURN ret_args { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); $$ = NEW_RETURN($2); } @@ -445,26 +446,41 @@ expr : mlhs '=' mrhs } | arg -command_call : operation call_args +command_call : command + | block_command + +block_command : block_call + | block_call '.' operation2 command_args + { + value_expr($1); + $$ = new_call($1, $3, $4); + } + | block_call tCOLON2 operation2 command_args + { + value_expr($1); + $$ = new_call($1, $3, $4); + } + +command : operation command_args { $$ = new_fcall($1, $2); fixpos($$, $2); } - | primary '.' operation2 call_args + | primary '.' operation2 command_args { value_expr($1); $$ = new_call($1, $3, $4); fixpos($$, $1); } - | primary tCOLON2 operation2 call_args + | primary tCOLON2 operation2 command_args { value_expr($1); $$ = new_call($1, $3, $4); fixpos($$, $1); } - | kSUPER call_args + | kSUPER command_args { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("super called outside of method"); $$ = new_super($2); fixpos($$, $2); @@ -475,7 +491,6 @@ command_call : operation call_args fixpos($$, $2); } - mlhs : mlhs_basic | tLPAREN mlhs_entry ')' { @@ -657,6 +672,9 @@ arg : lhs '=' arg if ($2 == tOROP) { $3->nd_value = $4; $$ = NEW_OP_ASGN_OR(gettable($1), $3); + if (is_instance_id($1)) { + $$->nd_aid = $1; + } } else if ($2 == tANDOP) { $3->nd_value = $4; @@ -897,14 +915,6 @@ aref_args : none { $$ = list_append($1, $3); } - | block_call opt_nl - { - $$ = NEW_LIST($1); - } - | args ',' block_call opt_nl - { - $$ = list_append($1, $3); - } | args trailer { $$ = $1; @@ -924,22 +934,31 @@ aref_args : none $$ = NEW_RESTARGS($2); } -opt_call_args : none - | call_args opt_nl - | block_call opt_nl +paren_args : '(' none ')' { - $$ = NEW_LIST($1); + $$ = $2; } - | args ',' block_call + | '(' call_args opt_nl ')' { - $$ = list_append($1, $3); + $$ = $2; + } + | '(' block_call opt_nl ')' + { + $$ = NEW_LIST($2); } + | '(' args ',' block_call opt_nl ')' + { + $$ = list_append($2, $4); + } + +opt_paren_args : none + | paren_args -call_args : command_call +call_args : command { $$ = NEW_LIST($1); } - | args ',' command_call + | args ',' command { $$ = list_append($1, $3); } @@ -953,10 +972,6 @@ call_args : command_call $$ = arg_concat($1, $4); $$ = arg_blk_pass($$, $5); } - | assocs ',' - { - $$ = NEW_LIST(NEW_HASH($1)); - } | assocs opt_block_arg { $$ = NEW_LIST(NEW_HASH($1)); @@ -973,10 +988,6 @@ call_args : command_call $$ = list_append($1, NEW_HASH($3)); $$ = arg_blk_pass($$, $4); } - | args ',' assocs ',' - { - $$ = list_append($1, NEW_HASH($3)); - } | args ',' assocs ',' tSTAR arg opt_block_arg { value_expr($6); @@ -990,6 +1001,12 @@ call_args : command_call } | block_arg +command_args : {CMDARG_PUSH;} call_args + { + CMDARG_POP; + $$ = $2; + } + block_arg : tAMPER arg { value_expr($2); @@ -1119,20 +1136,20 @@ primary : literal } | kRETURN '(' ret_args ')' { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); value_expr($3); $$ = NEW_RETURN($3); } | kRETURN '(' ')' { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); $$ = NEW_RETURN(0); } | kRETURN { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); $$ = NEW_RETURN(0); } @@ -1225,11 +1242,9 @@ primary : literal } | kCLASS cname superclass { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("class definition in method body"); - class_nest++; - cref_push(); local_push(); $$ = ruby_sourceline; } @@ -1239,30 +1254,35 @@ primary : literal $$ = NEW_CLASS($2, $5, $3); nd_set_line($$, $4); local_pop(); - cref_pop(); class_nest--; } - | kCLASS tLSHFT expr term + | kCLASS tLSHFT expr + { + $$ = in_def; + in_def = 0; + } + term { + $$ = in_single; + in_single = 0; class_nest++; - cref_push(); local_push(); } compstmt kEND { - $$ = NEW_SCLASS($3, $6); + $$ = NEW_SCLASS($3, $7); fixpos($$, $3); local_pop(); - cref_pop(); class_nest--; + in_def = $4; + in_single = $6; } | kMODULE cname { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("module definition in method body"); class_nest++; - cref_push(); local_push(); $$ = ruby_sourceline; } @@ -1272,14 +1292,15 @@ primary : literal $$ = NEW_MODULE($2, $4); nd_set_line($$, $3); local_pop(); - cref_pop(); class_nest--; } | kDEF fname { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("nested method definition"); + $$ = cur_mid; cur_mid = $2; + in_def++; local_push(); } f_arglist @@ -1301,7 +1322,8 @@ primary : literal if (is_attrset_id($2)) $$->nd_noex = NOEX_PUBLIC; fixpos($$, $4); local_pop(); - cur_mid = 0; + in_def--; + cur_mid = $3; } | kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname { @@ -1312,8 +1334,18 @@ primary : literal } f_arglist compstmt + rescue + opt_else + ensure kEND { + if ($9) $8 = NEW_RESCUE($8, $9, $10); + else if ($10) { + rb_warn("else without rescue is useless"); + $8 = block_append($8, $10); + } + if ($11) $8 = NEW_ENSURE($8, $11); + $$ = NEW_DEFS($2, $5, $7, $8); fixpos($$, $2); local_pop(); @@ -1341,7 +1373,7 @@ then : term | term kTHEN do : term - | kDO + | kDO_COND if_tail : opt_else | kELSIF expr then @@ -1377,7 +1409,7 @@ opt_block_var : none } -do_block : kDO +do_block : kDO_BLOCK { $$ = dyna_push(); } @@ -1390,47 +1422,7 @@ do_block : kDO dyna_pop($2); } -brace_block : '{' - { - $$ = dyna_push(); - } - opt_block_var - compstmt '}' - { - $$ = NEW_ITER($3, 0, $4); - fixpos($$, $4); - dyna_pop($2); - } - | kDO2 - { - $$ = dyna_push(); - } - opt_block_var - compstmt - kEND - { - $$ = NEW_ITER($3, 0, $4); - fixpos($$, $4); - dyna_pop($2); - } - - -generic_call : tIDENTIFIER - { - $$ = NEW_VCALL($1); - } - | tCONSTANT - { - $$ = NEW_VCALL($1); - } - | tFID - { - $$ = NEW_VCALL($1); - } - | method_call - | command_call - -block_call : generic_call do_block +block_call : command do_block { if ($1 && nd_type($1) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); @@ -1439,28 +1431,32 @@ block_call : generic_call do_block $$ = $2; fixpos($$, $2); } - -method_call : operation '(' opt_call_args close_paren + | block_call '.' operation2 opt_paren_args { - $$ = new_fcall($1, $3); - fixpos($$, $3); + value_expr($1); + $$ = new_call($1, $3, $4); } - | primary '.' operation2 '(' opt_call_args close_paren + | block_call tCOLON2 operation2 opt_paren_args { value_expr($1); - $$ = new_call($1, $3, $5); - fixpos($$, $1); + $$ = new_call($1, $3, $4); } - | primary '.' operation2 + +method_call : operation paren_args + { + $$ = new_fcall($1, $2); + fixpos($$, $2); + } + | primary '.' operation2 opt_paren_args { value_expr($1); - $$ = new_call($1, $3, 0); + $$ = new_call($1, $3, $4); fixpos($$, $1); } - | primary tCOLON2 operation2 '(' opt_call_args close_paren + | primary tCOLON2 operation2 paren_args { value_expr($1); - $$ = new_call($1, $3, $5); + $$ = new_call($1, $3, $4); fixpos($$, $1); } | primary tCOLON2 operation3 @@ -1468,28 +1464,43 @@ method_call : operation '(' opt_call_args close_paren value_expr($1); $$ = new_call($1, $3, 0); } - | kSUPER '(' opt_call_args close_paren + | kSUPER paren_args { - if (!compile_for_eval && !cur_mid && + if (!compile_for_eval && !in_def && !in_single && !in_defined) yyerror("super called outside of method"); - $$ = new_super($3); + $$ = new_super($2); } | kSUPER { - if (!compile_for_eval && !cur_mid && + if (!compile_for_eval && !in_def && !in_single && !in_defined) yyerror("super called outside of method"); $$ = NEW_ZSUPER(); } -close_paren : ')' +brace_block : '{' + { + $$ = dyna_push(); + } + opt_block_var + compstmt '}' { - if (!IN_COND) lex_state = EXPR_PAREN; + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $4); + dyna_pop($2); + } + | kDO + { + $$ = dyna_push(); + } + opt_block_var + compstmt kEND + { + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $4); + dyna_pop($2); } - -stmt_rhs : block_call - | command_call case_body : kWHEN when_args then compstmt @@ -1965,8 +1976,10 @@ yycompile(f, line) ruby_in_compile = 0; cond_nest = 0; cond_stack = 0; + cmdarg_stack = 0; class_nest = 0; in_single = 0; + in_def = 0; cur_mid = 0; if (n == 0) node = ruby_eval_tree; @@ -2043,10 +2056,7 @@ rb_compile_file(f, file, start) return yycompile(strdup(f), start); } -#if defined(__GNUC__) && __GNUC__ >= 2 -__inline__ -#endif -static int +static inline int nextc() { int c; @@ -2542,13 +2552,12 @@ parse_qstring(term, paren) c = '\\'; break; - case '\'': - if (term == '\'') { - c = '\''; - break; - } - /* fall through */ default: + /* fall through */ + if (c == term || (paren && c == paren)) { + tokadd(c); + continue; + } tokadd('\\'); } } @@ -2603,7 +2612,7 @@ parse_quotedwords(term, paren) c = '\\'; break; default: - if (c == term) { + if (c == term || (paren && c == paren)) { tokadd(c); continue; } @@ -2794,7 +2803,7 @@ arg_ambiguous() rb_warning("ambiguous first argument; make sure"); } -#ifndef strtod +#if !defined(strtod) && !defined(HAVE_STDLIB_H) double strtod (); #endif @@ -2919,8 +2928,7 @@ yylex() case '<': c = nextc(); if (c == '<' && - lex_state != EXPR_END && lex_state != EXPR_PAREN && - lex_state != EXPR_CLASS && + lex_state != EXPR_END && lex_state != EXPR_CLASS && (lex_state != EXPR_ARG || space_seen)) { int c2 = nextc(); int indent = 0; @@ -2979,7 +2987,7 @@ yylex() return parse_qstring(c,0); case '?': - if (lex_state == EXPR_END || lex_state == EXPR_PAREN) { + if (lex_state == EXPR_END) { lex_state = EXPR_BEG; return '?'; } @@ -3306,7 +3314,7 @@ yylex() return tCOLON2; } pushback(c); - if (lex_state == EXPR_END || lex_state == EXPR_PAREN || ISSPACE(c)) { + if (lex_state == EXPR_END || ISSPACE(c)) { lex_state = EXPR_BEG; return ':'; } @@ -3390,9 +3398,7 @@ yylex() return c; case '{': - if (lex_state != EXPR_END && - lex_state != EXPR_PAREN && - lex_state != EXPR_ARG) + if (lex_state != EXPR_END && lex_state != EXPR_ARG) c = tLBRACE; lex_state = EXPR_BEG; return c; @@ -3616,12 +3622,18 @@ yylex() if (state == EXPR_FNAME) { yylval.id = rb_intern(kw->name); } - if (kw->id[0] == kDO && - (state == EXPR_PAREN || - (!IN_COND && state == EXPR_ARG))) { - return kDO2; + if (kw->id[0] == kDO) { + if (COND_P()) return kDO_COND; + if (CMDARG_P()) return kDO_BLOCK; + return kDO; + } + if (state == EXPR_BEG) + return kw->id[0]; + else { + if (kw->id[0] != kw->id[1]) + lex_state = EXPR_BEG; + return kw->id[1]; } - return kw->id[state != EXPR_BEG]; } } @@ -4121,7 +4133,7 @@ assignable(id, val) return NEW_IASGN(id, val); } else if (is_const_id(id)) { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("dynamic constant assignment"); return NEW_CDECL(id, val); } @@ -4375,6 +4387,9 @@ void_expr(node) } } + +static NODE *cond2 _((NODE*)); + static void void_stmts(node) NODE *node; @@ -4390,8 +4405,6 @@ void_stmts(node) } } -static NODE *cond2(); - static int assign_in_cond(node) NODE *node; @@ -4733,12 +4746,6 @@ dyna_in_block() return (lvtbl->dlev > 0); } -static void -cref_pop() -{ - cur_cref = cur_cref->nd_next; -} - void rb_parser_append_print() { @@ -4822,7 +4829,6 @@ Init_sym() { sym_tbl = st_init_strtable_with_size(200); sym_rev_tbl = st_init_numtable_with_size(200); - rb_global_variable((VALUE*)&cur_cref); rb_global_variable((VALUE*)&lex_lastline); } diff --git a/prec.c b/prec.c index 8dcd121bc0..fab5ea3899 100644 --- a/prec.c +++ b/prec.c @@ -43,7 +43,7 @@ prec_prec_f(x) static VALUE prec_induced_from(module, x) - + VALUE module, x; { rb_raise(rb_eTypeError, "undefined conversion from %s into %s", rb_class2name(CLASS_OF(x)), rb_class2name(module)); diff --git a/process.c b/process.c index 3537841d43..90153977b8 100644 --- a/process.c +++ b/process.c @@ -234,7 +234,9 @@ proc_waitpid2(argc, argv) return rb_assoc_new(pid, rb_last_status); } +#ifndef HAVE_STRING_H char *strtok(); +#endif #ifdef HAVE_SETITIMER #define before_exec() rb_thread_stop_timer() diff --git a/re.c b/re.c index bb9898fdb4..0cf81ef607 100644 --- a/re.c +++ b/re.c @@ -288,11 +288,11 @@ rb_reg_desc(s, len, re) rb_str_cat2(str, "/"); if (re) { rb_reg_check(re); - if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) - rb_str_cat2(str, "m"); /* /p is obsolete; to be removed */ if ((RREGEXP(re)->ptr->options & RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) rb_str_cat2(str, "p"); + else if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) + rb_str_cat2(str, "m"); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) rb_str_cat2(str, "i"); if (RREGEXP(re)->ptr->options & RE_OPTION_EXTENDED) @@ -915,8 +915,7 @@ rb_reg_equal(re1, re2) if (min > RREGEXP(re2)->len) min = RREGEXP(re2)->len; if (memcmp(RREGEXP(re1)->str, RREGEXP(re2)->str, min) == 0 && rb_reg_cur_kcode(re1) == rb_reg_cur_kcode(re2) && - !((RREGEXP(re1)->ptr->options & RE_OPTION_IGNORECASE) ^ - (RREGEXP(re2)->ptr->options & RE_OPTION_IGNORECASE))) { + RREGEXP(re1)->ptr->options == RREGEXP(re2)->ptr->options) { return Qtrue; } return Qfalse; @@ -1015,6 +1014,7 @@ rb_reg_initialize_m(argc, argv, self) p = rb_str2cstr(src, &len); rb_reg_initialize(self, p, len, flag); } + return self; } static VALUE @@ -1123,6 +1123,12 @@ rb_reg_options(re) rb_reg_check(re); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) options |= RE_OPTION_IGNORECASE; + if ((RREGEXP(re)->ptr->options & RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) + options |= RE_OPTION_POSIXLINE; + else if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) + options |= RE_OPTION_MULTILINE; + if (RREGEXP(re)->ptr->options & RE_OPTION_EXTENDED) + options |= RE_OPTION_EXTENDED; if (FL_TEST(re, KCODE_FIXED)) { options |= rb_reg_get_kcode(re); } diff --git a/regex.c b/regex.c index d4c1c2a915..a3d8e2c243 100644 --- a/regex.c +++ b/regex.c @@ -370,6 +370,7 @@ enum regexpcode duplicate, /* Match a duplicate of something remembered. Followed by one byte containing the index of the memory register. */ + fail, /* always fails. */ wordchar, /* Matches any word-constituent character. */ notwordchar, /* Matches any char that is not a word-constituent. */ wordbeg, /* Succeeds if at word beginning. */ @@ -1049,7 +1050,7 @@ calculate_must_string(start, end) EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; if ((enum regexpcode)p[-3] == jump) { - p -= 3; + p -= 2; EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; } @@ -1438,6 +1439,9 @@ re_compile_pattern(pattern, size, bufp) EXTEND_BUFFER; } range_retry: + if (range && had_char_class) { + FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as an end value of range"); + } PATFETCH(c); if (c == ']') { @@ -1459,6 +1463,7 @@ re_compile_pattern(pattern, size, bufp) PATFETCH_MBC(c); had_mbchar++; } + had_char_class = 0; /* \ escapes characters when inside [...]. */ if (c == '\\') { @@ -1473,6 +1478,7 @@ re_compile_pattern(pattern, size, bufp) if (current_mbctype) { set_list_bits(0x80, 0xffffffff, b); } + had_char_class = 1; last = -1; continue; @@ -1483,6 +1489,7 @@ re_compile_pattern(pattern, size, bufp) !current_mbctype && SYNTAX(c) != Sword2)) SET_LIST_BIT(c); } + had_char_class = 1; last = -1; continue; @@ -1490,6 +1497,7 @@ re_compile_pattern(pattern, size, bufp) for (c = 0; c < 256; c++) if (ISSPACE(c)) SET_LIST_BIT(c); + had_char_class = 1; last = -1; continue; @@ -1499,12 +1507,14 @@ re_compile_pattern(pattern, size, bufp) SET_LIST_BIT(c); if (current_mbctype) set_list_bits(0x80, 0xffffffff, b); + had_char_class = 1; last = -1; continue; case 'd': for (c = '0'; c <= '9'; c++) SET_LIST_BIT(c); + had_char_class = 1; last = -1; continue; @@ -1514,6 +1524,7 @@ re_compile_pattern(pattern, size, bufp) SET_LIST_BIT(c); if (current_mbctype) set_list_bits(0x80, 0xffffffff, b); + had_char_class = 1; last = -1; continue; @@ -2236,32 +2247,23 @@ re_compile_pattern(pattern, size, bufp) case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - { - const char *p_save; - PATUNFETCH; - p_save = p; + p0 = p; had_mbchar = 0; c1 = 0; GET_UNSIGNED_NUMBER(c1); if (!ISDIGIT(c)) PATUNFETCH; - if (c1 >= regnum) { + if (9 < c1 && c1 >= regnum) { /* need to get octal */ - p = p_save; - c = scan_oct(p_save, 3, &numlen) & 0xff; - p = p_save + numlen; + c = scan_oct(p0, 3, &numlen) & 0xff; + p = p0 + numlen; c1 = 0; had_num_literal = 1; goto numeric_char; } - } - /* Can't back reference to a subexpression if inside of it. */ - for (stackt = stackp - 2; stackt > stackb; stackt -= 5) - if (*stackt == c1) - goto normal_char; laststart = b; BUFPUSH(duplicate); BUFPUSH(c1); @@ -3353,7 +3355,7 @@ re_search(bufp, string, size, startpos, range, regs) #define NUM_COUNT_ITEMS 2 /* Individual items aside from the registers. */ -#define NUM_NONREG_ITEMS 3 +#define NUM_NONREG_ITEMS 4 /* We push at most this many things on the stack whenever we fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are @@ -3403,6 +3405,7 @@ re_search(bufp, string, size, startpos, range, regs) \ *stackp++ = pattern_place; \ *stackp++ = string_place; \ + *stackp++ = (unsigned char*)options; /* current option status */ \ *stackp++ = (unsigned char*)0; /* non-greedy flag */ \ } while(0) @@ -3461,7 +3464,8 @@ re_search(bufp, string, size, startpos, range, regs) #define PREV_IS_A_LETTER(d) ((current_mbctype == MBCTYPE_SJIS)? \ IS_A_LETTER((d)-(!AT_STRINGS_BEG((d)-1)&& \ ismbchar((d)[-2])?2:1)): \ - ((d)[-1] >= 0x80 || IS_A_LETTER((d)-1))) + ((current_mbctype && ((d)[-1] >= 0x80)) || \ + IS_A_LETTER((d)-1))) static void init_regs(regs, num_regs) @@ -3725,11 +3729,12 @@ re_match(bufp, string_arg, size, pos, regs) int regno = *p++; /* Get which register to match against */ register unsigned char *d2, *dend2; - if (IS_ACTIVE(reg_info[regno])) break; + /* Check if corresponding group is still open */ + if (IS_ACTIVE(reg_info[regno])) goto fail; /* Where in input to try to start matching. */ d2 = regstart[regno]; - if (REG_UNSET(d2)) break; + if (REG_UNSET(d2)) goto fail; /* Where to stop matching; if both the place to start and the place to stop matching are in the same string, then @@ -3737,7 +3742,7 @@ re_match(bufp, string_arg, size, pos, regs) the end of the first string. */ dend2 = regend[regno]; - if (REG_UNSET(dend2)) break; + if (REG_UNSET(dend2)) goto fail; for (;;) { /* At end of register contents => success */ if (d2 == dend2) break; @@ -3776,7 +3781,7 @@ re_match(bufp, string_arg, size, pos, regs) case stop_nowidth: EXTRACT_NUMBER_AND_INCR(mcnt, p); stackp = stackb + mcnt; - d = stackp[-2]; + d = stackp[-3]; POP_FAILURE_POINT(); continue; @@ -4000,8 +4005,8 @@ re_match(bufp, string_arg, size, pos, regs) because didn't fail. Also remove the register information put on by the on_failure_jump. */ case finalize_jump: - if (stackp > stackb && stackp[-2] == d) { - p = stackp[-3]; + if (stackp > stackb && stackp[-3] == d) { + p = stackp[-4]; POP_FAILURE_POINT(); continue; } @@ -4017,7 +4022,7 @@ re_match(bufp, string_arg, size, pos, regs) case jump: nofinalize: EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt < 0 && stackp > stackb && stackp[-2] == d) /* avoid infinite loop */ + if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */ goto fail; p += mcnt; continue; @@ -4108,7 +4113,7 @@ re_match(bufp, string_arg, size, pos, regs) case finalize_push: POP_FAILURE_POINT(); EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt < 0 && stackp > stackb && stackp[-2] == d) /* avoid infinite loop */ + if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */ goto fail; PUSH_FAILURE_POINT(p + mcnt, d); stackp[-1] = NON_GREEDY; @@ -4273,11 +4278,12 @@ re_match(bufp, string_arg, size, pos, regs) /* If this failure point is from a dummy_failure_point, just skip it. */ - if (stackp[-3] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) { + if (stackp[-4] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) { POP_FAILURE_POINT(); goto fail; } - stackp--; /* discard flag */ + stackp--; /* discard greedy flag */ + options = (int)*--stackp; d = *--stackp; p = *--stackp; /* Restore register info. */ diff --git a/ruby.c b/ruby.c index 9649b69af4..eac3d8701c 100644 --- a/ruby.c +++ b/ruby.c @@ -12,7 +12,7 @@ **********************************************************************/ -#ifdef _WIN32 +#if defined _WIN32 || defined __CYGWIN__ #include #endif #include "ruby.h" @@ -106,7 +106,7 @@ extern VALUE rb_load_path; #define STATIC_FILE_LENGTH 255 -#if defined(_WIN32) || defined(DJGPP) +#if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__ static char * rubylib_mangle(s, l) char *s; @@ -172,7 +172,7 @@ ruby_incpush(path) const char sep = PATH_SEP_CHAR; if (path == 0) return; -#if defined(__CYGWIN32__) +#if defined(__CYGWIN__) { char rubylib[FILENAME_MAX]; conv_to_posix_path(path, rubylib, FILENAME_MAX); @@ -202,25 +202,44 @@ ruby_incpush(path) } } +#if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__ || defined __EMX__ +#define LOAD_RELATIVE 1 +#endif + void ruby_init_loadpath() { -#if defined(_WIN32) || defined(DJGPP) || defined(__EMX__) +#if defined LOAD_RELATIVE char libpath[FILENAME_MAX+1]; char *p; int rest; -#if defined(_WIN32) - GetModuleFileName(NULL, libpath, sizeof libpath); +#if defined _WIN32 || defined __CYGWIN__ +# if defined LIBRUBY_SO + HMODULE libruby = GetModuleHandle(LIBRUBY_SO); +# else + HMODULE libruby = NULL; +# endif + GetModuleFileName(libruby, libpath, sizeof libpath); #elif defined(DJGPP) extern char *__dos_argv0; strncpy(libpath, __dos_argv0, FILENAME_MAX); +#define CharNext(p) ((p) + mblen(p, MB_CUR_MAX)) #elif defined(__EMX__) _execname(libpath, FILENAME_MAX); #endif - p = strrchr(libpath, '\\'); + +#ifndef CharNext /* defined as CharNext[AW] on Windows. */ +#define CharNext(p) ((p) + 1) +#endif + + for (p = libpath; *p; p = CharNext(p)) + if (*p == '\\') + *p = '/'; + + p = strrchr(libpath, '/'); if (p) { *p = 0; - if (p-libpath > 3 && !strcasecmp(p-4, "\\bin")) { + if (p-libpath > 3 && !strcasecmp(p-4, "/bin")) { p -= 4; *p = 0; } @@ -229,14 +248,6 @@ ruby_init_loadpath() p = libpath + 1; } -#if !defined(__CYGWIN32__) -#ifndef CharNext /* defined as CharNext[AW] on Windows. */ -#define CharNext(p) ((p) + 1) -#endif - for (p = libpath; *p; p = CharNext(p)) - if (*p == '\\') - *p = '/'; -#endif rest = FILENAME_MAX - (p - libpath); #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath) @@ -428,6 +439,10 @@ proc_options(argc, argv) goto reswitch; case 'v': + if (verbose) { + s++; + goto reswitch; + } ruby_show_version(); verbose = 1; case 'w': @@ -663,6 +678,11 @@ proc_options(argc, argv) ruby_show_copyright(); } + if (rb_safe_level() >= 4) { + OBJ_TAINT(rb_argv); + OBJ_TAINT(rb_load_path); + } + if (!e_script && argc == 0) { /* no more args */ if (verbose) exit(0); script = "-"; @@ -708,6 +728,11 @@ proc_options(argc, argv) process_sflag(); xflag = 0; + + if (rb_safe_level() >= 4) { + FL_UNSET(rb_argv, FL_TAINT); + FL_UNSET(rb_load_path, FL_TAINT); + } } extern int ruby__end__seen; @@ -728,7 +753,7 @@ load_file(fname, script) FILE *fp = fopen(fname, "r"); if (fp == NULL) { - rb_raise(rb_eLoadError, "No such file to load -- %s", fname); + rb_load_fail(fname); } fclose(fp); @@ -871,9 +896,9 @@ set_arg0(val, id) #endif s = rb_str2cstr(val, &i); #ifndef __hpux - if (i > len) { - memcpy(origargv[0], s, len); - origargv[0][len] = '\0'; + if (i < len) { + memcpy(origargv[0], s, i); + origargv[0][i] = '\0'; } else { memcpy(origargv[0], s, i); @@ -983,6 +1008,7 @@ ruby_set_argv(argc, argv) if (origargv) dln_argv0 = origargv[0]; else dln_argv0 = argv[0]; #endif + rb_ary_clear(rb_argv); for (i=0; i < argc; i++) { rb_ary_push(rb_argv, rb_tainted_str_new2(argv[i])); } diff --git a/ruby.h b/ruby.h index ca97ee2c42..d9e3460684 100644 --- a/ruby.h +++ b/ruby.h @@ -164,6 +164,7 @@ VALUE rb_uint2inum _((unsigned long)); #define T_MATCH 0x23 #define T_SYMBOL 0x24 +#define T_BLKTAG 0x3b #define T_UNDEF 0x3c #define T_VARMAP 0x3d #define T_SCOPE 0x3e @@ -541,13 +542,13 @@ EXTERN VALUE rb_eNameError; EXTERN VALUE rb_eSyntaxError; EXTERN VALUE rb_eLoadError; -#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(RUBY_NO_INLINE) -extern __inline__ VALUE rb_class_of _((VALUE)); -extern __inline__ int rb_type _((VALUE)); -extern __inline__ int rb_special_const_p _((VALUE)); - -extern __inline__ VALUE +static inline VALUE +#if defined(__cplusplus) rb_class_of(VALUE obj) +#else +rb_class_of(obj) + VALUE obj; +#endif { if (FIXNUM_P(obj)) return rb_cFixnum; if (obj == Qnil) return rb_cNilClass; @@ -558,8 +559,13 @@ rb_class_of(VALUE obj) return RBASIC(obj)->klass; } -extern __inline__ int +static inline int +#if defined(__cplusplus) rb_type(VALUE obj) +#else +rb_type(obj) + VALUE obj; +#endif { if (FIXNUM_P(obj)) return T_FIXNUM; if (obj == Qnil) return T_NIL; @@ -570,19 +576,18 @@ rb_type(VALUE obj) return BUILTIN_TYPE(obj); } -extern __inline__ int +static inline int +#if defined(__cplusplus) rb_special_const_p(VALUE obj) +#else +rb_special_const_p(obj) + VALUE obj; +#endif { if (SPECIAL_CONST_P(obj)) return Qtrue; return Qfalse; } -#else -VALUE rb_class_of _((VALUE)); -int rb_type _((VALUE)); -int rb_special_const_p _((VALUE)); -#endif - #include "intern.h" #if defined(EXTLIB) && defined(USE_DLN_A_OUT) @@ -590,6 +595,10 @@ int rb_special_const_p _((VALUE)); static char *dln_libs_to_be_linked[] = { EXTLIB, 0 }; #endif +#ifndef rb_sys_stat +#define rb_sys_stat stat +#endif + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/sample/README b/sample/README index 82db05eec9..bf080c1d51 100644 --- a/sample/README +++ b/sample/README @@ -7,7 +7,6 @@ dbmtest.rb test for dbm dir.rb directory access dualstack-fetch.rb IPv6 demo dualstack-httpd.rb IPv6 demo -dstore.rb object database on dbm eval.rb simple evaluator export.rb method access example exyacc.rb extrace BNF from yacc file @@ -22,7 +21,6 @@ from.rb scan mail spool fullpath.rb convert ls -lR to fullpath format getopts.test test fot getopt.rb goodfriday.rb print various christian calendar event. -io.rb io test irb.rb interactive ruby less.rb front end for less list.rb stupid object sample @@ -41,7 +39,6 @@ pi.rb calculate PI rcs.awk random character stereogram (AWK) rcs.rb random character stereogram (Ruby) rcs.dat data for random character stereogram -rd2html.rb rd (Ruby Document) to HTML translator regx.rb regular expression tester sieve.rb sieve of Eratosthenes svr.rb socket server diff --git a/sample/dualstack-fetch.rb b/sample/dualstack-fetch.rb new file mode 100644 index 0000000000..ab8d0914f2 --- /dev/null +++ b/sample/dualstack-fetch.rb @@ -0,0 +1,48 @@ +# simple webpage fetcher + +# The code demonstrates how a multi-protocol client should be written. +# TCPsocket is using getaddrinfo() internally, so there should be no problem. + +require "socket" + +if ARGV.size != 1 + STDERR.print "requires URL\n" + exit +end + +url = ARGV[0] +if url !~ /^http:\/\/([^\/]+)(\/.*)$/ + STDERR.print "only http with full hostname is supported\n" + exit +end + +# split URL into host, port and path +hostport = $1 +path = $2 +if (hostport =~ /^(.*):([0-9]+)$/) + host = $1 + port = $2 +else + host = hostport + port = 80 +end +if host =~ /^\[(.*)\]$/ + host = $1 +end + +#STDERR.print "url=<#{ARGV[0]}>\n" +#STDERR.print "host=<#{host}>\n" +#STDERR.print "port=<#{port}>\n" +#STDERR.print "path=<#{path}>\n" + +STDERR.print "conntecting to #{host} port #{port}\n" +c = TCPsocket.new(host, port) +dest = Socket.getnameinfo(c.getpeername, + Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV) +STDERR.print "conntected to #{dest[0]} port #{dest[1]}\n" +c.print "GET #{path} HTTP/1.0\n" +c.print "Host: #{host}\n" +c.print "\n" +while c.gets + print +end diff --git a/sample/dualstack-httpd.rb b/sample/dualstack-httpd.rb new file mode 100644 index 0000000000..893b29feba --- /dev/null +++ b/sample/dualstack-httpd.rb @@ -0,0 +1,55 @@ +# simple httpd + +# The code demonstrates how a multi-protocol daemon should be written. + +require "socket" +require "thread" + +port = 8888 +res = Socket.getaddrinfo(nil, port, nil, Socket::SOCK_STREAM, nil, Socket::AI_PASSIVE) +sockpool = [] +names = [] +threads = [] + +res.each do |i| + s = TCPserver.new(i[3], i[1]) + n = Socket.getnameinfo(s.getsockname, Socket::NI_NUMERICHOST|Socket::NI_NUMERICSERV).join(" port ") + sockpool.push s + names.push n +end + +(0 .. sockpool.size - 1).each do |i| + mysock = sockpool[i] + myname = names[i] + STDERR.print "socket #{mysock} started, address #{myname}\n" + threads[i] = Thread.start do # Thread.start cannot be used here! + ls = mysock # copy to dynamic variable + t = Thread.current + STDERR.print "socket #{myname} listener started, pid #{$$} thread #{t}\n" + while TRUE + as = ls.accept + Thread.start do + STDERR.print "socket #{myname} accepted, thread ", Thread.current, "\n" + s = as # copy to dynamic variable + str = '' + while line = s.gets + break if line == "\r\n" or line == "\n" + str << line + end + STDERR.print "socket #{myname} got string\n" + s.write("HTTP/1.0 200 OK\n") + s.write("Content-type: text/plain\n\n") + s.write("this is test: my name is #{myname}, you sent:\n") + s.write("---start\n") + s.write(str) + s.write("---end\n") + s.close + STDERR.print "socket #{myname} processed, thread ", Thread.current, " terminating\n" + end + end + end +end + +for t in threads + t.join +end diff --git a/sample/io.rb b/sample/io.rb deleted file mode 100644 index 0b38d2112d..0000000000 --- a/sample/io.rb +++ /dev/null @@ -1,44 +0,0 @@ -# IO test -# usage: ruby io.rb file.. - -home = ENV["HOME"] -home.sub("m", "&&") -print(home, "\n") -print(home.reverse, "\n") - -if File.s("io.rb") - print(File.s("io.rb"), ": io.rb\n") -end - -$/="f\n" -for i in "abc\n\ndef\nghi\n" - print("tt: ", i) -end - -printf("%s:(%d)%s\n", $0, ARGV.length, ARGV[0]) -passwd = open(ARGV[0], "r") -#printf("%s", passwd.find{i|i =~ /\*/}) - -n = 1 -for i in passwd #.grep(/^\*/) - printf("%6d: %s", n, i) - n = n + 1; -end - -fp = open("|-", "r") - -if fp == nil - for i in 1..5 - print(i, "\n") - end -else - for line in fp - print(line) - end -end - -def printUsage() - if $USAGE - apply($USAGE); - end -end diff --git a/sample/irb.rb b/sample/irb.rb index 6746c59d42..58f3699139 100644 --- a/sample/irb.rb +++ b/sample/irb.rb @@ -1,19 +1,13 @@ #!/usr/bin/env ruby # # irb.rb - intaractive ruby -# $Release Version: 0.6 $ +# $Release Version: 0.7.3 $ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) -# -# -- -# Usage: -# -# irb.rb [options] file_name opts -# +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # -require "irb/main" +require "irb" if __FILE__ == $0 IRB.start(__FILE__) diff --git a/sample/rbc.rb b/sample/rbc.rb deleted file mode 100644 index c1b2999bdf..0000000000 --- a/sample/rbc.rb +++ /dev/null @@ -1,1015 +0,0 @@ -#!/usr/local/bin/ruby -# -# rbc.rb - -# $Release Version: 0.8 $ -# $Revision: 1.8 $ -# $Date: 1998/03/11 05:43:00 $ -# by Keiju ISHITSUKA(Nippon Rational Inc.) -# -# -- -# Usage: -# -# rbc.rb [options] file_name opts -# options: -# -d debug mode (not recommended) -# -f does not read ~/.irbrc -# -m bc mode (rational/matrix calc) -# -r load-module same as `ruby -r' -# --inspect use inspect for result output -# (default for non-bc mode) -# --noinspect does not use inspect for result output -# --noreadline does not use readline library -# (default: try to use readline) -# -# additional private method (as function): -# exit, quit terminate the interpreter -# inspect_mode(sw = nil) toggle inspect mode -# trace_load(sw = nil) change trace mode for file loading using -# load/require. (default: trace-mode on) -# -require "e2mmap.rb" - -$stdout.sync = TRUE - -module BC_APPLICATION__ - RCS_ID='-$Id: rbc.rb,v 1.8 1998/03/11 05:43:00 keiju Exp keiju $-' - - extend Exception2MessageMapper - def_exception :UnrecognizedSwitch, "Unrecognized switch: %s" - - CONFIG = {} - CONFIG[0] = $0 - CONFIG[:USE_READLINE] = TRUE - CONFIG[:LOAD_MODULES] = [] - CONFIG[:INSPECT] = nil - CONFIG[:TRACE_LOAD] = FALSE - CONFIG[:RC] = TRUE - - CONFIG[:DEBUG] = FALSE - - while opt = ARGV.shift - case opt - when "-d" - CONFIG[:DEBUG] = TRUE - when "-m" - CONFIG[:INSPECT] = FALSE if CONFIG[:INSPECT].nil? - require "mathn.rb" - include Math - when "-r" - opt = ARGV.shift - CONFIG[:LOAD_MODULES].push opt if opt - when "-f" - opt = ARGV.shift - CONFIG[:RC] = FALSE - when "--inspect" - CONFIG[:INSPECT] = TRUE - when "--noinspect" - CONFIG[:INSPECT] = FALSE - when "--noreadline" - CONFIG[:USE_READLINE] = FALSE - when /^-/ - # print UnrecognizedSwitch.inspect, "\n" - BC_APPLICATION__.fail UnrecognizedSwitch, opt - else - CONFIG[:USE_READLINE] = FALSE - $0 = opt - break - end - end - CONFIG[:INSPECT] = TRUE if CONFIG[:INSPECT].nil? - - PROMPTi = "rbc%d> " - PROMPTs = "rbc%d%s " - PROMPTe = "rbc%d* " - - class BC - def initialize - lex_init - end - - def eval_input(io, cont, bind) - line = '' - @io = io - @ltype = nil - @quoted = nil - @indent = 0 - @lex_state = EXPR_BEG - - @io.prompt = format(PROMPTi, @indent) - - loop do - @continue = FALSE - l = @io.gets - - unless l - break if line == '' - else - line = line + l - - lex(l) if l != "\n" - print @quoted.inspect, "\n" if CONFIG[:DEBUG] - if @ltype - @io.prompt = format(PROMPTs, @indent, @ltype) - next - elsif @continue - @io.prompt = format(PROMPTe, @indent) - next - elsif @indent > 0 - @io.prompt = format(PROMPTi, @indent) - next - end - end - - if line != "\n" - begin - if CONFIG[:INSPECT] - print((cont._=eval(line, bind)).inspect, "\n") - else - print((cont._=eval(line, bind)), "\n") - end - rescue StandardError, ScriptError - # $! = 'exception raised' unless $! - # print "ERR: ", $!, "\n" - $! = RuntimeError.new("exception raised") unless $! - print $!.type, ": ", $!, "\n" - end - end - break if not l - line = '' - indent = 0 - @io.prompt = format(PROMPTi, indent) - end - print "\n" - end - - EXPR_BEG = :EXPR_BEG - EXPR_MID = :EXPR_MID - EXPR_END = :EXPR_END - EXPR_ARG = :EXPR_ARG - EXPR_FNAME = :EXPR_FNAME - - CLAUSE_STATE_TRANS = { - "alias" => EXPR_FNAME, - "and" => EXPR_BEG, - "begin" => EXPR_BEG, - "case" => EXPR_BEG, - "class" => EXPR_BEG, - "def" => EXPR_FNAME, - "defined?" => EXPR_END, - "do" => EXPR_BEG, - "else" => EXPR_BEG, - "elsif" => EXPR_BEG, - "end" => EXPR_END, - "ensure" => EXPR_BEG, - "for" => EXPR_BEG, - "if" => EXPR_BEG, - "in" => EXPR_BEG, - "module" => EXPR_BEG, - "nil" => EXPR_END, - "not" => EXPR_BEG, - "or" => EXPR_BEG, - "rescue" => EXPR_MID, - "return" => EXPR_MID, - "self" => EXPR_END, - "super" => EXPR_END, - "then" => EXPR_BEG, - "undef" => EXPR_FNAME, - "unless" => EXPR_BEG, - "until" => EXPR_BEG, - "when" => EXPR_BEG, - "while" => EXPR_BEG, - "yield" => EXPR_END - } - - ENINDENT_CLAUSE = [ - "case", "class", "def", "do", "for", "if", - "module", "unless", "until", "while", "begin" #, "when" - ] - DEINDENT_CLAUSE = ["end" #, "when" - ] - - PARCENT_LTYPE = { - "q" => "\'", - "Q" => "\"", - "x" => "\`", - "r" => "\/" - } - - PARCENT_PAREN = { - "{" => "}", - "[" => "]", - "<" => ">", - "(" => ")" - } - - def lex_init() - @OP = Trie.new - @OP.def_rules("\0", "\004", "\032"){} - @OP.def_rules(" ", "\t", "\f", "\r", "\13") do - @space_seen = TRUE - next - end - @OP.def_rule("#") do - |op, rests| - @ltype = "#" - identify_comment(rests) - end - @OP.def_rule("\n") do - print "\\n\n" if CONFIG[:DEBUG] - if @lex_state == EXPR_BEG || @lex_state == EXPR_FNAME - @continue = TRUE - else - @lex_state = EXPR_BEG - end - end - @OP.def_rules("*", "*=", "**=", "**") {@lex_state = EXPR_BEG} - @OP.def_rules("!", "!=", "!~") {@lex_state = EXPR_BEG} - @OP.def_rules("=", "==", "===", "=~", "<=>") {@lex_state = EXPR_BEG} - @OP.def_rules("<", "<=", "<<") {@lex_state = EXPR_BEG} - @OP.def_rules(">", ">=", ">>") {@lex_state = EXPR_BEG} - @OP.def_rules("'", '"') do - |op, rests| - @ltype = op - @quoted = op - identify_string(rests) - end - @OP.def_rules("`") do - |op, rests| - if @lex_state != EXPR_FNAME - @ltype = op - @quoted = op - identify_string(rests) - end - end - @OP.def_rules('?') do - |op, rests| - @lex_state = EXPR_END - identify_question(rests) - end - @OP.def_rules("&", "&&", "&=", "|", "||", "|=") do - @lex_state = EXPR_BEG - end - @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) {} - @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) {} - @OP.def_rules("+=", "-=") {@lex_state = EXPR_BEG} - @OP.def_rules("+", "-") do - |op, rests| - if @lex_state == EXPR_ARG - if @space_seen and rests[0] =~ /[0-9]/ - identify_number(rests) - else - @lex_state = EXPR_BEG - end - elsif @lex_state != EXPR_END and rests[0] =~ /[0-9]/ - identify_number(rests) - else - @lex_state = EXPR_BEG - end - end - @OP.def_rule(".") do - |op, rests| - @lex_state = EXPR_BEG - if rests[0] =~ /[0-9]/ - rests.unshift op - identify_number(rests) - else - # handle ``obj.if'' and such - identify_identifier(rests, TRUE) - @lex_state = EXPR_ARG - end - end - @OP.def_rules("..", "...") {@lex_state = EXPR_BEG} - - lex_int2 - end - - def lex_int2 - @OP.def_rules("]", "}", ")") do - @lex_state = EXPR_END - @indent -= 1 - end - @OP.def_rule(":") {|op,rests| - identify_identifier(rests, TRUE) - } - @OP.def_rule("::") {|op,rests| - identify_identifier(rests, TRUE); - } - @OP.def_rule("/") do - |op, rests| - if @lex_state == EXPR_BEG || @lex_state == EXPR_MID - @ltype = op - @quoted = op - identify_string(rests) - elsif rests[0] == '=' - rests.shift - @lex_state = EXPR_BEG - elsif @lex_state == EXPR_ARG and @space_seen and rests[0] =~ /\s/ - @ltype = op - @quoted = op - identify_string(rests) - else - @lex_state = EXPR_BEG - end - end - @OP.def_rules("^", "^=") {@lex_state = EXPR_BEG} - @OP.def_rules(",", ";") {@lex_state = EXPR_BEG} - @OP.def_rule("~") {@lex_state = EXPR_BEG} - @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) {} - @OP.def_rule("(") do - @lex_state = EXPR_BEG - @indent += 1 - end - @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) {} - @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) {} - @OP.def_rule("[") do - @indent += 1 - if @lex_state != EXPR_FNAME - @lex_state = EXPR_BEG - end - end - @OP.def_rule("{") do - @lex_state = EXPR_BEG - @indent += 1 - end - @OP.def_rule('\\') {|op, rests| identify_escape(rests)} #') - @OP.def_rule('%') do - |op, rests| - if @lex_state == EXPR_BEG || @lex_state == EXPR_MID - identify_quotation(rests) - elsif rests[0] == '=' - rests.shift - elsif @lex_state == EXPR_ARG and @space_seen and rests[0] =~ /\s/ - identify_quotation(rests) - else - @lex_state = EXPR_BEG - end - end - @OP.def_rule('$') do #' - |op, rests| - identify_gvar(rests) - end - @OP.def_rule('@') do - |op, rests| - if rests[0] =~ /[\w_]/ - rests.unshift op - identify_identifier(rests) - end - end - @OP.def_rule("def", proc{|op, chrs| /\s/ =~ chrs[0]}) do - |op, rests| - @indent += 1 - @lex_state = EXPR_END - until rests[0] == "\n" or rests[0] == ";" - rests.shift - end - end - @OP.def_rule("") do - |op, rests| - printf "MATCH: start %s: %s\n", op, rests.inspect if CONFIG[:DEBUG] - if rests[0] =~ /[0-9]/ - identify_number(rests) - elsif rests[0] =~ /[\w_]/ - identify_identifier(rests) - end - printf "MATCH: end %s: %s\n", op, rests.inspect if CONFIG[:DEBUG] - end - - p @OP if CONFIG[:DEBUG] - end - - def lex(l) - chrs = l.split(//) - tokens = [] - - case @ltype - when "'", '"', '`', '/' - identify_string(chrs) - return if chrs.empty? - when "#" - identify_comment(chrs) - return - when "=" - if l =~ /^=end/ - $ltype = nil - return - end - else - if l =~ /^=begin/ - $ltype = "=" - return - end - end - - until chrs.empty? - @space_seen = FALSE - printf "perse: %s\n", chrs.join("") if CONFIG[:DEBUG] - @OP.match(chrs) - printf "lex_state: %s continue: %s\n", @lex_state.id2name, @continue if CONFIG[:DEBUG] - end - end - - def identify_gvar(chrs) - @lex_state = EXPR_END - - ch = chrs.shift - case ch - when /[_~*$?!@\/\\;,.=:<>"]/ #" - return - - when "-" - ch = chrs.shift - return - - when "&", "`", "'", "+" - return - - when /[1-9]/ - chrs.unshift ch - v = "$" - while (ch = chrs.shift) =~ /[0-9]/ - end - chrs.unshift ch - return - - when /\w/ - chrs.unshift ch - chrs.unshift "$" - identify_identifier(chrs) - return - - else - chrs.unshift ch - return - end - end - - def identify_identifier(chrs, escaped = FALSE) - token = "" - token.concat chrs.shift if chrs[0] =~ /[$@]/ or escaped - while (ch = chrs.shift) =~ /\w|_/ - print ":", ch, ":" if CONFIG[:DEBUG] - token.concat ch - end - chrs.unshift ch - - if ch == "!" or ch == "?" - chrs.shift - token.concat ch - end - # fix token - - if token =~ /^[$@]/ or escaped - @lex_state = EXPR_END - return - end - - print token, "\n" if CONFIG[:DEBUG] - if state = CLAUSE_STATE_TRANS[token] - if @lex_state != EXPR_BEG and token =~ /^(if|unless|while|until)/ - # modifiers - else - if ENINDENT_CLAUSE.include?(token) - @indent += 1 - elsif DEINDENT_CLAUSE.include?(token) - @indent -= 1 - end - end - @lex_state = state - return - end - if @lex_state == EXPR_FNAME - @lex_state = EXPR_END - if chrs[0] == '=' - chrs.shift - end - elsif @lex_state == EXPR_BEG - @lex_state = EXPR_ARG - else - @lex_state = EXPR_END - end - end - - def identify_quotation(chrs) - ch = chrs.shift - if lt = PARCENT_LTYPE[ch] - ch = chrs.shift - else - lt = "\"" - end - if ch !~ /\W/ - chrs.unshift ch - next - end - @ltype = lt - unless @quoted = PARCENT_PAREN[ch] - @quoted = ch - end - identify_string(chrs) - end - - def identify_number(chrs) - @lex_state = EXPR_END - - ch = chrs.shift - case ch - when /0/ - if (ch = chrs[0]) == "x" - chrs.shift - match = /[0-9a-f_]/ - else - match = /[0-7_]/ - end - while ch = chrs.shift - if ch !~ match - chrs.unshift ch - break - end - end - return - end - - while ch = chrs.shift - case ch - when /[0-9]/ - when "e", "E" - # type = FLOAT - unless (ch = chrs.shift) == "+" or ch == "-" - chrs.unshift ch - end - when "." - # type = FLOAT - when "_" - else - chrs.unshift ch - return - end - end - end - - def identify_question(chrs) - @lex_state = EXPR_END - - if chrs.shift == "\\" #" - identify_escape(chrs) - end - end - - def identify_string(chrs) - while ch = chrs.shift - if @quoted == ch - if @ltype == "/" - if chrs[0] =~ /i|o|n|e|s/ - chrs.shift - end - end - @ltype = nil - @quoted = nil - @lex_state = EXPR_END - break - elsif ch == '\\' #' - identify_escape(chrs) - end - end - end - - def identify_comment(chrs) - while ch = chrs.shift - if ch == "\\" #" - identify_escape(chrs) - end - if ch == "\n" - @ltype = nil - chrs.unshift ch - break - end - end - end - - def identify_escape(chrs) - ch = chrs.shift - case ch - when "\n", "\r", "\f" - @continue = TRUE - when "\\", "n", "t", "r", "f", "v", "a", "e", "b" #" - when /[0-7]/ - chrs.unshift ch - 3.times do - ch = chrs.shift - case ch - when /[0-7]/ - when nil - break - else - chrs.unshift ch - break - end - end - when "x" - 2.times do - ch = chrs.shift - case ch - when /[0-9a-fA-F]/ - when nil - break - else - chrs.unshift ch - break - end - end - when "M" - if (ch = chrs.shift) != '-' - chrs.unshift ch - elsif (ch = chrs.shift) == "\\" #" - identify_escape(chrs) - end - return - when "C", "c", "^" - if ch == "C" and (ch = chrs.shift) != "-" - chrs.unshift ch - elsif (ch = chrs.shift) == "\\" #" - identify_escape(chrs) - end - return - end - end - end - - class Trie - extend Exception2MessageMapper - def_exception :ErrNodeNothing, "node nothing" - def_exception :ErrNodeAlreadyExists, "node already exists" - - class Node - # abstract node if postproc is nil. - def initialize(preproc = nil, postproc = nil) - @Tree = {} - @preproc = preproc - @postproc = postproc - end - - attr :preproc, TRUE - attr :postproc, TRUE - - def search(chrs, opt = nil) - return self if chrs.empty? - ch = chrs.shift - if node = @Tree[ch] - node.search(chrs, opt) - else - if opt - chrs.unshift ch - self.create_subnode(chrs) - else - Trie.fail ErrNodeNothing - end - end - end - - def create_subnode(chrs, preproc = nil, postproc = nil) - if chrs.empty? - if @postproc - p node - Trie.fail ErrNodeAlreadyExists - else - print "Warn: change abstruct node to real node\n" if CONFIG[:DEBUG] - @preproc = preproc - @postproc = postproc - end - return self - end - - ch = chrs.shift - if node = @Tree[ch] - if chrs.empty? - if node.postproc - p node - Trie.fail ErrNodeAlreadyExists - else - print "Warn: change abstruct node to real node\n" if CONFIG[:DEBUG] - node.preproc = preproc - node.postproc = postproc - end - else - node.create_subnode(chrs, preproc, postproc) - end - else - if chrs.empty? - node = Node.new(preproc, postproc) - else - node = Node.new - node.create_subnode(chrs, preproc, postproc) - end - @Tree[ch] = node - end - node - end - - def match(chrs, op = "") - print "match>: ", chrs, "op:", op, "\n" if CONFIG[:DEBUG] - if chrs.empty? - if @preproc.nil? || @preproc.call(op, chrs) - printf "op1: %s\n", op if CONFIG[:DEBUG] - @postproc.call(op, chrs) - "" - else - nil - end - else - ch = chrs.shift - if node = @Tree[ch] - if ret = node.match(chrs, op+ch) - return ch+ret - else - chrs.unshift ch - if @postproc and @preproc.nil? || @preproc.call(op, chrs) - printf "op2: %s\n", op.inspect if CONFIG[:DEBUG] - @postproc.call(op, chrs) - return "" - else - return nil - end - end - else - chrs.unshift ch - if @postproc and @preproc.nil? || @preproc.call(op, chrs) - printf "op3: %s\n", op if CONFIG[:DEBUG] - @postproc.call(op, chrs) - return "" - else - return nil - end - end - end - end - end - - def initialize - @head = Node.new("") - end - - def def_rule(token, preproc = nil, postproc = nil) -# print node.inspect, "\n" if CONFIG[:DEBUG] - postproc = proc if iterator? - node = create(token, preproc, postproc) - end - - def def_rules(*tokens) - if iterator? - p = proc - end - for token in tokens - def_rule(token, nil, p) - end - end - - def preporc(token, proc) - node = search(token) - node.preproc=proc - end - - def postproc(token) - node = search(token, proc) - node.postproc=proc - end - - def search(token) - @head.search(token.split(//)) - end - - def create(token, preproc = nil, postproc = nil) - @head.create_subnode(token.split(//), preproc, postproc) - end - - def match(token) - token = token.split(//) if token.kind_of?(String) - ret = @head.match(token) - printf "match end: %s:%s", ret, token.inspect if CONFIG[:DEBUG] - ret - end - - def inspect - format("", @head.inspect) - end - end - - if /^-tt(.*)$/ =~ ARGV[0] -# Tracer.on - case $1 - when "1" - tr = Trie.new - print "0: ", tr.inspect, "\n" - tr.def_rule("=") {print "=\n"} - print "1: ", tr.inspect, "\n" - tr.def_rule("==") {print "==\n"} - print "2: ", tr.inspect, "\n" - - print "case 1:\n" - print tr.match("="), "\n" - print "case 2:\n" - print tr.match("=="), "\n" - print "case 3:\n" - print tr.match("=>"), "\n" - - when "2" - tr = Trie.new - print "0: ", tr.inspect, "\n" - tr.def_rule("=") {print "=\n"} - print "1: ", tr.inspect, "\n" - tr.def_rule("==", proc{FALSE}) {print "==\n"} - print "2: ", tr.inspect, "\n" - - print "case 1:\n" - print tr.match("="), "\n" - print "case 2:\n" - print tr.match("=="), "\n" - print "case 3:\n" - print tr.match("=>"), "\n" - end - exit - end - - module CONTEXT - def _=(value) - CONFIG[:_] = value - eval "_=BC_APPLICATION__::CONFIG[:_]", CONFIG[:BIND] - end - -# def _ -# eval "_", CONFIG[:BIND] -# end - - def quit - exit - end - - def trace_load(opt = nil) - if !opt.nil? - CONFIG[:TRACE_LOAD] = opt - else - CONFIG[:TRACE_LOAD] = !CONFIG[:TRACE_LOAD] - end - print "Switch to load/require #{unless CONFIG[:TRACE_LOAD]; ' non';end} trace mode.\n" - if CONFIG[:TRACE_LOAD] - eval %{ - class << self - alias load rbc_load - alias require rbc_require - end - } - else - eval %{ - class << self - alias load rbc_load_org - alias require rbc_require_org - end - } - end - CONFIG[:TRACE_LOAD] - end - - alias rbc_load_org load - def rbc_load(file_name) - return true if load_sub(file_name) - raise LoadError, "No such file to load -- #{file_name}" - end - - alias rbc_require_org require - def rbc_require(file_name) - rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?") - return false if $".find{|f| f =~ rex} - - case file_name - when /\.rb$/ - if load_sub(file_name) - $".push file_name - return true - end - when /\.(so|o|sl)$/ - rbc_require_org(file_name) - end - - if load_sub(f = file_name + ".rb") - $".push f - return true - end - rbc_require_org(file_name) - end - - def load_sub(fn) - if fn =~ /^#{Regexp.quote(File::Separator)}/ - return false unless File.exist?(fn) - BC.new.eval_input FileInputMethod.new(fn), self, CONFIG[:BIND] - return true - end - - for path in $: - if File.exist?(f = File.join(path, fn)) - BC.new.eval_input FileInputMethod.new(f), self, CONFIG[:BIND] - return true - end - end - return false - end - - def inspect_mode(opt = nil) - if opt - CONFIG[:INSPECT] = opt - else - CONFIG[:INSPECT] = !CONFIG[:INSPECT] - end - print "Switch to#{unless CONFIG[:INSPECT]; ' non';end} inspect mode.\n" - CONFIG[:INSPECT] - end - - def run(bind) - CONFIG[:BIND] = bind - - if CONFIG[:RC] - rc = File.expand_path("~/.irbrc") - if File.exists?(rc) - begin - load rc - rescue LoadError - print "load error: #{rc}\n" - print $!.type, ": ", $!, "\n" - for err in $@[0, $@.size - 2] - print "\t", err, "\n" - end - end - end - end - - if CONFIG[:TRACE_LOAD] - trace_load true - end - - for m in CONFIG[:LOAD_MODULES] - begin - require m - rescue LoadError - print $@[0], ":", $!.type, ": ", $!, "\n" - end - end - - if !$0.equal?(CONFIG[0]) - io = FileInputMethod.new($0) - elsif defined? Readline - io = ReadlineInputMethod.new - else - io = StdioInputMethod.new - end - - BC.new.eval_input io, self, CONFIG[:BIND] - end - end - - class InputMethod - attr :prompt, TRUE - - def gets - end - public :gets - end - - class StdioInputMethod < InputMethod - def gets - print @prompt - $stdin.gets - end - end - - class FileInputMethod < InputMethod - def initialize(file) - @io = open(file) - end - - def gets - l = @io.gets - print @prompt, l - l - end - end - - if CONFIG[:USE_READLINE] - begin - require "readline" - print "use readline module\n" - class ReadlineInputMethod < InputMethod - include Readline - def gets - if l = readline(@prompt, TRUE) - l + "\n" - else - l - end - end - end - rescue LoadError - CONFIG[:USE_READLINE] = FALSE - end - end -end - -extend BC_APPLICATION__::CONTEXT -run(binding) - diff --git a/signal.c b/signal.c index 2bb8bada28..1f820dac55 100644 --- a/signal.c +++ b/signal.c @@ -162,6 +162,9 @@ static struct signals { #endif #ifdef SIGSOUND "SOUND", SIGSOUND, +#endif +#ifdef SIGINFO + "INFO", SIGINFO, #endif NULL, 0, }; @@ -252,7 +255,7 @@ rb_f_kill(argc, argv) else { for (i=1; iorig, add); } -static ID to_str; +static ID id_to_s; VALUE rb_obj_as_string(obj) @@ -185,7 +185,7 @@ rb_obj_as_string(obj) if (TYPE(obj) == T_STRING) { return obj; } - str = rb_funcall(obj, to_str, 0); + str = rb_funcall(obj, id_to_s, 0); if (TYPE(str) != T_STRING) return rb_any_to_s(obj); if (OBJ_TAINTED(obj)) OBJ_TAINT(str); @@ -339,7 +339,6 @@ rb_str_substr(str, beg, len) if (len < 0) return Qnil; if (beg > RSTRING(str)->len) return Qnil; - if (beg == RSTRING(str)->len && len > 0) return Qnil; if (beg < 0) { beg += RSTRING(str)->len; if (beg < 0) return Qnil; @@ -367,7 +366,6 @@ str_independent(str) rb_raise(rb_eSecurityError, "Insecure: can't modify string"); if (!RSTRING(str)->orig || FL_TEST(str, STR_NO_ORIG)) return 1; if (TYPE(RSTRING(str)->orig) != T_STRING) rb_bug("non string str->orig"); - RSTRING(str)->orig = 0; return 0; } @@ -384,6 +382,7 @@ rb_str_modify(str) } ptr[RSTRING(str)->len] = 0; RSTRING(str)->ptr = ptr; + RSTRING(str)->orig = 0; } VALUE @@ -969,6 +968,7 @@ rb_str_replace(str, beg, len, val) } RSTRING(str)->len += RSTRING(val)->len - len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; + OBJ_INFECT(str, val); } static VALUE rb_str_sub_bang _((int, VALUE*, VALUE)); @@ -1127,7 +1127,7 @@ rb_str_sub_bang(argc, argv, str) iter = 1; } else if (argc == 2) { - repl = rb_obj_as_string(argv[1]);; + repl = rb_str_to_str(argv[1]);; if (OBJ_TAINTED(repl)) tainted = 1; } else { @@ -1200,7 +1200,7 @@ str_gsub(argc, argv, str, bang) iter = 1; } else if (argc == 2) { - repl = rb_obj_as_string(argv[1]); + repl = rb_str_to_str(argv[1]); if (OBJ_TAINTED(repl)) tainted = 1; } else { @@ -1278,6 +1278,9 @@ str_gsub(argc, argv, str, bang) if (str_independent(str)) { free(RSTRING(str)->ptr); } + else { + RSTRING(str)->orig = 0; + } } else { NEWOBJ(dup, struct RString); @@ -1316,15 +1319,19 @@ static VALUE rb_str_replace_m(str, str2) VALUE str, str2; { + if (str == str2) return str; if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); - rb_str_modify(str); - if (RSTRING(str2)->orig && FL_TEST(str2, STR_NO_ORIG)) { + if (RSTRING(str2)->orig && !FL_TEST(str2, STR_NO_ORIG)) { + if (str_independent(str)) { + free(RSTRING(str)->ptr); + } RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->orig = RSTRING(str2)->orig; } else { + rb_str_modify(str); rb_str_resize(str, RSTRING(str2)->len); memcpy(RSTRING(str)->ptr, RSTRING(str2)->ptr, RSTRING(str2)->len); } @@ -1395,6 +1402,7 @@ rb_str_reverse_bang(str) char *s, *e; char c; + rb_str_modify(str); s = RSTRING(str)->ptr; e = s + RSTRING(str)->len - 1; while (s < e) { @@ -1490,8 +1498,8 @@ rb_str_inspect(str) char c = *p++; if (ismbchar(c) && p < pend) { int len = mbclen(c); - rb_str_cat(result, p, len); - p += len; + rb_str_cat(result, p - 1, len); + p += len - 1; } else if (c == '"'|| c == '\\') { s[0] = '\\'; s[1] = c; @@ -1644,7 +1652,7 @@ rb_str_upcase_bang(str) if (ismbchar(*s)) { s+=mbclen(*s) - 1; } - else if (islower(*s)) { + else if (ISLOWER(*s)) { *s = toupper(*s); modify = 1; } @@ -1784,7 +1792,10 @@ trnext(t) if (!t->gen) { if (t->p == t->pend) return -1; t->now = *(USTR)t->p++; - if (t->p < t->pend - 1 && *t->p == '-') { + if (t->p < t->pend - 1 && *t->p == '\\') { + t->p++; + } + else if (t->p < t->pend - 1 && *t->p == '-') { t->p++; if (t->p < t->pend) { if (t->now > *(USTR)t->p) { @@ -1965,6 +1976,9 @@ rb_str_delete_bang(argc, argv, str) int init = 1; int i; + if (argc < 1) { + rb_raise(rb_eArgError, "wrong # of arguments"); + } for (i=0; ilen < 2) rb_raise(rb_eArgError, "salt too short(need >=2 bytes)"); - return rb_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr)); + + result = rb_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr)); + OBJ_INFECT(result, str); + return result; } static VALUE @@ -2702,6 +2720,7 @@ rb_str_ljust(str, w) while (p < pend) { *p++ = ' '; } + OBJ_INFECT(res, str); return res; } @@ -2721,6 +2740,7 @@ rb_str_rjust(str, w) *p++ = ' '; } memcpy(pend, RSTRING(str)->ptr, RSTRING(str)->len); + OBJ_INFECT(res, str); return res; } @@ -2746,6 +2766,7 @@ rb_str_center(str, w) while (p < pend) { *p++ = ' '; } + OBJ_INFECT(res, str); return res; } @@ -2877,7 +2898,7 @@ Init_String() rb_define_method(rb_cString, "slice", rb_str_aref_m, -1); rb_define_method(rb_cString, "slice!", rb_str_slice_bang, -1); - to_str = rb_intern("to_s"); + id_to_s = rb_intern("to_s"); rb_fs = Qnil; rb_define_hooked_variable("$;", &rb_fs, 0, rb_str_setter); diff --git a/time.c b/time.c index e45e2e854a..b9008c974d 100644 --- a/time.c +++ b/time.c @@ -324,11 +324,6 @@ make_time_t(tptr, utc_or_local) if (guess < 0) goto out_of_range; if (!utc_or_local) { /* localtime zone adjust */ -#if defined(HAVE_TM_ZONE) - tm = localtime(&guess); - if (!tm) goto error; - guess -= tm->tm_gmtoff; -#else struct tm gt, lt; long tzsec; @@ -357,10 +352,22 @@ make_time_t(tptr, utc_or_local) } tm = localtime(&guess); if (!tm) goto error; - if (lt.tm_isdst != tm->tm_isdst) { - guess -= 3600; + if (lt.tm_isdst != tm->tm_isdst || tptr->tm_hour != tm->tm_hour) { + time_t tmp = guess - 3600; + tm = localtime(&tmp); + if (!tm) goto error; + if (tptr->tm_hour == tm->tm_hour) { + guess = tmp; + } + else if (lt.tm_isdst == tm->tm_isdst) { + tmp = guess + 3600; + tm = localtime(&tmp); + if (!tm) goto error; + if (tptr->tm_hour == tm->tm_hour) { + guess = tmp; + } + } } -#endif if (guess < 0) { goto out_of_range; } @@ -891,7 +898,7 @@ rb_strftime(buf, format, time) return 0; } len = strftime(*buf, SMALLBUF, format, time); - if (len != 0) return len; + if (len != 0 || **buf == '\0') return len; for (size=1024; ; size*=2) { *buf = xmalloc(size); (*buf)[0] = '\0'; diff --git a/util.c b/util.c index 9cbfb5fc74..8fc543dbc0 100644 --- a/util.c +++ b/util.c @@ -16,45 +16,9 @@ #include "missing/file.h" #endif -#define RUBY_NO_INLINE +#define INLINE_DEFINE #include "ruby.h" -VALUE -rb_class_of(obj) - VALUE obj; -{ - if (FIXNUM_P(obj)) return rb_cFixnum; - if (obj == Qnil) return rb_cNilClass; - if (obj == Qfalse) return rb_cFalseClass; - if (obj == Qtrue) return rb_cTrueClass; - if (SYMBOL_P(obj)) return rb_cSymbol; - - return RBASIC(obj)->klass; -} - -int -rb_type(obj) - VALUE obj; -{ - if (FIXNUM_P(obj)) return T_FIXNUM; - if (obj == Qnil) return T_NIL; - if (obj == Qfalse) return T_FALSE; - if (obj == Qtrue) return T_TRUE; - if (obj == Qundef) return T_UNDEF; - if (SYMBOL_P(obj)) return T_SYMBOL; - - return BUILTIN_TYPE(obj); -} - -int -rb_special_const_p(obj) - VALUE obj; -{ - if (SPECIAL_CONST_P(obj)) return Qtrue; - - return Qfalse; -} - #include "util.h" #ifndef HAVE_STRING_H char *strchr _((char*,char)); diff --git a/variable.c b/variable.c index 69791ab26d..b5a92dc6cb 100644 --- a/variable.c +++ b/variable.c @@ -16,6 +16,7 @@ #include "env.h" #include "node.h" #include "st.h" +#include "util.h" static st_table *rb_global_tbl; st_table *rb_class_tbl; @@ -703,6 +704,8 @@ rb_alias_variable(name1, name2) { struct global_entry *entry1, *entry2; + if (rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: can't alias global variable"); entry1 = rb_global_entry(name1); entry2 = rb_global_entry(name2); @@ -1064,10 +1067,11 @@ rb_const_get(klass, id) VALUE klass; ID id; { - VALUE value; - VALUE tmp; + VALUE value, tmp; + int mod_retry = 0; tmp = klass; + retry: while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { return value; @@ -1075,15 +1079,17 @@ rb_const_get(klass, id) if (tmp == rb_cObject && top_const_get(id, &value)) return value; tmp = RCLASS(tmp)->super; } - if (BUILTIN_TYPE(klass) == T_MODULE) { - return rb_const_get(rb_cObject, id); + if (!mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { + mod_retry = 1; + tmp = rb_cObject; + goto retry; } /* Uninitialized constant */ if (klass && klass != rb_cObject) - rb_raise(rb_eNameError, "uninitialized constant %s::%s", - RSTRING(rb_class_path(klass))->ptr, - rb_id2name(id)); + rb_raise(rb_eNameError, "uninitialized constant %s at %s", + rb_id2name(id), + RSTRING(rb_class_path(klass))->ptr); else { rb_raise(rb_eNameError, "uninitialized constant %s",rb_id2name(id)); } diff --git a/version.h b/version.h index 71d484b8fd..f613255721 100644 --- a/version.h +++ b/version.h @@ -1,4 +1,4 @@ -#define RUBY_VERSION "1.6.2" -#define RUBY_RELEASE_DATE "2000-12-25" -#define RUBY_VERSION_CODE 162 -#define RUBY_RELEASE_CODE 20001225 +#define RUBY_VERSION "1.6.4" +#define RUBY_RELEASE_DATE "2001-06-04" +#define RUBY_VERSION_CODE 164 +#define RUBY_RELEASE_CODE 20010604 diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 227ab68b18..42100a5d92 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -30,13 +30,13 @@ AUTOCONF = autoconf prefix = /usr -CFLAGS = -nologo -DNT=1 -Zi -MD -O2b2x -G5 +CFLAGS = -nologo -DNT=1 -Zi -MD -O2b2xg- -G5 CPPFLAGS = -I$(srcdir) -I$(srcdir)/missing LDFLAGS = $(CFLAGS) -Fm XLDFLAGS = #EXTLIBS = LIBS = user32.lib advapi32.lib wsock32.lib $(EXTLIBS) -MISSING = crypt.obj alloca.obj win32.obj isinf.obj isnan.obj +MISSING = crypt.obj win32.obj isinf.obj isnan.obj LDSHARED = DLDFLAGS = SOLIBS = diff --git a/win32/config.h.in b/win32/config.h.in index a7e28120e6..f1ba8da5c3 100644 --- a/win32/config.h.in +++ b/win32/config.h.in @@ -1,6 +1,7 @@ #define HAVE_PROTOTYPES 1 #define HAVE_STDARG_PROTOTYPES 1 /* #define HAVE_ATTR_NORETURN 1 */ +#define inline __inline /* #define HAVE_DIRENT_H 1 */ /* #define HAVE_UNISTD_H 1 */ #define HAVE_STDLIB_H 1 diff --git a/win32/config.status.in b/win32/config.status.in index 461877b886..f337d97b35 100644 --- a/win32/config.status.in +++ b/win32/config.status.in @@ -3,8 +3,6 @@ s%@CFLAGS@%-nologo -DNT=1 -Zi -MD -O2b2x -G5%g s%@CPPFLAGS@%%g s%@CXXFLAGS@%%g s%@FFLAGS@%%g -s%@DEFS@% - -DUSE_THREAD -DSIZEOF_INT=4 -DSIZEOF_SHORT=2 -DSIZEOF_LONG=4 -DSIZEOF_VOIDP=4 -DSIZEOF_FLOAT=4 -DSIZEOF_DOUBLE=8 -DHAVE_PROTOTYPES=1 -DHAVE_STDARG_PROTOTYPES=1 -DHAVE_STDLIB_H=1 -DHAVE_LIMITS_H=1 -DHAVE_FCNTL_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_ST_RDEV=1 -DGETGROUPS_T=int -DRETSIGTYPE=void -DHAVE_ALLOCA=1 -DHAVE_FMOD=1 -DHAVE_WAITPID=1 -DHAVE_GETCWD=1 -DHAVE_CHSIZE=1 -DHAVE_GETGROUPS=1 -DHAVE_GETLOGIN=1 -DRSHIFT=\(x,y\)\ \(\(x\)\>\>y\) -DFILE_COUNT=_cnt -DDLEXT=\".so\" -DDLEXT2=\".dll\" -DRUBY_PLATFORM=\"i586-mswin32\" %g s%@LDFLAGS@%-nologo%g s%@LIBS@%user32.lib advapi32.lib wsock32.lib%g s%@exec_prefix@%${prefix}%g @@ -34,7 +32,7 @@ s%@RANLIB@%rem%g s%@AR@%lib -nologo%g s%@LN_S@%%g s%@SET_MAKE@%%g -s%@LIBOBJS@% crypt.obj alloca.obj win32.obj isinf.obj isnan.obj%g +s%@LIBOBJS@% crypt.obj win32.obj isinf.obj isnan.obj%g s%@ALLOCA@%%g s%@DEFAULT_KCODE@%%g s%@EXEEXT@%.exe%g diff --git a/win32/dir.h b/win32/dir.h new file mode 100644 index 0000000000..8aa793de42 --- /dev/null +++ b/win32/dir.h @@ -0,0 +1,20 @@ +struct direct +{ + long d_namlen; + ino_t d_ino; + char d_name[256]; +}; +typedef struct { + char *start; + char *curr; + long size; + long nfiles; + struct direct dirstr; +} DIR; + +DIR* opendir(const char*); +struct direct* readdir(DIR *); +long telldir(DIR *); +void seekdir(DIR *, long); +void rewinddir(DIR *); +void closedir(DIR *); diff --git a/win32/resource.rb b/win32/resource.rb index d25c26e8f5..9222b829a4 100644 --- a/win32/resource.rb +++ b/win32/resource.rb @@ -75,7 +75,7 @@ BEGIN VALUE "FileVersion", "#{fversion}\\0" VALUE "Home Page", "http://www.ruby-lang.org/\\0" VALUE "InternalName", "#{base + ext}\\0" - VALUE "LegalCopyright", "Copyright (C) 1993-2000 Yukihiro Matsumoto\\0" + VALUE "LegalCopyright", "Copyright (C) 1993-2001 Yukihiro Matsumoto\\0" VALUE "OriginalFilename", "#{base + ext}\\0" VALUE "Platform", "#{RUBY_PLATFORM}\\0" VALUE "ProductVersion", "#{fversion}\\0" diff --git a/win32/win32.c b/win32/win32.c index bd07bb644e..ce9265f924 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -29,6 +29,7 @@ #ifndef index #define index(x, y) strchr((x), (y)) #endif +#define isdirsep(x) ((x) == '/' || (x) == '\\') #ifndef bool #define bool int @@ -357,7 +358,7 @@ isInternalCmd(char *cmd) int vecc = NtMakeCmdVector(cmd, &vec, FALSE); for( i = 0; szInternalCmds[i] ; i++){ - if(!strcmp(szInternalCmds[i], vec[0])){ + if(!strcasecmp(szInternalCmds[i], vec[0])){ fRet = 1; break; } @@ -777,10 +778,10 @@ char *cmd; strcpy(cmd2, cmd); a = argv; for (s = cmd2; *s;) { - while (*s && isspace(*s)) s++; + while (*s && ISSPACE(*s)) s++; if (*s) *(a++) = s; - while (*s && !isspace(*s)) s++; + while (*s && !ISSPACE(*s)) s++; if (*s) *s++ = '\0'; } @@ -1054,7 +1055,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) // ptr = cmdline+(cmdlen - 1); - while(ptr >= cmdline && isspace(*ptr)) + while(ptr >= cmdline && ISSPACE(*ptr)) --ptr; *++ptr = '\0'; @@ -1074,7 +1075,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) // zap any leading whitespace // - while(isspace(*ptr)) + while(ISSPACE(*ptr)) ptr++; base = ptr; @@ -1277,7 +1278,6 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) } -#if !defined __MINGW32__ // // UNIX compatible directory access functions for NT // @@ -1291,7 +1291,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) // DIR * -opendir(char *filename) +opendir(const char *filename) { DIR *p; long len; @@ -1309,9 +1309,9 @@ opendir(char *filename) // check to see if we\'ve got a directory // - if ((stat (filename, &sbuf) < 0 || + if ((win32_stat (filename, &sbuf) < 0 || sbuf.st_mode & _S_IFDIR == 0) && - (!isalpha(filename[0]) || filename[1] != ':' || filename[2] != '\0' || + (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' || ((1 << (filename[0] & 0x5f) - 'A') & GetLogicalDrives()) == 0)) { return NULL; } @@ -1466,7 +1466,6 @@ closedir(DIR *dirp) free(dirp->start); free(dirp); } -#endif // @@ -2425,13 +2424,23 @@ waitpid (pid_t pid, int *stat_loc, int options) int _cdecl gettimeofday(struct timeval *tv, struct timezone *tz) { - struct timeb tb; + SYSTEMTIME st; + time_t t; + struct tm tm; + + GetLocalTime(&st); + tm.tm_sec = st.wSecond; + tm.tm_min = st.wMinute; + tm.tm_hour = st.wHour; + tm.tm_mday = st.wDay; + tm.tm_mon = st.wMonth - 1; + tm.tm_year = st.wYear - 1900; + tm.tm_isdst = -1; + t = mktime(&tm); + tv->tv_sec = t; + tv->tv_usec = st.wMilliseconds * 1000; - ftime(&tb); - tv->tv_sec = tb.time; - tv->tv_usec = tb.millitm * 1000; - - return 0; + return 0; } char * @@ -2545,7 +2554,7 @@ myrename(const char *oldpath, const char *newpath) newatts = GetFileAttributes(newpath); if (oldatts == -1) { - printf("file to move doesn't exist"); + errno = GetLastError(); return -1; } @@ -2583,6 +2592,56 @@ myrename(const char *oldpath, const char *newpath) return res; } +static int +isUNCRoot(const char *path) +{ + if (path[0] == '\\' && path[1] == '\\') { + const char *p; + for (p = path + 3; *p; p = CharNext(p)) { + if (*p == '\\') + break; + } + if (p[0] && p[1]) { + for (p++; *p; p = CharNext(p)) { + if (*p == '\\') + break; + } + if (!p[0] || !p[1]) + return 1; + } + } + return 0; +} + +int +win32_stat(const char *path, struct stat *st) +{ + const char *p; + char *buf1 = ALLOCA_N(char, strlen(path) + 1); + char *buf2 = ALLOCA_N(char, MAXPATHLEN); + char *s; + int len; + + for (p = path, s = buf1; *p; p++, s++) { + if (*p == '/') + *s = '\\'; + else + *s = *p; + } + *s = '\0'; + len = strlen(buf1); + p = CharPrev(buf1, buf1 + len); + if (isUNCRoot(buf1)) { + if (*p != '\\') + strcat(buf1, "\\"); + } else if (*p == '\\' || *p == ':') + strcat(buf1, "."); + if (_fullpath(buf2, buf1, MAXPATHLEN)) + return stat(buf2, st); + else + return -1; +} + static long filetime_to_clock(FILETIME *ft) { diff --git a/win32/win32.h b/win32/win32.h index ebffc5c8ab..ffbe967703 100644 --- a/win32/win32.h +++ b/win32/win32.h @@ -162,6 +162,8 @@ extern "C++" { #define pclose _pclose #define strcasecmp _stricmp #define strncasecmp _strnicmp +#undef rb_sys_stat +#define rb_sys_stat win32_stat /* these are defined in nt.c */ #ifdef __MINGW32__ -- cgit v1.2.3