diff options
author | (no author) <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2001-05-25 21:10:58 +0000 |
---|---|---|
committer | (no author) <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2001-05-25 21:10:58 +0000 |
commit | e149ee88cf53bb5665ab240a138be41d0b337ea8 (patch) | |
tree | 6e0ff9f8c510431cf675ca9be2640d8761085b97 | |
parent | 99020d6e50702eb371111d73280eb80b4b29ba5b (diff) |
This commit was manufactured by cvs2svn to create tag
'v1_6_4_preview4'.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_6_4_preview4@1459 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
166 files changed, 11401 insertions, 4846 deletions
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. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! @@ -1,3 +1,1159 @@ +Sat May 26 00:15:57 2001 Usaku Nakamura <usa@osb.att.ne.jp> + + * win32/dir.h: replace missing/dir.h . + + * dir.c: ditto. + +Fri May 25 14:19:25 2001 K.Kosako <kosako@sofnec.co.jp> + + * 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 <knu@iDaemons.org> + + * MANIFEST: Re-adjust the entries to coincide with HEAD. + +Fri May 25 01:36:52 2001 Akinori MUSHA <knu@iDaemons.org> + + * MANIFEST: update the entries I forgot to add or remove. + +Thu May 24 16:08:21 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * mkconfig.rb: autoconf 2.50 support. + +Thu May 24 14:23:35 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (rb_yield_0): need argument adjustment for C defined + blocks too. + +Tue May 22 17:10:35 2001 K.Kosako <kosako@sofnec.co.jp> + + * variable.c (rb_alias_variable): should not allow variable + aliasing if $SAFE >= 4. + +Mon May 21 15:26:05 JST 2001 Keiju Ishitsuka <keiju@ishitsuka.com> + + * lib/irb/multi-irb.rb: delete japanese messages. + +Mon May 21 13:15:25 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * bignum.c (rb_big2str): t should be protected from GC. + +Sun May 20 00:28:43 2001 Akinori MUSHA <knu@iDaemons.org> + + * ext/socket/extconf.rb: do not clobber $CFLAGS when setting + -DSOCKS. + +Fri May 18 05:42:28 2001 Akinori MUSHA <knu@iDaemons.org> + + * 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 <knu@iDaemons.org> + + * 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 <green@FreeBSD.org> + + * lib/mkmf.rb: unbreak "make install". lib/* must be installed + under $rubylibdir, not under $libdir. + +Thu May 17 19:36:47 2001 Akinori MUSHA <knu@iDaemons.org> + + * 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 <knu@iDaemons.org> + + * 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 <matz@ruby-lang.org> + + * eval.c (rb_call0): address of local_vars might change during eval. + +Thu May 17 07:30:15 2001 Akinori MUSHA <knu@iDaemons.org> + + * ext/md5/md5.txt, ext/md5/md5.txt.jp: s/SuperClass/Superclass/. + +Thu May 17 06:37:14 2001 Akinori MUSHA <knu@iDaemons.org> + + * ext/md5/md5.txt: make wording fixes. + + * ext/md5/md5.txt.jp: ditto. + +Thu May 17 05:23:52 2001 Keiju Ishitsuka <keiju@ishitsuka.com> + * 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 <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <akr@m17n.org> + + * signal.c: SIGINFO added. + +Mon May 14 08:57:06 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (rb_ensure): should not SEGV when prot_tag is NULL. + +Sun May 13 23:49:25 2001 Usaku Nakamura <usa@osb.att.ne.jp> + + * win32/resource.rb: Modify copyright in resource script. + +Fri May 11 23:51:54 2001 Usaku Nakamura <usa@osb.att.ne.jp> + + * process.c: silence VC++ warnings. + + * sprintf.c: ditto. + +Fri May 11 03:38:11 2001 Akinori MUSHA <knu@iDaemons.org> + + * README.EXT: Document find_library(), with_config() and + dir_config(). + +Fri May 11 03:37:53 2001 Akinori MUSHA <knu@iDaemons.org> + + * 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 <zn@mbf.nifty.com> + + * README, README.jp: Fix CVS access and mailing lists info. + +Fri May 11 02:00:44 2001 Ryo HAYASAKA <ryoh@jaist.ac.jp> + + * bignum.c (bigdivrem): access boundary bug. + +Tue May 8 17:12:43 2001 K.Kosako <kosako@sofnec.co.jp> + + * 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 <knu@iDaemons.org> + + * 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 <knu@iDaemons.org> + + * 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 <knu@iDaemons.org> + + * 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 <knu@iDaemons.org> + + * sample/rbc.rb: Obsoleted by IRB. + +Mon May 7 15:58:45 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * lib/ftools.rb (syscopy): chmod destination file only if + it does not exist. + +Thu May 3 03:41:01 2001 SHIROYAMA Takayuki <psi@fortune.nest.or.jp> + + * 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 <eban@ruby-lang.org> + + * dir.c (rb_glob, rb_iglob): remove unnecessary FNM_PATHNAME. + +Wed May 2 11:46:13 2001 K.Kosako <kosako@sofnec.co.jp> + + * eval.c (block_pass): should not downgrade safe level. + +Tue May 1 17:55:58 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * parse.y (yylex): lex_state after RESCUE_MOD should be EXPR_BEG. + +Tue May 1 03:36:50 2001 Akinori MUSHA <knu@iDaemons.org> + + * 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 <eban@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * eval.c (rb_eval): should preserve value of ruby_errinfo. + +Thu Apr 26 10:36:09 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (rb_thread_schedule): infinite sleep should not cause + dead lock. + +Wed Apr 25 16:40:44 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * array.c (rb_ary_flatten_bang): proper recursive detection. + +Wed Apr 25 15:36:15 2001 K.Kosako <kosako@sofnec.co.jp> + + * eval.c (yield_under): need not to prohibit at safe level 4. + +Tue Apr 24 16:03:25 2001 Hiroshi Igarashi <iga@ruby-lang.org> + + * 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 <knu@iDaemons.org> + + * 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 <matz@ruby-lang.org> + + * ruby.c (set_arg0): wrong predicate when new $0 value is bigger + than original space. + +Mon Apr 23 14:43:59 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * marshal.c (w_float): precision changed to "%.16g" + +Sat Apr 21 22:07:58 2001 Guy Decoux <decoux@moulon.inra.fr> + + * eval.c (rb_call0): wrong retry behavior. + +Fri Apr 20 19:12:20 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * numeric.c (fix_aref): a bug on long>int architecture. + +Fri Apr 20 14:57:15 2001 K.Kosako <kosako@sofnec.co.jp> + + * eval.c (rb_eval_string_wrap): should restore ruby_wrapper. + +Wed Apr 18 04:37:51 2001 Wakou Aoyama <wakou@fsinet.or.jp> + + * lib/cgi.rb: CGI::Cookie: no use PATH_INFO. + +Wed Apr 18 00:24:40 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * regex.c (re_compile_pattern): char class at either edge of range + should be invalid. + +Tue Apr 17 16:54:39 2001 K.Kosako <kosako@sofnec.co.jp> + + * eval.c (safe_getter): should use INT2NUM(). + +Tue Apr 17 15:12:56 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * bignum.c (rb_big2long): 2**31 cannot fit in 31 bit long. + +Sat Apr 14 22:46:43 2001 Guy Decoux <decoux@moulon.inra.fr> + + * regex.c (calculate_must_string): wrong length calculation. + +Sat Apr 14 13:33:32 2001 Usaku Nakamura <usa@osb.att.ne.jp> + + * win32/config.status.in: no longer use missing/alloca.c. + + * win32/Makefile.sub: ditto. + +Fri Apr 13 12:40:48 2001 K.Kosako <kosako@sofnec.co.jp> + + * eval.c (rb_thread_start_0): fixed memory leak. + +Fri Apr 13 16:41:18 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * parse.y (none): should clear cmdarg_stack too. + +Fri Apr 13 06:19:29 2001 GOTOU YUUZOU <gotoyuzo@notwork.org> + + * io.c (rb_fopen): use setvbuf() to avoid recursive malloc() on + some platforms. + +Wed Apr 11 23:36:26 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <kosako@sofnec.co.jp> + + * 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 <matz@ruby-lang.org> + + * 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 <nobu.nakada@nifty.ne.jp> + + * io.c (opt_i_set): should strdup() inplace_edit string. + +Mon Apr 9 23:29:54 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (exec_under): need to push cref too. + +Mon Apr 9 12:05:44 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * file.c (Init_File): should redifine "new" class method. + +Mon Apr 9 11:56:52 2001 Shugo Maeda <shugo@ruby-lang.org> + + * lib/net/imap.rb: fix typo. + +Thu Apr 5 22:40:12 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <kosako@sofnec.co.jp> + + * object.c (rb_obj_is_instance_of): nil belongs to false, not true. + +Thu Apr 5 02:19:03 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <knu@iDaemons.org> + + * 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 <eban@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <shugo@ruby-lang.org> + + * lib/monitor.rb (wait): ensure reentrance. + + * lib/monitor.rb (wait): fix timeout support. + +Mon Apr 2 12:44:53 2001 Shugo Maeda <shugo@ruby-lang.org> + + * lib/net/imap.rb: backport from ruby-1.7. + +Mon Apr 2 01:16:24 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * 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 <toyofuku@juice.or.jp> + + * numeric.c (flodivmod): a bug in no fmod case. + +Sun Apr 1 18:36:14 2001 Koji Arai <JCA02266@nifty.ne.jp> + + * process.c (pst_wifsignaled): should apply WIFSIGNALED for status + (int), not st (VALUE). + +Sat Mar 31 03:24:10 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * class.c (rb_include_module): module inclusion should be check + taints. + +Fri Mar 30 12:51:19 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * class.c (rb_include_module): freeze check at first. + +Thu Mar 29 17:05:09 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (rb_attr): sprintf() and rb_intern() moved into + conditional body. + +Wed Mar 28 23:43:00 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> + + * 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 <knu@iDaemons.org> + + * ext/extmk.rb.in, lib/mkmf.rb: move C++ rules to the right place. + +Wed Mar 28 17:39:04 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * object.c (rb_str2cstr): warn if string contains \0 and length + value is ignored. + +Wed Mar 28 15:00:31 2001 K.Kosako <kosako@sofnec.co.jp> + + * class.c (rb_singleton_class_clone): should copy class constant + table as well. + +Wed Mar 28 15:03:23 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * win32/Makefile.sub: disable global optimization. + +Tue Mar 27 15:00:54 2001 K.Kosako <kosako@sofnec.co.jp> + + * 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 <matz@ruby-lang.org> + + * ruby.h: changed "extern INLINE" to "static inline". + +Mon Mar 26 23:19:33 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * time.c (rb_strftime): check whether strftime returns empty string. + +Mon Mar 26 18:14:47 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * eval.c: remove TMP_PROTECT_END to prevent C_ALLOCA crash. + +Mon Mar 26 14:04:41 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * ext/Win32API/Win32API.c: remove Init_win32api(). + +Sat Mar 24 23:44:50 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <psi@fortune.nest.or.jp> + + * 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 <matz@ruby-lang.org> + + * marshal.c (w_object): should truncate trailing zero short for + bignums. + +Thu Mar 22 22:15:45 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * ext/Win32API/extconf.rb: add -fno-omit-frame-pointer. + +Thu Mar 22 17:43:44 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * win32/win32.c (win32_stat): WinNT/2k "//host/share" support. + +Wed Mar 21 01:26:14 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * gc.c (id2ref): sometimes confused symbol and reference. + +Tue Mar 20 23:09:33 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * win32/win32.c (win32_stat): UNC support. + + * dir.c (extract_path): fix "./*" problem. + +Mon Mar 19 19:14:47 2001 Guy Decoux <decoux@moulon.inra.fr> + + * marshal.c (shortlen): shortlen should return number of bytes + written. + +Mon Mar 19 18:56:55 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * stable version 1.6.3 released. + +Mon Mar 19 16:52:23 2001 K.Kosako <kosako@sofnec.co.jp> + + * 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 <matz@ruby-lang.org> + + * 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 <JCA02266@nifty.ne.jp> + + * 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 <wakou@fsinet.or.jp> + + * lib/cgi.rb: // === '' --> //.match('') + + * lib/cgi.rb: cgi#header(): improvement for mod_ruby. + + * lib/cgi.rb: cgi#rfc1123date(): improvement. + thanks to TADA Tadashi <sho@spc.gr.jp>. + + * lib/cgi.rb: cgi#rfc1123date(): document bug fix. + thanks to Kazuhiro NISHIYAMA <zn@mbf.nifty.com>. + + * lib/cgi.rb: cgi#header(): bug fix. + thanks to IWATSUKI Hiroyuki <don@na.rim.or.jp>. + +Fri Mar 16 17:21:25 2001 Akinori MUSHA <knu@iDaemons.org> + + * 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 <matz@ruby-lang.org> + + * eval.c (rb_thread_schedule): raise FATAL just once to + THREAD_TO_KILL. + +Wed Mar 14 10:41:34 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * dir.c (rb_glob_helper): fix drive letter handling on DOSISH. + +Tue Mar 13 15:01:12 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * 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 <matz@ruby-lang.org> + + * io.c (argf_seek): wrong calling sequence of rb_io_seek(). + +Mon Mar 12 18:59:38 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * lib/mkmf.rb (create_makefile): save/restore $libs and $LIBPATH. + +Sun Mar 11 00:55:31 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * lib/mkmf.rb (install_rb): fix handling of destination path. + +Sat Mar 10 02:34:18 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * 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 <aamine@dp.u-netsurf.ne.jp> + + * lib/net/protocol.rb: one write(2) per one line. + +Wed Mar 7 14:26:11 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * math.c (math_log, math_log10): should return NaN if x < 0.0 + on Cygwin. + +Thu Mar 7 10:31:26 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> + + * parse.y (stmt): while/until modifier must work for empty body. + +Tue Mar 6 22:53:58 2001 Kazuhiro Yoshida <moriq.kazuhiro@nifty.ne.jp> + + * ruby.c (ruby_set_argv): clear ARGV contents before adding args. + +Tue Mar 6 10:50:29 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * win32/win32.c (gettimeofday): use GetLocalTime() instead of ftime() + for high-resolution timing. + +Sun Mar 4 20:45:20 2001 Akinori MUSHA <knu@iDaemons.org> + + * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C + rules. + +Sun Mar 4 17:01:09 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * string.c (trnext): support backslash escape in String#tr. + +Wed Feb 28 11:02:41 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_delete_bang): delete! should take at least 1 + argument. + +Tue Feb 27 16:38:15 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <nobu.nakada@nifty.ne.jp> + + * 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 <matz@ruby-lang.org> + + * ruby.c (proc_options): call ruby_show_version() just once. + +Mon Feb 26 00:04:52 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <wakou@fsinet.or.jp> + + * lib/net/telnet.rb: #telnetmode(), #binmode(): bug fix. + thanks to nobu.nakada@nifty.ne.jp. + +Mon Feb 26 04:55:50 2001 Wakou Aoyama <wakou@fsinet.or.jp> + + * lib/cgi.rb: CGI#form(): bug fix. + thanks to MoonWolf <moonwolf@moonwolf.com>. + + * lib/cgi.rb: CGI#rfc1123_date(): improvement. + thanks to Tomoyasu Akita <genzo-@dm4lab.to>. + + * lib/cgi.rb: CGI#header(): improvement for mod_ruby. + thanks to Shugo Maeda <shugo@ruby-lang.org>. + +Sun Feb 25 02:45:30 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * file.c (rb_file_s_rename): avoid Cygwin's bug. + +Sat Feb 24 23:32:55 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (rb_thread_fd_close): should save current context before + raising exception. + +Sat Feb 24 22:14:00 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * win32/win32.c (myrename): fix error handling. + +Sat Feb 24 15:43:31 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * 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 <aamine@dp.u-netsurf.ne.jp> + + * lib/net/http.rb: always close connection if body is not exist. + +Fri Feb 23 13:27:05 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * lib/net/http.rb: keep-alive detection was incomplete. + +Fri Feb 23 08:24:53 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * 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 <matz@ruby-lang.org> + + * bignum.c (rb_big2long): should not raise RangeError for Bignum + LONG_MIN value. + +Mon Feb 19 17:46:37 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_substr): "a"[1,2] should return ""; need + rubicon upgrade. + +Mon Feb 19 01:55:43 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (secure_visibility): visibility check for untainted modules. + +Mon Feb 19 00:29:29 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> + + * 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 <eban@ruby-lang.org> + + * 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 <yashi@yashi.com> + + * array.c (rb_ary_subseq): wrong boundary check. + +Fri Feb 16 01:44:56 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * io.c (set_outfile): f should be the FILE* from the assigning value. + +Thu Feb 15 11:33:49 2001 Shugo Maeda <shugo@ruby-lang.org> + + * lib/cgi/session.rb (close): fixed reversed condition. + +Wed Feb 14 17:28:24 2001 Shugo Maeda <shugo@ruby-lang.org> + + * lib/net/imap.rb: supports unknown resp_text_code. + +Wed Feb 14 00:44:17 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * dir.c (lstat): should use rb_sys_stat if lstat(2) is not + available. + +Tue Feb 13 17:00:18 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * lib/net/http.rb: supports HTTP 1.0 server. + +Tue Feb 13 01:13:43 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * 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 <nobu.nakada@nifty.ne.jp> + + * hash.c (rb_any_hash): dumped core on machines sizeof(int) != sizeof(long). + +Sat Feb 10 23:07:15 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <nobu.nakada@nifty.ne.jp> + + * 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 <eban@ruby-lang.org> + + * ruby.c (ruby_init_loadpath): convert '\\' to '/' + before finding executable file path. + +Fri Feb 9 17:41:53 2001 Triet H. Lai <thlai@mail.usyd.edu.au> + + * dir.c (rb_glob_helper): do not follow symbolic links. + +Fri Feb 8 23:53:08 2001 Usaku Nakamura <usa@osb.att.ne.jp> + + * win32/config.h.in (inline): add inline definition. + +Thu Feb 8 21:27:24 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * 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 <nobu.nakada@nifty.ne.jp> + + * parse.y (parse_quotedwords): %w should allow parenthesis escape. + +Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * parse.y (parse_qstring): %q should allow terminator escape. + +Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * re.c (rb_reg_equal): all option flags should be same to be equal. + +Tue Feb 6 21:01:29 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * 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 <wbs01621@mail.wbs.ne.jp> + + * 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 <usa@osb.att.ne.jp> + + * win32/win32.c (isInternalCmd): ignore case for shell's internal + command. (marge from HEAD) + +Fri Feb 2 16:14:51 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * 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 <toyofuku@juice.or.jp> + + * 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 <matz@ruby-lang.org> + + * string.c (str_independent): should not clear str->orig here. + it's too early. + +Wed Jan 24 01:45:49 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <eban@ruby-lang.org> + + * mkconfig.rb: autoconf 2.49 support. + +Sat Jan 20 03:54:00 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <knu@iDaemons.org> + + * lib/irb/ruby-lex.rb: Merge from HEAD: rev.1.4 + +Wed Jan 17 13:28:26 2001 WATANABE Hirofumi <eban@ruby-lang.org> + + * configure.in: remove DEFS definition. + + * mkconfig.rb: ditto. + + * win32/config.status.in: ditto. + +Tue Jan 16 16:59:14 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * lib/net/protocol.rb: ignore EOFError for read + +Sun Jan 14 21:49:28 2001 Koji Arai <JCA02266@nifty.ne.jp> + + * sprintf.c (rb_f_sprintf): simple typo. binary base should be 2, + not '2'. + +Sun Jan 14 02:49:57 2001 Minero Aoki <aamine@dp.u-netsurf.ne.jp> + + * 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 <eban@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * string.c (rb_str_reverse_bang): forgot to call rb_str_modify(). + +Tue Jan 9 17:41:40 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <decoux@moulon.inra.fr> + + * file.c (path_check_1): should restore modified path. + +Mon Jan 8 21:24:37 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * pack.c (pack_pack): template "m2" or "u2" caused inifinite loop. + +Fri Jan 5 01:02:17 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * eval.c (ruby_finalize): should enclosed by PUSH_TAG/POP_TAG. + +Sun Dec 31 01:39:16 2000 Guy Decoux <decoux@moulon.inra.fr> + + * eval.c (rb_mod_define_method): wrong comparison for blocks. + +Sat Dec 30 19:28:50 2000 Yukihiro Matsumoto <matz@ruby-lang.org> + + * gc.c (id2ref): should handle Symbol too. + + * gc.c (id2ref): should print original ptr value + +Sat Dec 30 03:14:22 2000 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * gc.c (mem_error): prohibit recursive mem_error(). + (ruby-bugs-ja:PR#36) + +Fri Dec 29 11:05:41 2000 Yukihiro Matsumoto <matz@ruby-lang.org> + + * 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 <nakahiro@sarion.co.jp> + + * 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 <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * string.c (rb_str_inspect): should treat multibyte chracters + properly. + +Mon Dec 25 17:49:08 2000 K.Kosako <kosako@sofnec.co.jp> + + * 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 <matz@ruby-lang.org> + + * 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 <matz@ruby-lang.org> + + * stable version 1.6.2 released. + Mon Dec 25 05:11:04 2000 Wakou Aoyama <wakou@fsinet.or.jp> * lib/cgi.rb: version 2.1.2 (some bug fixes). @@ -21,10 +1177,6 @@ Mon Dec 25 00:04:54 2000 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> * eval.c (rb_thread_schedule): initial value of `max' changed to -1. -Fri Dec 22 17:59:30 2000 Yukihiro Matsumoto <matz@ruby-lang.org> - - * stable version 1.6.2 released. - Mon Dec 25 00:16:14 2000 Yukihiro Matsumoto <matz@ruby-lang.org> * string.c (rb_str_replace_m): copy-on-write replace. @@ -85,7 +1237,7 @@ Tue Dec 19 13:44:50 2000 K.Kosako <kosako@sofnec.co.jp> Tue Dec 19 00:57:10 2000 Yukihiro Matsumoto <matz@ruby-lang.org> - * 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 +1989,7 @@ Sat Sep 23 03:06:25 2000 Yukihiro Matsumoto <matz@ruby-lang.org> Fri Sep 22 15:46:21 2000 Minero Aoki <aamine@dp.u-netsurf.ne.jp> - * 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 <eban@os.rim.or.jp> @@ -894,7 +2046,7 @@ Wed Sep 20 23:21:38 2000 Yukihiro Matsumoto <matz@ruby-lang.org> Wed Sep 20 14:01:45 2000 Yukihiro Matsumoto <matz@ruby-lang.org> - * 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 +2111,7 @@ Thu Sep 14 02:46:54 2000 Yukihiro Matsumoto <matz@ruby-lang.org> Wed Sep 13 17:01:03 2000 Yukihiro Matsumoto <matz@ruby-lang.org> - * 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 <matz@ruby-lang.org> @@ -1084,7 +2236,7 @@ Fri Sep 1 10:36:29 2000 Yukihiro Matsumoto <matz@ruby-lang.org> * 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 +2404,7 @@ Fri Aug 11 15:43:46 2000 Yukihiro Matsumoto <matz@ruby-lang.org> Thu Aug 10 08:05:03 2000 Yukihiro Matsumoto <matz@ruby-lang.org> - * 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 <eban@os.rim.or.jp> @@ -1425,7 +2577,7 @@ Tue Jul 18 14:58:30 2000 Yukihiro Matsumoto <matz@netlab.co.jp> Mon Jul 17 04:29:50 2000 Minero Aoki <aamine@dp.u-netsurf.ne.jp> - * 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 <dave@thomases.com> @@ -1522,7 +2674,7 @@ Mon Jul 10 09:07:54 2000 Yukihiro Matsumoto <matz@netlab.co.jp> Sat Jul 8 23:08:40 2000 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 <komatsu@sarion.co.jp> @@ -1597,7 +2749,7 @@ Wed Jul 5 09:47:14 2000 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 +2840,7 @@ Mon Jul 3 13:15:02 2000 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 +2883,7 @@ Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto <matz@netlab.co.jp> Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 <komatsu@sarion.co.jp> @@ -2107,12 +3259,12 @@ Fri Jun 9 15:11:35 2000 Yukihiro Matsumoto <matz@netlab.co.jp> Thu Jun 8 14:25:45 2000 Hiroshi Igarashi <iga@ruby-lang.org> * 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 <dave@thomases.com> * numeric.c: add nan?, infinite?, and finite? to Float - + Thu Jun 8 00:31:04 2000 WATANABE Hirofumi <eban@os.rim.or.jp> * regex.h: export re_mbctab properly on cygwin. @@ -2217,11 +3369,11 @@ Sun May 28 19:21:43 2000 WATANABE Hirofumi <eban@os.rim.or.jp> * ruby.h: ditto. * main.c: turn off command line mingw32's globbing. - + Wed May 25 22:25:13 2000 WATANABE Hirofumi <eban@os.rim.or.jp> - + * ext/extmk.rb.in: use "ftools" instead of "rm -f". - + * lib/mkmf.rb: ditto. Thu May 25 22:01:32 2000 Katsuyuki Komatsu <komatsu@sarion.co.jp> @@ -2623,7 +3775,7 @@ Mon May 1 23:42:44 2000 WATANABE Hirofumi <eban@os.rim.or.jp> * 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 +3976,13 @@ Sat Mar 25 23:21:10 2000 Yukihiro Matsumoto <matz@netlab.co.jp> * marshal.c (w_object): symbols should be converted to ID before dumping out. +Sun Mar 25 16:52:48 2001 Koji Arai <JCA02266@nifty.ne.jp> + + * 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 <matz@netlab.co.jp> * file.c (test_check): should have checked exact number of arguments. @@ -3924,7 +5083,7 @@ Thu Oct 21 16:14:19 1999 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 <matz@netlab.co.jp> @@ -4832,7 +5991,7 @@ Thu Jun 10 16:41:48 1999 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 +7592,28 @@ Sun Nov 15 15:44:07 1998 Tadayoshi Funaba <tadf@kt.rim.or.jp> Sat Nov 14 11:02:05 1998 Motoyuki Kasahara <m-kasahr@sra.co.jp> * 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 <m-kasahr@sra.co.jp> * 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 <kbk@kt.rim.or.jp> @@ -6519,7 +7684,7 @@ Sun Nov 1 01:18:52 1998 EGUCHI Osamu <eguchi@shizuokanet.ne.jp> Sat Oct 31 23:18:34 1998 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 +7748,26 @@ Wed Oct 21 14:21:06 1998 Yukihiro Matsumoto <matz@netlab.co.jp> Mon Oct 19 11:50:00 1998 Motoyuki Kasahara <m-kasahr@sra.co.jp> * 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 <eguchi@shizuokanet.ne.jp> @@ -7346,7 +8519,7 @@ Mon May 18 16:40:50 1998 MAEDA shugo <shugo@aianet.ne.jp> * glob.c: #include <alloca.h> added. Mon May 18 14:52:21 1998 Yukihiro Matsumoto <matz@netlab.co.jp> - + * experimental release 1.1b9_21. Mon May 18 03:27:57 1998 MAEDA shugo <shugo@aianet.ne.jp> @@ -8648,7 +9821,7 @@ Thu Dec 11 13:14:35 1997 Yukihiro Matsumoto <matz@netlab.co.jp> not exist. * ext/curses/curses.c: remove CHECK macro for BSD curses. - + Thu Dec 11 12:44:01 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp> * pack.c: sun4 cc patch @@ -8775,7 +9948,7 @@ Wed Nov 12 13:44:47 1997 Yukihiro Matsumoto <matz@netlab.co.jp> Mon Nov 10 11:24:51 1997 Yukihiro Matsumoto <matz@netlab.co.jp> - * 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 +10204,7 @@ Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto <matz@netlab.co.jp> * 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 +10286,7 @@ Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp> * parse.y: did not generate here document strings properly. Mon Sep 1 11:43:57 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp> - + * parse.y (yylex): heredoc dropped an extra character. Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto <matz@netlab.co.jp> @@ -9256,7 +10429,7 @@ Sat Aug 16 00:17:44 1997 Yukihiro Matsumoto <matz@netlab.co.jp> Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp> * eval.c (call_trace_func): block context switch in the trace - function. + function. * eval.c (rb_eval): clear method cache at class extension. @@ -77,9 +77,17 @@ djgpp/config.sed djgpp/configure.bat djgpp/mkver.sed cygwin/GNUmakefile.in +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 +109,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 +161,16 @@ lib/profile.rb lib/pstore.rb lib/rational.rb lib/readbytes.rb +lib/resolv.rb +lib/resolv-replace.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 +188,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 +202,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 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: @@ -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 <ruby-talk-ctl@netlab.co.jp>. +in the mail body (not subject) to the address <ruby-talk-ctl@ruby-lang.org>. * 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-<withval>. + + dir_config(target[, default_dir]) + dir_config(target[, default_include, default_lib]) + +Parses the command line options and adds the directories specified by +--with-<target>-dir, --with-<target>-include, and/or --with-<target>-lib +to $CFLAGS and/or $LDFLAGS. --with-<target>-dir=/path is equivalent to +--with-<target>-include=/path/include --with-<target>-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-<withval>¤Ç»ØÄꤵ¤ì¤¿¥ª¥×¥·¥ç¥óÃͤòÆÀ¤ë¡¥ + ¥³¥Þ¥ó¥É¥é¥¤¥ó¾å¤Î--with-<withval>¤Ç»ØÄꤵ¤ì¤¿¥ª¥×¥·¥ç¥óÃͤòÆÀ¤ë¡¥ -dir_config(target) +dir_config(target[, default_dir]) +dir_config(target[, default_include, default_lib]) - --with-<target>-dir, --with-<target>-include, --with-<target>-lib - ¤Î¤¤¤º¤ì¤«¤Ç»ØÄꤵ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê¤ò $CFLAGS ¤ä $LDFLAGS - ¤ËÄɲ乤롥 + ¥³¥Þ¥ó¥É¥é¥¤¥ó¾å¤Î--with-<target>-dir, --with-<target>-include, + --with-<target>-lib¤Î¤¤¤º¤ì¤«¤Ç»ØÄꤵ¤ì¤ë¥Ç¥£¥ì¥¯¥È¥ê¤ò + $CFLAGS ¤ä $LDFLAGS ¤ËÄɲ乤롥--with-<target>-dir=/path¤Ï + --with-<target>-include=/path/include --with-<target>-lib=/path/lib + ¤ÈÅù²Á¤Ç¤¢¤ë¡¥Äɲ䵤줿 include ¥Ç¥£¥ì¥¯¥È¥ê¤È lib ¥Ç¥£¥ì¥¯¥È¥ê¤Î + ÇÛÎó¤òÊÖ¤¹¡¥ ([include_dir, lib_dir]) /* * Local variables: @@ -34,10 +34,10 @@ Ruby¤Ï¥Æ¥¥¹¥È½èÍý´Ø·¸¤ÎǽÎϤʤɤËÍ¥¤ì¡¤Perl¤ÈƱ¤¸¤¯¤é¤¤¶¯ÎÏ ** 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¤Î¥Û¡¼¥à¥Ú¡¼¥¸¤ÎURL¤Ï Ruby¤Î¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤¬¤¢¤ê¤Þ¤¹¡£»²²Ã´õ˾¤ÎÊý¤Ï - ruby-list-ctl@netlab.co.jp + ruby-list-ctl@ruby-lang.org ¤Þ¤ÇËÜʸ¤Ë @@ -65,11 +65,12 @@ Ruby³«È¯¼Ô¸þ¤±¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤â¤¢¤ê¤Þ¤¹¡£¤³¤Á¤é¤Ç¤Ï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³ÈÄ¥¥â¥¸¥å¡¼¥ë¤Ë¤Ä¤¤¤ÆÏ䷹礦ruby-ext¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤È °Ê²¼¤Î¼ê½ç¤Ç¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡¥ - 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³ÈÄ¥¥â¥¸¥å¡¼¥ë¤Ë¤Ä¤¤¤ÆÏ䷹礦ruby-ext¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤È ³ÈÄ¥¥â¥¸¥å¡¼¥ë¤òÍøÍѤ¹¤ë¤¿¤á¤Ë¤Ï¡¤¤¢¤é¤«¤¸¤áÀÅŪ¤Ë¥ê¥ó ¥¯¤·¤Æ¤ª¤¯É¬Íפ¬¤¢¤ê¤Þ¤¹¡¥ - 4. make¤ò¼Â¹Ô¤·¤Æ¥³¥ó¥Ñ¥¤¥ë¤¹¤ë + 5. make¤ò¼Â¹Ô¤·¤Æ¥³¥ó¥Ñ¥¤¥ë¤¹¤ë - 5. make test¤Ç¥Æ¥¹¥È¤ò¹Ô¤¦¡¥ + 6. make test¤Ç¥Æ¥¹¥È¤ò¹Ô¤¦¡¥ ¡Ötest succeeded¡×¤Èɽ¼¨¤µ¤ì¤ì¤ÐÀ®¸ù¤Ç¤¹¡¥¤¿¤À¤·¥Æ¥¹¥È ¤ËÀ®¸ù¤·¤Æ¤â´°àú¤À¤ÈÊݾڤµ¤ì¤Æ¤¤¤ëÌõ¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡¥ - 6. make install + 7. make install root¤Çºî¶È¤¹¤ëɬÍפ¬¤¢¤ë¤«¤â¤·¤ì¤Þ¤»¤ó¡¥ @@ -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; i<RARRAY(ary1)->len; 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; i<RARRAY(ary1)->len; 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; i<RARRAY(ary2)->len; 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; i<RARRAY(ary)->len; i++) { + while (i<RARRAY(ary)->len) { 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; @@ -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]; @@ -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; @@ -54,6 +44,47 @@ clone_method(mid, body, tbl) } 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..65a560be28 100644 --- a/configure.in +++ b/configure.in @@ -90,14 +90,20 @@ 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) + echo 'main(){}' > conftest.c + if $CC -mwin32 -c conftest.c 2> /dev/null; then + MWIN32=-mwin32 + CFLAGS="$CFLAGS $MWIN32" + fi + ;; esac +AC_SUBST(MWIN32) AC_PROG_LN_S AC_PROG_MAKE_SET @@ -163,6 +169,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=yes]) + dnl Checks for libraries. case "$target_os" in nextstep*) ;; @@ -171,7 +185,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 @@ -184,6 +199,8 @@ mingw*) LIBS="-lwsock32 -lmsvcrt $LIBS" ac_cv_func_times=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 +217,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 <osreldate.h> +#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 +364,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 +429,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 +501,7 @@ if test "$with_dln_a_out" != yes; then nextstep*) ;; openstep*) ;; rhapsody*) ;; - darwin*) ;; + darwin*) CCDLFLAGS=-fno-common;; human*) ;; bsdi*) ;; beos*) ;; @@ -494,6 +543,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 +808,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 +820,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 +828,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 +836,9 @@ if test "$enable_shared" = 'yes'; then LIBRUBY_ALIASES= # a.out platforms fi ;; + openbsd*) + SOLIBS='$(LIBS)' + ;; solaris*) XLDFLAGS='-R${prefix}/lib' ;; @@ -806,6 +865,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 +893,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 +956,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 +1027,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..0e89d15dec 100644 --- a/cygwin/GNUmakefile.in +++ b/cygwin/GNUmakefile.in @@ -21,7 +21,7 @@ $(LIBRUBY_SO): $(RUBYDEF) $(LIBRUBY_SO).res.@OBJEXT@ $(LIBRUBY): $(LIBRUBY_SO) %.res.@OBJEXT@: %.rc - @WINDRES@ --include-dir . --include-dir $(<D) --include-dir $(srcdir)/win32 $< $@ + @WINDRES@ --preprocessor '$(CC) -E -xc-header -DRC_INVOKE @MWIN32@' --include-dir . --include-dir $(<D) --include-dir $(srcdir)/win32 $< $@ $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(LIBRUBY_SO).rc: rbconfig.rb @@MINIRUBY@ $(srcdir)/win32/resource.rb \ @@ -26,10 +26,10 @@ #include <unistd.h> #endif -#if HAVE_DIRENT_H +#if defined HAVE_DIRENT_H && !defined NT # include <dirent.h> # define NAMLEN(dirent) strlen((dirent)->d_name) -#elif HAVE_DIRECT_H +#elif defined HAVE_DIRECT_H && !defined NT # include <direct.h> # define NAMLEN(dirent) strlen((dirent)->d_name) #else @@ -44,8 +44,8 @@ # if HAVE_NDIR_H # include <ndir.h> # 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 <ctype.h> +#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) == '\\') @@ -130,13 +134,13 @@ range(pat, test, flags) ((s) == string || pathname && isdirsep(*(s)))) 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; @@ -531,7 +535,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 { @@ -568,7 +576,7 @@ rb_glob_helper(path, flag, func, arg) char *p, *m; if (!has_magic(path, 0)) { - if (stat(path, &st) == 0) { + if (rb_sys_stat(path, &st) == 0) { (*func)(path, arg); } return; @@ -601,12 +609,27 @@ rb_glob_helper(path, flag, func, arg) rb_glob_helper(buf, flag, 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,7 +637,15 @@ 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, flag, func, arg); + } free(buf); continue; } @@ -662,7 +693,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 +702,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 +710,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 @@ -753,10 +791,12 @@ dir_s_glob(dir, str) char buffer[MAXPATHLEN], *buf = buffer; 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); @@ -783,14 +823,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=. @@ -1166,7 +1166,7 @@ dln_strerror() } -#if defined(_AIX) +#if defined(_AIX) && ! defined(_IA64) static void aix_loaderror(const char *pathname) { @@ -1214,7 +1214,7 @@ aix_loaderror(const char *pathname) } #endif -void +void* dln_load(file) const char *file; { @@ -1234,23 +1234,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 +1274,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 +1305,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 +1322,7 @@ dln_load(file) aix_loaderror(file); } (*init_fct)(); - return; + return (void*)init_fct; } #endif /* _AIX */ @@ -1362,7 +1361,7 @@ dln_load(file) init_fct = (void(*)())init_address; (*init_fct)(); - return; + return (void*)init_address; } #else/* OPENSTEP dyld functions */ { @@ -1392,7 +1391,7 @@ dln_load(file) init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); (*init_fct)(); - return; + return (void*)init_fct; } #endif /* rld or dyld */ #endif @@ -1440,7 +1439,7 @@ dln_load(file) /* call module initialize function. */ (*init_fct)(); - return; + return (void*)img_id; } #endif /* __BEOS__*/ @@ -1488,7 +1487,7 @@ dln_load(file) init_fct = (void (*)())symAddr; (*init_fct)(); - return; + return (void*)init_fct; } #endif /* __MACOS__ */ @@ -1669,7 +1668,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)) { @@ -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/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 <<END + foo = 1 + foo + END + --- + foo = 1 + ==>1 + foo + ==>1 + +=== XMP¥¤¥ó¥¹¥¿¥ó¥¹¤òÍѤ¤¤ë. + +¤³¤Î¾ì¹ç¤Ï, XMP¤¬¥³¥ó¥Æ¥¥¹¥È¾ðÊó¤ò»ý¤Ä¤Î¤Ç, ÊÑ¿ô¤ÎÃͤʤɤòÊÝ»ý¤·¤Æ¤¤ +¤Þ¤¹. + + require "irb/xmp" + xmp = XMP.new + xmp.puts <<END + foo = 1 + foo + END + xmp.puts <<END + foo + END + === + foo = 1 + ==>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 + #<Object:0x4027146c> + + ((|ÊÑ¿ô̾.|))¤Î¸å¤Ë(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..528e5e17fb --- /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 + `defalut', `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 (#<Thread:0x400fb7e4> : stop) + #1->irb#1 on main (#<Thread:0x40125d64> : 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 (#<Thread:0x400fb7e4> : running) + #1->irb#1 on main (#<Thread:0x40125d64> : stop) + #2->irb#2 on Foo (#<Thread:0x4011d54c> : 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 + #<Foo:0x4010af3c> + irb(main):008:0> irb f # invoke subirb which has the + # context of f (instance of Foo) + irb#3(#<Foo:0x4010af3c>):001:0> jobs + #0->irb on main (#<Thread:0x400fb7e4> : stop) + #1->irb#1 on main (#<Thread:0x40125d64> : stop) + #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop) + #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running) + nil + irb#3(#<Foo:0x4010af3c>):002:0> foo # evaluate f.foo + 1nil + irb#3(#<Foo:0x4010af3c>):003:0> bar # evaluate f.bar + barnil + irb#3(#<Foo:0x4010af3c>):004:0> kill 1, 2, 3# kill job + nil + irb(main):009:0> jobs + #0->irb on main (#<Thread:0x400fb7e4> : 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 #<Object:0x40283118> (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 #<Object:0x4013d0f0> + (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..8b0de3cc62 --- /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 + ¥×¥í¥ó¥×¥È¥â¡¼¥É¤òÀÚÂؤ¨¤Þ¤¹. ¸½ºßÄêµÁ¤µ¤ì¤Æ¤¤¤ë¥× + ¥í¥ó¥×¥È¥â¡¼¥É¤Ï, defalut, 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 (#<Thread:0x400fb7e4> : stop) + #1->irb#1 on main (#<Thread:0x40125d64> : 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 (#<Thread:0x400fb7e4> : running) + #1->irb#1 on main (#<Thread:0x40125d64> : stop) + #2->irb#2 on Foo (#<Thread:0x4011d54c> : 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 + #<Foo:0x4010af3c> + irb(main):008:0> irb f # Foo¤Î¥¤¥ó¥¹¥¿¥ó¥¹¤Çirb¤ò + # Ω¤Á¤¢¤²¤ë. + irb#3(#<Foo:0x4010af3c>):001:0> jobs + #0->irb on main (#<Thread:0x400fb7e4> : stop) + #1->irb#1 on main (#<Thread:0x40125d64> : stop) + #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop) + #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running) + nil + irb#3(#<Foo:0x4010af3c>):002:0> foo # f.foo¤Î¼Â¹Ô + nil + irb#3(#<Foo:0x4010af3c>):003:0> bar # f.bar¤Î¼Â¹Ô + barnil + irb#3(#<Foo:0x4010af3c>):004:0> kill 1, 2, 3# job¤Îkill + nil + irb(main):009:0> jobs + #0->irb on main (#<Thread:0x400fb7e4> : running) + nil + irb(main):010:0> exit # ½ªÎ» + dim% + += »ÈÍѾå¤ÎÀ©¸Â + +irb¤Ï, ɾ²Á¤Ç¤¤ë»þÅÀ(¼°¤¬ÊĤ¸¤¿»þÅÀ)¤Ç¤ÎÃ༡¼Â¹Ô¤ò¹Ô¤Ê¤¤¤Þ¤¹. ¤·¤¿¤¬¤Ã +¤Æ, ruby¤òľÀܻȤä¿»þ¤È, ¼ã´³°Û¤Ê¤ëÆ°ºî¤ò¹Ô¤Ê¤¦¾ì¹ç¤¬¤¢¤ê¤Þ¤¹. + +¸½ºßÌÀ¤é¤«¤Ë¤Ê¤Ã¤Æ¤¤¤ëÌäÂêÅÀ¤òÀâÌÀ¤·¤Þ¤¹. + +== ¥í¡¼¥«¥ëÊÑ¿ô¤ÎÀë¸À + +ruby¤Ç¤Ï, °Ê²¼¤Î¥×¥í¥°¥é¥à¤Ï¥¨¥é¡¼¤Ë¤Ê¤ê¤Þ¤¹. + + eval "foo = 0" + foo + -- + -:2: undefined local variable or method `foo' for #<Object:0x40283118> (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 #<Object:0x4013d0f0> + (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 <path> as a Shell method + <command>. + + 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 <pre> 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 + <path>. + +== Process management + +--- Shell#jobs + + Returns a list of scheduled jobs. + +--- Shell#kill sig, job + + Sends a signal <sig> to <job>. + +== Current directory operations + +--- Shell#cd(path, &block) +--- Shell#chdir + + Changes the current directory to <path>. 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 <path>. If <path> 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 <command> with <opts>. + + 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 <dev>. + +== 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 <src>, which is either a string of a file name or an + IO. + +--- Filter#>(to) + + Outputs to <to>, which is either a string of a file name or an + IO. + +--- Filter#>>(to) + + Appends the ouput to <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 @@ -695,6 +695,13 @@ rb_sys_fail(mesg) } void +rb_load_fail(path) + char *path; +{ + rb_loaderror("%s -- %s", strerror(errno), path); +} + +void rb_error_frozen(what) char *what; { @@ -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 <stdio.h> @@ -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 <alloca.h> +# elif !defined(alloca) +char *alloca(); +# endif +#endif /* __GNUC__ */ + +#ifdef _AIX +#pragma alloca +#endif + #ifdef HAVE_STDARG_PROTOTYPES #include <stdarg.h> #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; } @@ -1411,34 +1446,13 @@ ev_const_get(cref, 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; @@ -3467,7 +3509,7 @@ rb_yield_0(val, self, klass, acheck) 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"); } @@ -3489,7 +3531,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 +3560,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 +3575,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 +3597,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 +3607,56 @@ 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; 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 +3823,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 +3888,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 +3999,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 +4131,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 +4151,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 +4160,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 +4345,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 +4429,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 +4453,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 +4467,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 +4501,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 +4771,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 +4790,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 +4802,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 +4837,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 +4959,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 +4968,7 @@ exec_under(func, under, args) val = (*func)(args); } POP_TAG(); + POP_CREF(); SCOPE_SET(mode); POP_FRAME(); POP_CLASS(); @@ -4932,8 +5044,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 +5124,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 +5142,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 +5153,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 +5196,7 @@ rb_load(fname, wrap) free(ruby_scope->local_tbl); } POP_TAG(); + ruby_cref = saved_cref; POP_SCOPE(); POP_FRAME(); POP_CLASS(); @@ -5092,8 +5206,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 +5239,7 @@ rb_f_load(argc, argv) return Qtrue; } +VALUE ruby_dln_librefs; static VALUE rb_features; static st_table *loading_tbl; @@ -5167,7 +5281,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 +5407,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); @@ -5333,6 +5450,15 @@ rb_require(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; int argc; @@ -5341,6 +5467,7 @@ set_method_visibility(self, argc, argv, ex) { int i; + secure_visibility(self); for (i=0; i<argc; i++) { rb_export_method(self, rb_to_id(argv[i]), ex); } @@ -5352,6 +5479,7 @@ rb_mod_public(argc, argv, module) VALUE *argv; VALUE module; { + secure_visibility(module); if (argc == 0) { SCOPE_SET(SCOPE_PUBLIC); } @@ -5367,6 +5495,7 @@ rb_mod_protected(argc, argv, module) VALUE *argv; VALUE module; { + secure_visibility(module); if (argc == 0) { SCOPE_SET(SCOPE_PROTECTED); } @@ -5382,6 +5511,7 @@ rb_mod_private(argc, argv, module) VALUE *argv; VALUE module; { + secure_visibility(module); if (argc == 0) { SCOPE_SET(SCOPE_PRIVATE); } @@ -5441,6 +5571,7 @@ rb_mod_modfunc(argc, argv, module) rb_raise(rb_eTypeError, "module_function must be called for modules"); } + secure_visibility(module); if (argc == 0) { SCOPE_SET(SCOPE_MODFUNC); return module; @@ -5849,6 +5980,9 @@ Init_load() rb_define_global_function("require", rb_f_require, 1); rb_define_global_function("autoload", rb_f_autoload, 2); rb_global_variable(&ruby_wrapper); + + ruby_dln_librefs = rb_ary_new(); + rb_global_variable(&ruby_dln_librefs); } static void @@ -5883,6 +6017,7 @@ blk_mark(data) rb_gc_mark(data->self); rb_gc_mark(data->dyna_vars); rb_gc_mark(data->klass); + rb_gc_mark(data->tag); data = data->prev; } } @@ -5916,6 +6051,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 +6061,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 +6123,7 @@ static VALUE rb_f_binding(self) VALUE self; { - struct BLOCK *data; + struct BLOCK *data, *p; struct RVarmap *vars; VALUE bind; @@ -6002,10 +6145,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 +6210,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 +6222,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 +6230,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 +6314,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 +6323,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); @@ -6243,6 +6384,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; NODE *node; @@ -6278,10 +6452,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 +6475,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 +6628,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 +6794,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 +6809,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 +6838,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 +6913,7 @@ struct thread { struct tag *tag; VALUE klass; VALUE wrapper; + NODE *cref; int flags; /* misc. states (vmode/rb_trap_immediate/raised) */ @@ -6758,7 +6947,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 +6957,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 +7013,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 +7091,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 +7131,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 +7222,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 +7283,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 +7443,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 +7549,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 +7566,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 +7579,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 +7593,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 +7613,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 +7626,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 +7686,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 +7753,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 +7853,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 +8021,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 +8037,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 +8089,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 +8127,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 +8145,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 +8176,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 +8274,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 +8620,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/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 <curses_colr/curses.h> # else # include <curses.h> -# 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 <fcntl.h> #include <errno.h> -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,7 +103,8 @@ 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; @@ -95,6 +112,25 @@ fdbm_s_open(argc, argv, klass) } 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..9e454cc429 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 @@ -492,19 +506,43 @@ EOS mfile.puts " .c.@OBJEXT@: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +.cc.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< +.cpp.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< +.cxx.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< +.C.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< " elsif /nmake/i =~ $make mfile.print " {$(srcdir)}.c{}.@OBJEXT@: $(CC) -I. -I$(<D) $(CFLAGS) $(CPPFLAGS) -c $(<:/=\\) - .c.@OBJEXT@: $(CC) $(CFLAGS) $(CPPFLAGS) -c $(<:/=\\) + +{$(srcdir)}.cc{}.@OBJEXT@: + $(CXX) -I. -I$(<D) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +.cc.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +{$(srcdir)}.cpp{}.@OBJEXT@: + $(CXX) -I. -I$(<D) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +.cpp.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +{$(srcdir)}.cxx{}.@OBJEXT@: + $(CXX) -I. -I$(<D) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +.cxx.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) " else mfile.print " .c.@OBJEXT@: $(CC) $(CFLAGS) $(CPPFLAGS) -c $(subst /,\\\\,$<) + +.cc.@OBJEXT@ .cpp.@OBJEXT@ .cxx.@OBJEXT@ .C.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(subst /,\\\\,$<) " end @@ -577,23 +615,12 @@ def extmake(target) $local_flags = "-link /INCREMENTAL:no /EXPORT:Init_$(TARGET)" end $LOCAL_LIBS = "" # to be assigned in extconf.rb - dir = with_config("opt-dir") - if dir - idir = "-I"+dir+"/include" - ldir = dir+"/lib" - end - unless idir - dir = with_config("opt-include") - idir = "-I"+dir if dir - end - unless ldir - ldir = with_config("opt-lib") - end - $CFLAGS = "" - $CPPFLAGS = idir || "" + $CPPFLAGS = "" $LDFLAGS = "" - $LIBPATH = [ldir].compact + $LIBPATH = [] + + dir_config("opt") begin Dir.mkdir target unless File.directory?(target) @@ -625,7 +652,7 @@ def extmake(target) if $install system "#{$make} install DESTDIR=#{$destdir}" elsif $clean - system "#{$make} clean" + system "#{$make} #{$clean}" else unless system "#{$make} all" if ENV["MAKEFLAGS"] != "k" and ENV["MFLAGS"] != "-k" @@ -654,15 +681,15 @@ $static_ext = {} for setup in ["@setup@", "#{$top_srcdir}/ext/@setup@"] if File.file? setup f = open(setup) - while f.gets() - $_.chomp! - sub!(/#.*$/, '') - next if /^\s*$/ - if /^option +nodynamic/ + while line = f.gets() + line.chomp! + line.sub!(/#.*$/, '') + next if /^\s*$/ =~ line + if /^option +nodynamic/ =~ line $nodynamic = true next end - target = $_.split[0] + target = line.split[0] target = target.downcase if /mswin32/ =~ RUBY_PLATFORM $static_ext[target] = true end diff --git a/ext/fcntl/.cvsignore b/ext/fcntl/.cvsignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/ext/fcntl/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/ext/gdbm/.cvsignore b/ext/gdbm/.cvsignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/ext/gdbm/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/ext/gdbm/gdbm.c b/ext/gdbm/gdbm.c index d84c7bedd4..d43450229f 100644 --- a/ext/gdbm/gdbm.c +++ b/ext/gdbm/gdbm.c @@ -14,7 +14,7 @@ #include <fcntl.h> #include <errno.h> -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,25 +79,37 @@ 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; @@ -90,6 +117,25 @@ fgdbm_s_open(argc, argv, klass) } 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; { @@ -103,33 +149,130 @@ fgdbm_close(obj) } 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; i<argc; i++) { - rb_ary_push(new, fgdbm_fetch(obj, argv[i])); + rb_ary_push(new, rb_gdbm_fetch3(obj, argv[i])); } return new; } static VALUE +rb_gdbm_delete(obj, keystr) + VALUE obj, keystr; +{ + datum key; + struct dbmdata *dbmp; + GDBM_FILE dbm; + + rb_secure(4); + keystr = rb_str_to_str(keystr); + key.dptr = RSTRING(keystr)->ptr; + 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; @@ -593,22 +796,100 @@ fgdbm_reorganize(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..92c96f26d0 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) 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 <fcntl.h> #include <errno.h> -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/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..262adec3f2 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 <matz@netlab.co.jp> @@ -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(/></,',') + tk_split_simplelist(tk_call(*what)).collect!{|seq| + l = seq.scan(/<*[^<>]+>*/).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,76 @@ module TkCore end end +module TkPackage + include TkCore + extend TkPackage + + 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") + + TCL_PACKAGE_PATH = INTERP._invoke("set", "tcl_pkgPath") + AUTO_PATH = tk_split_simplelist(INTERP._invoke("set", "auto_path")) + + PLATFORM = Hash[*tk_split_simplelist(INTERP._eval('array get tcl_platform'))] + JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "") def root @@ -680,6 +754,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 +788,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 +1056,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 +1079,11 @@ class TkBindTag end class TkBindTagAll<TkBindTag - BindTagALL = [] def TkBindTagAll.new(*args) - if BindTagALL[0] - BindTagALL[0].bind(*args) if args != [] - else - new = super() - BindTagALL[0] = new - end - BindTagALL[0] - end + $stderr.puts "Warning: TkBindTagALL is obsolete. Use TkBindTag::ALL\n" - def initialize(*args) - @id = 'all' - BindTagALL[0].bind(*args) if args != [] + TkBindTag::ALL.bind(*args) if args != [] + TkBindTag::ALL end end @@ -1446,7 +1521,7 @@ module TkXIM end def useinputmethods(value=nil) - TkXIM.useinputmethods(self, value=nil) + TkXIM.useinputmethods(self, value) end def imconfigure(window, slot, value=None) @@ -2370,7 +2445,7 @@ class TkWindow<TkObject def grid_propagate(mode=nil) if mode - tk_call('grid', 'propagate', epath, bool) + tk_call('grid', 'propagate', epath, mode) else bool(tk_call('grid', 'propagate', epath)) end @@ -2507,7 +2582,7 @@ class TkWindow<TkObject def bindtags(taglist=nil) if taglist - fail unless taglist.kind_of? Array + fail ArgumentError unless taglist.kind_of? Array tk_call('bindtags', path, taglist) else list(tk_call('bindtags', path)).collect{|tag| @@ -2708,8 +2783,16 @@ class TkScale<TkWindow tk_call 'scale', path end - def get - number(tk_send('get')) + def get(x=None, y=None) + number(tk_send('get', x, y)) + end + + def coords(val=None) + tk_split_list(tk_send('coords', val)) + end + + def identify(x, y) + tk_send('identify', x, y) end def set(val) @@ -2744,8 +2827,8 @@ class TkScrollbar<TkWindow number(tk_send('fraction', x, y)) end - def identify(x=None, y=None) - tk_send('fraction', x, y) + def identify(x, y) + tk_send('identify', x, y) end def get @@ -2760,6 +2843,10 @@ class TkScrollbar<TkWindow def set(first, last) tk_send "set", first, last end + + def activate(element=None) + tk_send('activate', element) + end end class TkTextWin<TkWindow @@ -3033,12 +3120,12 @@ class TkMenu<TkWindow tk_send 'invoke', index end def insert(index, type, keys=nil) - tk_send 'add', index, type, *hash_kv(keys) + tk_send 'insert', index, type, *hash_kv(keys) end def delete(index, last=None) tk_send 'delete', index, last end - def popup(x, y, index=nil) + def popup(x, y, index=None) tk_call 'tk_popup', path, x, y, index end def post(x, y) @@ -3128,12 +3215,12 @@ class TkMenu<TkWindow end class TkMenuClone<TkMenu - def initialize(parent, type=nil) + def initialize(parent, type=None) unless parent.kind_of?(TkMenu) fail ArgumentError, "parent must be TkMenu" end @parent = parent - install_win(@parent) + install_win(@parent.path) tk_call @parent.path, 'clone', @path, type end end diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb index ff06e9305a..9b323e9cbb 100644 --- a/ext/tk/lib/tkcanvas.rb +++ b/ext/tk/lib/tkcanvas.rb @@ -172,7 +172,7 @@ class TkCanvas<TkWindow end def bbox(tagOrId, *tags) - list(tk_send('bbox', tagid(tagOrId), *tags)) + list(tk_send('bbox', tagid(tagOrId), *tags.collect{|t| tagid(t)})) end def itembind(tag, context, cmd=Proc.new, args=nil) @@ -207,7 +207,7 @@ class TkCanvas<TkWindow end def delete(*args) - tk_send 'delete', *args + tk_send 'delete', *args.collect{|t| tagid(t)} end alias remove delete @@ -375,7 +375,7 @@ class TkCanvas<TkWindow end def lower(tag, below=None) - tk_send 'lower', tagid(tag), below + tk_send 'lower', tagid(tag), tagid(below) end def move(tag, x, y) @@ -387,7 +387,7 @@ class TkCanvas<TkWindow end def raise(tag, above=None) - tk_send 'raise', tagid(tag), above + tk_send 'raise', tagid(tag), tagid(above) end def scale(tag, x, y, xs, ys) diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb index 6b25be376b..7af3f26748 100644 --- a/ext/tk/lib/tkentry.rb +++ b/ext/tk/lib/tkentry.rb @@ -136,7 +136,7 @@ class TkEntry<TkLabel tk_send 'selection', 'from', index end def selection_present() - tk_send('selection', 'present') == 1 + bool(tk_send('selection', 'present')) end def selection_range(s, e) tk_send 'selection', 'range', s, e diff --git a/ext/tk/lib/tktext.rb b/ext/tk/lib/tktext.rb index bb3d537bc4..51b5d82b60 100644 --- a/ext/tk/lib/tktext.rb +++ b/ext/tk/lib/tktext.rb @@ -189,6 +189,14 @@ class TkText<TkTextWin } end + def mark_next(index) + tagid2obj(tk_send('mark', 'next', index)) + end + + def mark_previous(index) + tagid2obj(tk_send('mark', 'previous', index)) + end + def window_names tk_send('window', 'names').collect{|elt| tagid2obj(elt) diff --git a/ext/tk/lib/tkvirtevent.rb b/ext/tk/lib/tkvirtevent.rb index b31b99062f..d3721e362e 100644 --- a/ext/tk/lib/tkvirtevent.rb +++ b/ext/tk/lib/tkvirtevent.rb @@ -7,12 +7,27 @@ require 'tk' class TkVirtualEvent<TkObject extend Tk - TkVirturlEventID = [0] - TkVirturlEventTBL = {} + TkVirtualEventID = [0] + TkVirtualEventTBL = {} + + class PreDefVirtEvent<self + def initialize(event) + @path = @id = event + TkVirtualEvent::TkVirtualEventTBL[@id] = self + end + end def TkVirtualEvent.getobj(event) - obj = TkVirturlEventTBL[event] - obj ? obj : event + obj = TkVirtualEventTBL[event] + if obj + obj + else + if tk_call('event', 'info').index("<#{event}>") + PreDefVirtEvent.new(event) + else + fail ArgumentError, "undefined virtual event '<#{event}>'" + end + end end def TkVirtualEvent.info @@ -22,8 +37,8 @@ class TkVirtualEvent<TkObject end def initialize(*sequences) - @path = @id = format("<VirtEvent%.4d>", TkVirturlEventID[0]) - TkVirturlEventID[0] += 1 + @path = @id = format("<VirtEvent%.4d>", TkVirtualEventID[0]) + TkVirtualEventID[0] += 1 add(*sequences) end @@ -31,7 +46,7 @@ class TkVirtualEvent<TkObject if sequences != [] tk_call('event', 'add', "<#{@id}>", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) - TkVirturlEventTBL[@id] = self + TkVirtualEventTBL[@id] = self end self end @@ -39,11 +54,11 @@ class TkVirtualEvent<TkObject def delete(*sequences) if sequences == [] tk_call('event', 'delete', "<#{@id}>") - 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 @@ -67,7 +67,7 @@ char *strrchr _((const char*,const char)); #include <sys/stat.h> #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,8 +1163,8 @@ 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; @@ -1164,14 +1173,19 @@ rb_file_s_unlink(obj, args) } 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 +1267,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 +1402,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 +1421,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 +1430,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 +1523,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 +1559,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 @@ -1716,6 +1736,30 @@ rb_f_test(argc, argv) } 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 +2073,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 +2101,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 +2137,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 +2207,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 +2303,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); @@ -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 <alloca.h> +# 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; i<RARRAY(table)->len; 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); -} @@ -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 = { 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 @@ -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)); @@ -27,6 +27,10 @@ # define NO_LONG_FNAME #endif +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(sun) +# define USE_SETVBUF +#endif + #include <sys/types.h> #if !defined(DJGPP) && !defined(NT) && !defined(__human68k__) #include <sys/ioctl.h> @@ -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<argc; i++) { rb_p(argv[i]); } + if (TYPE(rb_defout) == T_FILE) { rb_io_flush(rb_defout); + } return Qnil; } @@ -2238,8 +2259,6 @@ set_outfile(val, var, orig, stdf) GetOpenFile(val, fptr); rb_io_check_writable(fptr); - - GetOpenFile(*var, fptr); f = GetWriteFile(fptr); dup2(fileno(f), fileno(stdf)); @@ -2281,7 +2300,7 @@ prep_stdio(f, mode, klass) return (VALUE)io; } -static VALUE +static void prep_path(io, path) VALUE io; char *path; @@ -2771,6 +2790,7 @@ rb_f_select(argc, argv, obj) return res; /* returns an empty array on interrupt */ } +#if !defined(MSDOS) && !defined(__human68k__) static int io_cntl(fd,cmd,narg,io_p) int fd, cmd, io_p; @@ -2796,6 +2816,7 @@ io_cntl(fd,cmd,narg,io_p) #endif return retval; } +#endif static VALUE rb_io_ctl(io, req, arg, io_p) @@ -3095,8 +3116,9 @@ argf_tell() } static VALUE -argf_seek(self, offset, ptrname) - VALUE self, offset, ptrname; +argf_seek(argc, argv) + int argc; + VALUE *argv; { if (!next_argv()) { rb_raise(rb_eArgError, "no stream to seek"); @@ -3105,7 +3127,7 @@ argf_seek(self, offset, ptrname) if (TYPE(current_file) != T_FILE) { return argf_forward(); } - return rb_io_seek(current_file, offset, ptrname); + return rb_io_seek(argc, argv, current_file); } static VALUE @@ -3321,11 +3343,12 @@ static void opt_i_set(val) VALUE val; { + if (ruby_inplace_mode) free(ruby_inplace_mode); if (!RTEST(val)) { ruby_inplace_mode = 0; return; } - ruby_inplace_mode = STR2CSTR(val); + ruby_inplace_mode = strdup(STR2CSTR(val)); } void @@ -3474,7 +3497,7 @@ Init_IO() rb_define_singleton_method(argf, "getc", argf_getc, 0); rb_define_singleton_method(argf, "readchar", argf_readchar, 0); rb_define_singleton_method(argf, "tell", argf_tell, 0); - rb_define_singleton_method(argf, "seek", argf_seek, 2); + rb_define_singleton_method(argf, "seek", argf_seek, -1); rb_define_singleton_method(argf, "rewind", argf_rewind, 0); rb_define_singleton_method(argf, "pos", argf_tell, 0); rb_define_singleton_method(argf, "pos=", argf_set_pos, 1); diff --git a/lib/Env.rb b/lib/Env.rb index 7101b84c91..452a28659e 100644 --- a/lib/Env.rb +++ b/lib/Env.rb @@ -6,19 +6,7 @@ # $USER = "matz" # p ENV["USER"] -for k,v in ENV - next unless /^[a-zA-Z][_a-zA-Z0-9]*/ =~ k - eval <<EOS - $#{k} = %q!#{v}! - trace_var "$#{k}", proc{|v| - ENV[%q!#{k}!] = v; - $#{k} = %q!#{v}! - if v == nil - untrace_var "$#{k}" - end - } -EOS -end +require 'importenv' if __FILE__ == $0 p $TERM diff --git a/lib/README b/lib/README index de6a43af09..9aaf4524c9 100644 --- a/lib/README +++ b/lib/README @@ -2,10 +2,12 @@ English.rb access global variables by english names Env.rb access environment variables as globals README this file base64.rb encode/decode base64 (obsolete) -cgi-lib.rb decode CGI data +cgi.rb CGI access +cgi/session.rb CGI session +cgi-lib.rb decode CGI data (old style) complex.rb complex number suppor date.rb date object -date2.rb date object (compatible) +date2.rb date object (obsolete; use date) debug.rb ruby debugger delegate.rb delegate messages to other object e2mmap.rb exception utilities @@ -13,11 +15,13 @@ eregex.rb extended regular expression (just a proof of concept) final.rb add finalizer to the object (simple) finalize.rb add finalizer to the object find.rb traverse directory tree +forwardable.rb explicit delegation library ftools.rb file tools -ftplib.rb ftp access library +ftplib.rb ftp access library (obsolete; use net/ftp) getoptlong.rb GNU getoptlong compatible -getopts.rb parse command line options +getopts.rb parse command line options (use getoptlong) importenv.rb access environment variables as globals +irb.rb interactive ruby jcode.rb japanese text handling (replace String methods) mailread.rb read mail headers mathn.rb extended math operation @@ -25,6 +29,13 @@ matrix.rb matrix calculation library mkmf.rb Makefile maker monitor.rb exclusive region monitor for thread mutex_m.rb mutex mixin +net/ftp.rb ftp access +net/http.rb HTTP access +net/imap.rb IMAP4 access +net/pop.rb POP3 access +net/protocol.rb abstract class for net library +net/smtp.rb SMTP access +net/telnet.rb telnet library observer.rb observer desing pattern library (provides Observable) open3.rb open subprocess connection stdin/stdout/stderr ostruct.rb python style object @@ -35,11 +46,11 @@ profile.rb ruby profiler pstore.rb persistent object strage using marshal rational.rb rational number support readbytes.rb define IO#readbytes -shell.rb shell like operation under Ruby (imcomplete) +shell.rb shell like facilities under Ruby shellwords.rb split into words like shell singleton.rb singleton design pattern library sync.rb 2 phase lock -telnet.rb telnet library +telnet.rb telnet library (obsolete; use net/telnet) tempfile.rb temporary file that automatically removed thread.rb thread support thwait.rb thread syncronization class diff --git a/lib/cgi.rb b/lib/cgi.rb index 7d27cecd67..cfbdab8686 100644 --- a/lib/cgi.rb +++ b/lib/cgi.rb @@ -4,7 +4,7 @@ cgi.rb - cgi support library -Version 2.1.2 +Version 2.1.4 Copyright (C) 2000 Network Applied Communication Laboratory, Inc. @@ -185,12 +185,13 @@ class CGI CR = "\015" LF = "\012" EOL = CR + LF - VERSION = "2.1.2" - RELEASE_DATE = "2000-12-25" - VERSION_CODE = 212 - RELEASE_CODE = 20001225 + VERSION = '2.1.4' + RELEASE_DATE = '2001-04-18' + VERSION_CODE = 214 + RELEASE_CODE = 20010418 + REVISION = '$Id$' - NEEDS_BINMODE = true if /WIN/ni === RUBY_PLATFORM + NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) PATH_SEPARATOR = {'UNIX'=>'/', '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" } # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM> - form({"METHOD" => "post", ENCTYPE => "enctype"}){ "string" } + form({"METHOD" => "post", "ENCTYPE" => "enctype"}){ "string" } # <FORM METHOD="post" ENCTYPE="enctype">string</FORM> + +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 <kjana@os.xaxon.ne.jp> - * bug fix: CGI::unescapeHTML(): support for "	" - thanks to OHSHIMA Ryunosuke <ryu@jaist.ac.jp> - * 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 <akira@ruby-lang.org> - -* Wed Sep 13 06:09:26 JST 2000 - wakou - * version 2.0.1 - * bug fix: CGI::header(): output status header. - thanks to Yasuhiro Fukuma <yasuf@bsdclub.org> - -* 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 <eban@os.rim.or.jp> - * bug fix: CGI::escapeElement(). - * improvement: CGI::unescapeHTML(). - thanks to Kazuhiro NISHIYAMA <zn@mbf.nifty.com> - -* 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 <ryu@jaist.ac.jp> - -* 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 <ikeda@auc.co.jp> - * 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 <markj@altern.org> - 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..1a3379b88a 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,19 @@ class CGI end class FileStore + def check_id(id) + /[^0-9a-zA-Z]/ =~ id.to_s ? false : true + end + module_function :check_id + 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 +143,7 @@ class CGI end def close + return if @f.closed? update @f.close end @@ -146,9 +158,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 +176,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] <obj> show methods of object m[ethod] <class|module> show instance methods of class or module th[read] l[ist] list all threads - th[read] c[ur[rent]] show current threads - th[read] <nnn> stop thread nnn - th[read] stop <nnn> alias for th[read] <nnn> - th[read] c[ur[rent]] <nnn> alias for th[read] <nnn> - th[read] resume <nnn> run thread nnn + th[read] c[ur[rent]] show current thread + th[read] [sw[itch]] <nnn> switch thread context to nnn + th[read] stop <nnn> stop thread nnn + th[read] resume <nnn> resume thread nnn p expression evaluate expression and print its value h[elp] print this help <everything else> 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 <<DEBUGGER__ def stdout @stdout end + def stdout=(s) @stdout = s end @@ -707,10 +767,51 @@ EOHELP @break_points end + def waiting + @waiting + end + + def set_trace( arg ) + Thread.critical = true + make_thread_list + for th in @thread_list + context(th[0]).set_trace arg + end + Thread.critical = false + end + def set_last_thread(th) @last_thread = th end + def suspend + Thread.critical = true + make_thread_list + for th in @thread_list + next if th[0] == Thread.current + context(th[0]).set_suspend + end + Thread.critical = false + # Schedule other threads to suspend as soon as possible. + Thread.pass + end + + def resume + Thread.critical = true + make_thread_list + for th in @thread_list + next if th[0] == Thread.current + context(th[0]).clear_suspend + end + waiting.each do |th| + th.run + end + waiting.clear + Thread.critical = false + # Schedule other threads to restart as soon as possible. + Thread.pass + end + def context(thread=Thread.current) c = thread[:__debugger_data__] unless c @@ -726,7 +827,7 @@ EOHELP def get_thread(num) th = @thread_list.index(num) unless th - @stdout.print "no thread no.", num, "\n" + @stdout.print "No thread ##{num}\n" throw :debug_error end th @@ -773,31 +874,52 @@ EOHELP make_thread_list thread_list_all - when /^c(?:ur(?:rent)?)?\s+(\d+)/, /^stop\s+(\d+)/, /^(\d+)/ + when /^c(?:ur(?:rent)?)?$/ + make_thread_list + thread_list(@thread_list[Thread.current]) + + when /^(?:sw(?:itch)?\s+)?(\d+)/ make_thread_list th = get_thread($1.to_i) - thread_list(@thread_list[th]) - context(th).stop_next - th.run - return :cont + if th == Thread.current + @stdout.print "It's the current thread.\n" + else + thread_list(@thread_list[th]) + context(th).stop_next + th.run + return :cont + end - when /^c(?:ur(?:rent)?)?$/ + when /^stop\s+(\d+)/ make_thread_list - thread_list(@thread_list[Thread.current]) + th = get_thread($1.to_i) + if th == Thread.current + @stdout.print "It's the current thread.\n" + elsif th.stop? + @stdout.print "Already stopped.\n" + else + thread_list(@thread_list[th]) + context(th).suspend + end when /^resume\s+(\d+)/ make_thread_list th = get_thread($1.to_i) - thread_list(@thread_list[th]) - th.run - return :cont + if th == Thread.current + @stdout.print "It's the current thread.\n" + elsif !th.stop? + @stdout.print "Already running." + else + thread_list(@thread_list[th]) + th.run + end end end end stdout.printf "Debug.rb\n" stdout.printf "Emacs support available.\n\n" - set_trace_func proc{|event, file, line, id, binding,klass,*rest| - DEBUGGER__.context.trace_func event, file, line, id, binding,klass + set_trace_func proc { |event, file, line, id, binding, klass, *rest| + DEBUGGER__.context.trace_func event, file, line, id, binding, klass } end diff --git a/lib/delegate.rb b/lib/delegate.rb index 480e1ef6b8..a72ea943ba 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -8,7 +8,7 @@ # Usage: # foo = Object.new # foo2 = SimpleDelegator.new(foo) -# foo.hash == foo2.hash # => 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<<self + attr_accessor :debug + end + + def def_instance_delegators(accessor, *methods) + for method in methods + def_instance_delegator(accessor, method) + end + end + + def def_instance_delegator(accessor, method, ali = method) + accessor = accessor.id2name if accessor.kind_of?(Integer) + method = method.id2name if method.kind_of?(Integer) + ali = ali.id2name if ali.kind_of?(Integer) + + module_eval(<<-EOS, "(__FORWARDABLE__)", 1) + def #{ali}(*args, &block) + begin + #{accessor}.__send__(:#{method}, *args, &block) + rescue Exception + $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::debug + raise + end + end + EOS + end + + alias def_delegators def_instance_delegators + alias def_delegator def_instance_delegator +end + +module SingleForwardable + def def_singleton_delegators(accessor, *methods) + for method in methods + def_singleton_delegator(accessor, method) + end + end + + def def_singleton_delegator(accessor, method, ali = method) + accessor = accessor.id2name if accessor.kind_of?(Integer) + method = method.id2name if method.kind_of?(Integer) + ali = ali.id2name if ali.kind_of?(Integer) + + instance_eval(<<-EOS, "(__FORWARDABLE__)", 1) + def #{ali}(*args, &block) + begin + #{accessor}.__send__(:#{method}, *args,&block) + rescue Exception + $@.delete_if{|s| /^\\(__FORWARDABLE__\\):/ =~ s} unless Forwardable::debug + raise + end + end + EOS + end + + alias def_delegators def_singleton_delegators + alias def_delegator def_singleton_delegator +end + + + + diff --git a/lib/ftools.rb b/lib/ftools.rb index 369a6177d2..5e6203b1a3 100644 --- a/lib/ftools.rb +++ b/lib/ftools.rb @@ -26,6 +26,7 @@ class << File fmode = stat(from).mode tpath = to + not_exist = !exist?(tpath) from = open(from, "r") from.binmode @@ -50,7 +51,7 @@ class << File to.close from.close end - chmod(fmode, tpath) + chmod(fmode, tpath) if not_exist ret end diff --git a/lib/importenv.rb b/lib/importenv.rb index fcf306a9ab..586f37661b 100644 --- a/lib/importenv.rb +++ b/lib/importenv.rb @@ -10,10 +10,10 @@ for k,v in ENV next unless /^[a-zA-Z][_a-zA-Z0-9]*/ =~ k eval <<EOS - $#{k} = %q!#{v}! + $#{k} = v trace_var "$#{k}", proc{|v| - ENV[%q!#{k}!] = v; - $#{k} = %q!#{v}! + ENV[%q!#{k}!] = v + $#{k} = v if v == nil untrace_var "$#{k}" end diff --git a/lib/irb.rb b/lib/irb.rb new file mode 100644 index 0000000000..1b8444b5b3 --- /dev/null +++ b/lib/irb.rb @@ -0,0 +1,314 @@ +# +# irb.rb - irb main module +# $Release Version: 0.7.4 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +require "e2mmap" + +require "irb/init" +require "irb/context" +require "irb/extend-command" +require "irb/workspace" + +require "irb/ruby-lex" +require "irb/input-method" +require "irb/locale" + +STDOUT.sync = true + +module IRB + @RCS_ID='-$Id$-' + + class Abort < Exception;end + + # + @CONF = {} + + def IRB.conf + @CONF + 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 + + # 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 + + if @CONF[:SCRIPT] + irb = Irb.new(nil, @CONF[:SCRIPT]) + else + irb = Irb.new + 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 + + 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(workspace = nil, input_method = nil) + @context = Context.new(self, workspace, input_method) + @context.main.extend ExtendCommand + @signal_status = :IN_IRB + + @scanner = RubyLex.new + @scanner.exception_on_syntax_error = false + end + attr_reader :context + attr_accessor :scanner + + def eval_input + @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._ = @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<<self + alias_method :exit, ExtendCommand.irb_original_method_name('exit') + end + if iterator? + begin + yield + ensure + exit + end + end + end + pid + end + + def irb_change_binding(*main) + irb_context.change_binding(*main) + end + alias irb_change_workspace irb_change_binding + + def irb_source(file) + irb_context.source(file) + end + + def irb(*obj) + require "irb/multi-irb" + IRB.irb(nil, *obj) + end + + def irb_context + IRB.conf[:MAIN_CONTEXT] + end + + def irb_jobs + require "irb/multi-irb" + IRB.JobManager + end + + def irb_fg(key) + require "irb/multi-irb" + IRB.JobManager.switch(key) + end + + def irb_kill(*keys) + require "irb/multi-irb" + IRB.JobManager.kill(*keys) + end + + # extend command functions + def ExtendCommand.extend_object(obj) + super + unless (class<<obj;ancestors;end).include?(ExtendCommand) + obj.install_aliases + end + end + + OVERRIDE_NOTHING = 0 + OVERRIDE_PRIVATE_ONLY = 0x01 + OVERRIDE_ALL = 0x02 + + def install_aliases(override = OVERRIDE_NOTHING) + + install_alias_method(:exit, :irb_exit, override | OVERRIDE_PRIVATE_ONLY) + install_alias_method(:quit, :irb_quit, override | OVERRIDE_PRIVATE_ONLY) + install_alias_method(:fork, :irb_fork, override | OVERRIDE_PRIVATE_ONLY) + install_alias_method(:kill, :irb_kill, override | OVERRIDE_PRIVATE_ONLY) + + install_alias_method(:irb_cb, :irb_change_binding, override) + install_alias_method(:irb_ws, :irb_change_workspace, override) + install_alias_method(:source, :irb_source, override) + install_alias_method(:conf, :irb_context, override) + install_alias_method(:jobs, :irb_jobs, override) + install_alias_method(:fg, :irb_fg, override) + end + + # override = {OVERRIDE_NOTHING, OVERRIDE_PRIVATE_ONLY, OVERRIDE_ALL} + def install_alias_method(to, from, override = OVERRIDE_NOTHING) + to = to.id2name unless to.kind_of?(String) + from = from.id2name unless from.kind_of?(String) + + if override == OVERRIDE_ALL or + (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or + (override == OVERRIDE_NOTHING) && !respond_to?(to, true) + target = self + (class<<self;self;end).instance_eval{ + if target.respond_to?(to, true) && + !target.respond_to?(ExtendCommand.irb_original_method_name(to), true) + alias_method(ExtendCommand.irb_original_method_name(to), to) + end + alias_method to, from + } + else + print "irb: warn: can't alias #{to} from #{from}.\n" + end + end + + def self.irb_original_method_name(method_name) + "irb_" + method_name + "_org" + end + end +end diff --git a/lib/irb/frame.rb b/lib/irb/frame.rb index dcfa5c1d13..1090cd9684 100644 --- a/lib/irb/frame.rb +++ b/lib/irb/frame.rb @@ -1,6 +1,6 @@ # # frame.rb - -# $Release Version: 0.6$ +# $Release Version: 0.7.1$ # $Revision$ # $Date$ # by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) diff --git a/lib/irb/help.rb b/lib/irb/help.rb new file mode 100644 index 0000000000..0821f68d13 --- /dev/null +++ b/lib/irb/help.rb @@ -0,0 +1,33 @@ +# +# irb/help.rb - print usase module +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# + +module IRB + def IRB.print_usage + lc = IRB.conf[:LC_MESSAGES] + path = lc.find("irb/help-message") + space_line = false + File.foreach(path) do + |l| + if /^\s*$/ =~ l + lc.puts l unless space_line + space_line = true + next + end + space_line = false + + l.sub!(/#.*$/, "") + next if /^\s*$/ =~ l + lc.puts l + end + end +end + diff --git a/lib/irb/init.rb b/lib/irb/init.rb new file mode 100644 index 0000000000..f34a51b345 --- /dev/null +++ b/lib/irb/init.rb @@ -0,0 +1,232 @@ +# +# irb/init.rb - irb initialize module +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# + +module IRB + + # initialize config + def IRB.initialize(ap_path) + IRB.init_config(ap_path) + IRB.init_error + IRB.run_config + end + + # @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 # 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..8a3d63803b --- /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 + `defalut', `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..59f5c7a72b --- /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, defalut, 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<B9T;~$K%H%l!<%9$r9T$J$&(B. + --back-trace-limit n + $B%P%C%/%H%l!<%9I=<($r%P%C%/%H%l!<%9$NF,$+$i(B n, $B8e$m(B + $B$+$i(Bn$B$@$19T$J$&(B. $B%G%U%)%k%H$O(B16 + --irb_debug n irb$B$N%G%P%C%0%G%P%C%0%l%Y%k$r(Bn$B$K@_Dj$9$k(B($BMxMQ$7$J(B + $B$$J}$,L5Fq$G$7$g$&(B). + -v, --version irb$B$N%P!<%8%g%s$rI=<($9$k(B diff --git a/lib/irb/loader.rb b/lib/irb/loader.rb index 83b10a55a0..6e7a89e454 100644 --- a/lib/irb/loader.rb +++ b/lib/irb/loader.rb @@ -1,9 +1,9 @@ # -# irb-loader.rb - -# $Release Version: 0.6$ +# irb/loader.rb - irb loader +# $Release Version: 0.7.3$ # $Revision$ # $Date$ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# by Keiju ISHITSUKA(keiju@ishitsuka.com) # # -- # diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb new file mode 100644 index 0000000000..ef92ea1377 --- /dev/null +++ b/lib/irb/locale.rb @@ -0,0 +1,187 @@ +# +# irb/locale.rb - internationalization module +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# + +require "kconv" + +module IRB + class Locale + @RCS_ID='-$Id$-' + + JPDefaultLocale = "ja" + LOCALE_DIR = "/lc/" + + LC2KCONV = { +# "ja" => 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 <<EOF - $binding = binding -EOF - f.close - load f.path - bind = $binding - - when 2 - unless defined? BINDING_QUEUE - require "thread" - - IRB.const_set("BINDING_QUEUE", SizedQueue.new(1)) - Thread.abort_on_exception = true - Thread.start do - eval "require \"irb/workspace-binding-2\"", TOPLEVEL_BINDING, __FILE__, __LINE__ - end - Thread.pass - - end - - bind = BINDING_QUEUE.pop - - when 3 - bind = eval("def irb_binding; binding; end; irb_binding", - TOPLEVEL_BINDING, - __FILE__, - __LINE__ - 3) - end - end - unless main.empty? - @CONF[:__MAIN__] = main[0] - case main[0] - when Module - bind = eval("IRB.conf[:__MAIN__].module_eval('binding')", bind) - else - begin - bind = eval("IRB.conf[:__MAIN__].instance_eval('binding')", bind) - rescue TypeError - IRB.fail CanNotChangeBinding, main[0].inspect - end - end - end - eval("_=nil", bind) - bind - end - - def IRB.delete_caller - end -end diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb new file mode 100644 index 0000000000..68559a1173 --- /dev/null +++ b/lib/irb/workspace.rb @@ -0,0 +1,106 @@ +# +# irb/workspace-binding.rb - +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# +module IRB + class WorkSpace + # create new workspace. + # set self to main if specified, otherwise inherit main + # from TOPLEVEL_BINDING. + def initialize(*main) + if IRB.conf[:SINGLE_IRB] + @binding = TOPLEVEL_BINDING + else + case IRB.conf[:CONTEXT_MODE] + when 0 # binding in proc on TOPLEVEL_BINDING + @binding = eval("proc{binding}.call", + TOPLEVEL_BINDING, + __FILE__, + __LINE__) + when 1 # binding in loaded file + require "tempfile" + f = Tempfile.open("irb-binding") + f.print <<EOF + $binding = binding +EOF + f.close + load f.path + @binding = $binding + + when 2 # binding in loaded file(thread use) + unless defined? BINDING_QUEUE + require "thread" + + IRB.const_set("BINDING_QUEUE", SizedQueue.new(1)) + Thread.abort_on_exception = true + Thread.start do + eval "require \"irb/ws-for-case-2\"", TOPLEVEL_BINDING, __FILE__, __LINE__ + end + Thread.pass + end + @binding = BINDING_QUEUE.pop + + when 3 # binging in function on TOPLEVEL_BINDING(default) + @binding = eval("def irb_binding; binding; end; irb_binding", + TOPLEVEL_BINDING, + __FILE__, + __LINE__ - 3) + end + end + if main.empty? + @main = eval "self", @binding + else + @main = main[0] + IRB.conf[:__MAIN__] = @main + case @main + when Module + @binding = eval("IRB.conf[:__MAIN__].module_eval('binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__) + else + begin + @binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, __FILE__, __LINE__) + rescue TypeError + IRB.fail CanNotChangeBinding, @main.inspect + end + end + end + eval("_=nil", @binding) + end + + attr_reader :binding + attr_reader :main + + def evaluate(statements, file = __FILE__, line = __LINE__) + eval statements, @binding, file, line + end + + # error message manupilator + def filter_backtrace(bt) + case IRB.conf[:CONTEXT_MODE] + when 0 + return nil if bt =~ /\(irb_local_binding\)/ + when 1 + if(bt =~ %r!/tmp/irb-binding! or + bt =~ %r!irb/.*\.rb! or + bt =~ /irb\.rb/) + return nil + end + when 2 + return nil if bt =~ /irb\/.*\.rb/ + when 3 + return nil if bt =~ /irb\/.*\.rb/ + bt.sub!(/:\s*in `irb_binding'/){""} + end + bt + end + + def IRB.delete_caller + end + end +end diff --git a/lib/irb/ws-for-case-2.rb b/lib/irb/ws-for-case-2.rb new file mode 100644 index 0000000000..8cfa87ae3d --- /dev/null +++ b/lib/irb/ws-for-case-2.rb @@ -0,0 +1,15 @@ +# +# irb/ws-for-case-2.rb - +# $Release Version: 0.7.3$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(keiju@ishitsuka.com) +# +# -- +# +# +# + +while true + IRB::BINDING_QUEUE.push b = binding +end diff --git a/lib/irb/xmp.rb b/lib/irb/xmp.rb index fc745a2757..e0bcee4bdb 100644 --- a/lib/irb/xmp.rb +++ b/lib/irb/xmp.rb @@ -1,6 +1,6 @@ # # xmp.rb - irb version of gotoken xmp -# $Release Version: 0.6$ +# $Release Version: 0.7.1$ # $Revision$ # $Date$ # by Keiju ISHITSUKA(Nippon Rational Inc.) diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 317200ba79..e9c78dace7 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -12,12 +12,14 @@ SRC_EXT = ["c", "cc", "m", "cxx", "cpp", "C"] $config_cache = CONFIG["compile_dir"]+"/ext/config.cache" $srcdir = CONFIG["srcdir"] -$libdir = CONFIG["libdir"]+"/ruby/"+CONFIG["MAJOR"]+"."+CONFIG["MINOR"] -$archdir = $libdir+"/"+CONFIG["arch"] -$sitelibdir = CONFIG["sitedir"]+"/"+CONFIG["MAJOR"]+"."+CONFIG["MINOR"] -$sitearchdir = $sitelibdir+"/"+CONFIG["arch"] - -if File.exist? $archdir + "/ruby.h" +$libdir = CONFIG["libdir"] +$rubylibdir = CONFIG["rubylibdir"] +$archdir = CONFIG["archdir"] +$sitedir = CONFIG["sitedir"] +$sitelibdir = CONFIG["sitelibdir"] +$sitearchdir = CONFIG["sitearchdir"] + +if File.exist? Config::CONFIG["archdir"] + "/ruby.h" $hdrdir = $archdir elsif File.exist? $srcdir + "/ruby.h" $hdrdir = $srcdir @@ -43,7 +45,7 @@ else $null = open('test.log', 'w') end -LINK = "#{CONFIG['CC']} -o conftest -I#{$hdrdir} #{CFLAGS} -I#{CONFIG['includedir']} %s #{CONFIG['LDFLAGS']} %s conftest.c %s %s #{CONFIG['LIBS']}" +LINK = "#{CONFIG['CC']} -o conftest -I#{$hdrdir} #{CFLAGS} -I#{CONFIG['includedir']} %s %s #{CONFIG['LDFLAGS']} %s conftest.c %s %s #{CONFIG['LIBS']}" CPP = "#{CONFIG['CPP']} -E %s -I#{$hdrdir} #{CFLAGS} -I#{CONFIG['includedir']} %s %s conftest.c" def rm_f(*files) @@ -60,6 +62,7 @@ end $orgerr = $stderr.dup $orgout = $stdout.dup def xsystem command + Config.expand(command) if $DEBUG print command, "\n" return system(command) @@ -155,7 +158,9 @@ def install_rb(mfile, dest, srcdir = nil) mfile.printf "\t@$(RUBY) -r ftools -e 'File::makedirs(*ARGV)' %s/%s\n", dest, f end for f in path - mfile.printf "\t@$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0644, true)' lib/%s %s/%s\n", f, dest, f + d = '/' + File::dirname(f) + d = '' if d == '/.' + mfile.printf "\t@$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0644, true)' %s/%s %s%s\n", libdir, f, dest, d end end @@ -334,24 +339,32 @@ 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, srcdir = File.dirname($0)) + save_libs = $libs.dup + save_libpath = $LIBPATH.dup print "creating Makefile\n" rm_f "conftest*" STDOUT.flush @@ -370,15 +383,16 @@ def create_makefile(target, srcdir = File.dirname($0)) end $DLDFLAGS = CONFIG["DLDFLAGS"] - if $configure_args['--enable-shared'] or CONFIG['LIBRUBY'] != CONFIG['LIBRUBY_A'] - $libs = CONFIG["LIBRUBYARG"] + " " + $libs - $LIBPATH |= ["$(topdir)", CONFIG["libdir"]] - end + $libs = CONFIG["LIBRUBYARG"] + " " + $libs + $configure_args['--enable-shared'] or $LIBPATH |= [$topdir] + $LIBPATH |= [CONFIG["libdir"]] defflag = '' if RUBY_PLATFORM =~ /cygwin|mingw/ - 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 @@ -427,6 +441,8 @@ LIBPATH = #{libpath} RUBY_INSTALL_NAME = #{CONFIG["RUBY_INSTALL_NAME"]} RUBY_SO_NAME = #{CONFIG["RUBY_SO_NAME"]} +arch = #{CONFIG["arch"]} +ruby_version = #{Config::CONFIG["ruby_version"]} #{ if destdir = CONFIG["prefix"].scan(drive)[0] and !destdir.empty? "\nDESTDIR = " + destdir @@ -435,11 +451,13 @@ else end } prefix = $(DESTDIR)#{CONFIG["prefix"].sub(drive, '')} -exec_prefix = $(DESTDIR)#{CONFIG["exec_prefix"].sub(drive, '')} -libdir = $(DESTDIR)#{$libdir.sub(drive, '')}#{target_prefix} -archdir = $(DESTDIR)#{$archdir.sub(drive, '')}#{target_prefix} -sitelibdir = $(DESTDIR)#{$sitelibdir.sub(drive, '')}#{target_prefix} -sitearchdir = $(DESTDIR)#{$sitearchdir.sub(drive, '')}#{target_prefix} +exec_prefix = #{CONFIG["exec_prefix"].sub(drive, '')} +libdir = #{$libdir.sub(drive, '')}#{target_prefix} +rubylibdir = #{$rubylibdir.sub(drive, '')}#{target_prefix} +archdir = #{$archdir.sub(drive, '')}#{target_prefix} +sitedir = #{$sitedir.sub(drive, '')}#{target_prefix} +sitelibdir = #{$sitelibdir.sub(drive, '')}#{target_prefix} +sitearchdir = #{$sitearchdir.sub(drive, '')}#{target_prefix} #### End of system configuration section. #### @@ -471,10 +489,10 @@ install: $(archdir)/$(DLLIB) site-install: $(sitearchdir)/$(DLLIB) $(archdir)/$(DLLIB): $(DLLIB) - @$(RUBY) -r ftools -e 'File::makedirs(*ARGV)' $(libdir) $(archdir) + @$(RUBY) -r ftools -e 'File::makedirs(*ARGV)' $(rubylibdir) $(archdir) @$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0555, true)' $(DLLIB) $(archdir)/$(DLLIB) EOMF - install_rb(mfile, "$(libdir)") + install_rb(mfile, "$(rubylibdir)", srcdir) mfile.printf "\n" mfile.printf <<EOMF @@ -482,21 +500,42 @@ $(sitearchdir)/$(DLLIB): $(DLLIB) @$(RUBY) -r ftools -e 'File::makedirs(*ARGV)' $(libdir) $(sitearchdir) @$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0555, true)' $(DLLIB) $(sitearchdir)/$(DLLIB) EOMF - install_rb(mfile, "$(sitelibdir)") + install_rb(mfile, "$(sitelibdir)", srcdir) mfile.printf "\n" if /mswin32/ !~ RUBY_PLATFORM mfile.print " .c.#{$OBJEXT}: $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +.cc.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +.cpp.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +.cxx.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +.C.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< " elsif /nmake/i =~ $make mfile.print " {$(srcdir)}.c.#{$OBJEXT}: $(CC) $(CFLAGS) -I$(<D) $(CPPFLAGS) -c $(<:/=\\) - .c.#{$OBJEXT}: $(CC) $(CFLAGS) -I$(<D) $(CPPFLAGS) -c $(<:/=\\) + +{$(srcdir)}.cc{}.#{$OBJEXT}: + $(CXX) -I. -I$(<D) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +.cc.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +{$(srcdir)}.cpp{}.#{$OBJEXT}: + $(CXX) -I. -I$(<D) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +.cpp.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +{$(srcdir)}.cxx{}.#{$OBJEXT}: + $(CXX) -I. -I$(<D) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) +.cxx.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(<:/=\\) " else mfile.print " @@ -504,6 +543,9 @@ EOMF .c.#{$OBJEXT}: $(CC) $(CFLAGS) $(CPPFLAGS) -c $(subst /,\\\\,$<) + +.cc.#{$OBJEXT} .cpp.#{$OBJEXT} .cxx.#{$OBJEXT} .C.#{$OBJEXT}: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(subst /,\\\\,$<) " end @@ -536,6 +578,8 @@ EOMF dfile.close end mfile.close + $libs = save_libs + $LIBPATH = save_libpath end $OBJEXT = CONFIG["OBJEXT"] @@ -550,20 +594,10 @@ $LOCAL_LIBS = "" $defs = [] $make = with_config("make-prog", ENV["MAKE"] || "make") -dir = with_config("opt-dir") -if dir - idir = "-I"+dir+"/include" - ldir = dir+"/lib" -end -unless idir - dir = with_config("opt-include") - idir = "-I"+dir if dir -end -unless ldir - ldir = with_config("opt-lib") -end $CFLAGS = with_config("cflags", "") -$CPPFLAGS = [with_config("cppflags", ""), idir].compact.join(" ") +$CPPFLAGS = with_config("cppflags", "") $LDFLAGS = with_config("ldflags", "") -$LIBPATH = [ldir].compact +$LIBPATH = [] + +dir_config("opt") diff --git a/lib/monitor.rb b/lib/monitor.rb index 75d9c35821..721c51a9f5 100644 --- a/lib/monitor.rb +++ b/lib/monitor.rb @@ -1,27 +1,44 @@ =begin -monitor.rb -Author: Shugo Maeda <shugo@netlab.co.jp> -Version: 1.2.1 += monitor.rb -USAGE: +Copyright (C) 2001 Shugo Maeda <shugo@ruby-lang.org> - 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 <aamine@dp.u-netsurf.ne.jp> -maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp> 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 - "#<Net::HTTPCommand>" + 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 = %r<bytes\s+(\d+)-(\d+)/(?:\d+|\*)>i.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<bytes\s+(\d+)-(\d+)/\d+>.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 <shugo@ruby-lang.org> 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 ((<Net::IMAP::MailboxList>)). ex). imap.create("foo/bar") imap.create("foo/baz") p imap.list("", "foo/%") - #=> [#<Net::IMAP::MailboxList attr=[:NoSelect], delim="/", name="foo/">, #<Net::IMAP::MailboxList attr=[:NoInferiors, :Marked], delim="/", name="foo/bar">, #<Net::IMAP::MailboxList attr=[:NoInferiors], delim="/", name="foo/baz">] + #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, #<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">] : 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 ((<Net::IMAP::MailboxList>)). : 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 ((<Net::IMAP::FetchData>)). 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 ((<Net::IMAP::FetchData>)). 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 ((<Net::IMAP::MailboxList>)) 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*<any ATOM_CHAR except "+"> + + 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 ((<Net::IMAP::ResponseText>)). + +: 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 ((<Net::IMAP::ResponseCode>)). + +: 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*<any TEXT_CHAR except "]">] + +=== 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[<section>]<<origin_octet>> + A string expressing the body contents of the specified section. + : BODYSTRUCTURE + An object that describes the ((<[MIME-IMB]>)) body structure of a message. + See ((<Net::IMAP::BodyTypeBasic>)), ((<Net::IMAP::BodyTypeText>)), + ((<Net::IMAP::BodyTypeMessage>)), ((<Net::IMAP::BodyTypeMultipart>)). + : ENVELOPE + A ((<Net::IMAP::Envelope>)) 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 ((<Net::IMAP::Address>)) that represents the from. + +: sender + Retunns an array of ((<Net::IMAP::Address>)) that represents the sender. + +: reply_to + Retunns an array of ((<Net::IMAP::Address>)) that represents the reply-to. + +: to + Retunns an array of ((<Net::IMAP::Address>)) that represents the to. + +: cc + Retunns an array of ((<Net::IMAP::Address>)) that represents the cc. + +: bcc + Retunns an array of ((<Net::IMAP::Address>)) 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 + +((<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 ((<Net::IMAP::ContentDisposition>)) 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::BodyTypeBasic>)). + +== Net::IMAP::BodyTypeMessage + +Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: envelope + Returns a ((<Net::IMAP::Envelope>)) giving the envelope structure. + +: body + Returns an object giving the body structure. + +And Net::IMAP::BodyTypeMessage has all methods of ((<Net::IMAP::BodyTypeText>)). + +== 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 ((<Net::IMAP::ContentDisposition>)) 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 <aamine@dp.u-netsurf.ne.jp> @@ -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 <aamine@dp.u-netsurf.ne.jp> @@ -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 << %<read "#{Net.quote s}"\n> 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 <aamine@dp.u-netsurf.ne.jp> @@ -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 <wakou@fsinet.or.jp> @@ -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 <zn@mbf.nifty.com> - * 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 <Dave@thomases.com> - -* 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 <Hirofumi.Watanabe@jp.sony.com> - -* 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 <sinara@blade.nagaokaut.ac.jp> - * 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 <tadf@kt.rim.or.jp> - 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 <tetsu@jpn.hp.com> - * 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<Filter + def wait? + false + end + def active? + true + end + end + + class Echo < BuiltInCommand + def initialize(sh, *strings) + super sh + @strings = strings + end + + def each(rs = nil) + rs = @shell.record_separator unless rs + for str in @strings + yield str + rs + end + end + end + + class Cat < BuiltInCommand + def initialize(sh, *filenames) + super sh + @cat_files = filenames + end + + def each(rs = nil) + if @cat_files.empty? + super + else + for src in @cat_files + @shell.foreach(src, rs){|l| yield l} + end + end + end + end + + class Glob < BuiltInCommand + def initialize(sh, pattern) + super sh + + @pattern = pattern + Thread.critical = true + back = Dir.pwd + begin + Dir.chdir @shell.cwd + @files = Dir[pattern] + ensure + Dir.chdir back + Thread.critical = false + end + end + + def each(rs = nil) + rs = @shell.record_separator unless rs + for f in @files + yield f+rs + end + end + end + +# class Sort < Cat +# def initialize(sh, *filenames) +# super +# end +# +# def each(rs = nil) +# ary = [] +# super{|l| ary.push l} +# for l in ary.sort! +# yield l +# end +# end +# end + + class AppendIO < BuiltInCommand + def initialize(sh, io, filter) + super sh + @input = filter + @io = io + end + + def input=(filter) + @input.input=filter + for l in @input + @io << l + end + end + + end + + class AppendFile < AppendIO + def initialize(sh, to_filename, filter) + @file_name = to_filename + io = sh.open(to_filename, "a") + super(sh, io, filter) + end + + def input=(filter) + begin + super + ensure + @io.close + end + end + end + + class Tee < BuiltInCommand + def initialize(sh, filename) + super sh + @to_filename = filename + end + + def each(rs = nil) + to = @shell.open(@to_filename, "w") + begin + super{|l| to << l; yield l} + ensure + to.close + end + end + end + + class Concat < BuiltInCommand + def initialize(sh, *jobs) + super(sh) + @jobs = jobs + end + + def each(rs = nil) + while job = @jobs.shift + job.each{|l| yield l} + end + end + end +end diff --git a/lib/shell/command-processor.rb b/lib/shell/command-processor.rb new file mode 100644 index 0000000000..fa253b3705 --- /dev/null +++ b/lib/shell/command-processor.rb @@ -0,0 +1,584 @@ +# +# shell/command-controller.rb - +# $Release Version: 0.6.0 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# + +require "e2mmap" +require "ftools" +require "thread" + +require "shell/error" +require "shell/filter" +require "shell/system-command" +require "shell/builtin-command" + +class Shell + class CommandProcessor + + # + # initialize of Shell and related classes. + # + NoDelegateMethods = ["initialize", "expand_path"] + def self.initialize + + install_builtin_commands + + # define CommandProccessor#methods to Shell#methods and Filter#methods + for m in CommandProcessor.instance_methods - NoDelegateMethods + add_delegate_command_to_shell(m) + end + + def self.method_added(id) + add_delegate_command_to_shell(id) + end + end + + # + # include run file. + # + def self.run_config + begin + load File.expand_path("~/.rb_shell") if ENV.key?("HOME") + rescue LoadError, Errno::ENOENT + rescue + print "load error: #{rc}\n" + print $!.type, ": ", $!, "\n" + for err in $@[0, $@.size - 2] + print "\t", err, "\n" + end + end + end + + def initialize(shell) + @shell = shell + @system_commands = {} + end + + # + # CommandProcessor#expand_path(path) + # path: String + # return: String + # returns the absolute path for <path> + # + 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<<self + + def process_controllers_exclusive + begin + @ProcessControllers.lock unless Thread.critical + yield + ensure + @ProcessControllers.unlock unless Thread.critical + end + end + + def activate(pc) + process_controllers_exclusive do + @ProcessControllers[pc] ||= 0 + @ProcessControllers[pc] += 1 + end + end + + def inactivate(pc) + process_controllers_exclusive do + if @ProcessControllers[pc] + if (@ProcessControllers[pc] -= 1) == 0 + @ProcessControllers.delete(pc) + end + end + end + end + + def each_active_object + process_controllers_exclusive do + for ref in @ProcessControllers.keys + yield ref + end + end + end + end + + def initialize(shell) + @shell = shell + @waiting_jobs = [] + @active_jobs = [] + @jobs_sync = Sync.new + + @job_monitor = Mutex.new + @job_condition = ConditionVariable.new + end + + def jobs + jobs = [] + @jobs_sync.synchronize(:SH) do + jobs.concat @waiting_jobs + jobs.concat @active_jobs + end + jobs + end + + def active_jobs + @active_jobs + end + + def waiting_jobs + @waiting_jobs + end + + def jobs_exist? + @jobs_sync.synchronize(:SH) do + @active_jobs.empty? or @waiting_jobs.empty? + end + end + + def active_jobs_exist? + @jobs_sync.synchronize(:SH) do + @active_jobs.empty? + end + end + + def waiting_jobs_exist? + @jobs_sync.synchronize(:SH) do + @waiting_jobs.empty? + end + end + + # schedule a command + def add_schedule(command) + @jobs_sync.synchronize(:EX) do + ProcessController.activate(self) + if @active_jobs.empty? + start_job command + else + @waiting_jobs.push(command) + end + end + end + + # start a job + def start_job(command = nil) + @jobs_sync.synchronize(:EX) do + if command + return if command.active? + @waiting_jobs.delete command + else + command = @waiting_jobs.shift + return unless command + end + @active_jobs.push command + command.start + + # start all jobs that input from the job + for job in @waiting_jobs + start_job(job) if job.input == command + end + end + end + + def waiting_job?(job) + @jobs_sync.synchronize(:SH) do + @waiting_jobs.include?(job) + end + end + + def active_job?(job) + @jobs_sync.synchronize(:SH) do + @active_jobs.include?(job) + end + end + + # terminate a job + def terminate_job(command) + @jobs_sync.synchronize(:EX) do + @active_jobs.delete command + ProcessController.inactivate(self) + if @active_jobs.empty? + start_job + end + end + end + + # kill a job + def kill_job(sig, command) + @jobs_sync.synchronize(:SH) do + if @waiting_jobs.delete command + ProcessController.inactivate(self) + return + elsif @active_jobs.include?(command) + begin + r = command.kill sig + ProcessController.inactivate(self) + rescue + print "Shell: Warn: $!\n" if @shell.verbose? + return nil + end + @active_jobs.delete command + r + end + end + end + + # wait for all jobs to terminate + def wait_all_jobs_execution + @job_monitor.synchronize do + begin + while !jobs.empty? + @job_condition.wait(@job_monitor) + end + ensure + redo unless jobs.empty? + end + end + end + + # simple fork + def sfork(command, &block) + pipe_me_in, pipe_peer_out = IO.pipe + pipe_peer_in, pipe_me_out = IO.pipe + Thread.critical = true + + STDOUT.flush + ProcessController.each_active_object do |pc| + for jobs in pc.active_jobs + jobs.flush + end + end + + pid = fork { + Thread.critical = true + + Thread.list.each do |th| + th.kill unless [Thread.main, Thread.current].include?(th) + end + + STDIN.reopen(pipe_peer_in) + STDOUT.reopen(pipe_peer_out) + + ObjectSpace.each_object(IO) do |io| + if ![STDIN, STDOUT, STDERR].include?(io) + io.close unless io.closed? + end + end + yield + } + + pipe_peer_in.close + pipe_peer_out.close + command.notify "job(%name:##{pid}) start", @shell.debug? + Thread.critical = false + + th = Thread.start { + Thread.critical = true + begin + _pid = nil + command.notify("job(%id) start to waiting finish.", @shell.debug?) + Thread.critical = false + _pid = Process.waitpid(pid, nil) + rescue Errno::ECHILD + command.notify "warn: job(%id) was done already waitipd." + _pid = true + ensure + # when the process ends, wait until the command termintes + if _pid + else + command.notify("notice: Process finishing...", + "wait for Job[%id] to finish.", + "You can use Shell#transact or Shell#check_point for more safe execution.") + redo + end + Thread.exclusive do + terminate_job(command) + @job_condition.signal + command.notify "job(%id) finish.", @shell.debug? + end + end + } + return pid, pipe_me_in, pipe_me_out + end + end +end diff --git a/lib/shell/system-command.rb b/lib/shell/system-command.rb new file mode 100644 index 0000000000..c22b9ac0a4 --- /dev/null +++ b/lib/shell/system-command.rb @@ -0,0 +1,168 @@ +# +# shell/system-command.rb - +# $Release Version: 0.6.0 $ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +require "shell/filter" + +class Shell + class SystemCommand < Filter + def initialize(sh, command, *opts) + if t = opts.find{|opt| !opt.kind_of?(String) && opt.type} + Shell.Fail TypeError, t.type, "String" + end + super(sh) + @command = command + @opts = opts + + @input_queue = Queue.new + @pid = nil + + sh.process_controller.add_schedule(self) + end + + attr_reader :command + alias name command + + def wait? + @shell.process_controller.waiting_job?(self) + end + + def active? + @shell.process_controller.active_job?(self) + end + + def input=(inp) + super + if active? + start_export + end + end + + def start + @pid, @pipe_in, @pipe_out = @shell.process_controller.sfork(self) { + Dir.chdir @shell.pwd + exec(@command, *@opts) + } + if @input + start_export + end + start_import + end + + def flush + @pipe_out.flush if @pipe_out and !@pipe_out.closed? + end + + def terminate + begin + @pipe_in.close + rescue IOError + end + begin + @pipe_out.close + rescue IOError + end + end + + def kill(sig) + if @pid + Process.kill(sig, @pid) + end + end + + + def start_import +# Thread.critical = true + notify "Job(%id) start imp-pipe.", @shell.debug? + rs = @shell.record_separator unless rs + _eop = true +# Thread.critical = false + th = Thread.start { + Thread.critical = true + begin + Thread.critical = false + while l = @pipe_in.gets + @input_queue.push l + end + _eop = false + rescue Errno::EPIPE + _eop = false + ensure + if _eop + notify("warn: Process finishing...", + "wait for Job[%id] to finish pipe importing.", + "You can use Shell#transact or Shell#check_point for more safe execution.") +# Tracer.on + Thread.current.run + redo + end + Thread.exclusive do + notify "job(%id}) close imp-pipe.", @shell.debug? + @input_queue.push :EOF + @pipe_in.close + end + end + } + end + + def start_export + notify "job(%id) start exp-pipe.", @shell.debug? + _eop = true + th = Thread.start{ + Thread.critical = true + begin + Thread.critical = false + @input.each{|l| @pipe_out.print l} + _eop = false + rescue Errno::EPIPE + _eop = false + ensure + if _eop + notify("shell: warn: Process finishing...", + "wait for Job(%id) to finish pipe exporting.", + "You can use Shell#transact or Shell#check_point for more safe execution.") +# Tracer.on + redo + end + Thread.exclusive do + notify "job(%id) close exp-pipe.", @shell.debug? + @pipe_out.close + end + end + } + end + + alias super_each each + def each(rs = nil) + while (l = @input_queue.pop) != :EOF + yield l + end + end + + # ex) + # if you wish to output: + # "shell: job(#{@command}:#{@pid}) close pipe-out." + # then + # mes: "job(%id) close pipe-out." + # yorn: Boolean(@shell.debug? or @shell.verbose?) + def notify(*opts, &block) + Thread.exclusive do + @shell.notify(*opts) {|mes| + yield mes if iterator? + + mes.gsub!("%id", "#{@command}:##{@pid}") + mes.gsub!("%name", "#{@command}") + mes.gsub!("%pid", "#{@pid}") + } + end + end + end +end diff --git a/lib/shell/version.rb b/lib/shell/version.rb new file mode 100644 index 0000000000..6694c804d8 --- /dev/null +++ b/lib/shell/version.rb @@ -0,0 +1,16 @@ +# +# version.rb - shell version definition file +# $Release Version: 0.6.0$ +# $Revision$ +# $Date$ +# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd) +# +# -- +# +# +# + +class Shell + @RELEASE_VERSION = "0.6.0" + @LAST_UPDATE_DATE = "01/03/19" +end diff --git a/lib/thread.rb b/lib/thread.rb index d4b6ad6ec1..0537c78650 100644 --- a/lib/thread.rb +++ b/lib/thread.rb @@ -74,7 +74,10 @@ class Mutex retry end Thread.critical = false - t.run if t + begin + t.run if t + rescue ThreadError + end self end @@ -160,7 +163,10 @@ class Queue ensure Thread.critical = false end - t.run if t + begin + t.run if t + rescue ThreadError + end end def enq(obj) push(obj) @@ -170,7 +176,7 @@ class Queue Thread.critical = true begin loop do - if @que.length == 0 + if @que.empty? if non_block raise ThreadError, "queue empty" end @@ -184,13 +190,11 @@ class Queue Thread.critical = false end end - def shift(non_block=false) - pop(non_block=false) - end - alias deq shift + alias shift pop + alias deq pop def empty? - @que.length == 0 + @que.empty? end def clear @@ -223,11 +227,11 @@ class SizedQueue<Queue def max=(max) Thread.critical = true - if max >= @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 SizedQueue<Queue end def pop(*args) + retval = super Thread.critical = true if @que.length < @max begin @@ -263,9 +268,12 @@ class SizedQueue<Queue ensure Thread.critical = false end - t.run if t + begin + t.run if t + rescue ThreadError + end end - super + retval end def num_waiting @@ -14,7 +14,7 @@ #include "rubyio.h" #include "st.h" -#ifndef atof +#if !defined(atof) && !defined(HAVE_STDLIB_H) double strtod(); #endif @@ -46,7 +46,7 @@ shortlen(len, ds) num = SHORTDN(num); offset++; } - return len*sizeof(BDIGIT)/sizeof(short) - offset; + return (len - 1)*sizeof(BDIGIT)/sizeof(short) + offset; } #define SHORTLEN(x) shortlen((x),d) #endif @@ -187,7 +187,7 @@ w_float(d, arg) { char buf[100]; - sprintf(buf, "%.12g", d); + sprintf(buf, "%.16g", d); w_bytes(buf, strlen(buf), arg); } @@ -378,7 +378,7 @@ w_object(obj, arg, limit) for (i=0; i<SIZEOF_BDIGITS; i+=sizeof(short)) { w_short(num & SHORTMASK, arg); num = SHORTDN(num); - if (num == 0) break; + if (len == 0 && num == 0) break; } #else w_short(*d, arg); @@ -823,7 +823,11 @@ r_object(arg) OBJSETUP(big, rb_cBignum, T_BIGNUM); big->sign = (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); @@ -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 <fcntl.h> +#include <unistd.h> +#include <errno.h> + +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 <unistd.h> #include <errno.h> @@ -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 <fcntl.h> -#include <unistd.h> -#include <errno.h> - -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 <math.h> + +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 <stddef.h> #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 <stddef.h> - #if defined(__STDC__) # include <stdarg.h> #else diff --git a/mkconfig.rb b/mkconfig.rb index 175a4c3b15..272cfdcfc1 100644 --- a/mkconfig.rb +++ b/mkconfig.rb @@ -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,7 +58,7 @@ 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 @@ -102,6 +89,11 @@ end print v_fast, v_others print <<EOS + CONFIG["ruby_version"] = "$(MAJOR).$(MINOR)" + CONFIG["rubylibdir"] = "$(libdir)/ruby/$(ruby_version)" + CONFIG["archdir"] = "$(rubylibdir)/$(arch)" + CONFIG["sitelibdir"] = "$(sitedir)/$(ruby_version)" + CONFIG["sitearchdir"] = "$(sitelibdir)/$(arch)" CONFIG["compile_dir"] = "#{Dir.pwd}" MAKEFILE_CONFIG = {} CONFIG.each{|k,v| MAKEFILE_CONFIG[k] = v.dup} @@ -109,7 +101,7 @@ print <<EOS val.gsub!(/\\$\\(([^()]+)\\)/) do |var| key = $1 if CONFIG.key? key - "\#{Config::expand(CONFIG[\\\"\#{key}\\\"])}" + Config::expand(CONFIG[key]) else var end @@ -21,6 +21,7 @@ enum node_type { NODE_METHOD, NODE_FBODY, NODE_CFUNC, + NODE_IFUNC, NODE_SCOPE, NODE_BLOCK, NODE_IF, @@ -234,8 +235,9 @@ typedef struct RNode { #define NEW_DEFN(i,a,d,p) rb_node_newnode(NODE_DEFN,p,i,NEW_RFUNC(a,d)) #define NEW_DEFS(r,i,a,d) rb_node_newnode(NODE_DEFS,r,i,NEW_RFUNC(a,d)) #define NEW_CFUNC(f,c) rb_node_newnode(NODE_CFUNC,f,c,0) +#define NEW_IFUNC(f,c) rb_node_newnode(NODE_IFUNC,f,c,0) #define NEW_RFUNC(b1,b2) NEW_SCOPE(block_append(b1,b2)) -#define NEW_SCOPE(b) rb_node_newnode(NODE_SCOPE,local_tbl(),cur_cref,(b)) +#define NEW_SCOPE(b) rb_node_newnode(NODE_SCOPE,local_tbl(),0,(b)) #define NEW_BLOCK(a) rb_node_newnode(NODE_BLOCK,a,0,0) #define NEW_IF(c,t,e) rb_node_newnode(NODE_IF,c,t,e) #define NEW_UNLESS(c,t,e) NEW_IF(c,e,t) @@ -307,14 +309,12 @@ typedef struct RNode { #define NEW_ALIAS(n,o) rb_node_newnode(NODE_ALIAS,o,n,0) #define NEW_VALIAS(n,o) rb_node_newnode(NODE_VALIAS,o,n,0) #define NEW_UNDEF(i) rb_node_newnode(NODE_UNDEF,0,i,0) -#define NEW_CLASS(n,b,s) rb_node_newnode(NODE_CLASS,n,NEW_CBODY(b),(s)) -#define NEW_SCLASS(r,b) rb_node_newnode(NODE_SCLASS,r,NEW_CBODY(b),0) -#define NEW_MODULE(n,b) rb_node_newnode(NODE_MODULE,n,NEW_CBODY(b),0) +#define NEW_CLASS(n,b,s) rb_node_newnode(NODE_CLASS,n,NEW_SCOPE(b),(s)) +#define NEW_SCLASS(r,b) rb_node_newnode(NODE_SCLASS,r,NEW_SCOPE(b),0) +#define NEW_MODULE(n,b) rb_node_newnode(NODE_MODULE,n,NEW_SCOPE(b),0) #define NEW_COLON2(c,i) rb_node_newnode(NODE_COLON2,c,i,0) #define NEW_COLON3(i) rb_node_newnode(NODE_COLON3,0,i,0) -#define NEW_CREF0() (cur_cref=RNODE(ruby_frame->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) @@ -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<<i)) + } + if (val & (1L<<i)) return INT2FIX(1); return INT2FIX(0); } @@ -162,6 +162,7 @@ inspect_i(id, value, str) if (!rb_is_instance_id(id)) return ST_CONTINUE; if (RSTRING(str)->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,6 +286,9 @@ rb_obj_taint(obj) VALUE obj; { rb_secure(4); + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } OBJ_TAINT(obj); return obj; } @@ -514,33 +517,6 @@ sym_to_s(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 +752,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 +777,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 +1027,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; } @@ -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; { @@ -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 <node> singleton string %type <val> literal numeric -%type <node> compstmt stmts stmt expr arg primary command_call method_call +%type <node> compstmt stmts stmt expr arg primary command command_call method_call %type <node> if_tail opt_else case_body cases rescue exc_list exc_var ensure -%type <node> opt_call_args call_args ret_args args when_args -%type <node> aref_args opt_block_arg block_arg stmt_rhs -%type <node> mrhs mrhs_basic superclass generic_call block_call var_ref +%type <node> args ret_args when_args call_args paren_args opt_paren_args +%type <node> command_args aref_args opt_block_arg block_arg var_ref +%type <node> mrhs mrhs_basic superclass block_call block_command %type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg %type <node> assoc_list assocs assoc undef_list backref %type <node> block_var opt_block_var brace_block do_block lhs none @@ -251,7 +265,6 @@ program : { $<vars>$ = 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 = $<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) { $<node>3->nd_value = $4; $$ = NEW_OP_ASGN_OR(gettable($1), $<node>3); + if (is_instance_id($1)) { + $$->nd_aid = $1; + } } else if ($2 == tANDOP) { $<node>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(); $<num>$ = ruby_sourceline; } @@ -1239,30 +1254,35 @@ primary : literal $$ = NEW_CLASS($2, $5, $3); nd_set_line($$, $<num>4); local_pop(); - cref_pop(); class_nest--; } - | kCLASS tLSHFT expr term + | kCLASS tLSHFT expr + { + $<num>$ = in_def; + in_def = 0; + } + term { + $<num>$ = 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 = $<num>4; + in_single = $<num>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(); $<num>$ = ruby_sourceline; } @@ -1272,14 +1292,15 @@ primary : literal $$ = NEW_MODULE($2, $4); nd_set_line($$, $<num>3); local_pop(); - cref_pop(); class_nest--; } | kDEF fname { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("nested method definition"); + $<id>$ = 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 = $<id>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 { $<vars>$ = dyna_push(); } @@ -1390,47 +1422,7 @@ do_block : kDO dyna_pop($<vars>2); } -brace_block : '{' - { - $<vars>$ = dyna_push(); - } - opt_block_var - compstmt '}' - { - $$ = NEW_ITER($3, 0, $4); - fixpos($$, $4); - dyna_pop($<vars>2); - } - | kDO2 - { - $<vars>$ = dyna_push(); - } - opt_block_var - compstmt - kEND - { - $$ = NEW_ITER($3, 0, $4); - fixpos($$, $4); - dyna_pop($<vars>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 : '{' + { + $<vars>$ = dyna_push(); + } + opt_block_var + compstmt '}' { - if (!IN_COND) lex_state = EXPR_PAREN; + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $4); + dyna_pop($<vars>2); + } + | kDO + { + $<vars>$ = dyna_push(); + } + opt_block_var + compstmt kEND + { + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $4); + dyna_pop($<vars>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); } @@ -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)); @@ -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() @@ -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); } @@ -1049,7 +1049,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 +1438,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 +1462,7 @@ re_compile_pattern(pattern, size, bufp) PATFETCH_MBC(c); had_mbchar++; } + had_char_class = 0; /* \ escapes characters when inside [...]. */ if (c == '\\') { @@ -1473,6 +1477,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 +1488,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 +1496,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 +1506,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 +1523,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; @@ -3461,7 +3471,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) @@ -214,13 +214,23 @@ ruby_init_loadpath() #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 +239,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 +430,10 @@ proc_options(argc, argv) goto reswitch; case 'v': + if (verbose) { + s++; + goto reswitch; + } ruby_show_version(); verbose = 1; case 'w': @@ -728,7 +734,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 +877,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 +989,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])); } @@ -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("<Trie: @head = %s>", @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) - @@ -163,6 +163,9 @@ static struct signals { #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; i<argc; i++) { Check_Type(argv[i], T_FIXNUM); - if (kill(FIX2UINT(argv[i]), sig) < 0) + if (kill(FIX2INT(argv[i]), sig) < 0) rb_sys_fail(0); } } @@ -386,6 +389,16 @@ sigsegv(sig) } #endif +#ifdef SIGPIPE +static RETSIGTYPE sigpipe _((int)); +static RETSIGTYPE +sigpipe(sig) + int sig; +{ + /* do nothing */ +} +#endif + void rb_trap_exit() { @@ -546,7 +559,7 @@ trap(arg) #endif #ifdef SIGPIPE case SIGPIPE: - func = SIG_IGN; + func = sigpipe; break; #endif } @@ -659,7 +672,7 @@ Init_signal() ruby_signal(SIGSEGV, sigsegv); #endif #ifdef SIGPIPE - ruby_signal(SIGPIPE, SIG_IGN); + ruby_signal(SIGPIPE, sigpipe); #endif #endif /* MACOS_UNUSE_SIGNAL */ } @@ -18,7 +18,7 @@ #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */ -#ifndef atof +#if !defined(atof) && !defined(HAVE_STDLIB_H) double strtod(); #endif @@ -573,7 +573,7 @@ rb_f_sprintf(argc, argv) break; case 8: c = '7'; break; - case '2': + case 2: c = '1'; break; } s = &buf[pos]; @@ -174,7 +174,7 @@ rb_str_associate(str, add) rb_ary_push(RSTRING(str)->orig, 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; i<argc; i++) { VALUE s = argv[i]; @@ -2621,11 +2635,15 @@ rb_str_crypt(str, salt) VALUE str, salt; { extern char *crypt(); + VALUE result; if (TYPE(salt) != T_STRING) salt = rb_str_to_str(salt); if (RSTRING(salt)->len < 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); @@ -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'; @@ -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)); } @@ -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-05-26" +#define RUBY_VERSION_CODE 164 +#define RUBY_RELEASE_CODE 20010526 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..9fb120e09d 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 // @@ -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__ |