From 210367ec889f5910e270d6ea2c7ddb8a8d939e61 Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 20 Jan 1999 04:59:39 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r372, which included commits to RCS files with non-trunk default branches. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@373 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- COPYING | 358 ++-- ChangeLog | 2354 ++++++++++++++++++++++ MANIFEST | 64 +- Makefile.in | 102 +- README | 42 +- README.EXT | 499 +++-- README.jp | 38 +- ToDo | 41 +- array.c | 1037 ++++++---- bignum.c | 568 +++--- class.c | 268 ++- compar.c | 48 +- config.guess | 485 ++++- config.sub | 156 +- configure | 1397 ++++++++----- configure.bat | 3 +- configure.in | 249 ++- defines.h | 24 +- dir.c | 155 +- dln.c | 298 ++- dln.h | 14 +- enum.c | 141 +- env.h | 11 +- error.c | 656 ++++-- eval.c | 4820 +++++++++++++++++++++++++++++---------------- ext/Setup | 1 + ext/aix_ld.rb | 2 +- ext/curses/curses.c | 107 +- ext/curses/extconf.rb | 5 +- ext/curses/hello.rb | 4 +- ext/curses/view.rb | 1 + ext/dbm/dbm.c | 175 +- ext/dbm/extconf.rb | 6 +- ext/etc/etc.c | 91 +- ext/etc/extconf.rb | 24 + ext/extmk.rb.in | 235 ++- ext/extmk.rb.nt | 6 +- ext/fcntl/fcntl.c | 2 +- ext/kconv/kconv.c | 89 +- ext/md5/md5init.c | 14 +- ext/socket/depend | 2 +- ext/socket/extconf.rb | 12 +- ext/socket/socket.c | 829 ++++---- ext/tcltklib/extconf.rb | 114 +- ext/tcltklib/lib/tcltk.rb | 287 ++- ext/tcltklib/tcltklib.c | 293 ++- file.c | 905 +++++---- fnmatch.c | 83 +- gc.c | 496 +++-- glob.c | 119 +- hash.c | 921 ++++++--- inits.c | 10 +- instruby.rb | 54 +- intern.h | 484 ++--- io.c | 1562 +++++++++------ keywords | 2 + lex.c | 44 +- lib/base64.rb | 45 +- lib/cgi-lib.rb | 39 +- lib/complex.rb | 14 +- lib/date.rb | 91 +- lib/debug.rb | 12 +- lib/delegate.rb | 100 +- lib/e2mmap.rb | 77 +- lib/eregex.rb | 11 +- lib/finalize.rb | 66 +- lib/find.rb | 4 +- lib/ftools.rb | 31 +- lib/ftplib.rb | 1123 +++++------ lib/getopts.rb | 3 +- lib/importenv.rb | 15 +- lib/jcode.rb | 23 +- lib/mailread.rb | 5 +- lib/mathn.rb | 5 +- lib/matrix.rb | 239 ++- lib/mkmf.rb | 144 +- lib/mutex_m.rb | 60 +- lib/observer.rb | 8 +- lib/parsearg.rb | 5 +- lib/parsedate.rb | 81 +- lib/ping.rb | 33 +- lib/pstore.rb | 39 +- lib/rational.rb | 9 +- lib/shellwords.rb | 16 +- lib/sync.rb | 13 +- lib/thread.rb | 163 +- lib/thwait.rb | 113 +- lib/tracer.rb | 147 +- lib/weakref.rb | 39 +- main.c | 1 + marshal.c | 289 +-- math.c | 74 +- missing/dir.h | 126 +- missing/file.h | 1 - missing/x68.c | 24 + mkconfig.rb | 4 +- node.h | 231 ++- numeric.c | 1066 ++++++---- object.c | 871 ++++---- pack.c | 407 ++-- parse.y | 2025 +++++++++++-------- process.c | 410 ++-- random.c | 122 +- range.c | 174 +- re.c | 705 ++++--- re.h | 16 +- regex.c | 2515 ++++++++++++++++------- regex.h | 205 +- ruby.1 | 216 +- ruby.c | 393 ++-- ruby.h | 428 ++-- rubytest.rb | 2 + sample/fib.scm | 4 +- sample/freq.rb | 8 +- sample/from.rb | 36 +- sample/mkproto.rb | 8 +- sample/observ.rb | 15 +- sample/occur.rb | 8 +- sample/rbc.rb | 257 ++- sample/sieve.rb | 3 +- sample/test.rb | 218 +- sample/trojan.rb | 4 +- sample/tsvr.rb | 2 +- signal.c | 141 +- sprintf.c | 463 +++-- st.c | 280 +-- st.h | 18 +- string.c | 2015 ++++++++++--------- struct.c | 414 ++-- time.c | 405 ++-- top.sed | 96 +- util.c | 353 +++- util.h | 26 +- variable.c | 613 ++++-- version.c | 12 +- version.h | 4 +- win32/Makefile | 31 +- win32/config.h | 12 +- win32/ruby.def | 469 ++--- win32/sdbm.c | 2 +- 140 files changed, 25700 insertions(+), 14102 deletions(-) diff --git a/COPYING b/COPYING index 3c68f02bb4..eeb586b392 100644 --- a/COPYING +++ b/COPYING @@ -1,37 +1,40 @@ GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 + Version 2, June 1991 - Copyright (C) 1989 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, 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. +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 software, or if you modify it. - For example, if you distribute copies of a such a program, whether + For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. +source code. And you must show them these terms so they know their +rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, @@ -44,120 +47,207 @@ want its recipients to know that what they have is not the original, 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 redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's 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 -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) 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. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +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 give any other recipients of the Program a copy of this License +along with the Program. + +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 Program or any portion +of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +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 Program, 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 Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) 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; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, 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 executable. 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. + +If distribution of executable or 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 counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program 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. + + 5. 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 Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program 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. + + 7. 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 Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program 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 Program. + +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. - 7. The Free Software Foundation may publish revised and/or new versions + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program 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. + + 9. The Free Software Foundation may publish revised and/or new versions of the 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 Program -specifies a version number of the license which applies to it and "any +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 Program does not specify a version number of -the license, you may choose any version ever published by the Free Software +this License, you may choose any version ever published by the Free Software Foundation. - 8. If you wish to incorporate parts of the Program into other free + 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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 @@ -167,7 +257,7 @@ of promoting the sharing and reuse of software generally. NO WARRANTY - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED @@ -177,7 +267,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + 12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING @@ -189,25 +279,24 @@ POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - Appendix: How to Apply These Terms to Your New Programs + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. - To do so, attach the following notices to the program. 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. + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -216,33 +305,36 @@ the exclusion of warranty; and each file should have at least the You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: +necessary. Here is a sample; alter the names: - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice -That's all there is to it! +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog index 029e20077c..6a317e294b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,2355 @@ +Wed Jan 20 03:39:48 1999 Yukihiro Matsumoto + + * parse.y (yycompile): rb_in_compile renamed to ruby_in_compile. + + * ruby.c (load_file): define DATA iff __END__ appeared in script. + +Tue Jan 19 14:57:51 1999 Yukihiro Matsumoto + + * parse.y (here_document): need to protect lex_lastline. + + * parse.y (yylex): disable %//, %'', %``. + +Tue Jan 19 05:01:16 1999 Koji Arai + + * array.c (beg_len): round range value too much. + +Mon Jan 18 13:02:27 1999 Kuroda Jun + + * hash.c (env_keys): strchr() may return NULL. + +Mon Jan 18 17:51:47 1999 Yukihiro Matsumoto + + * instruby.rb (wdir): install libruby.a in archdir. + + * lib/ftools.rb (install): removes file before installing. + +Mon Jan 18 16:55:31 1999 MAEDA shugo + + * eval.c (rb_callcc): experimental continuation support. + +Sun Jan 17 19:45:37 1999 WATANABE Hirofumi + + * pack.c (pack_pack): nil packing caused SEGV. + +Sat Jan 16 13:18:03 1999 Yukihiro Matsumoto + + * string.c (rb_str_concat): character (fixnum) can be append to + strings + + * array.c (rb_ary_unshift): unshift returns array. + +Sat Jan 16 01:39:19 1999 Yoshida Masato + + * string.c (rb_str_split_method): UTF-8 support. + + * regex.c: UTF-8 support. + +Thu Jan 14 00:42:55 1999 Yukihiro Matsumoto + + * string.c (rb_str_gsub_bang): forget to add offset for null match. + + * eval.c (rb_thread_local_aset): can't modify in tainted mode. + + * hash.c (env_each_key): avoid generating temporary array. + +Wed Jan 13 23:58:50 1999 Yukihiro Matsumoto + + * hash.c (rb_f_setenv): name and value can be tainted. + +Wed Jan 6 02:42:08 1999 Yukihiro Matsumoto + + * bignum.c (Init_Bignum): forgot to define Bignum#===. + + * gc.c (gc_sweep): if add_heap() is called during GC, objects on + allocated heap page(s) are not marked, should not be recycled. + + * gc.c (gc_sweep): should refer latest freelist. + + * gc.c (id2ref): modified to support performance patch. + + * object.c (rb_obj_id): performance patch (no bignum for id). + +Tue Jan 5 01:56:18 1999 Yukihiro Matsumoto + + * config.guess: merge up-to-date from autoconf 2.12. + + * array.c (rb_ary_join): avoid calling rb_protect_inspect() till + it is really needed. + + * object.c (rb_obj_inspect): show detailed information for the + instance variables (infinite loop can avoid now). + + * struct.c (rb_struct_inspect): avoid infinite loop. + +Sun Jan 3 01:37:58 1999 Takao KAWAMURA + + * misc/ruby-mode.el (ruby-end-of-defun): moved too much. + + * misc/ruby-mode.el (ruby-mode-variables): set paragraph-separator + for the mode. + + * misc/ruby-mode.el: proper font-lock for `def' and `nil' etc. + +Sat Jan 2 17:09:06 1999 Yukihiro Matsumoto + + * eval.c (rb_jump_tag): new api to invoke JUMP_TAG. tag values + can obtained from rb_eval_string_protect()/rb_load_protect(). + + * eval.c (rb_rescue): now catches all exceptions but SystemExit. + + * eval.c (rb_eval_string_protect): eval string with protection. + + * eval.c (rb_load_protect): load file with protection. + + * io.c (rb_io_puts): avoid infinite loop for cyclic arrays. + + * eval.c (rb_thread_local_aref): thread local hash tables. + + * object.c (rb_equal): check exact equal before calling `=='. + +Thu Dec 31 22:28:53 1998 MAEDA shugo + + * eval.c (rb_f_require): feature names should be provided with + DLEXT extension. + + * marshal.c (Init_marshal): need to provide `marshal.so'. + +Wed Dec 30 02:29:16 1998 Yukihiro Matsumoto + + * variable.c (classname): do not call rb_ivar_set(). + + * eval.c (ruby_run): finalizers were called too early. + +Fri Dec 25 12:19:30 1998 Fukuda Masaki + + * gc.c (rb_gc_mark): should not return on FL_EXIVAR. + +Fri Dec 25 11:56:51 1998 Yukihiro Matsumoto + + * gc.c (gc_mark): proper scanning for temporary region. + + * eval.c (TMP_ALLOC): protection for C_ALLOCA was broken. + +Thu Dec 24 18:26:04 1998 Yukihiro Matsumoto + + * development version 1.3 released. + +Thu Dec 24 00:17:00 1998 Yukihiro Matsumoto + + * eval.c (rb_load): top self should be set properly. + + * variable.c (classname): check __classpath__ iff it is defined. + + * variable.c (classname): invalid warning at -v with static linked + ruby interpreter. + + * eval.c (is_defined): modified for expr::Const support. + + * eval.c (rb_eval): invoke method expr::Const if expr is not class + nor module. + + * parse.y (primary): enable expr::identifier as method + invocation. + +Wed Dec 23 03:04:36 1998 Yukihiro Matsumoto + + * regex.c (re_match): avoid too many loop pops for (?:..). + +Tue Dec 22 18:01:08 1998 Yukihiro Matsumoto + + * experimental version 1.1d1 released. + +Mon Dec 21 01:33:03 1998 Yukihiro Matsumoto + + * eval.c (TMP_PROTECT): add volatile to ensure GC protection. + + * string.c (rb_str_gsub_bang): calculate buffer size properly. + + * parse.y (lex_get_str): needed to return Qnil at EOS. + + * eval.c (find_file): check policy modified, raise exception + immediately for tainted load_path. + + * hash.c (rb_f_setenv): do not depend on setenv() nor putenv(). + +Thu Dec 17 06:29:23 1998 Yukihiro Matsumoto + + * ext/tk/tkutil.c (tk_s_new): use rb_obj_instance_eval(), instead + of rb_yield_0(). + + * eval.c (rb_f_require): forgot to call find_file in some cases. + + * eval.c (rb_f_require): `require "feature.so"' to load dynamic + libraries. old `require "feature.o"' is still OK. + + * eval.c (rb_eval): yield without value dumped core. + +Wed Dec 16 16:28:31 1998 Yukihiro Matsumoto + + * experimental version 1.1d0 (pre1.2) released. + +Wed Dec 16 10:43:34 1998 Yukihiro Matsumoto + + * regex.c (re_search): bound check before calling re_match(). + +Tue Dec 15 13:59:01 1998 Yukihiro Matsumoto + + * error.c (exc_to_s): returns class name for unset mesg. + + * error.c (exc_initialize): do not initialize @mesg by "". + + * parse.y (nextc): __END__ should handle CR+LF newlines. + +Wed Dec 9 13:37:12 1998 MAEDA shugo + + * pack.c (encodes): use buffering for B-encoding. + + * pack.c (pack_pack): Q-encoding by 'M'. + +Tue Dec 8 14:10:00 1998 Yukihiro Matsumoto + + * variable.c (generic_ivar_get): any object can have instance + variables now. great improvement. + + * variable.c (rb_name_class): do not set __classpath__ by default, + use __classid__ instead. + +Mon Dec 7 22:08:22 1998 Yukihiro Matsumoto + + * ruby.h (struct RFile): IO objects can have instance variables now. + + * parse.y (primary): allows `def obj::foo; .. end'. + +Mon Dec 7 18:24:50 1998 WATANABE Tetsuya + + * ruby.c (set_arg0): $0 supprt for HP-UX. + +Mon Dec 7 01:30:28 1998 WATANABE Hirofumi + + * dln.c (dln_strerror): better error messages on win32. + +Sat Dec 5 23:27:23 1998 Yukihiro Matsumoto + + * parse.y (here_document): indentable here-doc delimiter by + `<<-'. Proposed by Clemens . Thanks. + +Thu Dec 3 16:50:17 1998 Yukihiro Matsumoto + + * ext/extmk.rb.in (realclean): trouble on install. + +Sun Nov 29 22:25:39 1998 Takaaki Tateishi + + * process.c (f_exec): check number of argument. + +Thu Nov 26 17:27:30 1998 Yukihiro Matsumoto + + * version 1.1c9 released. + +Wed Nov 25 13:07:12 1998 Yukihiro Matsumoto + + * string.c (rb_str_dup): do not copy additional data (STR_NO_ORIG). + + * parse.y (yycompile): reduce known memory leak (hard to remove). + +Wed Nov 25 03:41:21 1998 Yukihiro Matsumoto + + * st.c (st_init_table_with_size): round size up to prime number. + +Sat Nov 21 23:27:23 1998 Yukihiro Matsumoto + + * hash.c (rb_hash_aset): reduce copying key strings. + + * gc.c (looks_pointerp): declare as inline function if possible. + + * st.c (PTR_NOT_EQUAL): compare hash values first before calling + comparing function. + + * st.c (ADD_DIRECT): save hash value in entries to reduce hash + calculation. + + * string.c (rb_str_gsub_bang): avoid rb_scan_args() to speed-up. + + * string.c (rb_str_sub_bang): ditto. + +Sat Nov 21 18:44:06 1998 Masaki Fukushima + + * time.c (time_s_now): had memory leak. + + * ext/md5/md5init.c (md5_new): had memory leak. + + * ext/md5/md5init.c (md5_clone): ditto. + +Fri Nov 20 23:23:23 1998 Yukihiro Matsumoto + + * lib/delegate.rb: do not propagate hash and eql?. + +Thu Nov 19 01:40:52 1998 Yukihiro Matsumoto + + * sample/ruby-mode.el (ruby-expr-beg): failed to find reserved + word boundary. + + * eval.c (rb_eval): avoid calling `concat' method. calls + rb_ary_concat() directly for efficiency. + + * eval.c (rb_eval): actual rest arguments extended arrays too much. + +Wed Nov 18 14:30:24 1998 Yukihiro Matsumoto + + * class.c (rb_define_global_function): global functions now be + module function of the Kernel. + +Wed Nov 18 10:48:09 1998 Yukihiro Matsumoto + + * io.c (read_all): SEGV on large files. + +Tue Nov 17 18:11:20 1998 Yukihiro Matsumoto + + * version 1.1c8 released. + +Tue Nov 17 16:58:47 1998 Yukihiro Matsumoto + + * parse.y (arg): assignment to attribute name start with capital + should be allowed. + + * eval.c (thread_alloc): needed to mark terminated threads too. + +Tue Nov 17 12:33:48 1998 Motoyuki Kasahara + + * ext/extmk.rb.in (create_makefile): Set `libdir' to `@libdir@', + Set `pkglibdir' to `$libdir/$(RUBY_INSTALL_NAME)'. + +Tue Nov 17 10:30:46 1998 Yukihiro Matsumoto + + * sprintf.c (f_sprintf): %l%%c -> %%l%c + +Tue Nov 17 01:08:50 1998 Yukihiro Matsumoto + + * parse.y (ret_args): distinguish `a' and `*a' for the arguments + of yield and return. + + * eval.c (rb_eval): flip3 should work like sed. + + * eval.c (rb_eval): flip{2,3} now have independent state for each + scope to work fine with thread. + +Mon Nov 16 23:26:29 1998 Yukihiro Matsumoto + + * parse.y (primary): exec else clause if no exception raised. + +Sun Nov 15 15:44:07 1998 Tadayoshi Funaba + + * ext/extmk.rb.in (install): bug in target. + +Sat Nov 14 11:02:05 1998 Motoyuki Kasahara + + * Makefile.in (install): Give the argument `$(DESTDIR)' to + `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. + * ext/extmk.rb.in: Likewise. + +Sat Nov 14 10:56:55 1998 Motoyuki Kasahara + + * instruby.rb: Add the variable `pkglibdir'. + * instruby.rb: Set the variable `libdir' to `$(libdir)', not + `$(libdir)/$(ruby_install_name)'. `libruby.so' and `libruby.so.LIB' + are installed at `libdir'. + * instruby.rb: Set the variable `archdir' to `$(pkglibdir)/$(arch)'. + +Fri Nov 13 19:43:29 1998 KIMURA Koichi + + * missing/nt.c (SafeFree): wrong free offset. + +Thu Nov 12 20:11:53 1998 Koji Arai + + * sample/ruby-mode.el: wrong highlight. + + * parse.y (parse_regx): newline in regexp was ignored. + +Wed Nov 11 10:54:57 1998 Yukihiro Matsumoto + + * parse.y (here_document): <<'FOO' should not escape anything. + + * parse.y (here_document): bare << here-doc available, even though + it's deprecated. + + * file.c (rb_file_s_readlink): return value should be tainted. + + * ext/etc/etc.c (setup_passwd): information (eg. GCOS name) should + be tainted (modified at Perl Conference). + +Tue Nov 10 00:22:11 1998 EGUCHI Osamu + + * configure.in: elf supprt for FreeBSD 3.x + +Tue Nov 10 00:05:43 1998 Yukihiro Matsumoto + + * parse.y (yylex): here document available in eval. + +Mon Nov 9 17:55:19 1998 Yukihiro Matsumoto + + * version 1.1c7 released. + +Fri Nov 6 19:25:27 1998 Takao KAWAMURA + + * sample/ruby-mode.el: font-lock patch. + +Thu Nov 5 15:42:22 1998 Yukihiro Matsumoto + + * sample/README, lib/README: simple description for each file. + +Wed Nov 4 18:14:19 1998 Yukihiro Matsumoto + + * eval.c (assign): attribute assignment should be called as public. + +Tue Nov 3 23:36:39 1998 Yukihiro Matsumoto + + * string.c (rb_str_dump): dumps core for negative char value. + + * regex.c (re_compile_pattern): out of boundary access for empty + regexp. + +Mon Nov 2 22:54:01 1998 Yukihiro Matsumoto + + * string.c (rb_str_aset): `str[str]' replaces first match. + +Mon Nov 2 18:24:33 1998 Yukihiro Matsumoto + + * eval.c (thread_create): was accessing modified status. + +Sun Nov 1 01:18:52 1998 EGUCHI Osamu + + * gc.c (xrealloc): size 0 needs round up to 1. + +Sat Oct 31 23:18:34 1998 Yukihiro Matsumoto + + * string.c (rb_str_split_method): negative LIMIT means number of + splitted fields are unlimited, as in perl. + + * string.c (rb_str_split_method): if LIMIT is unspecified, + trailing null fields are stripped. + +Sat Oct 31 04:16:14 1998 Inaba Hiroto + + * string.c (str_aref): regexp index SEGVed. + +Fri Oct 30 14:33:47 1998 Yukihiro Matsumoto + + * re.c (reg_match): returns nil for unmatch. + + * dir.c (dir_entries): new method. + + * eval.c (block_pass): do not push block, substitute it. + +Fri Oct 30 01:28:52 1998 Yukihiro Matsumoto + + * range.c (range_check): avoid <=> check for Fixnums. + + * array.c (rb_ary_aset): accept negative index. + +Wed Oct 28 22:00:54 1998 Yukihiro Matsumoto + + * regex.c (re_match): access out of boundary fixed. + +Wed Oct 28 11:37:42 1998 TAMITO + + * io.c (f_select): fd number comparison bug. + +Tue Oct 27 23:07:11 1998 Yukihiro Matsumoto + + * sample/ruby-mode.el (ruby-parse-region): forgot to support %w() + style array literal. + + * eval.c (rb_eval): unused block raises warning. + +Mon Oct 26 09:37:53 1998 Yukihiro Matsumoto + + * eval.c (dvar_asgn_push): dvar pushed too many times if + variable-in-block first appear in loops. + +Sun Oct 25 22:59:27 1998 Yukihiro Matsumoto + + * regex.c (set_list_bits): was using wrong offset. + +Thu Oct 22 00:07:11 1998 Yukihiro Matsumoto + + * eval.c (rb_obj_method): method retrieved from tainted object + should be tainted too. + + * eval.c (method_call): safe_level should be restored during + Method#call. + +Wed Oct 21 14:21:06 1998 Yukihiro Matsumoto + + * io.c (Init_IO): new constants IO::SEEK_{SET,CUR,END}. + + * io.c (rb_f_ungetc): ungetc pushes a char back into STDIN. + +Mon Oct 19 11:50:00 1998 Motoyuki Kasahara + + * ext/extmk.rb: Load '@top_srcdir@/lib/find.rb', not + '../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'. + * 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. + * instruby.rb: Chdir to wdir before install `config.h' and + `rbconfig.rb'. + +Mon Oct 19 10:07:01 1998 EGUCHI Osamu + + * eval.c (rb_eval): reduce recursive calls to rb_eval(). + +Fri Oct 16 15:31:45 1998 Yukihiro Matsumoto + + * time.c (time_new_internal): timeval must be positive. + +Thu Oct 15 13:54:48 1998 Yukihiro Matsumoto + + * parse.y (arg): local variabls can be accessed within right side + expression in assignment, notably in blocks. + +Wed Oct 14 00:18:33 1998 Yukihiro Matsumoto + + * array.c (Init_Array): Array#=== is now for equal check, not + inclusion check. + + * parse.y (when_args): `when a, *b' style new syntax for array + expansion in `case'. + +Tue Oct 13 14:30:32 1998 Yukihiro Matsumoto + + * object.c (rb_obj_untaint): taint marks can be unset. + + * eval.c (rb_eval): taint propagation for embedded strings. + +Mon Oct 12 13:27:15 1998 Yukihiro Matsumoto + + * eval.c (rb_call0): check stack depth more frequently. + +Mon Oct 12 08:08:30 1998 Yukihiro Matsumoto + + * io.c (rb_p): can print even in secure mode. + +Sun Oct 11 22:50:13 1998 Yukihiro Matsumoto + + * variable.c (rb_const_set): taint check for modification. + + * variable.c (rb_ivar_set): taint check for modification. + + * string.c (rb_str_modify): taint check for modification. + + * hash.c (rb_hash_modify): taint check for modification. + + * array.c (rb_ary_modify): taint check for modification. + + * ruby.h (FL_TAINT): taint for all objects, not only strings. + +Fri Oct 9 17:01:14 1998 Yukihiro Matsumoto + + * io.c (read_all): read() returns "" at immediate EOF. + + * io.c (io_read): read(nil) read all until EOF. + +Thu Oct 8 13:32:13 1998 Yukihiro Matsumoto + + * time.c (time_dump): marshal can dump Time object now. + + * marshal.c (Init_marshal): rename marshal methods `_dump_to' to + `_dump', `_load_from' to `_load'. + + * parse.y (rb_intern): "+=".intern generates proper symbol. + +Mon Oct 5 18:31:53 1998 Yukihiro Matsumoto + + * version 1.1c6 released. + +Fri Oct 2 14:22:33 1998 Yukihiro Matsumoto + + * regex.c (re_search): `/\s*(--)$/ =~ "- --"' did not match, + because of wrong optimize condition. + +Mon Oct 1 01:55:16 1998 Yukihiro Matsumoto + + * parse.y (rb_intern): should not raise exceptions. + + * parse.y (yylex): symbol like `:foo?=' should not be allowed. + + * ext/extmk.rb.in: makes *.a for static link modules. + +Wed Sep 30 14:13:06 1998 Yukihiro Matsumoto + + * eval.c (rb_thread_start): supports making a subclass of the + Thread class. + +Tue Sep 29 17:46:01 1998 Yukihiro Matsumoto + + * eval.c (rb_thread_join): join is now an instance method. + +Fri Sep 25 12:01:19 1998 Yukihiro Matsumoto + + * parse.y (yylex): `@foo!' should be an error. + +Thu Sep 24 14:55:06 1998 WATANABE Tetsuya + + * ext/etc/etc.c (Init_etc): wrong field definition. + +Thu Sep 17 17:09:05 1998 Yukihiro Matsumoto + + * io.c (io_reopen): was creating FILE* for wrong fd. + +Tue Sep 15 05:28:11 1998 Koji Arai + + * regex.c (re_compile_pattern): forgot to fixup for the pattern + like (?=(A)|(B)). + +Tue Sep 15 01:06:08 1998 Yukihiro Matsumoto + + * io.c (rb_io_gets_internal): do not set $_ by default, only + gets/readline set the variable. + + * eval.c (rb_f_load): load toplevel class is set to anonymous + module if safe_level >= 5, to encapsulate modification. + + * eval.c (rb_f_load): set frame properly. + + * string.c (rb_str_each_line): do not set $_. + +Mon Sep 14 14:42:27 1998 Yukihiro Matsumoto + + * regex.c (re_match): beginning and end of the string, do not + automatically match `\b'. + + * string.c (scan_once): comsume at leaset on character. + + * regex.c (re_search): wrong behavior for negative range. + +Sat Sep 12 21:21:26 1998 Koji Arai + + * regex.c (re_search): range value should be maintained. + +Thu Sep 10 10:55:00 1998 Yukihiro Matsumoto + + * parse.y (backref_error): yyerror does not understand formats. + +Tue Sep 8 18:05:33 1998 Yukihiro Matsumoto + + * version 1.1c5 released. + +Tue Sep 8 10:03:39 1998 Yukihiro Matsumoto + + * string.c (str_each_line): wrong line splitting with newline at + top of the string. + + * string.c: non bang methods return copied string. + + * eval.c (f_END): needed to initialize frame->argc; + +Fri Sep 4 11:27:40 1998 Yukihiro Matsumoto + + * bignum.c (bigadd): proper sign combination. + + * regex.c (re_search): wrong return value for \A. + +>>>>>>> 1.1.1.2.2.154 +Thu Sep 3 14:08:14 1998 Yukihiro Matsumoto + + * version 1.1c4 released. + +Tue Sep 1 10:47:16 1998 Yukihiro Matsumoto + + * regex.c (slow_search): do not compare llen and blen. llen may + be longer than blen, if little contains 0xff. + + * regex.c (mbctab_euc): set 0x8e as multibyte character. + + * string.c (str_inspect): mask character for octal output. + +Mon Aug 31 15:32:41 1998 Yukihiro Matsumoto + + * regex.c (re_search): use calculated offset if exactn is the + first opcode in the compiled regexp. + + * regex.c (bm_search): use Boyer-Moore search for simple search. + + * regex.c (must_instr): wrong length check if pattern includes + byte escape by 0xff. + + * regex.c (re_compile_pattern): need not to check current_mbctype. + +Sat Aug 29 16:31:40 1998 Yukihiro Matsumoto + + * eval.c (rb_check_safe_str): avoid calling rb_id2name() in normal + cases to speed-up. + + * eval.c (thread_raise): do not save context of terminated thread. + + * regex.c (re_compile_pattern): mask \nnn over 256. + +Sat Aug 29 02:09:46 1998 1998 Koji Arai + + * sprintf.c (f_sprintf): wrong buffer size check. + +Fri Aug 28 01:57:04 1998 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): accepts (?ix-ix) and (?ix-ix:...). + +Fri Aug 28 12:25:33 1998 Hiroshi Igarashi + + * ruby.c (ruby_require_modules): load modules in appearing order. + +Fri Aug 28 01:57:04 1998 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): accepts (?ix-ix) and (?ix-ix:...). + +Thu Aug 27 12:54:28 1998 Yukihiro Matsumoto + + * version 1.1c3 released. + +Wed Aug 26 14:40:56 1998 Yukihiro Matsumoto + + * eval.c (rb_eval): check whether ruby_class is properly set, + before accessing it. + + * eval.c (rb_obj_instance_eval): ruby_class should be Qnil for + special objects like Fixnums. + + * ext/tkutil/tkutil.c (Init_tkutil): removes calls to + rb_yield_0(). used instance_eval() instead in the tk.rb. + +Wed Aug 26 11:47:00 1998 Yukihiro Matsumoto + + * regex.c (re_match): pop non-greedy stack elements on success. + +Wed Aug 26 09:25:35 1998 WATANABE Hirofumi + + * ruby.h: add #define environ for cygwin32. + +Tue Aug 25 08:57:41 1998 Yukihiro Matsumoto + + * array.c (rb_ary_sort_bang): temporarily freeze sorting array. + +Mon Aug 24 18:46:44 1998 WATANABE Hirofumi + + * dln.c (dln_find_1): path check was too strict. + +Mon Aug 24 15:28:11 1998 WATANABE Hirofumi + + * parse.y (f_arglist): opt_nl added after f_args. + +Fri Aug 21 01:06:01 1998 Yukihiro Matsumoto + + * ext/socket/socket.c: grand renaming on socket.c. + + * ext/socket/socket.c (inet_aton): supply inet_aton for those + systems that do not have it. + + * ext/socket/socket.c (setipaddr): use inet_aton instead of + inet_addr. + + * ext/socket/socket.c (tcp_s_gethostbyname): new method: works + like Socket.gethostbyname but returning array contains ip-addrs + as octet decimal string format like "127.0.0.1". + + * ext/socket/socket.c (mkhostent): return format changed to + [host, aliases, type, ipaddr..] as documented. + +Wed Aug 19 00:31:09 1998 Yukihiro Matsumoto + + * io.c (io_ctl): forgot to place TRAP_END at right position. + +Fri Aug 14 11:01:47 1998 Yukihiro Matsumoto + + * eval.c (call_trace_func): save __FILE__, __LINE__ before + executing trace_func, since trace function should not corrupt + line number information. + +Thu Aug 13 15:09:02 1998 Yukihiro Matsumoto + + * array.c (ary_s_new): was marking unallocated region on GC. + +Tue Aug 11 11:57:35 1998 Yukihiro Matsumoto + + * version 1.1c2 released. + +Mon Aug 10 14:05:30 1998 Yukihiro Matsumoto + + * process.c (f_system): removed fflush(stdin). + +Fri Aug 7 17:44:44 1998 Yukihiro Matsumoto + + * error.c (err_snprintf): replace sprintf for fixed sized buffer, + with snprintf to avoid buffer over-run. For systems which does + dot provide snprintf, missing/snprintf.c added. + +Wed Aug 5 00:47:35 1998 Yukihiro Matsumoto + + * re.c (rb_reg_search): recycle match object. + +Mon Aug 3 09:17:55 1998 Yukihiro Matsumoto + + * string.c (rb_str_gsub_bang): do not allocate temporary string. + + * string.c (rb_str_sub_bang): use inline replace. + +Wed Jul 29 00:36:08 1998 Yukihiro Matsumoto + + * hash.c (hash_s_new): the default value can be specified. + + * hash.c (hash_default): method to set the default value. + + * hash.c (hash_aref): now returns the default value. + +Tue Jul 28 13:03:25 1998 Yukihiro Matsumoto + + * array.c (ary_s_new): argument to specify initial value is added. + + * array.c (ary_s_new): specifies size, not capacity. + +Mon Jul 27 12:39:34 1998 Yukihiro Matsumoto + + * string.c (str_replace): zero fill for expansion gap. + + * regex.c (mbctab_euc): set flags on for 0xA1-0xFE. suggested by + . + + * string.c (str_inspect): consider current_mbctype. + +Sun Jul 26 15:37:11 1998 Tadayoshi Funaba + + * array.c (ary_s_new): Array.new(1<<30) dumps core. + +Fri Jul 24 13:40:19 1998 Yukihiro Matsumoto + + * version 1.1c1 released. + +Fri Jul 24 02:10:22 1998 Yukihiro Matsumoto + + * marshal.c (r_bytes2): allocated buffer size was too short. + + * marshal.c (w_object): saves all options, not only casefold flag. + + * re.c (reg_clone): now copies options properly. + + * re.c (reg_get_kcode): code number was wrong. + +Thu Jul 23 13:11:32 1998 Yukihiro Matsumoto + + * eval.c (rb_attr): argument should be symbol or string. + +Wed Jul 22 11:59:34 1998 Yukihiro Matsumoto + + * regex.c (calculate_must_string): wrong offset added. + +Wed Jul 22 11:59:59 1998 Yukihiro Matsumoto + + * st.c (rehash): still had a GC problem. fixed. + +Tue Jul 21 13:19:30 1998 Yukihiro Matsumoto + + * eval.c (gc_mark_threads): crashed on GC before thread allocation. + + * st.c (rehash): GC during rehash caused SEGV. + +Tue Jul 21 01:25:10 1998 Yukihiro Matsumoto + + * sprintf.c (f_sprintf): integer formatter totally re-written. + + * sprintf.c (remove_sign_bits): support uppercase hexadecimal. + +Sat Jul 18 00:14:13 1998 Yukihiro Matsumoto + + * sprintf.c (f_sprintf): proper sign position for %X and %O. + +Fri Jul 17 14:10:20 1998 Yukihiro Matsumoto + + * version 1.1c0 released. + +Fri Jul 17 08:01:49 1998 Tadayoshi Funaba + + * process.c (f_exec): Check_SafeStr() added. + + * process.c (f_system): Check_SafeStr() moved before fork(). + +Thu Jul 16 22:58:48 1998 Yukihiro Matsumoto + + * string.c (scan_once): substrings to the block should not be + tainted. use reg_nth_match(), not str_substr(). + + * string.c (str_substr): needed to transfer taint. + +Thu Jul 16 16:15:57 1998 Yukihiro Matsumoto + + * gc.c (xmalloc): object allocation count added to GC trigger. + + * eval.c (thread_save_context): avoid marking uninitialized stack + in thread_mark. GC may be triggered by REALLOC_N(). + +Wed Jul 15 15:11:57 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_31. + +Wed Jul 15 15:05:27 1998 Yukihiro Matsumoto + + * eval.c (thread_create): exit() and abort() in threads now + forwarded to main_thread. + +Tue Jul 14 14:03:47 1998 Yukihiro Matsumoto + + * variable.c (obj_instance_variables): list names that is not + instance variables. + + * gc.c (GC_MALLOC_LIMIT): choose smaller limit value. + +Mon Jul 13 12:39:38 1998 Yukihiro Matsumoto + + * object.c (str2cstr): should not return NULL. + +Fri Jul 10 11:51:46 1998 Yukihiro Matsumoto + + * parse.y (gettable): needed to add dyna_in_block() check. + +Thu Jul 9 17:38:23 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_30. + +Thu Jul 9 16:01:48 1998 Yukihiro Matsumoto + + * sprintf.c (fmt_setup): format specifier for long needed. + + * sprintf.c (f_sprintf): ditto. + + * numeric.c (fix2str): ditto. + + * eval.c (thread_create): no more ITIMER_REAL. + + * eval.c (thread_create): thread finalization needed before + aborting thread if thread_abort is set. + +Wed Jul 8 18:17:33 1998 Yukihiro Matsumoto + + * bignum.c (big_pow): abandon power by bignum (too big). + +Tue Jul 7 13:58:43 1998 Yukihiro Matsumoto + + * eval.c (rb_catch): add C level catch/throw feature. + +Mon Jul 6 15:18:09 1998 Yukihiro Matsumoto + + * parse.y (arg): proper return values for `||=' and `&&='. + +Fri Jul 3 16:05:11 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_29. + +Fri Jul 3 11:20:46 1998 Yukihiro Matsumoto + + * marshal.c (r_byte): byte should not extend sign bit. + + * numeric.c (fix_mul): use FIX2LONG() instead of FIX2INT() for + 64bit architectures. + + * marshal.c (r_bytes): remove weird casting bwetween pointer and int. + + * process.c (proc_setsid): new method Process#setsid(). + +Thu Jul 2 12:49:21 1998 Yukihiro Matsumoto + + * marshal.c (w_object): remove `write_bignum' label for 64bit + architectures. + + * marshal.c (r_bytes): needs int, not long. + +Wed Jul 1 14:21:06 1998 Yukihiro Matsumoto + + * numeric.c (flo_plus): should not allow addition with strings. + +Wed Jul 1 13:09:01 1998 Keiju ISHITSUKA + + * numeric.c (num_uminus): wrong coerce direction. + +Tue Jun 30 10:13:44 1998 Yukihiro Matsumoto + + * io.c (f_p): accepts arbitrary number of arguments. + + * eval.c (rb_yield_0): there's some case that iterator_p() returns + true even if the_block was not set. check added. + +Tue Jun 30 01:05:20 1998 Yukihiro Matsumoto + + * eval.c (BEGIN_CALLARGS): adjust the_block before evaluating the + receiver's value and the arguments. + +Fri Jun 26 18:02:50 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_28. + +Fri Jun 26 11:01:26 1998 WATANABE Hirofumi + + * string.c (str_aset_method): needed to convert to string. + +Thu Jun 25 02:05:50 1998 Yukihiro Matsumoto + + * regex.c (re_search): optimize for `.*' at beginning of the + pattern. + + * regex.c (re_search): optimize for character class repeat at + beginning of the pattern. + + * regex.c (re_compile_pattern): detect optimization potential for + the compiled patterns. + +Thu Jun 25 00:02:26 1998 WATANABE Hirofumi + + * re.c (reg_s_new): flag value was wrong. + +Wed Jun 24 23:45:06 1998 Yukihiro Matsumoto + + * regex.c (re_search): wrong anchor handling for reverse search. + +Wed Jun 24 02:18:57 1998 Yukihiro Matsumoto + + * parse.y (mlhs): `((a,b)),c = [[1,2]],3' assigns a=1,b=2,c=3. + +Tue Jun 23 11:46:16 1998 Yukihiro Matsumoto + + * parse.y (yylex): `&&=' and `||=' added. + +Sat Jun 20 02:53:50 1998 Yukihiro Matsumoto + + * parse.y (assignable): nesting local variables should have higher + priority than normal local variables for assignment too. + +Fri Jun 19 18:28:19 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_27. + +Fri Jun 19 14:34:49 1998 Yukihiro Matsumoto + + * eval.c (assign): support hack for nested multiple assignment. + + * parse.y (mlhs): nested multiple assignment. + + * eval.c (rb_eval): in-block variables now honors static scope. + + * configure.in: RSHIFT check moved to configure. + +Thu Jun 18 16:46:04 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_26. + +Thu Jun 18 13:37:19 1998 Yukihiro Matsumoto + + * file.c (file_s_ftype): uses lstat(2) instead of stat(2). + + * dir.c (dir_s_glob): there can be buffer overrun, check added. + + * eval.c (f_binding): handles in-block variables declared after + binding's generation. + + * numeric.c (flo_floor): floor, ceil, round added to Float. + +Wed Jun 17 11:20:00 1998 Yukihiro Matsumoto + + * parse.y (gettable): nesting local variables should have higher + priority than normal local variables. + +Tue Jun 16 12:30:46 1998 Yukihiro Matsumoto + + * bignum.c (str2inum): handles `+ddd'. + + * struct.c (make_struct): name parameter can be nil for unnamed + structures. + +Mon Jun 15 16:30:10 1998 Yukihiro Matsumoto + + * object.c (class_s_inherited): prohibiting to make subclass of + class Class. + + * object.c (module_s_new): support for making subclass of Module. + + * parse.y (yycompile): clear eval_tree before compiling. + +Fri Jun 12 17:58:18 1998 Yukihiro Matsumoto + + * eval.c (eval): write back the_dyna_var into the block. + +Thu Jun 11 18:19:18 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_25. + + * eval.c (dvar_add_compiling): register dyna_var at compile time. + + * regex.c (re_compile_pattern): RE_DUP_MAX iteration is too big. + +Wed Jun 10 15:12:04 1998 Yukihiro Matsumoto + + * io.c (io_eof): do not block other threads. + + * signal.c (trap): reserve SIGALRM for thread. + + * eval.c (thread_create): use ITIMER_REAL also to avoid system + call blocking. + + * io.c (f_syscall): add TRAP_BEG, TRAP_END around system calls. + + * io.c (io_ctl): add TRAP_BEG, TRAP_END around system calls. + + * enum.c (enum_collect): did not collect false values. + + * array.c (ary_new2): forgot to initialize capa field. + +Tue Jun 9 18:36:15 1998 WATANABE Hirofumi + + * string.c (str_split_method): split dumped core for "\xff". + +Tue Jun 9 16:22:12 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_24. + +Tue Jun 9 16:04:07 1998 WATANABE Hirofumi + + * ext/kconv/kconv.c (kconv_guess): more precise decision for EUC, + using jless algorithm (3 sequential EUC hiragana characters). + +Tue Jun 9 15:12:44 1998 Yukihiro Matsumoto + + * ext/kconv/kconv.c (kconv_guess): wrong guess for EUC as SJIS in + some cases (0xe0 - 0xef). + + * gc.c (xmalloc): insert size check for big (negative in signed) + allocation size. + +Tue Jun 9 02:54:51 1998 Yukihiro Matsumoto + + * lib/parsedate.rb: wday moved to the last in the return values. + +Mon Jun 8 10:40:16 1998 Yukihiro Matsumoto + + * string.c (str_split_method): split dumped core for "\0". + +Sat Jun 6 22:50:52 1998 Yukihiro Matsumoto + + * regex.c (calculate_must_string): wrong condition for + {start,stop}_nowidth. + + * regex.c (re_match): various features imported from GNU regex.c + 0.12, such as nested grouping, avoiding infinite loop with empty + match, etc. + + * regex.c (register_info_type): now use union. + + * regex.c (re_search): more precise anchor(^) check. + +Wed Jun 3 18:07:54 1998 Yukihiro Matsumoto + + * re.c (reg_raise): check rb_in_compile, not rb_in_eval. + +Mon Jun 1 05:26:06 1998 WATANABE Tetsuya + + * string.c (trnext): casting to signed char* needed. + +Tue Jun 2 16:00:12 1998 Yukihiro Matsumoto + + * ext/socket/socket.c (udp_addrsetup): error check enhanced. + + * ext/socket/socket.c (sock_s_getservbyaname): use strtoul(), if + possible. + +Sat May 30 07:10:02 1998 Yukihiro Matsumoto + + * re.c (reg_prepare_re): no more needless regular expression + recompile on casefold conditions. + +Thu May 28 18:02:55 1998 Yukihiro Matsumoto + + * object.c (nil_plus): no more `+' method for nil. + +Wed May 27 17:33:46 1998 Yukihiro Matsumoto + + * hash.c (hash_fetch): new method. + + * regex.c (re_search): check whether translate table is set. + +Tue May 26 11:39:50 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_23. + + * parse.y (yylex): no UPLUS/UMINUS for 1st argument if + parenthesises are omitted. + +Tue May 26 01:09:55 1998 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): (?XI) for turns off the + corresponding option. + +Mon May 25 12:38:56 1998 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): inline i option (?i). + + * regex.c (re_compile_pattern): inline x option (?x). + + * regex.c (re_compile_pattern): x option for regexp. + + * dir.c (dir_s_open): returns block's evaluated value. + + * io.c (f_open): returns block's evaluated value. + + * ext/curses/curses.c (curses_addstr): nil argument caused SEGV. + +Fri May 22 11:52:45 1998 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): push mark on (?:), so that + laststart check for {a,b} can be done. + +Thu May 21 17:31:16 1998 Yukihiro Matsumoto + + * regex.c (re_match): wrong match (too non-greedy) for `{a,b}?'. + + * io.c (io_lineno): new method IO#lineno, IO#lineno=. + +Wed May 20 06:04:43 1998 MAEDA shugo + + * BeOS patch. + +Wed May 20 16:32:19 1998 Yukihiro Matsumoto + + * bignum.c (BIGDN): use RSHIFT(), instead of mere `>>'. + +Tue May 19 16:36:26 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_22. + +Tue May 19 16:31:57 1998 Yukihiro Matsumoto + + * parse.y (assignable): specification changed for in-block + variable definition. + + * eval.c (dyna_var_asgn): error in in-block variables' compile + time definition. + + * parse.y (str_extend): wrong nesting detection. + +Tue May 19 09:47:55 1998 WATANABE Hirofumi + + * numeric.c (num2int): re-defined (extensions may use this). + +Mon May 18 16:40:50 1998 MAEDA shugo + + * error.c (get_syserr): BeOS support. + + * configure.in: modified for BeOS. + + * string.c (str_dump): do not call isascii(). + + * sprintf.c (remove_sign_bits): forgot to initialize end pointer. + + * glob.c: #include added. + +Mon May 18 14:52:21 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_21. + +Mon May 18 03:27:57 1998 MAEDA shugo + + * file.c (file_s_expand_path): optional second argument + `default_directory' added. + +Sat May 16 22:06:52 1998 WATANABE Hirofumi + + * error.c (RAISE_ERROR): wrong error message + +Fri May 15 14:43:25 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_20. + +Thu May 14 14:44:21 1998 WATANABE Hirofumi + + * sun4 cc patches for intern.h and regex.h. + +Thu May 14 14:03:16 1998 Yukihiro Matsumoto + + * random.c (RANDOM_MAX): guessing proper maximum value for random + numbers. + + * random.c (f_rand): use drand48 if possible. + +Wed May 13 19:05:20 1998 1998 MAEDA shugo + + * BeOS patches for io.c, error.c and config.guess. + +Wed May 13 14:56:23 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_19. + + * most of the Mac and BeOS patches merged, except path separators. + + * error.c (err_append): generated SyntaxError was String. + + * ruby.h: xxx2INT, xxx2UINT checks values as int, not long. + + * ruby.h: remove typedef's. INT, UINT, UCHAR, USHORT. + +Tue May 12 17:38:00 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_18. + +Tue May 12 11:38:08 1998 Yukihiro Matsumoto + + * error.c (syserr_errno): returns errno of the SystemCallError. + + * error.c (rb_sys_fail): saves errno in the Exception. + + * error.c (set_syserr): no need to protect syserr_list. + + * error.c (rb_sys_fail): no more bufsize limit. + + * error.c (set_syserr): integer value of errno can be accessed by + Errno::EXXX::Errno. + +Sun May 10 03:10:33 1998 WATANABE Tetsuya + + * io.c (io_tell etc.): moved from File class to IO class. + +Fri May 8 12:26:37 1998 Yukihiro Matsumoto + + * pack.c (pack_unpack): should be unsigned int (was signed int). + +Thu May 7 16:34:10 1998 Yukihiro Matsumoto + + * pack.c (pack_pack): `V', `N' uses newly created NUM2UINT(). + + * ruby.h (NUM2UINT): new macro. + + * bignum.c (big2uint): try to convert bignum into UINT. + + * re.c (reg_match): needed to return false for match with nil. + + * gc.c (obj_free): wrong condition to free string. + +Wed May 6 21:08:08 1998 WATANABE Hirofumi + + * ruby.c (ruby_process_options): modified for DJGPP. + +Wed May 6 15:48:03 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_17. + +Wed May 6 01:37:39 1998 Yukihiro Matsumoto + + * eval.c: remove global variable `errat'. + + * eval.c (rb_longjmp): embed error position information in the + exception object. + +Sat May 2 12:20:02 1998 Yukihiro Matsumoto + + * re.c (reg_search): supports reverse search. + + * string.c (str_index_method): does update $~ etc. + + * eval.c (f_load): needed to clear the_dyna_vars. + + * eval.c (dyna_var_asgn): do not push dyna_var, which is id == 0. + + * error.c (Init_Exception): NotImplementError is no longer + StandardError, which is not handled by default rescue. + +Fri May 1 00:35:51 1998 Yukihiro Matsumoto + + * ruby.c (proc_options): `-d' turns on verbose flag too. + + * error.c (exception): last argument may be the superclass of the + defining exception(s). + + * io.c (Init_IO): EOFError is now subclass of the IOError. + + * io.c (Init_IO): forgot to define IOError. + + * error.c (Init_Exception): old Exception class renamed to + StandardError. Exception now replaces old GlobalExit. + + * error.c (Init_Exception): Exception is now the root of the + Global Exits. There's no longer GlobalExit class. + + * util.c (ruby_mktemp): check TMP, TMPDIR first. + +Thu Apr 30 01:08:35 1998 Yukihiro Matsumoto + + * lib/tk.rb: call 'unknown', if proc not defined. + + * eval.c (handle_rescue): default rescue handles `Exceptional' not + only the instance of the `Exception's. + + * eval.c (f_raise): exception can be any object. + + * time.c (time_gm_or_local): call time_gmtime or time_localtime. + + * eval.c (f_raise): raises TypeError if the class which is not a + subclass of String is specified (checked in exc_new()). + + * error.c (exc_new): need to check whether invalid class (not a + subclass of String) is specified. + +Wed Apr 29 21:05:44 1998 WATANABE Hirofumi + + * ruby.c (proc_options): option '-e' via tempfile. + +Tue Apr 28 15:27:58 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_16. + +Tue Apr 28 00:07:38 1998 Yukihiro Matsumoto + + * eval.c (obj_is_proc): type check predicate. + + * eval.c (obj_is_block): ditto. + +Mon Apr 27 16:59:17 1998 Yukihiro Matsumoto + + * ext/gtk/gtk.c (Init_gtk): use timeout, not idle to avoid + comsuming CPU too much. + + * lib/tk.rb: use tcltklib#_invoke instead of `_eval'. + +Mon Apr 27 16:59:17 1998 Yukihiro Matsumoto + + * array.c (ary_sort): use dup, not clone. + +Mon Apr 27 13:46:27 1998 Tadahiro Maebashi + + * ext/tcltklib/tcltklib.c (ip_invoke): invoke tcl command + directly. need not worry about escaping tcl characters. + +Mon Apr 27 12:04:43 1998 Yukihiro Matsumoto + + * random.c (f_rand): do not call srand() implicitly. + +Fri Apr 24 14:35:45 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_15. + + * parse.y (assignable): dyna_var_asgn actually defines nested + local variables in outer context. + + * random.c (f_rand): call srand(), if it has not called yet. + + * random.c (f_srand): use tv_usec as the default seed. + + * eval.c (rb_eval): values of nested local variables should be + independent. + + * eval.c (rb_yield_0): local variables wrong nested conditions. + +Wed Apr 22 23:27:17 1998 Yukihiro Matsumoto + + * io.c (select_get_io): get IO object by `to_io'. + + * io.c (io_to_io): method to retrieve IO object, from delegating + object for example. + +Wed Apr 22 16:52:37 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_14. + + * string.c (str_modify): check for embedded pointer reference. + + * gc.c (obj_free): ditto. + + * pack.c (pack_pack): p/P template to embed pointers. + +Wed Apr 22 00:07:10 1998 Tadayoshi Funaba + + * array.c (ary_rindex): embarrassing typo. + +Tue Apr 21 12:31:48 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_13. + + * configure.in (RUBY_LIB): supports --program-{prefix,suffix}. + + * array.c (ary_rindex): new method. + + * io.c (io_binmode): should return self. + +Tue Apr 21 08:23:04 1998 Tadayoshi Funaba + + * parse.y (here_document): calling parse_string with wrong + arguments. + + * struct.c (struct_aset): problem member assignment with name. + +Mon Apr 20 14:47:49 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_12. + + * time.c (time_arg): args may be string (support for reduced + implicit type conversion). + + * lib/base64.rb: changed to use pack/unpack with `m' template. + +Mon Apr 20 06:23:20 1998 Yukihiro Matsumoto + + * variable.c (mod_remove_const): new method. + +Sat Apr 18 03:53:27 1998 Yukihiro Matsumoto + + * hash.c (hash_each_with_index): removed. use Enumerable's + each_with_index instead. + + * class.c (rb_include_module): check for super modules, since + module's included modules may be changed. + +Fri Apr 17 21:50:47 1998 WATANABE Hirofumi + + * marshal.c (r_long): r_byte() may return signed byte. + +Fri Apr 17 11:58:30 1998 NAGAI Hidetoshi + + * ext/tcltklib/tcltklib.c (lib_mainloop): thread and interrupt check. + +Fri Apr 17 11:06:30 1998 Yukihiro Matsumoto + + * eval.c (find_file): try to fopen() to check whether file exists. + + * ruby.c (load_file): ditto. + + * struct.c (struct_aset): struct member can be set by member name. + +Fri Apr 17 00:47:19 1998 WATANABE Hirofumi + + * ext/extmk.rb.in: added m68k-human support + + * file.c (LOCK_SH): defines moved. + + * array.c (ary_flatten_bang): simplified loop. + +Thu Apr 16 16:52:01 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_11. + + * lib/tk.rb: thread support (experimental - maybe slow). + + * eval.c (rb_longjmp): trace event on exception in raising + context, just before raising exception. + + * struct.c (struct_s_members): forgot to check singletons. + + * struct.c (struct_aref): members can be accessed by names too. + + * array.c (ary_flatten): new method. + + * eval.c (rb_longjmp): prints exception information with `-d'. + + * object.c (any_to_s): remove class name restriction. + +Thu Apr 16 01:38:02 1998 Yukihiro Matsumoto + + * file.c (thread_flock): do not block other threads. + + * eval.c (thread_trap_eval): signals are now delivered to the + current thread again. In case that the current thread is dead, + signals are forwarded to the main thread. + + * string.c (str_new4): need not to duplicate frozen strings. + +Wed Apr 15 08:33:47 1998 Tadayoshi Funaba + + * struct.c (struct_inspect): remove restriction for struct names. + +Wed Apr 15 02:55:02 1998 Kazuya 'Sharl' Masuda + + * x68 patches to config.sub, ext/extmk.rb.in + +Wed Apr 15 01:22:56 1998 Yukihiro Matsumoto + + * string.c (str_dup_frozen): do not duplicate frozen strings. + + * parse.y (yylex): allow nested parenthesises. + + * io.c (obj_displayln): prints newline after `display'ing the + receiver. + + * io.c (io_puts): avoid generating "\n" each time. use RS_default + instead. + + * io.c (f_p): ditto. + +Tue Apr 14 22:18:17 1998 Tadayoshi Funaba + + * struct.c (struct_aref): should not subtract negative index. + +Tue Apr 14 11:34:50 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_10. + + * parse.y: token names prefixed by `t'. + + * struct.c (struct_s_def): supports subclassing of Struct. + + * io.c (io_s_new): supports subclassing of IO. + +Mon Apr 13 11:07:39 1998 Yukihiro Matsumoto + + * eval.c (f_binding): need to restore method name. + + * eval.c (rb_call0): raises SystemStackError, not Fatal. + + * io.c (obj_display): same as `print self'. + + * io.c (f_p): can now be called in the method form. + + * re.c (reg_regsub): needed to be mbchar aware. + +Mon Apr 13 13:18:32 1998 Yukihiro Matsumoto + + * eval.c (thread_trap_eval): all signals delivered to main_thread. + +Mon Apr 13 12:47:03 1998 TAKAHASHI Masayoshi + + * re.c (kcode_set_option): did not set SJIS on SJIS condition. + +Sun Apr 12 22:14:07 1998 Kazunori NISHI + + * array.c (ary_uniq_bang): should be `==', not `='. embarrassing. + +Sat Apr 11 02:13:30 1998 Yukihiro Matsumoto + + * array.c (ary_subseq): SEGVed for `[][1,1]'. + +Fri Apr 10 21:29:06 1998 Tadayoshi Funaba + + * array.c (ary_subseq): add check for beg larger than array length. + +Wed Apr 8 17:24:11 1998 MAEDA shugo + + * dir.c (dir_s_open): can be called with block (like IO#open). + + * dir.c (dir_s_chdir): print directory path on error. + + * dir.c (dir_s_chroot): ditto + + * dir.c (Init_Dir): needed to override `new'. + +Thu Apr 9 18:24:58 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_09. + + * string.c (str_cmp): do not depend on sentinel at the end of the + strings. + + * string.c (str_chomp_bang): forgot to set the sentinel. + +Wed Apr 8 00:59:13 1998 Yukihiro Matsumoto + + * bignum.c (big2int): converted int may be too big to fit in + signed int. + + * parse.y (arg): `foo += 1' should not cause an error. + + * variable.c (rb_const_defined): returned false even if the + constant is defined at the top level. + + * eval.c (f_local_variables): dyna_var->id may be null. should + have checked before calling str_new2(). + +Tue Apr 7 01:15:15 1998 Kaneko Naoshi + + * re.c (reg_regsub): need to check string boundary. + +Tue Apr 7 19:19:12 1998 Yukihiro Matsumoto + + * string.c (str_cmp): returns either 1, 0, -1. + + * array.c (ary_cmp): should check array length, too + +Tue Apr 7 18:50:16 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_08. + +Tue Apr 7 18:31:27 1998 WATANABE Hirofumi + + * instruby.rb (mandir): dll installation for cygwin32 + +Tue Apr 7 01:16:45 1998 Yukihiro Matsumoto + + * config.sub (maybe_os): TOWNS support? + + * config.guess: too strict check for libc versions on linuxes. + + * experimental release 1.1b9_07. + + * array.c (ary_cmp): compare each element using `<=>'. + + * hash.c (hash_each_with_index): yields [value, key] pair. + + * class.c (class_protected_instance_methods): list protected + method names. + + * class.c (ins_methods_i): exclude protected methods. + + * eval.c (PUSH_BLOCK): dynamic variables can be accessed from + eval() with bindings. + +Mon Apr 6 14:49:06 1998 Yukihiro Matsumoto + + * eval.c (thread_yield): must return evaluated value. + +Fri Apr 3 13:07:29 1998 Yukihiro Matsumoto + + * eval.c (thread_schedule): context switch bypassed on wrong + conditions. + + * variable.c (rb_name_class): set classname by id before String + class is initialized (1.0 behavior restored). + +Fri Apr 3 11:25:45 1998 Yukihiro Matsumoto + + * numeric.c (num2int): no implicit conversion from string. + + * numeric.c (num2int): check whether `to_i' returns an Integer. + + * numeric.c (num_zero_p): new method. + + * numeric.c (num_nonzero_p): new method. returns the receiver if + it's not zero. + + * eval.c (obj_instance_eval): the_class should be the object's + singleton class. + + * error.c (exc_s_new): message is converted into a string. + +Thu Apr 2 18:31:46 1998 Yukihiro Matsumoto + + * eval.c (obj_call_init): every object call `initialize'. + +Wed Apr 1 08:51:53 1998 Tadayoshi Funaba + + * parse.y (stmt): UNTIL_MOD should be for stmt, not only for expr. + +Wed Apr 1 01:20:31 1998 Yukihiro Matsumoto + + * object.c (true_and): boolean operators &, | and ^. + +Tue Mar 31 13:23:58 1998 Yukihiro Matsumoto + + * array.c (ary_compact_bang): returns nil, if it does not modify + the array like String's bang methods. + + * array.c (ary_uniq_bang): new method to remove duplicate items. + + * eval.c (bind_s_new): new method. + + * numeric.c (num2int): raise exception if Fixnums too big to + convert into `int' in case that sizeof(int) < sizeof(INT). + + * string.c (str_center): SEGV on negative width. + + * eval.c (eval): forgot to set sourcefile. + +Mon Mar 30 11:12:29 1998 Yukihiro Matsumoto + + * file.c (f_test): raises exception for unkown command. + + * eval.c (Init_eval): `class_eval': alias to the module_eval. + +Mon Mar 30 18:50:42 1998 Tadayoshi Funaba + + * string.c (str_capitalize_bang): did not check string modification. + + * string.c (str_delete_bang): wrong conversion. + + * string.c (str_intern): typo in error message. + +Mon Mar 30 01:44:13 1998 Yukihiro Matsumoto + + * eval.c (obj_instance_eval): accepts block as evaluation body. + No compilation needed each time. + + * eval.c (mod_module_eval): ditto + + * file.c (file_s_umask): umask did not return old values, if no + argument given. + +Sun Mar 29 00:54:23 1998 Yukihiro Matsumoto + + * eval.c (f_throw): nil returned always. + +Sat Mar 28 20:40:12 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_06. + +Sat Mar 28 16:07:11 1998 WATANABE Hirofumi + + * io.c (io_closed): should not cause exception fot closed IO. + + * string.c (str_tr): returned nil for success. + +Sat Mar 28 00:47:19 1998 Yukihiro Matsumoto + + * eval.c (f_local_variables): new method to return an array of + local variable names. + + * variable.c (obj_instance_variables): now returns an array of + variable names, as described in the reference. + + * eval.c (rb_attr): honors default method visibility of the + current scope. + +Fri Mar 27 13:49:27 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_05. + + * ruby.c (ruby_prog_init): `site_ruby' added to load_path. + + * ruby.c (ruby_prog_init): load-path order changed. Paths in + the RUBYLIB environment variable comes first in non-tainted + mode. + +Thu Mar 26 11:51:09 1998 Yukihiro Matsumoto + + * eval.c (rb_call): new feature: `protected' methods. + + * string.c (str_dump): new method. + + * eval.c (block_pass): block argument can be nil, which means no + block is supplied for the method. + +Wed Mar 25 21:20:13 1998 Tadayoshi Funaba + + * string.c (str_reverse_bang): string copied to wrong place. + +Wed Mar 25 08:12:07 1998 Yukihiro Matsumoto + + * numeric.c (flo_modulo): caused SEGV if left operand is not a + float value. + + * eval.c (f_eval): optional third and fourth argument to specify + file-name and line-number. + + * eval.c (eval): file-name and line-number set properly. + + * parse.y (assign_in_cond): literal assignment is now warning, not + compile error. + + * error.c (Warn): Warn() always print message, OTOH Waring() + prints when verbose flag is set. + +Tue Mar 24 12:50:06 1998 Yukihiro Matsumoto + + * ruby.c (ruby_prog_init): `.' should come last in the load-path. + + * eval.c (Init_eval): `__send__', alias for `send'. + +Mon Mar 23 12:44:12 1998 Yukihiro Matsumoto + + * string.c (str_chomp_bang): now takes `rs' as an argument. + + * eval.c (thread_free): main_thread should not be freed. + +Fri Mar 20 16:40:34 1998 Yukihiro Matsumoto + + * string.c (str_chomp_bang): chomp! (and other ! methods) returns + nil if it does not modify the string. + + * string.c (str_sub_iter_s): should check last pattern since it + may be matched to null. + +Thu Mar 19 13:48:55 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_04. + + * parse.y (yylex): `10e0.9' should cause syntax error. + +Wed Mar 18 17:46:31 1998 Yukihiro Matsumoto + + * ruby.c (load_file): new file object constant DATA. Only + available for the script from the file. + + * regex.c (re_match): forwading failure point popped too much. + +Tue Mar 17 18:23:06 1998 Yukihiro Matsumoto + + * math.c (math_frexp): newly added. + + * math.c (math_ldexp): ditto. + + * bignum.c (bigdivmod): calculates modulo. + + * numeric.c (fix_remainder): returns reminder, formerly introduced + as modulo. + + * numeric.c (fix_modulo): calculates proper `modulo'. + + * bignum.c (bigdivmod): wrong sign for reminder. + +Mon Mar 16 17:07:28 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_03. + +Mon Mar 16 16:33:53 1998 WATANABE Hirofumi + + * io.c (pipe_finalize): needed to add pipe_finalize to pipes on + cygwin32. + +Mon Mar 16 14:11:06 1998 Yukihiro Matsumoto + + * class.c (ins_methods_i): needed to consider NOEX_UNDEF. + +Mon Mar 16 13:23:53 1998 WATANABE Hirofumi + + * io.c (io_check_closed): check for `fptr->f2 == NULL'. + + * io.c (io_fptr_close): ditto. + +Mon Mar 16 11:49:25 1998 Yukihiro Matsumoto + + * io.c (pipe_atexit): free()ing referencing pipe_list. + + * range.c (range_length): returns zero, if the first is greater + than the last. + + * signal.c (trap_restore_mask): restore signal mask before raising + exceptions and throws. + +Fri Mar 13 13:49:24 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_02. + + * object.c (mod_clone): need to dups constants and instance + variables. + + * eval.c (rb_eval): forgot to initialize body for NODE_DEFS. + + * eval.c (rb_eval): retrieve self from calling frame, since self + changes sometimes. + + * env.h (FRAME): need to save self in the calling frame. + + * io.c (f_gets_method): rs should be initialized by RS. + +Thu Mar 12 15:33:57 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_01. + + * range.c (range_s_new): check values by `first <= last'. + + * parse.y (lastline_set): fixed offset for $_ and $~ in the local + variable space. + +Wed Mar 11 02:14:17 1998 Yukihiro Matsumoto + + * io.c (io_gets): handle normal case specially for speed. + + * eval.c (rb_disable_super): function to disable superclass's + method explicitly. + + * eval.c (rb_eval): inherits previous method definition's + NOEX_UNDEF-ness, if exists. + + * class.c (rb_define_method): disables superclass's overriding + method by default. + +Wed Mar 11 01:40:48 1998 MAEDA shugo + + * numeric.c (flo_gt,etc.): do not depend on `<=>', to handle NaN. + +Tue Mar 10 00:03:24 1998 Yukihiro Matsumoto + + * ruby.c (load_file): understands multiple options in #! line. + + * regex.c (re_compile_pattern): support for [:alpha:] etc. + +Mon Mar 9 16:53:51 1998 Yukihiro Matsumoto + + * io.h (GetOpenFile): embed io_check_closed in GetOpenFile. + + * sprintf.c (f_sprintf): zero padding failed for negative + integers. + + * sprintf.c (remove_sign_bits): failed to remove some bits. + +Sat Mar 7 21:51:46 1998 MAEDA shugo + + * class.c (ins_methods_i): body may be NULL for some case. + +Fri Mar 6 17:23:07 1998 Yukihiro Matsumoto + + * regex.c (mbcinit): table driven mbchar detection. + + * object.c (obj_alloc): check for allocating instance for the + primitive classes (mostly perfect). + + * ext/curses/curses.c (curses_finalize): restore original state at + interpreter temination. + + * ext/curses/curses.c (curses_addstr): forgot to check argument + type (caused SEGV). now uses STR2CSTR() macro. + +Thu Mar 5 13:47:39 1998 Yukihiro Matsumoto + + * eval.c (block_pass): accepts method object as block args. + + * eval.c (f_missing): use any_to_s() for stringify. + +Wed Mar 4 01:39:52 1998 Yukihiro Matsumoto + + * parse.y (block_arg): new syntax - block argument in the + calling arglist. + + * eval.c (rb_call): no module search. simplified a lot. + + * eval.c (rb_eval): block arg support. + + * parse.y (f_block_arg): new syntax - block argument in the + formal arglist. + +Tue Mar 3 14:20:15 1998 Yukihiro Matsumoto + + * eval.c (obj_method): returns bound method object. + + * eval.c (rb_call): argument check for empty methods. + + * ruby.h (NUM2CHR): new macro, originally from curses module. + +Tue Mar 3 13:03:35 1998 MAEDA shugo + + * io.c (io_putc): new method. + +Tue Mar 3 11:21:28 1998 Yukihiro Matsumoto + + * string.c (str_inspect): more strict charcode detection. + + * eval.c (thread_stop): stopping only thread raises ThreadError + exception. + +Tue Mar 3 08:04:56 1998 Tadayoshi Funaba + + * struct.c (struct_alloc): imcomplete struct initialization made + GC to access unallocated addresses. + +Mon Mar 2 16:28:27 1998 Yukihiro Matsumoto + + * eval.c (thread_stop_method): remove Thread#stop. + +Fri Feb 27 18:16:26 1998 Yukihiro Matsumoto + + * version 1.1b9 released. + +Fri Feb 27 09:36:35 1998 Yukihiro Matsumoto + + * hash.c (hash_delete_nil): needed to compare value to nil, since + nil is the valid key for hashes. + + * hash.c (hash_foreach_iter): rehashing causes IndexError. + + * hash.c (hash_foreach_iter): rehash check by pointer comparison. + +Thu Feb 26 17:22:13 1998 Yukihiro Matsumoto + + * parse.y (fname): convert reswords into symbols. + + * parse.y (reswords): reserved words are now embedded in the + syntax (sigh). + + * parse.y: now reserved words can be method names safely. + +Wed Feb 25 15:50:07 1998 Yukihiro Matsumoto + + * eval.c (mod_module_eval): clear the_scope's PRIVATE flag before + calling eval(). + + * gc.c (gc_call_finalizer_at_exit): run finalizers before any data + object being freed. + + * eval.c (rb_eval): needed to keep prot_tag->retval before + evaluating the ensure clause. + +Tue Feb 24 11:16:32 1998 Yukihiro Matsumoto + + * parse.y (yylex): reserved words can be appear as method names at + right after 'def' and `.'(dot), like foo.next. + + * eval.c (return_check): checks for return out of thread (formerly + done in return_value). + + * eval.c (POP_TAG): copy retval to outer level. + + * eval.c (return_value): just set retval, no check, no unwinding. + + * parse.y (nextc): line continuation by backslash at end of line. + + * regex.c (re_compile_pattern): forgot to clear pending_exact on + closing parentheses. + + * parse.y (assignable): should not assign dyna_var to true, if it + is already defined. + +Mon Feb 23 14:35:03 1998 Yukihiro Matsumoto + + * object.c (obj_is_kind_of): no longer accepts true/false/nil. + + * object.c ({true,false,nil}_to_i): can be converted into integers. + +Mon Feb 23 12:11:51 1998 Yukihiro Matsumoto + + * re.c (reg_s_quote): needed to be mbchar aware. + + * eval.c (proc_s_new): wrong iter mark. + +Sat Feb 21 22:59:30 1998 MAEDA shugo + + * io.c (f_syscall): no argument check. + +Fri Feb 20 10:17:51 1998 Yukihiro Matsumoto + + * version 1.1b8 released. + + * ext/kconv/kconv.c (kconv_kconv): default output code now be + determined according to the value of $KCODE. + + * re.c (rb_get_kcode): can retrieve $KCODE from C code. + + * parse.y (stmt): if/unless modifiers returns nil, if condition is + not established. + +Thu Feb 19 11:06:47 1998 Yukihiro Matsumoto + + * ext/kconv/kconv.c (kconv_kconv): charcode can be specified by + code name (JIS, SJIS, EUC like value of $KCODE). + + * regex.c (re_compile_pattern): forgot to fixup_jump for (?:..). + + * regex.c (re_compile_pattern): needed to clear pending_exact on + non-registering grouping (?:...). + +Wed Feb 18 19:54:21 1998 Yukihiro Matsumoto + + * parse.y (here_document): needed to set lex_state to EXPR_END. + +Wed Feb 18 18:45:10 1998 WATANABE Hirofumi + + * patches for cygwin32 applied. + +Wed Feb 18 00:41:31 1998 Yukihiro Matsumoto + + * string.c (str_sub_s): needed to be mbchar aware to increment one + character. + + * regex.c (re_match): \Z matches newline just before the end of + the string. + +Tue Feb 17 00:04:32 1998 Yukihiro Matsumoto + + * time.c (time_arg): Time.gm and Time.local now understands + Time#to_a format. + + * string.c (str_sub_s): replace happened twice for null pattern. + + * regex.c (re_search): null pattern should not match after newline + at the end of string. + + * time.c (time_isdst): now returns boolean value. + + * error.c (rb_check_type): treat special constants in messages. + + * parse.y (yylex): new form `::Const' to see toplevel constants. + + * parse.y (cond): SEGV on `if ()'. + + * gc.c (obj_free): some data needed explicit free(). + +Mon Feb 16 23:55:40 1998 Yukihiro Matsumoto + + * eval.c (blk_free): release duplicated block informations. + + * eval.c (blk_copy_prev): duplicate outer block information into + the heap, when proc/binding created. + +Mon Feb 16 14:38:25 1998 Yukihiro Matsumoto + + * time.c (time_mon): now 1 for January and so on. + + * time.c (time_year): year in 19xx (no + 1900 needed anymore). + +Mon Feb 16 13:28:33 1998 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): need to fetch mbchar's second byte + without translation. + +Mon Feb 16 12:29:27 1998 MAEDA shugo + + * eval.c (f_pass_block): pass iterator block to other method. + +Fri Feb 13 08:16:11 1998 Yukihiro Matsumoto + + * parse.y (parse_regx): handle \s before read_escape(). + + * parse.y (read_escape): `\s' in strings as space. + +Tue Feb 10 17:29:08 1998 Yukihiro Matsumoto + + * version 1.1b7 released. + + * string.c (str_aset): string insertion by `str[n] = str2'. + + * string.c (str_oct): does recognize `0x'. + + * sprintf.c (f_sprintf): use baes 10 for conversion from string to + integer. + +Mon Feb 9 14:51:56 1998 Yukihiro Matsumoto + + * numeric.c (do_coerce): proper error message. + + * string.c (str_sum): bug - masked by wrong value. (sigh..) + +Sat Feb 7 15:11:14 1998 Yukihiro Matsumoto + + * string.c (str_empty): new method + +Fri Feb 6 01:42:15 1998 Yukihiro Matsumoto + + * time.c (time_asctime): use asctime(3), not strftime(3). + +Thu Feb 5 18:58:46 1998 Yukihiro Matsumoto + + * io.c (io_fptr_close): do not free path on close(). + + * array.c (ary_filter): new method. + + * enum.c (enum_each_with_index): new method. + +Thu Feb 5 14:10:35 1998 Yukihiro Matsumoto + + * parse.y (primary): singleton class def can be appeared inside + method bodies. + + * hash.c (hash_replace): replace content. + + * string.c (str_replace_method): replace content. + + * array.c (ary_replace_method): replace elements. + + * string.c (str_succ_bang): String#succ! + +Thu Feb 5 18:20:30 1998 WATANABE Hirofumi + + * string.c (str_upcase_bang): multi byte character support. + +Wed Feb 4 13:55:26 1998 Yukihiro Matsumoto + + * array.c (ary_reverse): SEGV on empty array reverse. + +Tue Feb 3 12:24:07 1998 Yukihiro Matsumoto + + * re.c (match_to_a): non matching element should be nil. + + * ruby.c (ruby_load_script): load script after all initialization. + + * bignum.c (str2inum): need to interpret prefix `0' of `0x'. + +Tue Feb 3 10:00:18 1998 WATANABE Hirofumi + + * numeric.c (fix_rshift): use `sizeof(INT)*8' instead of 32. + +Mon Feb 2 14:09:24 1998 Yukihiro Matsumoto + + * ruby.c (set_arg0): grab environment region too. + +Thu Jan 29 18:36:25 1998 WATANABE Hirofumi + + * process.c (rb_proc_exec): check `sh' to be exist. + +Thu Jan 29 18:18:19 1998 Yukihiro Matsumoto + + * io.c (io_stdio_set): assignment to $stdin or $stdout does + reopen() as well as $stderr. + +Thu Jan 29 14:18:40 1998 Yukihiro Matsumoto + + * class.c (mod_ancestors): should not include singleton classes. + + * object.c (obj_type): should not return internal class. + + * io.c (io_reopen): unwillingly closes stdio streams. + +Thu Jan 29 11:50:35 1998 Toshihiko SHIMOKAWA + + * ext/socket/socket.c (udp_addrsetup): forgot to use htons(). + +Tue Jan 27 23:15:24 1998 Yukihiro Matsumoto + + * keywords: __FILE__, __LINE__ are available again. + +Fri Jan 23 14:19:28 1998 Yukihiro Matsumoto + + * version 1.1b6 released. + + * object.c (mod_to_s): need to duplicate classpath. + + * error.c (exc_inspect): need to duplicate classpath. + +Thu Jan 22 00:37:47 1998 Yukihiro Matsumoto + + * ruby.h (STR2CSTR): new macro to retrieve char*. + + * class.c (rb_define_method): `initialize' should always be + private, even if it defined by C extensions. + + * eval.c (rb_eval): `initialize' should always be private. + +Thu Jan 22 16:21:08 1998 Yukihiro Matsumoto + + * eval.c (rb_eval): some singleton class def cause SEGV. + + * eval.c (TMP_ALLOC): replace ALLOCA_N, where thread context + switch may happen. + +Wed Jan 21 01:43:42 1998 Yukihiro Matsumoto + + * eval.c (PUSH_FRAME): do not use ALLOCA_N(). crash on some + platforms that use missing/alloca.c. + + * regex.c (re_compile_pattern): too many pops for non register + subexpr. + + * parse.y (yylex): open parentheses after identifiers are argument + list, even if whitespaces have seen. + +Tue Jan 20 15:19:59 1998 Yukihiro Matsumoto + + * parse.y (terms): quoted word list by %w(a b c). + + * ext/tcltklib/extconf.rb: more accurate check for tcl/tk libs. + + * file.c (rb_stat): most of the FileTest methods (and function + `test') accept File objects as the argument. + +Tue Jan 19 18:19:24 1998 WATANABE Hirofumi + + * ext/extmk.rb.in (install): there should be no newline after install: + + * re.c (MIN): renamed from min(). there's a local variable named + min in the file, so that some cpp will raise an error. + +Mon Jan 19 16:30:05 1998 Yukihiro Matsumoto + + * version 1.1b5 released. + + * process.c (rb_syswait): no exception raised. + Fri Jan 16 00:43:43 1998 Yukihiro Matsumoto * ruby.h (CLONESETUP): copies its singleton classes too. @@ -27,6 +2379,8 @@ Tue Jan 13 10:00:18 1998 Yukihiro Matsumoto Fri Jan 9 13:19:55 1998 Yukihiro Matsumoto + * version 1.1b4 released. + * eval.c (f_missing): class name omitted from the error message. * error.c (exc_inspect): description changed. diff --git a/MANIFEST b/MANIFEST index 2bdaf290b3..5c697d612f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -5,6 +5,7 @@ Makefile.in README README.jp README.EXT +README.EXT.jp ToDo array.c bignum.c @@ -13,7 +14,8 @@ compar.c configure configure.bat configure.in -config.dj +config_h.dj +config_s.dj config.guess config.sub defines.h @@ -36,7 +38,6 @@ install-sh instruby.rb intern.h io.c -io.h keywords lex.c main.c @@ -47,6 +48,7 @@ node.h numeric.c object.c pack.c +parse.c parse.y process.c random.c @@ -58,8 +60,9 @@ regex.h ruby.1 ruby.c ruby.h +rubyio.h +rubysig.h rubytest.rb -sig.h signal.c sprintf.c st.c @@ -73,74 +76,89 @@ util.c variable.c version.c version.h +beos/ruby.def.in ext/Setup ext/Setup.dj ext/Setup.nt ext/Setup.x68 +ext/aix_ld.rb +ext/cygwin32_ld.rb ext/extmk.rb.in ext/extmk.rb.nt -ext/aix_ld.rb lib/English.rb +lib/Env.rb +lib/README lib/base64.rb lib/cgi-lib.rb lib/complex.rb lib/date.rb +lib/date2.rb lib/debug.rb lib/delegate.rb lib/e2mmap.rb lib/eregex.rb lib/find.rb +lib/final.rb lib/finalize.rb lib/ftplib.rb lib/ftools.rb lib/getopts.rb +lib/getoptlong.rb lib/importenv.rb lib/jcode.rb lib/mailread.rb lib/mathn.rb lib/matrix.rb lib/mkmf.rb +lib/monitor.rb lib/mutex_m.rb lib/observer.rb +lib/open3.rb lib/ostruct.rb lib/parsearg.rb lib/parsedate.rb lib/ping.rb +lib/profile.rb lib/pstore.rb lib/rational.rb +lib/readbytes.rb lib/shellwords.rb +lib/singleton.rb lib/sync.rb +lib/telnet.rb +lib/tempfile.rb lib/thread.rb lib/thwait.rb -lib/tk.rb -lib/tkcanvas.rb -lib/tkclass.rb -lib/tkdialog.rb -lib/tkentry.rb -lib/tkscrollbox.rb -lib/tktext.rb +lib/timeout.rb lib/tracer.rb lib/weakref.rb +misc/README +misc/inf-ruby.el +misc/ruby-mode.el +misc/rubydb2x.el +misc/rubydb3x.el missing/alloca.c missing/crypt.c missing/dir.h missing/dup2.c missing/file.h missing/flock.c +missing/memcmp.c missing/memmove.c missing/mkdir.c -missing/nt.c -missing/nt.h -missing/setenv.c missing/strcasecmp.c +missing/strchr.c missing/strdup.c missing/strerror.c missing/strftime.c missing/strstr.c missing/strtol.c missing/strtoul.c +missing/vsnprintf.c missing/x68.c +sample/README sample/biorhythm.rb +sample/cal.rb sample/cbreak.rb sample/clnt.rb sample/dbmtest.rb @@ -151,44 +169,38 @@ sample/exyacc.rb sample/fact.rb sample/fib.awk sample/fib.pl +sample/fib.py sample/fib.rb sample/fib.scm sample/freq.rb sample/from.rb sample/fullpath.rb sample/getopts.test +sample/goodfriday.rb sample/less.rb sample/list.rb sample/list2.rb sample/list3.rb -sample/mrshtest.rb +sample/mine.rb sample/mkproto.rb sample/mpart.rb +sample/mrshtest.rb sample/observ.rb sample/occur.pl sample/occur.rb sample/occur2.rb sample/philos.rb sample/pi.rb +sample/rename.rb sample/rbc.rb sample/rcs.awk sample/rcs.dat sample/rcs.rb sample/regx.rb -sample/ruby-mode.el -sample/rubydb2x.el -sample/rubydb3x.el sample/sieve.rb sample/svr.rb sample/test.rb sample/time.rb -sample/tkbiff.rb -sample/tkbrowse.rb -sample/tkdialog.rb -sample/tkfrom.rb -sample/tkhello.rb -sample/tkline.rb -sample/tktimer.rb sample/trojan.rb sample/tsvr.rb sample/uumerge.rb @@ -198,6 +210,8 @@ win32/ntsetup.bat win32/ruby.def win32/sdbm.c win32/sdbm.h +win32/win32.c +win32/win32.h x68/fconvert.c x68/select.c x68/_dtos18.c diff --git a/Makefile.in b/Makefile.in index 3c616d9983..628b0e0778 100644 --- a/Makefile.in +++ b/Makefile.in @@ -8,19 +8,26 @@ VPATH = @srcdir@:@srcdir@/missing CC = @CC@ YACC = @YACC@ PURIFY = +AUTOCONF = autoconf @SET_MAKE@ -CFLAGS = @CFLAGS@ -I@srcdir@ +prefix = @prefix@ +CFLAGS = @CFLAGS@ -I. -I@srcdir@ -I@includedir@ LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@ +EXTLIBS = LIBS = @LIBS@ $(EXTLIBS) MISSING = @LIBOBJS@ @ALLOCA@ +LDSHARED = @LDSHARED@ +DLDFLAGS = @DLDFLAGS@ +SOLIBS = @SOLIBS@ binsuffix = @binsuffix@ #### End of system configuration section. #### -LIBRUBY = libruby.a +LIBRUBY = @LIBRUBY@ +LIBRUBYARG = @LIBRUBYARG@ EXTOBJS = @@ -42,8 +49,8 @@ OBJS = array.o \ hash.o \ inits.o \ io.o \ - math.o \ marshal.o \ + math.o \ numeric.o \ object.o \ pack.o \ @@ -66,44 +73,58 @@ OBJS = array.o \ $(MISSING) all: miniruby$(binsuffix) rbconfig.rb - @cd ext; ../miniruby$(binsuffix) ./extmk.rb @EXTSTATIC@ + @./miniruby$(binsuffix) -Xext extmk.rb @EXTSTATIC@ -miniruby$(binsuffix): $(OBJS) $(MAINOBJ) dmyext.o +miniruby$(binsuffix): libruby.a $(MAINOBJ) dmyext.o @rm -f $@ - $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(OBJS) dmyext.o $(LIBS) -o miniruby + $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) dmyext.o libruby.a $(LIBS) -o $@ ruby$(binsuffix): $(LIBRUBY) $(MAINOBJ) $(EXTOBJS) @rm -f $@ - $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby + $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@ -$(LIBRUBY): $(OBJS) dmyext.o - @AR@ rcu $(LIBRUBY) $(OBJS) dmyext.o - @-@RANLIB@ $(LIBRUBY) 2> /dev/null || true +libruby.a: $(OBJS) dmyext.o + @AR@ rcu $@ $(OBJS) dmyext.o + @-@RANLIB@ $@ 2> /dev/null || true + +libruby.so: $(OBJS) dmyext.o + $(LDSHARED) $(DLDFLAGS) $(SOLIBS) $(OBJS) dmyext.o -o $@ install: rbconfig.rb - ./miniruby$(binsuffix) $(srcdir)/instruby.rb + ./miniruby$(binsuffix) $(srcdir)/instruby.rb $(DESTDIR) clean:; @rm -f $(OBJS) $(LIBRUBY) $(MAINOBJ) rbconfig.rb @rm -f ext/extinit.c ext/extinit.o dmyext.o - @if test -f ./miniruby; then cd ext; ../miniruby ./extmk.rb clean; fi - -realclean: clean - @rm -f Makefile ext/extmk.rb ext/config.cache - @rm -f config.cache config.h config.log config.status - @rm -f parse.c lex.c *~ core *.core gmon.out + @if test -f ./miniruby$(binsuffix); then \ + ./miniruby$(binsuffix) -Xext extmk.rb clean; \ + fi + +distclean: clean + @rm -f Makefile ext/extmk.rb config.h + @rm -f ext/config.cache config.cache config.log config.status + @rm -f parse.c *~ core *.core gmon.out y.tab.c y.output @rm -f ruby$(binsuffix) miniruby$(binsuffix) +realclean: distclean + @rm -f lex.c + test: miniruby$(binsuffix) @./miniruby$(binsuffix) $(srcdir)/rubytest.rb rbconfig.rb: config.status miniruby$(binsuffix) @./miniruby$(binsuffix) $(srcdir)/mkconfig.rb rbconfig.rb +config.status: $(srcdir)/configure + $(SHELL) ./config.status --recheck + +$(srcdir)/configure: $(srcdir)/configure.in + cd $(srcdir) && $(AUTOCONF) + .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< lex.c: keywords - gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$$ keywords > lex.c + gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$$ @srcdir@/keywords > lex.c parse.c: parse.y $(YACC) $< @@ -121,24 +142,30 @@ dup2.o: @srcdir@/missing/dup2.c flock.o: @srcdir@/missing/flock.c $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/flock.c +memcmp.o: @srcdir@/missing/memcmp.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/memcmp.c + memmove.o: @srcdir@/missing/memmove.c $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/memmove.c mkdir.o: @srcdir@/missing/mkdir.c $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/mkdir.c -setenv.o: @srcdir@/missing/setenv.c - $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/setenv.c +vsnprintf.o: @srcdir@/missing/vsnprintf.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/vsnprintf.c strcasecmp.o: @srcdir@/missing/strcasecmp.c $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strcasecmp.c -strerror.o: @srcdir@/missing/strerror.c - $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strerror.c +strchr.o: @srcdir@/missing/strchr.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strchr.c strdup.o: @srcdir@/missing/strdup.c $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strdup.c +strerror.o: @srcdir@/missing/strerror.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strerror.c + strftime.o: @srcdir@/missing/strftime.c $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strftime.c @@ -160,40 +187,43 @@ x68.o: @srcdir@/missing/x68.c # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: ### -parse.o : parse.y ruby.h defines.h config.h intern.h env.h node.h st.h regex.h lex.c +parse.o: parse.y ruby.h config.h defines.h intern.h env.h node.h st.h regex.h util.h lex.c ### array.o: array.c ruby.h config.h defines.h intern.h bignum.o: bignum.c ruby.h config.h defines.h intern.h class.o: class.c ruby.h config.h defines.h intern.h node.h st.h compar.o: compar.c ruby.h config.h defines.h intern.h dir.o: dir.c ruby.h config.h defines.h intern.h -dln.o: dln.c config.h defines.h dln.h st.h +dln.o: dln.c config.h defines.h dln.h dmyext.o: dmyext.c enum.o: enum.c ruby.h config.h defines.h intern.h error.o: error.c ruby.h config.h defines.h intern.h env.h -eval.o: eval.c ruby.h config.h defines.h intern.h env.h node.h sig.h st.h dln.h -file.o: file.c ruby.h config.h defines.h intern.h io.h sig.h -gc.o: gc.c ruby.h config.h defines.h intern.h env.h sig.h st.h node.h re.h regex.h -hash.o: hash.c ruby.h config.h defines.h intern.h st.h +eval.o: eval.c ruby.h config.h defines.h intern.h node.h env.h rubysig.h st.h dln.h +file.o: file.c ruby.h config.h defines.h intern.h rubyio.h rubysig.h +fnmatch.o: fnmatch.c config.h fnmatch.h +gc.o: gc.c ruby.h config.h defines.h intern.h rubysig.h st.h node.h env.h re.h regex.h +glob.o: config.h glob.c fnmatch.h +hash.o: hash.c ruby.h config.h defines.h intern.h st.h rubysig.h inits.o: inits.c ruby.h config.h defines.h intern.h -io.o: io.c ruby.h config.h defines.h intern.h io.h sig.h -main.o: main.c -marshal.o: marshal.c ruby.h config.h defines.h intern.h io.h sig.h st.h +io.o: io.c ruby.h config.h defines.h intern.h rubyio.h rubysig.h +main.o: main.c ruby.h config.h defines.h intern.h +marshal.o: marshal.c ruby.h config.h defines.h intern.h rubyio.h st.h math.o: math.c ruby.h config.h defines.h intern.h numeric.o: numeric.c ruby.h config.h defines.h intern.h object.o: object.c ruby.h config.h defines.h intern.h st.h pack.o: pack.c ruby.h config.h defines.h intern.h -process.o: process.c ruby.h config.h defines.h intern.h sig.h st.h +process.o: process.c ruby.h config.h defines.h intern.h rubysig.h st.h random.o: random.c ruby.h config.h defines.h intern.h range.o: range.c ruby.h config.h defines.h intern.h re.o: re.c ruby.h config.h defines.h intern.h re.h regex.h -ruby.o: ruby.c ruby.h config.h defines.h intern.h re.h regex.h dln.h -signal.o: signal.c ruby.h config.h defines.h intern.h sig.h +regex.o: regex.c config.h regex.h util.h +ruby.o: ruby.c ruby.h config.h defines.h intern.h dln.h util.h +signal.o: signal.c ruby.h config.h defines.h intern.h rubysig.h sprintf.o: sprintf.c ruby.h config.h defines.h intern.h st.o: st.c config.h st.h string.o: string.c ruby.h config.h defines.h intern.h re.h regex.h struct.o: struct.c ruby.h config.h defines.h intern.h time.o: time.c ruby.h config.h defines.h intern.h -util.o: util.c defines.h intern.h config.h util.h -variable.o: variable.c ruby.h config.h defines.h intern.h env.h st.h +util.o: util.c ruby.h config.h defines.h intern.h util.h +variable.o: variable.c ruby.h config.h defines.h intern.h env.h node.h st.h version.o: version.c ruby.h config.h defines.h intern.h version.h diff --git a/README b/README index d41fb9f79a..dd93c592be 100644 --- a/README +++ b/README @@ -3,7 +3,7 @@ Ruby is the interpreted scripting language for quick and easy object-oriented programming. It has many features to process text files and to do system management tasks (as in -perl). It is simple, straight-forward, and extensible. +Perl). It is simple, straight-forward, and extensible. * Features of Ruby @@ -15,7 +15,8 @@ perl). It is simple, straight-forward, and extensible. + Iterators and Closures + Garbage Collection + Dynamic Loading of Object files(on some architecture) - + Highly Portable(works on many UNIX machines) + + Highly Portable(works on many UNIX machines, and on DOS, + Windows, Mac, BeOS etc.) * How to get Ruby @@ -31,21 +32,26 @@ This is what you need to do to compile and install Ruby: 2. Edit defines.h if you need. Probably this step will not need. - 3. Remove comment mark(#) before the module names from ext/Setup, if - you want to link modules statically. + 3. Remove comment mark(#) before the module names from ext/Setup (or + add module names if not present), if you want to link modules + statically. - If you want to link all the extension modules, remove comment - mark from the line "#option nodynamic". + If you don't want to compile non static extension modules + (probably on architectures which does not allow dynamic loading), + remove comment mark from the line "#option nodynamic" in + ext/Setup. 4. Run make. - 5. Optionally, run 'make test' to check that the compiled Ruby - interpreter works well. If you see the message "test succeeded", - your Ruby works as it should (hopefully). + 5. 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' -If you fail to compile Ruby, please send the detailed error report with + You may have to be a super user to install ruby. + +If you fail to compile ruby, please send the detailed error report with the error log and machine/OS type, to help others. * Copying @@ -61,12 +67,13 @@ You can redistribute it and/or modify it under either the terms of the GPL 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet - or an equivalent medium, or by allowing the author to include your - modifications in the software. + a) place your modifications in the Public Domain or otherwise + make them Freely Available, such as by posting said + modifications to Usenet or an equivalent medium, or by allowing + the author to include your modifications in the software. - b) use the modified software only within your corporation or organization. + b) use the modified software only within your corporation or + organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided. @@ -84,8 +91,7 @@ You can redistribute it and/or modify it under either the terms of the GPL the software. c) give non-standard executables non-standard names, with - instructions on where to get the original software - distribution. + instructions on where to get the original software distribution. d) make other distribution arrangements with the author. @@ -94,7 +100,7 @@ You can redistribute it and/or modify it under either the terms of the GPL are not written by the author, so that they are not under this terms. They are gc.c(partly), utils.c(partly), regex.[ch], fnmatch.[ch], glob.c, st.[ch] and some files under the ./missing directory. See - each files for the copying condition. + each file for the copying condition. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the diff --git a/README.EXT b/README.EXT index c2f81d1a7a..f169e54995 100644 --- a/README.EXT +++ b/README.EXT @@ -1,21 +1,16 @@ .\" README.EXT - -*- Text -*- created at: Mon Aug 7 16:45:54 JST 1995 -This document explains how to make extention modules for ruby. +This document explains how to make extention modules for Ruby. 1ˇĄBasic knowledge In C, variables have types and data do not have types. In contrast, -ruby variables do not have static type and data themselves have +Ruby variables do not have static type and data themselves have types. So, data need to be converted across the languages. -Data in ruby represented C type `VALUE'. Each VALUE data have its +Data in Ruby represented C type `VALUE'. Each VALUE data have its data-type. -ruby¤ÎĄÇˇĽĄż¤ĎVALUE¤Č¤¤¤¦C¤Î·ż¤ÇÉ˝¸˝¤µ¤ě¤Ţ¤ąˇĄVALUE·ż¤ÎĄÇˇĽ -Ąż¤Ď¤˝¤ÎĄÇˇĽĄżĄżĄ¤Ą×¤ňĽ«Ę¬¤ÇĂΤäƤ¤¤Ţ¤ąˇĄ¤ł¤ÎĄÇˇĽĄżĄżĄ¤Ą×¤Č -¤¤¤¦¤Î¤ĎĄÇˇĽĄż(ĄŞĄÖĄ¸Ą§ĄŻĄČ)¤ÎĽÂşÝ¤Îą˝Â¤¤ň°ŐĚŁ¤·¤Ć¤¤¤Ćˇ¤ruby -¤ÎĄŻĄéĄą¤Č¤Ď¤Ţ¤ż°ă¤Ă¤ż¤â¤Î¤Ç¤ąˇĄ - To retrieve an C data from the VALUE, you need to: (1) Identify VALUE's data type @@ -38,7 +33,7 @@ Ruby interpreter has data-types as below: T_ARRAY array T_FIXNUM Fixnum(31bit integer) T_HASH assosiative array - T_STRUCT (ruby) structure + T_STRUCT (Ruby) structure T_BIGNUM multi precision integer T_TRUE true T_FALSE false @@ -89,37 +84,28 @@ There are faster check-macros for fixnums and nil. 1.3 Convert VALUE into C data -ĄÇˇĽĄżĄżĄ¤Ą×¤¬T_NIL, T_FALSE, T_TRUE¤Ç¤˘¤ë»ţˇ¤ĄÇˇĽĄż¤Ď¤˝¤ě¤ľ -¤ěnil, FALSE, TRUE¤Ç¤ąˇĄ¤ł¤ÎĄÇˇĽĄżĄżĄ¤Ą×¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ¤Ď¤Ň¤Č -¤Ä¤ş¤Ä¤·¤«Â¸şß¤·¤Ţ¤»¤óˇĄ - -ĄÇˇĽĄżĄżĄ¤Ą×¤¬T_FIXNUM¤Î»ţˇ¤¤ł¤ě¤Ď31bit¤ÎĄµĄ¤Ąş¤ň»ý¤ÄŔ°żô¤Ç -¤ąˇĄFIXNUM¤ňC¤ÎŔ°żô¤ËĘŃ´ą¤ą¤ë¤ż¤á¤Ë¤ĎĄŢĄŻĄíˇÖFIX2INT()ˇ×¤ň»Č -¤¤¤Ţ¤ąˇĄ¤˝¤ě¤«¤éˇ¤FIXNUM¤Ë¸Â¤é¤şruby¤ÎĄÇˇĽĄż¤ňŔ°żô¤ËĘŃ´ą¤ą¤ë -ˇÖNUM2INT()ˇ×¤Č¤¤¤¦ĄŢĄŻĄí¤¬¤˘¤ę¤Ţ¤ąˇĄ¤ł¤ÎĄŢĄŻĄí¤ĎĄÇˇĽĄżĄżĄ¤ -Ą×¤ÎĄÁĄ§ĄĂĄŻĚµ¤·¤Ç»Č¤¨¤Ţ¤ą(Ŕ°żô¤ËĘŃ´ą¤Ç¤­¤Ę¤¤ľěąç¤Ë¤ĎÎăł°¤¬ -ČŻŔ¸¤ą¤ë)ˇĄ - -¤˝¤ě°Ęł°¤ÎĄÇˇĽĄżĄżĄ¤Ą×¤ĎÂбţ¤ą¤ëC¤Îą˝Â¤ÂΤ¬¤˘¤ę¤Ţ¤ąˇĄÂбţ¤ą -¤ëą˝Â¤ÂΤΤ˘¤ëVALUE¤Ď¤˝¤Î¤Ţ¤ŢĄ­ĄăĄąĄČ(·żĘŃ´ą)¤ą¤ě¤Đą˝Â¤ÂΤΠ-ĄÝĄ¤ĄóĄż¤ËĘŃ´ą¤Ç¤­¤Ţ¤ąˇĄ +The data for type T_NIL, T_FALSE, T_TRUE are nil, true, false +respectively. They are singletons for the data type. -ą˝Â¤ÂΤϡÖstruct RXxxxxˇ×¤Č¤¤¤¦ĚľÁ°¤Çruby.h¤ÇÄęµÁ¤µ¤ě¤Ć¤¤¤Ţ -¤ąˇĄÎ㤨¤Đʸ»úÎó¤ĎˇÖstruct RStringˇ×¤Ç¤ąˇĄĽÂşÝ¤Ë»Č¤¦˛ÄÇ˝Ŕ­¤¬ -¤˘¤ë¤Î¤Ďʸ»úÎó¤ČÇŰÎ󤯤餤¤Ŕ¤Č»×¤¤¤Ţ¤ąˇĄ +The T_FIXNUM data is the 31bit length fixed integer (63bit length on +some machines), which can be conver to the C integer by using +FIX2INT() macro. There also be NUM2INT() which converts any Ruby +numbers into C integer. The NUM2INT() macro includes type check, so +the exception will be raised if conversion failed. -ruby.h¤Ç¤Ďą˝Â¤ÂΤإ­ĄăĄąĄČ¤ą¤ëĄŢĄŻĄí¤âˇÖRXXXXX()ˇ×(Á´ÉôÂçʸ -»ú¤Ë¤·¤ż¤â¤Î)¤Č¤¤¤¦ĚľÁ°¤ÇÄ󶡤µ¤ě¤Ć¤¤¤Ţ¤ą(Îă: RSTRING())ˇĄ +Other data types have corresponding C structures, e.g. struct RArray +for T_ARRAY etc. VALUE of the type which has corresponding structure +can be cast to retrieve the pointer to the struct. The casting macro +RXXXX for each data type like RARRAY(obj). see "ruby.h". -Î㤨¤Đˇ¤Ę¸»úÎóstr¤ÎÄą¤µ¤ňĆŔ¤ë¤ż¤á¤Ë¤ĎˇÖRSTRING(str)->lenˇ×¤Č -¤·ˇ¤Ę¸»úÎóstr¤ňchar*¤Č¤·¤ĆĆŔ¤ë¤ż¤á¤Ë¤ĎˇÖRSTRING(str)->ptrˇ× -¤Č¤·¤Ţ¤ąˇĄÇŰÎó¤Îľěąç¤Ë¤Ďˇ¤¤˝¤ě¤ľ¤ěˇÖRARRAT(str)->lenˇ×ˇ¤ -ˇÖRARRAT(str)->ptrˇ×¤Č¤Ę¤ę¤Ţ¤ąˇĄ +For example, `RSTRING(size)->len' is the way to get the size of the +Ruby String object. The allocated region can be accessed by +`RSTRING(str)->ptr'. For arrays, `RARRAY(ary)->len' and +`RARRAY(ary)->ptr' respectively. -ruby¤Îą˝Â¤ÂΤňÄľŔÜĄ˘ĄŻĄ»Ąą¤ą¤ë»ţ¤Ëµ¤¤ň¤Ä¤±¤Ę¤±¤ě¤Đ¤Ę¤é¤Ę¤¤¤ł -¤Č¤Ďˇ¤ÇŰÎó¤äʸ»úÎó¤Îą˝Â¤ÂΤÎĂćżČ¤Ď»˛ľČ¤ą¤ë¤Ŕ¤±¤Çˇ¤ÄľŔÜĘŃąą¤· -¤Ę¤¤¤ł¤Č¤Ç¤ąˇĄÄľŔÜĘŃąą¤·¤żľěąçˇ¤ĄŞĄÖĄ¸Ą§ĄŻĄČ¤ÎĆâÍƤÎŔ°ąçŔ­¤¬ -¤Č¤ě¤Ę¤Ż¤Ę¤Ă¤Ćˇ¤»×¤ď¤ĚĄĐĄ°¤Î¸¶°ř¤Ë¤Ę¤ę¤Ţ¤ąˇĄ +Notice: Do not change the value of the structure directly, unless you +are responsible about the result. It will be the cause of interesting +bugs. 1.4 Convert C data into VALUE @@ -137,10 +123,10 @@ VALUE ¤¦¤«¤ď¤«¤ë¤ď¤±¤Ç¤ą(ĄÝĄ¤ĄóĄż¤ÎLSB¤¬Î©¤Ă¤Ć¤¤¤Ę¤¤¤ł¤Č¤ň˛ľÄꤷ¤Ć ¤¤¤ë)ˇĄ -¤Ç¤ą¤«¤éˇ¤FIXNUM°Ęł°¤Îruby¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ¤Îą˝Â¤ÂΤĎñ¤ËVALUE +¤Ç¤ą¤«¤éˇ¤FIXNUM°Ęł°¤ÎRuby¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ¤Îą˝Â¤ÂΤĎñ¤ËVALUE ¤ËĄ­ĄăĄąĄČ¤ą¤ë¤Ŕ¤±¤ÇVALUE¤ËĘŃ´ą˝ĐÍč¤Ţ¤ąˇĄ¤ż¤Ŕ¤·ˇ¤Ç¤°Ő¤Îą˝Â¤ ÂΤ¬VALUE¤ËĄ­ĄăĄąĄČ˝ĐÍč¤ë¤ď¤±¤Ç¤Ď¤˘¤ę¤Ţ¤»¤óˇĄĄ­ĄăĄąĄČ¤ą¤ë¤Î -¤Ďruby¤ÎĂΤäƤ¤¤ëą˝Â¤ÂÎ(ruby.h¤ÇÄęµÁ¤µ¤ě¤Ć¤¤¤ëstruct RXxxx +¤ĎRuby¤ÎĂΤäƤ¤¤ëą˝Â¤ÂÎ(ruby.h¤ÇÄęµÁ¤µ¤ě¤Ć¤¤¤ëstruct RXxxx ¤Î¤â¤Î)¤Ŕ¤±¤Ë¤·¤Ć¤Ş¤¤¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ FIXNUM¤Ë´Ř¤·¤Ć¤ĎĘŃ´ąĄŢĄŻĄí¤ň·ĐÍł¤ą¤ëɬÍפ¬¤˘¤ę¤Ţ¤ąˇĄC¤ÎŔ°żô @@ -153,256 +139,241 @@ FIXNUM INT2NUM()¤ĎŔ°żô¤¬FIXNUM¤ÎČϰϤ˼ý¤Ţ¤é¤Ę¤¤ľěąçˇ¤Bignum¤ËĘŃ´ą ¤·¤Ć¤Ż¤ě¤Ţ¤ą(¤¬ˇ¤ľŻ¤·Ă٤¤)ˇĄ -1.5 Manipulate ruby data +1.5 Manipulate Ruby data -ŔčÄř¤â˝Ň¤Ů¤żÄ̤ꡤruby¤Îą˝Â¤ÂΤňĄ˘ĄŻĄ»Ąą¤ą¤ë»ţ¤ËĆâÍƤιąż·¤ň -ąÔ¤¦¤ł¤Č¤Ď´«¤á¤é¤ě¤Ţ¤»¤óˇĄ¤Çˇ¤ruby¤ÎĄÇˇĽĄż¤ňÁŕşî¤ą¤ë»ţ¤Ë¤Ď -ruby¤¬ÍŃ°Ő¤·¤Ć¤¤¤ë´Řżô¤ňÍѤ¤¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ - -¤ł¤ł¤Ç¤Ď¤â¤Ă¤Č¤â»Č¤ď¤ě¤ë¤Ç¤˘¤í¤¦Ę¸»úÎó¤ČÇŰÎó¤ÎŔ¸Ŕ®/Áŕşî¤ňąÔ -¤¤´Řżô¤ň¤˘¤˛¤Ţ¤ą(Á´Éô¤Ç¤Ď¤Ę¤¤¤Ç¤ą)ˇĄ +As I already told, it is not recommended to modify object's internal +structure. To manipulate objects, use functions supplied by Ruby +interpreter. Useful functions are listed below (not all): String funtions - str_new(char *ptr, int len) + rb_str_new(char *ptr, int len) - Creates a new ruby string. + Creates a new Ruby string. - str_new2(char *ptr) + rb_str_new2(char *ptr) - Creates a new ruby string from C string. This is equivalent to - str_new(ptr, strlen(ptr)). + Creates a new Ruby string from C string. This is equivalent to + rb_str_new(ptr, strlen(ptr)). - str_cat(VALUE str, char *ptr, int len) + rb_str_cat(VALUE str, char *ptr, int len) - Appends len bytes data from ptr to the ruby string. + Appends len bytes data from ptr to the Ruby string. Array functions - ary_new() + rb_ary_new() Creates an array with no element. - ary_new2(int len) + rb_ary_new2(int len) Creates an array with no element, with allocating internal buffer for len elements. - ary_new3(int n, ...) + rb_ary_new3(int n, ...) Creates an n-elements array from arguments. - ary_new4(int n, VALUE *elts) + rb_ary_new4(int n, VALUE *elts) Creates an n-elements array from C array. - ary_push(VALUE ary) - ary_pop(VALUE ary, VALUE val) - ary_shift(VALUE ary) - ary_unshift(VALUE ary, VALUE val) - ary_entry(VALUE ary, int idx) + rb_ary_push(VALUE ary, VALUE val) + rb_ary_pop(VALUE ary) + rb_ary_shift(VALUE ary) + rb_ary_unshift(VALUE ary, VALUE val) + rb_ary_entry(VALUE ary, int idx) Array operations. The first argument to each functions must be an array. They may dump core if other types given. -2. Extend ruby with C +2. Extend Ruby with C -¸¶ÍýĹŞ¤Ëruby¤Ç˝ń¤±¤ë¤ł¤Č¤ĎC¤Ç¤â˝ń¤±¤Ţ¤ąˇĄruby¤˝¤Î¤â¤Î¤¬C¤Çµ­ +¸¶ÍýĹŞ¤ËRuby¤Ç˝ń¤±¤ë¤ł¤Č¤ĎC¤Ç¤â˝ń¤±¤Ţ¤ąˇĄRuby¤˝¤Î¤â¤Î¤¬C¤Çµ­ ˝Ň¤µ¤ě¤Ć¤¤¤ë¤ó¤Ç¤ą¤«¤éˇ¤ĹöÁł¤Č¤¤¤¨¤ĐĹöÁł¤Ę¤ó¤Ç¤ą¤±¤ÉˇĄ¤ł¤ł¤Ç -¤Ďruby¤ÎłČÄĄ¤Ë»Č¤¦¤ł¤Č¤¬Âż¤¤¤Ŕ¤í¤¦¤Čͽ¬¤µ¤ě¤ëµˇÇ˝¤ňĂćż´¤ËľŇ +¤ĎRuby¤ÎłČÄĄ¤Ë»Č¤¦¤ł¤Č¤¬Âż¤¤¤Ŕ¤í¤¦¤Čͽ¬¤µ¤ě¤ëµˇÇ˝¤ňĂćż´¤ËľŇ ˛đ¤·¤Ţ¤ąˇĄ -2.1 Add new features to ruby +2.1 Add new features to Ruby -ruby¤ÇÄ󶡤µ¤ě¤Ć¤¤¤ë´Řżô¤ň»Č¤¨¤ĐrubyĄ¤ĄóĄżĄ×ĄęĄż¤Ëż·¤·¤¤µˇÇ˝ -¤ňÄɲ乤뤳¤Č¤¬¤Ç¤­¤Ţ¤ąˇĄruby¤Ç¤Ď°Ę˛Ľ¤ÎµˇÇ˝¤ňÄɲ乤ë´Řżô¤¬ +Ruby¤ÇÄ󶡤µ¤ě¤Ć¤¤¤ë´Řżô¤ň»Č¤¨¤ĐRubyĄ¤ĄóĄżĄ×ĄęĄż¤Ëż·¤·¤¤µˇÇ˝ +¤ňÄɲ乤뤳¤Č¤¬¤Ç¤­¤Ţ¤ąˇĄRuby¤Ç¤Ď°Ę˛Ľ¤ÎµˇÇ˝¤ňÄɲ乤ë´Řżô¤¬ Ä󶡤µ¤ě¤Ć¤¤¤Ţ¤ąˇĄ - * ĄŻĄéĄąˇ¤ĄâĄ¸ĄĺˇĽĄë - * ĄáĄ˝ĄĂĄÉˇ¤Ćðۥ᥽ĄĂĄÉ¤Ę¤É - * Äężô + * Classes, Modules + * Methods, Singleton Methods + * Constants ¤Ç¤Ď˝ç¤ËľŇ˛đ¤·¤Ţ¤ąˇĄ 2.1.1 Class/module definition -ĄŻĄéĄą¤äĄâĄ¸ĄĺˇĽĄë¤ňÄęµÁ¤ą¤ë¤ż¤á¤Ë¤Ďˇ¤°Ę˛Ľ¤Î´Řżô¤ň»Č¤¤¤Ţ¤ąˇĄ +To define class or module, use functions below: VALUE rb_define_class(char *name, VALUE super) VALUE rb_define_module(char *name) -¤ł¤ě¤é¤Î´Řżô¤Ďż·¤·¤ŻÄęµÁ¤µ¤ě¤żĄŻĄéĄą¤äĄâĄ¸ĄĺˇĽĄë¤ňĘÖ¤·¤Ţ¤ąˇĄ -ĄáĄ˝ĄĂĄÉ¤äÄężô¤ÎÄęµÁ¤Ë¤ł¤ě¤é¤ÎĂͤ¬É¬ÍפʤΤǡ¤¤Ű¤Č¤ó¤É¤Îľěąç -¤ĎĚá¤ęĂͤňĘŃżô¤ËłĘÇĽ¤·¤Ć¤Ş¤ŻÉ¬Íפ¬¤˘¤ë¤Ç¤·¤ç¤¦ˇĄ +These functions return the newly created class ot module. You may +want to save this reference into the variable to use later. 2.1.2 Method/singleton method definition -ĄáĄ˝ĄĂĄÉ¤äĆðۥ᥽ĄĂĄÉ¤ňÄęµÁ¤ą¤ë¤Ë¤Ď°Ę˛Ľ¤Î´Řżô¤ň»Č¤¤¤Ţ¤ąˇĄ +To define methods or singleton methods, use functions below: void rb_define_method(VALUE class, char *name, VALUE (*func)(), int argc) void rb_define_singleton_method(VALUE object, char *name, - VALUE (*func)(), int argc) + VALUE (*func)(), int argc) +The `argc' represents the number of the arguments to the C function, +which must be less than 17. But I believe you don't need that much. :-) -Ç°¤Î¤ż¤áŔâĚŔ¤ą¤ë¤ČˇÖĆðۥ᥽ĄĂĄÉˇ×¤Č¤Ďˇ¤¤˝¤ÎĆĂÄę¤ÎĄŞĄÖĄ¸Ą§ĄŻ -ĄČ¤ËÂФ·¤Ć¤Ŕ¤±Í­¸ú¤ĘĄáĄ˝ĄĂĄÉ¤Ç¤ąˇĄruby¤Ç¤Ď¤č¤ŻSmalltalk¤Ë¤Ş -¤±¤ëĄŻĄéĄąĄáĄ˝ĄĂĄÉ¤Č¤·¤Ćˇ¤ĄŻĄéĄą¤ËÂФą¤ëĆðۥ᥽ĄĂĄÉ¤¬»Č¤ď¤ě -¤Ţ¤ąˇĄ +If `argc' is negative, it specifies calling sequence, not number of +the arguments. + +If argc is -1, the function will be called like: -¤ł¤ě¤é¤Î´Řżô¤Î argc¤Č¤¤¤¦°úżô¤ĎC¤Î´Řżô¤ŘĹϤµ¤ě¤ë°úżô¤Îżô(¤Č -·ÁĽ°)¤ň·č¤á¤Ţ¤ąˇĄargc¤¬Ŕµ¤Î»ţ¤Ď´Řżô¤Ë°ú¤­ĹϤą°úżô¤Îżô¤ň°ŐĚŁ -¤·¤Ţ¤ąˇĄ16¸Ä°Ęľĺ¤Î°úżô¤Ď»Č¤¨¤Ţ¤»¤ó(¤¬ˇ¤Íפę¤Ţ¤»¤ó¤č¤Íˇ¤¤˝¤ó -¤Ę¤Ë)ˇĄ + VALUE func(int argc, VALUE *argv, VALUE obj) -argc¤¬Éé¤Î»ţ¤Ď°úżô¤Îżô¤Ç¤Ď¤Ę¤Żˇ¤·ÁĽ°¤ň»ŘÄꤷ¤ż¤ł¤Č¤Ë¤Ę¤ę¤Ţ¤ąˇĄ -argc¤¬-1¤Î»ţ¤Ď°úżô¤ňÇŰÎó¤ËĆţ¤ě¤ĆĹϤµ¤ě¤Ţ¤ąˇĄargc¤¬-2¤Î»ţ¤Ď°ú -żô¤Ďruby¤ÎÇŰÎó¤Č¤·¤ĆĹϤµ¤ě¤Ţ¤ąˇĄ +where argc is the actual number of arguments, argv is the C array of +the arguments, and obj is the receiver. -ĄáĄ˝ĄĂĄÉ¤ňÄęµÁ¤ą¤ë´Řżô¤Ď¤â¤¦Ćó¤Ä¤˘¤ę¤Ţ¤ąˇĄ¤Ň¤Č¤Ä¤ĎprivateĄá -Ą˝ĄĂĄÉ¤ňÄęµÁ¤ą¤ë´Řżô¤Çˇ¤°úżô¤Ďrb_define_method()¤ČƱ¤¸¤Ç¤ąˇĄ +if argc is -2, the arguments are passed in Ruby array. The function +will be called like: + + VALUE func(VALUE obj, VALUE args) + +where obj is the receiver, and args is the Ruby array containing +actual arguments. + +There're two more functions to define method. One is to define +private method: void rb_define_private_method(VALUE class, char *name, VALUE (*func)(), int argc) -privateĄáĄ˝ĄĂĄÉ¤Č¤Ď´Řżô·ÁĽ°¤Ç¤·¤«¸Ć¤Ó˝Đ¤ą¤ł¤Č¤Î˝ĐÍč¤Ę¤¤ĄáĄ˝ĄĂ -ĄÉ¤Ç¤ąˇĄ - -¤â¤¦¤Ň¤Č¤Ä¤ĎĄâĄ¸ĄĺˇĽĄë´Řżô¤ňÄęµÁ¤ą¤ë¤â¤Î¤Ç¤ąˇĄĄâĄ¸ĄĺˇĽĄë´Řżô -¤Č¤ĎĄâĄ¸ĄĺˇĽĄë¤ÎĆðۥ᥽ĄĂĄÉ¤Ç¤˘¤ęˇ¤Ć±»ţ¤ËprivateĄáĄ˝ĄĂĄÉ¤Ç -¤â¤˘¤ë¤â¤Î¤Ç¤ąˇĄÎă¤ň¤˘¤˛¤ë¤ČMathĄâĄ¸ĄĺˇĽĄë¤Îsqrt()¤Ę¤É¤¬¤˘¤˛ -¤é¤ě¤Ţ¤ąˇĄ¤ł¤ÎĄáĄ˝ĄĂĄÉ¤Ď +The other is to define module function, which is private AND singleton +method of the module. For example, sqrt is the module function +defined in Math module. It can be call in the form like: Math.sqrt(4) -¤Č¤¤¤¦·ÁĽ°¤Ç¤â +or include Math sqrt(4) -¤Č¤¤¤¦·ÁĽ°¤Ç¤â»Č¤¨¤Ţ¤ąˇĄĄâĄ¸ĄĺˇĽĄë´Řżô¤ňÄęµÁ¤ą¤ë´Řżô¤Ď°Ę˛Ľ¤Î -Ä̤ę¤Ç¤ąˇĄ +To define module function void rb_define_module_function(VALUE module, char *name, VALUE (*func)(), int argc) -´ŘżôĹŞĄáĄ˝ĄĂĄÉ(KernelĄâĄ¸ĄĺˇĽĄë¤Îprivaet method)¤ňÄęµÁ¤ą¤ë¤ż -¤á¤Î´Řżô¤Ď°Ę˛Ľ¤ÎÄ̤ę¤Ç¤ąˇĄ +Oh, in addition, function-like method, which is private method defined +in Kernel module, can be defined using: void rb_define_global_function(char *name, VALUE (*func)(), int argc) 2.1.3 Constant definition -łČÄĄĄâĄ¸ĄĺˇĽĄë¤¬É¬ÍפĘÄężô¤Ď¤˘¤é¤«¤¸¤áÄęµÁ¤·¤Ć¤Ş¤¤¤żĘý¤¬Îɤ¤ -¤Ç¤·¤ç¤¦ˇĄÄężô¤ňÄęµÁ¤ą¤ë´Řżô¤ĎĆó¤Ä¤˘¤ę¤Ţ¤ąˇĄ +We have 2 functions to define constants: void rb_define_const(VALUE class, char *name, VALUE val) void rb_define_global_const(char *name, VALUE val) -Á°ĽÔ¤ĎĆĂÄę¤ÎĄŻĄéĄą/ĄâĄ¸ĄĺˇĽĄë¤Ë°¤ą¤ëÄężô¤ňÄęµÁ¤ą¤ë¤â¤Îˇ¤¸ĺ -ĽÔ¤ĎĄ°ĄíˇĽĄĐĄë¤ĘÄężô¤ňÄęµÁ¤ą¤ë¤â¤Î¤Ç¤ąˇĄ - -2.2 Use ruby features from C +The former is to define constant under specified class/module. The +latter is to define global constant. -´ű¤ËˇŘ1.5 ruby¤ÎĄÇˇĽĄż¤ňÁŕşî¤ą¤ëˇŮ¤Ç°ěÉôľŇ˛đ¤·¤ż¤č¤¦¤Ę´Řżô¤ň -»Č¤¨¤Đˇ¤ruby¤ÎµˇÇ˝¤ňĽÂ¸˝¤·¤Ć¤¤¤ë´Řżô¤ňÄľŔܸƤӽФą¤ł¤Č¤¬˝ĐÍč -¤Ţ¤ąˇĄ - -# ¤ł¤Î¤č¤¦¤Ę´Řżô¤Î°ěÍ÷É˝¤Ď¤¤¤Ţ¤Î¤Č¤ł¤í¤˘¤ę¤Ţ¤»¤óˇĄĄ˝ˇĽĄą¤ň¸« -# ¤ë¤·¤«¤Ę¤¤¤Ç¤ą¤ÍˇĄ +2.2 Use Ruby features from C -¤˝¤ě°Ęł°¤Ë¤âruby¤ÎµˇÇ˝¤ň¸Ć¤Ó˝Đ¤ąĘýˡ¤Ď¤¤¤Ż¤Ä¤«¤˘¤ę¤Ţ¤ąˇĄ +There are several ways to invoke Ruby's features from C code. -2.2.1 ruby¤ÎĄ×ĄíĄ°ĄéĄŕ¤ňeval¤ą¤ë +2.2.1 Evaluate Ruby Program in String -C¤«¤éruby¤ÎµˇÇ˝¤ň¸Ć¤Ó˝Đ¤ą¤â¤Ă¤Č¤â´Ęñ¤ĘĘýˡ¤Č¤·¤Ćˇ¤Ę¸»úÎó¤Ç -Íż¤¨¤é¤ě¤żruby¤ÎĄ×ĄíĄ°ĄéĄŕ¤ňÉľ˛Á¤ą¤ë´Řżô¤¬¤˘¤ę¤Ţ¤ąˇĄ +Easiest way to call Ruby's function from C program is to evaluate the +string as Ruby program. This function will do the job. VALUE rb_eval_string(char *str) -¤ł¤ÎÉľ˛Á¤Ď¸˝şß¤Î´Ä¶­¤ÇąÔ¤ď¤ě¤Ţ¤ąˇĄ¤Ä¤Ţ¤ęˇ¤¸˝şß¤ÎĄíˇĽĄ«ĄëĘŃżô -¤Ę¤É¤ňĽő¤±·Ń¤®¤Ţ¤ąˇĄ +Evaluation is done under current context, thus current local variables +of the innermost method (which is defined by Ruby) can be accessed. 2.2.2 ID or Symbol -C¤«¤éʸ»úÎó¤ň·ĐÍł¤»¤ş¤Ëruby¤ÎĄáĄ˝ĄĂĄÉ¤ň¸Ć¤Ó˝Đ¤ą¤ł¤Č¤â¤Ç¤­¤Ţ -¤ąˇĄ¤˝¤ÎÁ°¤Ëˇ¤rubyĄ¤ĄóĄżĄ×ĄęĄżĆâ¤ÇĄáĄ˝ĄĂĄÉ¤äĘŃżôĚľ¤ň»ŘÄꤹ¤ë -»ţ¤Ë»Č¤ď¤ě¤Ć¤¤¤ëID¤Ë¤Ä¤¤¤ĆŔâĚŔ¤·¤Ć¤Ş¤­¤Ţ¤·¤ç¤¦ˇĄ - -ID¤Č¤ĎĘŃżôĚľˇ¤ĄáĄ˝ĄĂĄÉĚľ¤ňÉ˝¤ąŔ°żô¤Ç¤ąˇĄruby¤ÎĂć¤Ç¤Ď +You can invoke methods directly, without parsing the string. First I +need to explain about symbols (which data type is ID). ID is the +integer number to represent Ruby's identifiers such as variable names. +It can be accessed from Ruby in the form like: - :Ľ±ĘĚ»Ň + :Identifier -¤ÇĄ˘ĄŻĄ»Ąą¤Ç¤­¤Ţ¤ąˇĄC¤«¤é¤ł¤ÎŔ°żô¤ňĆŔ¤ë¤ż¤á¤Ë¤Ď´Řżô +You can get the symbol value from string within C code, by using rb_intern(char *name) -¤ň»Č¤¤¤Ţ¤ąˇĄ¤Ţ¤ż°ěʸ»ú¤Î±é»»»Ň¤Ď¤˝¤Îʸ»úĄłˇĽĄÉ¤¬¤˝¤Î¤Ţ¤ŢĄ·Ąó -ĄÜĄë¤Ë¤Ę¤Ă¤Ć¤¤¤Ţ¤ąˇĄ +In addition, the symbols for one character operators (e.g +) is the +code for that character. -2.2.3 Invoke ruby method from C +2.2.3 Invoke Ruby method from C -C¤«¤éʸ»úÎó¤ň·ĐÍł¤»¤ş¤Ëruby¤ÎĄáĄ˝ĄĂĄÉ¤ň¸Ć¤Ó˝Đ¤ą¤ż¤á¤Ë¤Ď°Ę˛Ľ -¤Î´Řżô¤ň»Č¤¤¤Ţ¤ąˇĄ +To invoke methods directly, you can use the function below VALUE rb_funcall(VALUE recv, ID mid, int argc, ...) -¤ł¤Î´Řżô¤ĎĄŞĄÖĄ¸Ą§ĄŻĄČrecv¤Îmid¤Ç»ŘÄꤵ¤ě¤ëĄáĄ˝ĄĂĄÉ¤ň¸Ć¤Ó˝Đ -¤·¤Ţ¤ąˇĄ +This function invokes the method of the recv, which name is specified +by the symbol mid. -2.2.4 ĘŃżô/Äężô¤ň»˛ľČ/ąąż·¤ą¤ë +2.2.4 Accessing the variables and constants C¤«¤é´Řżô¤ň»Č¤Ă¤Ć»˛ľČˇ¦ąąż·¤Ç¤­¤ë¤Î¤Ďˇ¤ĄŻĄéĄąÄężôˇ¤Ą¤ĄóĄąĄż ĄóĄąĘŃżô¤Ç¤ąˇĄÂç°čĘŃżô¤Ď°ěÉô¤Î¤â¤Î¤ĎC¤ÎÂç°čĘŃżô¤Č¤·¤ĆĄ˘ĄŻĄ» Ąą¤Ç¤­¤Ţ¤ąˇĄĄíˇĽĄ«ĄëĘŃżô¤ň»˛ľČ¤ą¤ëĘýˡ¤Ď¸řł«¤·¤Ć¤¤¤Ţ¤»¤óˇĄ -ĄŞĄÖĄ¸Ą§ĄŻĄČ¤ÎĄ¤ĄóĄąĄżĄóĄąĘŃżô¤ň»˛ľČˇ¦ąąż·¤ą¤ë´Řżô¤Ď°Ę˛Ľ¤ÎÄĚ -¤ę¤Ç¤ąˇĄ +The functions to access/modify instance variables are below: VALUE rb_ivar_get(VALUE obj, ID id) VALUE rb_ivar_set(VALUE obj, ID id, VALUE val) -id¤Ďrb_intern()¤ÇĆŔ¤é¤ě¤ë¤â¤Î¤ň»Č¤Ă¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ +id must be the symbol, which can be retrieved by rb_intern(). -ĄŻĄéĄąÄężô¤ň»˛ľČ¤ą¤ë¤Ë¤Ď°Ę˛Ľ¤Î´Řżô¤ň»Č¤Ă¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ +To access the constants of the class/module: VALUE rb_const_get(VALUE obj, ID id) -ĄŻĄéĄąÄężô¤ňż·¤·¤ŻÄęµÁ¤ą¤ë¤ż¤á¤Ë¤ĎˇŘ2.1.3 ÄężôÄęµÁˇŮ¤ÇľŇ˛đ¤µ -¤ě¤Ć¤¤¤ë´Řżô¤ň»Č¤Ă¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ +See 2.1.3 for defining new constant. -3. Informatin sharing between ruby and C +3. Informatin sharing between Ruby and C -C¸Ŕ¸ě¤Čruby¤Î´Ö¤ÇľđĘó¤ň¶¦Í­¤ą¤ëĘýˡ¤Ë¤Ä¤¤¤Ć˛ňŔ⤷¤Ţ¤ąˇĄ +C¸Ŕ¸ě¤ČRuby¤Î´Ö¤ÇľđĘó¤ň¶¦Í­¤ą¤ëĘýˡ¤Ë¤Ä¤¤¤Ć˛ňŔ⤷¤Ţ¤ąˇĄ -3.1 Ruby constant that C¤«¤é»˛ľČ¤Ç¤­¤ëruby¤ÎÄężô +3.1 Ruby constant that C¤«¤é»˛ľČ¤Ç¤­¤ëRuby¤ÎÄężô -Following ruby constants can be referred from C. +Following Ruby constants can be referred from C. - TRUE - FALSE + Qtrue + Qfalse -Boolean values. FALSE is false in the C also (i.e. 0). +Boolean values. Qfalse is false in the C also (i.e. 0). Qnil Ruby nil in C scope. -3.2 Global variables shared between C and ruby +3.2 Global variables shared between C and Ruby -C¤Čruby¤ÇÂç°čĘŃżô¤ň»Č¤Ă¤ĆľđĘó¤ň¶¦Í­¤Ç¤­¤Ţ¤ąˇĄ¶¦Í­¤Ç¤­¤ëÂç°č +C¤ČRuby¤ÇÂç°čĘŃżô¤ň»Č¤Ă¤ĆľđĘó¤ň¶¦Í­¤Ç¤­¤Ţ¤ąˇĄ¶¦Í­¤Ç¤­¤ëÂç°č ĘŃżô¤Ë¤Ď¤¤¤Ż¤Ä¤«¤ÎĽďÎब¤˘¤ę¤Ţ¤ąˇĄ¤˝¤Î¤Ę¤«¤Ç¤â¤Ă¤Č¤âÎɤŻ»Č¤ď ¤ě¤ë¤Č»×¤ď¤ě¤ë¤Î¤Ďrb_define_variable()¤Ç¤ąˇĄ void rb_define_variable(char *name, VALUE *var) -¤ł¤Î´Řżô¤Ďruby¤ČC¤Č¤Ç¶¦Í­¤ą¤ëÂç°čĘŃżô¤ňÄęµÁ¤·¤Ţ¤ąˇĄĘŃżôĚľ¤¬ +¤ł¤Î´Řżô¤ĎRuby¤ČC¤Č¤Ç¶¦Í­¤ą¤ëÂç°čĘŃżô¤ňÄęµÁ¤·¤Ţ¤ąˇĄĘŃżôĚľ¤¬ `$'¤Ç»Ď¤Ţ¤é¤Ę¤¤»ţ¤Ë¤ĎĽ«Ć°ĹޤËÄɲ䵤ě¤Ţ¤ąˇĄ¤ł¤ÎĘŃżô¤ÎĂͤňĘŃ -ąą¤ą¤ë¤ČĽ«Ć°ĹޤËruby¤ÎÂбţ¤ą¤ëĘŃżô¤ÎĂͤâĘѤď¤ę¤Ţ¤ąˇĄ +ąą¤ą¤ë¤ČĽ«Ć°ĹޤËRuby¤ÎÂбţ¤ą¤ëĘŃżô¤ÎĂͤâĘѤď¤ę¤Ţ¤ąˇĄ -¤Ţ¤żruby¦¤«¤é¤Ďąąż·¤Ç¤­¤Ę¤¤ĘŃżô¤â¤˘¤ę¤Ţ¤ąˇĄ¤ł¤Îread only¤Î +¤Ţ¤żRuby¦¤«¤é¤Ďąąż·¤Ç¤­¤Ę¤¤ĘŃżô¤â¤˘¤ę¤Ţ¤ąˇĄ¤ł¤Îread only¤Î ĘŃżô¤Ď°Ę˛Ľ¤Î´Řżô¤ÇÄęµÁ¤·¤Ţ¤ąˇĄ void rb_define_readonly_variable(char *name, VALUE *var) @@ -421,13 +392,13 @@ setter # getter¤âsetter¤â0¤Ę¤é¤Đrb_define_variable()¤ČƱ¤¸¤Ë¤Ę¤ëˇĄ -¤˝¤ě¤«¤éˇ¤C¤Î´Řżô¤Ë¤č¤Ă¤ĆĽÂ¸˝¤µ¤ě¤ëruby¤ÎÂç°čĘŃżô¤ňÄęµÁ¤ą¤ë +¤˝¤ě¤«¤éˇ¤C¤Î´Řżô¤Ë¤č¤Ă¤ĆĽÂ¸˝¤µ¤ě¤ëRuby¤ÎÂç°čĘŃżô¤ňÄęµÁ¤ą¤ë ´Řżô¤¬¤˘¤ę¤Ţ¤ąˇĄ void rb_define_virtual_variable(char *name, VALUE (*getter)(), VALUE (*setter)()) -¤ł¤Î´Řżô¤Ë¤č¤Ă¤ĆÄęµÁ¤µ¤ě¤żruby¤ÎÂç°čĘŃżô¤¬»˛ľČ¤µ¤ě¤ż»ţ¤Ë¤Ď +¤ł¤Î´Řżô¤Ë¤č¤Ă¤ĆÄęµÁ¤µ¤ě¤żRuby¤ÎÂç°čĘŃżô¤¬»˛ľČ¤µ¤ě¤ż»ţ¤Ë¤Ď getter¤¬ˇ¤ĘŃżô¤ËĂͤ¬Ą»ĄĂĄČ¤µ¤ě¤ż»ţ¤Ë¤Ďsetter¤¬¸Ć¤Đ¤ě¤Ţ¤ąˇĄ The prototypes of the getter and setter functions are as following: @@ -435,14 +406,14 @@ The prototypes of the getter and setter functions are as following: (*getter)(ID id, void *data, struct global_entry* entry); (*setter)(VALUE val, ID id, void *data, struct global_entry* entry); -3.3 Encapsulate C data into ruby object +3.3 Encapsulate C data into Ruby object -C¤ÎŔ¤ł¦¤ÇÄęµÁ¤µ¤ě¤żĄÇˇĽĄż(ą˝Â¤ÂÎ)¤ňruby¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ¤Č¤·¤Ć +C¤ÎŔ¤ł¦¤ÇÄęµÁ¤µ¤ě¤żĄÇˇĽĄż(ą˝Â¤ÂÎ)¤ňRuby¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ¤Č¤·¤Ć Ľč¤ę°·¤¤¤ż¤¤ľěąç¤¬¤˘¤ę¤¨¤Ţ¤ąˇĄ¤ł¤Î¤č¤¦¤Ęľěąç¤Ë¤Ďˇ¤Data¤Č¤¤¤¦ -rubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ËC¤Îą˝Â¤ÂÎ(¤Ř¤ÎĄÝĄ¤ĄóĄż)¤ň¤Ż¤ë¤ŕ¤ł¤Č¤Çruby +RubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ËC¤Îą˝Â¤ÂÎ(¤Ř¤ÎĄÝĄ¤ĄóĄż)¤ň¤Ż¤ë¤ŕ¤ł¤Č¤ÇRuby ĄŞĄÖĄ¸Ą§ĄŻĄČ¤Č¤·¤ĆĽč¤ę°·¤¨¤ë¤č¤¦¤Ë¤Ę¤ę¤Ţ¤ąˇĄ -DataĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňŔ¸Ŕ®¤·¤Ćą˝Â¤ÂΤňrubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ËĄ«Ą×Ą»Ąë +DataĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňŔ¸Ŕ®¤·¤Ćą˝Â¤ÂΤňRubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ËĄ«Ą×Ą»Ąë ˛˝¤ą¤ë¤ż¤á¤Ë¤Ďˇ¤°Ę˛Ľ¤ÎĄŢĄŻĄí¤ň»Č¤¤¤Ţ¤ąˇĄ Data_Wrap_Struct(class,mark,free,ptr) @@ -450,7 +421,7 @@ Data ¤ł¤ÎĄŢĄŻĄí¤ÎĚá¤ęĂͤĎŔ¸Ŕ®¤µ¤ě¤żDataĄŞĄÖĄ¸Ą§ĄŻĄČ¤Ç¤ąˇĄ class¤Ď¤ł¤ÎDataĄŞĄÖĄ¸Ą§ĄŻĄČ¤ÎĄŻĄéĄą¤Ç¤ąˇĄptr¤ĎĄ«Ą×Ą»Ąë˛˝¤ą¤ë -C¤Îą˝Â¤ÂΤؤΥݥ¤ĄóĄż¤Ç¤ąˇĄmark¤Ď¤ł¤Îą˝Â¤ÂΤ¬ruby¤ÎĄŞĄÖĄ¸Ą§ +C¤Îą˝Â¤ÂΤؤΥݥ¤ĄóĄż¤Ç¤ąˇĄmark¤Ď¤ł¤Îą˝Â¤ÂΤ¬Ruby¤ÎĄŞĄÖĄ¸Ą§ ĄŻĄČ¤Ř¤Î»˛ľČ¤¬¤˘¤ë»ţ¤Ë»Č¤¦´Řżô¤Ç¤ąˇĄ¤˝¤Î¤č¤¦¤Ę»˛ľČ¤ň´Ţ¤Ţ¤Ę¤¤ »ţ¤Ë¤Ď0¤ň»ŘÄꤷ¤Ţ¤ąˇĄ @@ -482,47 +453,38 @@ C 4ˇĄExample - Create dbm module -¤ł¤ł¤Ţ¤Ç¤ÎŔâĚŔ¤Ç¤Č¤ę¤˘¤¨¤şłČÄĄĄâĄ¸ĄĺˇĽĄë¤Ďşî¤ě¤ë¤Ď¤ş¤Ç¤ąˇĄ -ruby¤ÎextĄÇĄŁĄěĄŻĄČĄę¤Ë¤ą¤Ç¤Ë´Ţ¤Ţ¤ě¤Ć¤¤¤ëdbmĄâĄ¸ĄĺˇĽĄë¤ňÎă¤Ë +¤ł¤ł¤Ţ¤Ç¤ÎŔâĚŔ¤Ç¤Č¤ę¤˘¤¨¤şłČÄĄĄéĄ¤ĄÖĄéĄę¤Ďşî¤ě¤ë¤Ď¤ş¤Ç¤ąˇĄ +Ruby¤ÎextĄÇĄŁĄěĄŻĄČĄę¤Ë¤ą¤Ç¤Ë´Ţ¤Ţ¤ě¤Ć¤¤¤ëdbmĄâĄ¸ĄĺˇĽĄë¤ňÎă¤Ë ¤·¤ĆĂĘł¬ĹޤËŔâĚŔ¤·¤Ţ¤ąˇĄ (1) make the directory % mkdir ext/dbm -ruby¤ňŸł«¤·¤żĄÇĄŁĄěĄŻĄČĄę¤Î˛Ľˇ¤extĄÇĄŁĄěĄŻĄČĄę¤ÎĂć¤ËłČÄĄĄâ -Ą¸ĄĺˇĽĄëÍѤΥǥŁĄěĄŻĄČĄę¤ňşî¤ę¤Ţ¤ąˇĄĚľÁ°¤ĎŬĹö¤ËÁޤó¤Çą˝¤¤¤Ţ -¤»¤óˇĄ +Make a directory for the extension library under ext directory. (2) create MANIFEST file % cd ext/dbm % touch MANIFEST -łČÄĄĄâĄ¸ĄĺˇĽĄë¤ÎĄÇĄŁĄěĄŻĄČĄę¤Î˛Ľ¤Ë¤ĎMANIFEST¤Č¤¤¤¦ĄŐĄˇĄ¤Ąë¤¬ -ɬÍפʤΤǡ¤¤Č¤ę¤˘¤¨¤ş¶ő¤ÎĄŐĄˇĄ¤Ąë¤ňşî¤Ă¤Ć¤Ş¤­¤Ţ¤ąˇĄ¸ĺ¤Ç¤ł¤Î -ĄŐĄˇĄ¤Ąë¤Ë¤ĎɬÍפʥեˇĄ¤Ąë°ěÍ÷¤¬Ćţ¤ë¤ł¤Č¤Ë¤Ę¤ę¤Ţ¤ąˇĄ - -MANIFEST¤Č¤¤¤¦ĄŐĄˇĄ¤Ąë¤Ďˇ¤make¤Î»ţ¤ËĄÇĄŁĄěĄŻĄČĄę¤¬łČÄĄĄâĄ¸ĄĺˇĽ -Ąë¤ň´Ţ¤ó¤Ç¤¤¤ë¤«¤É¤¦¤«Č˝Äꤹ¤ë¤ż¤á¤Ë»Č¤ď¤ě¤ě¤Ć¤¤¤Ţ¤ąˇĄ +There should be MANIFEST file in the directory for the extension +library. Make empty file now. (3) design the library -¤Ţ¤˘ˇ¤ĹöÁł¤Ę¤ó¤Ç¤ą¤±¤Éˇ¤¤É¤¦¤¤¤¦µˇÇ˝¤ňĽÂ¸˝¤ą¤ë¤«¤É¤¦¤«¤Ţ¤şŔß -·×¤ą¤ëɬÍפ¬¤˘¤ę¤Ţ¤ąˇĄ¤É¤ó¤ĘĄŻĄéĄą¤ň¤Ä¤Ż¤ë¤«ˇ¤¤˝¤ÎĄŻĄéĄą¤Ë¤Ď -¤É¤ó¤ĘĄáĄ˝ĄĂĄÉ¤¬¤˘¤ë¤«ˇ¤ĄŻĄéĄą¤¬Ä󶡤ą¤ëÄężô¤Ę¤É¤Ë¤Ä¤¤¤ĆŔß·× -¤·¤Ţ¤ąˇĄdbmĄŻĄéĄą¤Ë¤Ä¤¤¤Ć¤Ďext/dbm.doc¤ň»˛ľČ¤·¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ +You need to design the library features, before making it. (4) write C code. -łČÄĄĄâĄ¸ĄĺˇĽĄëËÜÂΤȤʤëC¸Ŕ¸ě¤ÎĄ˝ˇĽĄą¤ň˝ń¤­¤Ţ¤ąˇĄC¸Ŕ¸ě¤ÎĄ˝ˇĽ +łČÄĄĄéĄ¤ĄÖĄéĄęËÜÂΤȤʤëC¸Ŕ¸ě¤ÎĄ˝ˇĽĄą¤ň˝ń¤­¤Ţ¤ąˇĄC¸Ŕ¸ě¤ÎĄ˝ˇĽ Ąą¤¬¤Ň¤Č¤Ä¤Î»ţ¤Ë¤ĎˇÖĄâĄ¸ĄĺˇĽĄëĚľ.cˇ×¤ňÁޤ֤ČÎɤ¤¤Ç¤·¤ç¤¦ˇĄC ¸Ŕ¸ě¤ÎĄ˝ˇĽĄą¤¬ĘŁżô¤Îľěąç¤Ë¤ĎµŐ¤ËˇÖĄâĄ¸ĄĺˇĽĄëĚľ.cˇ×¤Č¤¤¤¦ĄŐĄˇ Ą¤ĄëĚľ¤ĎČň¤±¤ëɬÍפ¬¤˘¤ę¤Ţ¤ąˇĄĄŞĄÖĄ¸Ą§ĄŻĄČĄŐĄˇĄ¤Ąë¤ČĄâĄ¸ĄĺˇĽ ĄëŔ¸Ŕ®»ţ¤ËĂć´ÖĹŞ¤ËŔ¸Ŕ®¤µ¤ě¤ëˇÖĄâĄ¸ĄĺˇĽĄëĚľ.oˇ×¤Č¤¤¤¦ĄŐĄˇĄ¤Ąë ¤Č¤¬ľ×Ćͤą¤ë¤«¤é¤Ç¤ąˇĄ -ruby¤ĎłČÄĄĄâĄ¸ĄĺˇĽĄë¤ňĄíˇĽĄÉ¤ą¤ë»ţ¤ËˇÖInit_ĄâĄ¸ĄĺˇĽĄëĚľˇ×¤Č +Ruby¤ĎłČÄĄĄéĄ¤ĄÖĄéĄę¤ňĄíˇĽĄÉ¤ą¤ë»ţ¤ËˇÖInit_ĄâĄ¸ĄĺˇĽĄëĚľˇ×¤Č ¤¤¤¦´Řżô¤ňĽ«Ć°ĹŞ¤ËĽÂąÔ¤·¤Ţ¤ąˇĄdbmĄâĄ¸ĄĺˇĽĄë¤ÎľěąçˇÖInit_dbmˇ× ¤Ç¤ąˇĄ¤ł¤Î´Řżô¤ÎĂć¤ÇĄŻĄéĄąˇ¤ĄâĄ¸ĄĺˇĽĄëˇ¤ĄáĄ˝ĄĂĄÉˇ¤Äężô¤Ę¤É¤Î ÄęµÁ¤ňąÔ¤¤¤Ţ¤ąˇĄdbm.c¤«¤é°ěÉô°úÍѤ·¤Ţ¤ąˇĄ @@ -530,27 +492,25 @@ ruby -- Init_dbm() { - /* DBMĄŻĄéĄą¤ňÄęµÁ¤ą¤ë */ - cDBM = rb_define_class("DBM", cObject); - /* DBM¤ĎEnumerateĄâĄ¸ĄĺˇĽĄë¤ňĄ¤ĄóĄŻĄëˇĽĄÉ¤ą¤ë */ - rb_include_module(cDBM, mEnumerable); + /* define DBM class */ + cDBM = rb_define_class("DBM", rb_cObject); + /* DBM includes Enumerate module */ + rb_include_module(cDBM, rb_mEnumerable); - /* DBMĄŻĄéĄą¤ÎĄŻĄéĄąĄáĄ˝ĄĂĄÉopen(): °úżô¤ĎC¤ÎÇŰÎó¤ÇĽő¤±¤ë */ + /* DBM has class method open(): arguments are received as C array */ rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); - /* DBMĄŻĄéĄą¤ÎĄáĄ˝ĄĂĄÉclose(): °úżô¤Ď¤Ę¤· */ + /* DBM instance method close(): no args */ rb_define_method(cDBM, "close", fdbm_close, 0); - /* DBMĄŻĄéĄą¤ÎĄáĄ˝ĄĂĄÉ[]: °úżô¤Ď1¸Ä */ + /* DBM instance method []: 1 argument */ rb_define_method(cDBM, "[]", fdbm_fetch, 1); : - /* DBMĄÇˇĽĄż¤ňłĘÇĽ¤ą¤ëĄ¤ĄóĄąĄżĄóĄąĘŃżôĚľ¤Î¤ż¤á¤ÎID */ - id_dbm = rb_intern("dbm"); } -- DBMĄâĄ¸ĄĺˇĽĄë¤Ďdbm¤ÎĄÇˇĽĄż¤ČÂбţ¤ą¤ëĄŞĄÖĄ¸Ą§ĄŻĄČ¤Ë¤Ę¤ë¤Ď¤ş¤Ç -¤ą¤«¤éˇ¤C¤ÎŔ¤ł¦¤Îdbm¤ňruby¤ÎŔ¤ł¦¤ËĽč¤ęąţ¤ŕɬÍפ¬¤˘¤ę¤Ţ¤ąˇĄ +¤ą¤«¤éˇ¤C¤ÎŔ¤ł¦¤Îdbm¤ňRuby¤ÎŔ¤ł¦¤ËĽč¤ęąţ¤ŕɬÍפ¬¤˘¤ę¤Ţ¤ąˇĄ dbm.c¤Ç¤ĎData_Make_Struct¤ň°Ę˛Ľ¤Î¤č¤¦¤Ë»Č¤Ă¤Ć¤¤¤Ţ¤ąˇĄ @@ -600,7 +560,7 @@ fdbm_delete(obj, keystr) °úżô¤Îżô¤¬¸ÇÄę¤ÎĄżĄ¤Ą×¤ĎÂč1°úżô¤¬selfˇ¤Âč2°úżô°Ęąß¤¬ĄáĄ˝ĄĂĄÉ ¤Î°úżô¤Č¤Ę¤ę¤Ţ¤ąˇĄ -°úżô¤Îżô¤¬ÉÔÄę¤Î¤â¤Î¤ĎC¤ÎÇŰÎó¤ÇĽő¤±¤ë¤â¤Î¤Čruby¤ÎÇŰÎó¤ÇĽő¤± +°úżô¤Îżô¤¬ÉÔÄę¤Î¤â¤Î¤ĎC¤ÎÇŰÎó¤ÇĽő¤±¤ë¤â¤Î¤ČRuby¤ÎÇŰÎó¤ÇĽő¤± ¤ë¤â¤Î¤Č¤¬¤˘¤ę¤Ţ¤ąˇĄdbmĄâĄ¸ĄĺˇĽĄë¤ÎĂć¤Çˇ¤C¤ÎÇŰÎó¤ÇĽő¤±¤ë¤â¤Î ¤ĎDBM¤ÎĄŻĄéĄąĄáĄ˝ĄĂĄÉ¤Ç¤˘¤ëopen()¤Ç¤ąˇĄ¤ł¤ě¤ňĽÂÁő¤·¤Ć¤¤¤ë´Ř żôfdbm_s_open()¤Ď¤ł¤¦¤Ę¤Ă¤Ć¤¤¤Ţ¤ąˇĄ @@ -634,7 +594,7 @@ fdbm_s_open(argc, argv, class) ¤Çˇ¤2¤Ä¤Ţ¤Çµö¤µ¤ě¤ë¤Č¤¤¤¦°ŐĚŁ¤Ë¤Ę¤ę¤Ţ¤ąˇĄľĘά¤µ¤ě¤Ć¤¤¤ë»ţ¤Î ĘŃżô¤ÎĂͤĎnil(C¸Ŕ¸ě¤ÎĄěĄŮĄë¤Ç¤ĎQnil)¤Ë¤Ę¤ę¤Ţ¤ąˇĄ -ruby¤ÎÇŰÎó¤Ç°úżô¤ňĽő¤±Ľč¤ë¤â¤Î¤Ďindexes¤¬¤˘¤ę¤Ţ¤ąˇĄĽÂÁő¤Ď¤ł +Ruby¤ÎÇŰÎó¤Ç°úżô¤ňĽő¤±Ľč¤ë¤â¤Î¤Ďindexes¤¬¤˘¤ę¤Ţ¤ąˇĄĽÂÁő¤Ď¤ł ¤¦¤Ç¤ąˇĄ -- @@ -647,15 +607,14 @@ fdbm_indexes(obj, args) } -- -Âč1°úżô¤Ďselfˇ¤Âč2°úżô¤Ďruby¤ÎÇŰÎó¤Ç¤ąˇĄ¤ł¤ł¤Ç¤ĎĄ­ĄăĄąĄČ¤ň¸ş +Âč1°úżô¤Ďselfˇ¤Âč2°úżô¤ĎRuby¤ÎÇŰÎó¤Ç¤ąˇĄ¤ł¤ł¤Ç¤ĎĄ­ĄăĄąĄČ¤ň¸ş ¤é¤ą¤ż¤á struct RArray* ¤ÇĽő¤±¤Ć¤¤¤Ţ¤ą¤¬ˇ¤VALUE¤Ç¤âƱ¤¸¤ł¤Č ¤Ç¤ąˇĄ -** Ăí°Ő»öąŕ +** Notice -ruby¤Č¶¦Í­¤Ď¤·¤Ę¤¤¤¬ruby¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňłĘÇĽ¤ą¤ë˛ÄÇ˝Ŕ­¤Î¤˘¤ë -C¤ÎÂç°čĘŃżô¤Ď°Ę˛Ľ¤Î´Řżô¤ň»Č¤Ă¤ĆrubyĄ¤ĄóĄżĄ×ĄęĄż¤ËĘŃżô¤Î¸şß -¤ň¶µ¤¨¤Ć¤˘¤˛¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ¤Ç¤Ę¤¤¤ČGC¤ÇĄČĄéĄÖĄë¤ňµŻ¤ł¤·¤Ţ¤ąˇĄ +GC should know about global variables which refers Ruby's objects, but +not exported to the Ruby world. You need to protect them by void rb_global_variable(VALUE *var) @@ -665,7 +624,7 @@ C make»ţ¤ËĽÂąÔ¤µ¤ě¤Ţ¤ąˇĄ¤Ę¤±¤ě¤ĐŬĹö¤ËMakefile¤¬Ŕ¸Ŕ®¤µ¤ě¤Ţ¤ąˇĄ extconf.rb¤ĎĄâĄ¸ĄĺˇĽĄë¤ÎĄłĄóĄŃĄ¤Ąë¤ËɬÍפʾň·ď¤ÎĄÁĄ§ĄĂĄŻ¤Ę¤É -¤ňąÔ¤¦¤ł¤Č¤¬ĚÜĹŞ¤Ç¤ąˇĄextconf.rb¤ÎĂć¤Ç¤Ď°Ę˛Ľ¤Îruby´Řżô¤ň»Č¤¦ +¤ňąÔ¤¦¤ł¤Č¤¬ĚÜĹŞ¤Ç¤ąˇĄextconf.rb¤ÎĂć¤Ç¤Ď°Ę˛Ľ¤ÎRuby´Řżô¤ň»Č¤¦ ¤ł¤Č¤¬˝ĐÍč¤Ţ¤ąˇĄ have_library(lib, func): ĄéĄ¤ĄÖĄéĄę¤Î¸şßĄÁĄ§ĄĂĄŻ @@ -704,31 +663,31 @@ make (8) make -ruby¤ÎĄÇĄŁĄěĄŻĄČĄę¤Çmake¤ňĽÂąÔ¤ą¤ë¤ČMakefile¤ňŔ¸Ŕ®¤«¤émakeˇ¤ -ɬÍפˤč¤Ă¤Ć¤Ď¤˝¤ÎĄâĄ¸ĄĺˇĽĄë¤Îruby¤Ř¤ÎĄęĄóĄŻ¤Ţ¤ÇĽ«Ć°ĹŞ¤ËĽÂąÔ +Ruby¤ÎĄÇĄŁĄěĄŻĄČĄę¤Çmake¤ňĽÂąÔ¤ą¤ë¤ČMakefile¤ňŔ¸Ŕ®¤«¤émakeˇ¤ +ɬÍפˤč¤Ă¤Ć¤Ď¤˝¤ÎĄâĄ¸ĄĺˇĽĄë¤ÎRuby¤Ř¤ÎĄęĄóĄŻ¤Ţ¤ÇĽ«Ć°ĹŞ¤ËĽÂąÔ ¤·¤Ć¤Ż¤ě¤Ţ¤ąˇĄextconf.rb¤ň˝ń¤­´ą¤¨¤ë¤Ę¤É¤·¤ĆMakefile¤ÎşĆŔ¸Ŕ® -¤¬É¬Íפʻţ¤Ď¤Ţ¤żrubyĄÇĄŁĄěĄŻĄČĄę¤Çmake¤·¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ +¤¬É¬Íפʻţ¤Ď¤Ţ¤żRubyĄÇĄŁĄěĄŻĄČĄę¤Çmake¤·¤Ć¤Ż¤Ŕ¤µ¤¤ˇĄ (9) debug -¤Ţ¤˘ˇ¤ĄÇĄĐĄĂĄ°¤·¤Ę¤¤¤ČĆ°¤«¤Ę¤¤¤Ç¤·¤ç¤¦¤ÍˇĄext/Setup¤ËĄÇĄŁĄě -ĄŻĄČĄęĚľ¤ň˝ń¤Ż¤ČŔĹĹŞ¤ËĄęĄóĄŻ¤ą¤ë¤Î¤ÇĄÇĄĐĄĂĄ¬¤¬»Č¤¨¤ë¤č¤¦¤Ë¤Ę -¤ę¤Ţ¤ąˇĄ¤˝¤ÎʬĄłĄóĄŃĄ¤Ąë¤¬Ă٤Ż¤Ę¤ę¤Ţ¤ą¤±¤ÉˇĄ +You may need to rb_debug the module. The modules can be linked +statically by adding directory name in the ext/Setup file, +so that you can inspect the module by the debugger. -(10) done, now you have the extension module +(10) done, now you have the extension library ¸ĺ¤Ď¤ł¤Ă¤˝¤ę»Č¤¦¤Ę¤ęˇ¤ą­¤Ż¸řł«¤ą¤ë¤Ę¤ęˇ¤Çä¤ë¤Ę¤ęˇ¤¤´Ľ«Íł¤Ë¤Ş -»Č¤¤¤Ż¤Ŕ¤µ¤¤ˇĄruby¤ÎşîĽÔ¤ĎłČÄĄĄâĄ¸ĄĺˇĽĄë¤Ë´Ř¤·¤Ć°ěŔڤθ˘Íř¤ň +»Č¤¤¤Ż¤Ŕ¤µ¤¤ˇĄRuby¤ÎşîĽÔ¤ĎłČÄĄĄéĄ¤ĄÖĄéĄę¤Ë´Ř¤·¤Ć°ěŔڤθ˘Íř¤ň ĽçÄĄ¤·¤Ţ¤»¤óˇĄ -Appendix A. ruby¤ÎĄ˝ˇĽĄąĄłˇĽĄÉ¤ÎʬÎŕ +Appendix A. Ruby¤ÎĄ˝ˇĽĄąĄłˇĽĄÉ¤ÎʬÎŕ -ruby¤ÎĄ˝ˇĽĄą¤Ď¤¤¤Ż¤Ä¤«¤ËʬÎह¤ë¤ł¤Č¤¬˝ĐÍč¤Ţ¤ąˇĄ¤ł¤Î¤¦¤ÁĄŻĄé -ĄąĄéĄ¤ĄÖĄéĄę¤ÎÉôʬ¤Ď´đËÜĹŞ¤ËłČÄĄĄâĄ¸ĄĺˇĽĄë¤ČƱ¤¸şî¤ęĘý¤Ë¤Ę¤Ă +Ruby¤ÎĄ˝ˇĽĄą¤Ď¤¤¤Ż¤Ä¤«¤ËʬÎह¤ë¤ł¤Č¤¬˝ĐÍč¤Ţ¤ąˇĄ¤ł¤Î¤¦¤ÁĄŻĄé +ĄąĄéĄ¤ĄÖĄéĄę¤ÎÉôʬ¤Ď´đËÜĹŞ¤ËłČÄĄĄéĄ¤ĄÖĄéĄę¤ČƱ¤¸şî¤ęĘý¤Ë¤Ę¤Ă ¤Ć¤¤¤Ţ¤ąˇĄ¤ł¤ě¤é¤ÎĄ˝ˇĽĄą¤ĎşŁ¤Ţ¤Ç¤ÎŔâĚŔ¤Ç¤Ű¤Č¤ó¤ÉÍý˛ň¤Ç¤­¤ë¤Č »×¤¤¤Ţ¤ąˇĄ -coore ruby language +ruby language core class.c error.c @@ -780,13 +739,13 @@ class library Appendix B. łČÄĄÍŃ´ŘżôĄęĄŐĄˇĄěĄóĄą -C¸Ŕ¸ě¤«¤éruby¤ÎµˇÇ˝¤ňÍřÍѤą¤ëAPI¤Ď°Ę˛Ľ¤ÎÄ̤ę¤Ç¤˘¤ëˇĄ +C¸Ŕ¸ě¤«¤éRuby¤ÎµˇÇ˝¤ňÍřÍѤą¤ëAPI¤Ď°Ę˛Ľ¤ÎÄ̤ę¤Ç¤˘¤ëˇĄ ** ·ż VALUE -rubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňÉ˝¸˝¤ą¤ë·żˇĄÉ¬Íפ˱ţ¤¸¤ĆĄ­ĄăĄąĄČ¤·¤ĆÍѤ¤¤ëˇĄ +RubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňÉ˝¸˝¤ą¤ë·żˇĄÉ¬Íפ˱ţ¤¸¤ĆĄ­ĄăĄąĄČ¤·¤ĆÍѤ¤¤ëˇĄ ÁȤ߹ţ¤ß·ż¤ňÉ˝¸˝¤ą¤ëC¤Î·ż¤Ďruby.h¤Ëµ­˝Ň¤·¤Ć¤˘¤ëR¤Ç»Ď¤Ţ¤ëą˝Â¤ ÂΤǤ˘¤ëˇĄVALUE·ż¤ň¤ł¤ě¤é¤ËĄ­ĄăĄąĄČ¤ą¤ë¤ż¤á¤ËR¤Ç»Ď¤Ţ¤ëą˝Â¤ÂÎ Ěľ¤ňÁ´¤ĆÂçʸ»ú¤Ë¤·¤żĚľÁ°¤ÎĄŢĄŻĄí¤¬ÍŃ°Ő¤µ¤ě¤Ć¤¤¤ëˇĄ @@ -797,21 +756,21 @@ ruby const: nil object - TRUE + Qtrue -const: TRUE object(default true value) +const: Qtrue object(default true value) - FALSE + Qfalse -const: FALSE object +const: Qfalse object ** CĄÇˇĽĄż¤ÎĄ«Ą×Ą»Ąë˛˝ Data_Wrap_Struct(VALUE class, void (*mark)(), void (*free)(), void *sval) -C¤ÎǤ°Ő¤ÎĄÝĄ¤ĄóĄż¤ňĄ«Ą×Ą»Ąë˛˝¤·¤żrubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňĘÖ¤ąˇĄ¤ł -¤ÎĄÝĄ¤ĄóĄż¤¬ruby¤«¤éĄ˘ĄŻĄ»Ąą¤µ¤ě¤Ę¤Ż¤Ę¤Ă¤ż»ţˇ¤free¤Ç»ŘÄꤷ¤ż -´Řżô¤¬¸Ć¤Đ¤ě¤ëˇĄ¤Ţ¤żˇ¤¤ł¤ÎĄÝĄ¤ĄóĄż¤Î»Ř¤ąĄÇˇĽĄż¤¬Âľ¤ÎrubyĄŞĄÖ +C¤ÎǤ°Ő¤ÎĄÝĄ¤ĄóĄż¤ňĄ«Ą×Ą»Ąë˛˝¤·¤żRubyĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňĘÖ¤ąˇĄ¤ł +¤ÎĄÝĄ¤ĄóĄż¤¬Ruby¤«¤éĄ˘ĄŻĄ»Ąą¤µ¤ě¤Ę¤Ż¤Ę¤Ă¤ż»ţˇ¤free¤Ç»ŘÄꤷ¤ż +´Řżô¤¬¸Ć¤Đ¤ě¤ëˇĄ¤Ţ¤żˇ¤¤ł¤ÎĄÝĄ¤ĄóĄż¤Î»Ř¤ąĄÇˇĽĄż¤¬Âľ¤ÎRubyĄŞĄÖ Ą¸Ą§ĄŻĄČ¤ň»Ř¤·¤Ć¤¤¤ëľěąçˇ¤mark¤Ë»ŘÄꤹ¤ë´Řżô¤ÇĄŢˇĽĄŻ¤ą¤ëɬÍ× ¤¬¤˘¤ëˇĄ @@ -828,20 +787,20 @@ data VALUE rb_define_class(char *name, VALUE super) -super¤ÎĄµĄÖĄŻĄéĄą¤Č¤·¤Ćż·¤·¤¤rubyĄŻĄéĄą¤ňÄęµÁ¤ą¤ëˇĄ +super¤ÎĄµĄÖĄŻĄéĄą¤Č¤·¤Ćż·¤·¤¤RubyĄŻĄéĄą¤ňÄęµÁ¤ą¤ëˇĄ VALUE rb_define_class_under(VALUE module, char *name, VALUE super) -super¤ÎĄµĄÖĄŻĄéĄą¤Č¤·¤Ćż·¤·¤¤rubyĄŻĄéĄą¤ňÄęµÁ¤·ˇ¤module¤ÎÄę +super¤ÎĄµĄÖĄŻĄéĄą¤Č¤·¤Ćż·¤·¤¤RubyĄŻĄéĄą¤ňÄęµÁ¤·ˇ¤module¤ÎÄę żô¤Č¤·¤ĆÄęµÁ¤ą¤ëˇĄ VALUE rb_define_module(char *name) -ż·¤·¤¤rubyĄâĄ¸ĄĺˇĽĄë¤ňÄęµÁ¤ą¤ëˇĄ +ż·¤·¤¤RubyĄâĄ¸ĄĺˇĽĄë¤ňÄęµÁ¤ą¤ëˇĄ VALUE rb_define_module_under(VALUE module, char *name, VALUE super) -ż·¤·¤¤rubyĄâĄ¸ĄĺˇĽĄë¤ňÄęµÁ¤·ˇ¤module¤ÎÄężô¤Č¤·¤ĆÄęµÁ¤ą¤ëˇĄ +ż·¤·¤¤RubyĄâĄ¸ĄĺˇĽĄë¤ňÄęµÁ¤·ˇ¤module¤ÎÄężô¤Č¤·¤ĆÄęµÁ¤ą¤ëˇĄ void rb_include_module(VALUE class, VALUE module) @@ -852,61 +811,70 @@ super ĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňĄâĄ¸ĄĺˇĽĄë(¤ÇÄęµÁ¤µ¤ě¤Ć¤¤¤ëĄáĄ˝ĄĂĄÉ)¤ÇłČÄĄ¤ą¤ëˇĄ -** Âç°čĘŃżôÄęµÁ +** Defining Global Variables void rb_define_variable(char *name, VALUE *var) -ruby¤ČC¤Č¤Ç¶¦Í­¤ą¤ëĄ°ĄíˇĽĄĐĄëĘŃżô¤ňÄęµÁ¤ą¤ëˇĄĘŃżôĚľ¤¬`$'¤Ç»Ď -¤Ţ¤é¤Ę¤¤»ţ¤Ë¤ĎĽ«Ć°ĹޤËÄɲ䵤ě¤ëˇĄname¤Č¤·¤Ćruby¤ÎĽ±Ę̻ҤȤ· -¤Ćµö¤µ¤ě¤Ę¤¤Ę¸»ú(Î㤨¤Đ` ')¤ň´Ţ¤ŕľěąç¤Ë¤ĎrubyĄ×ĄíĄ°ĄéĄŕ¤«¤é -¤Ď¸«¤¨¤Ę¤Ż¤Ę¤ëˇĄ +Defines a global variable which is shared between C and Ruby. If name +contains the character which is not allowed to be part of the symbol, +it can't be seen from Ruby programs. void rb_define_readonly_variable(char *name, VALUE *var) -ruby¤ČC¤Č¤Ç¶¦Í­¤ą¤ëread only¤ÎĄ°ĄíˇĽĄĐĄëĘŃżô¤ňÄęµÁ¤ą¤ëˇĄread -only¤Ç¤˘¤ë¤ł¤Č°Ęł°¤Ďrb_define_variable()¤ČƱ¤¸ˇĄ +Defines a read-only global variable. Works just like +rb_define_variable(), except defined variable is read-only. void rb_define_virtual_variable(char *name, VALUE (*getter)(), VALUE (*setter)()) -´Řżô¤Ë¤č¤Ă¤ĆĽÂ¸˝¤µ¤ě¤ërubyĘŃżô¤ňÄęµÁ¤ą¤ëˇĄĘŃżô¤¬»˛ľČ¤µ¤ě¤ż»ţ -¤Ë¤Ďgetter¤¬ˇ¤ĘŃżô¤ËĂͤ¬Ą»ĄĂĄČ¤µ¤ě¤ż»ţ¤Ë¤Ďsetter¤¬¸Ć¤Đ¤ě¤ëˇĄ +Defines a virtual variable, whose behavior is defined by pair of C +functions. The getter function is called when the variable is +referred. The setter function is called when the value is set to the +variable. The prototype for getter/setter functions are: + + VALUE getter(ID id) + void setter(VALUE val, ID id) + +The getter function must return the value for the access. void rb_define_hooked_variable(char *name, VALUE *var, VALUE (*getter)(), VALUE (*setter)()) -´Řżô¤Ë¤č¤Ă¤Ćhook¤Î¤Ä¤±¤é¤ě¤żĄ°ĄíˇĽĄĐĄëĘŃżô¤ňÄęµÁ¤ą¤ëˇĄĘŃżô¤¬ -»˛ľČ¤µ¤ě¤ż»ţ¤Ë¤Ďgetter¤¬ˇ¤´Řżô¤ËĂͤ¬Ą»ĄĂĄČ¤µ¤ě¤ż»ţ¤Ë¤Ďsetter -¤¬¸Ć¤Đ¤ě¤ëˇĄgetter¤äsetter¤Ë0¤ň»ŘÄꤷ¤ż»ţ¤Ë¤Ďhook¤ň»ŘÄꤷ¤Ę -¤¤¤Î¤ČƱ¤¸»ö¤Ë¤Ę¤ëˇĄ +Defines hooked variable. It's virtual variable with C variable. The +getter is called as + + VALUE getter(ID id, VALUE *var) + +returning new value. The setter is called as + + void setter(VALUE val, ID id, VALUE *var) + +GC requires to mark the C global variables which hold Ruby values. void rb_global_variable(VALUE *var) -GC¤Î¤ż¤áˇ¤rubyĄ×ĄíĄ°ĄéĄŕ¤«¤é¤ĎĄ˘ĄŻĄ»Ąą¤µ¤ě¤Ę¤¤¤¬, rubyĄŞĄÖĄ¸Ą§ -ĄŻĄČ¤ň´Ţ¤ŕÂç°čĘŃżô¤ňĄŢˇĽĄŻ¤ą¤ëˇĄ +Tells GC to protect these variables. -** ĄŻĄéĄąÄężô +** Constant Definition - void rb_define_const(VALUE class, char *name, VALUE val) + void rb_define_const(VALUE klass, char *name, VALUE val) -ĄŻĄéĄąÄężô¤ňÄęµÁ¤ą¤ëˇĄ +Defines a new constant under the class/module. void rb_define_global_const(char *name, VALUE val) -Âç°čÄężô¤ňÄęµÁ¤ą¤ëˇĄ +Defines global contant. This is just work as rb_define_const(cKernal, name, val) -¤ČƱ¤¸°ŐĚŁˇĄ - -** ĄáĄ˝ĄĂĄÉÄęµÁ +** Method Definition rb_define_method(VALUE class, char *name, VALUE (*func)(), int argc) ĄáĄ˝ĄĂĄÉ¤ňÄęµÁ¤ą¤ëˇĄargc¤Ďself¤ň˝ü¤Ż°úżô¤ÎżôˇĄargc¤¬-1¤Î»ţ, ´Řżô¤Ë¤Ď°úżô¤Îżô(self¤ň´Ţ¤Ţ¤Ę¤¤)¤ňÂč1°úżô, °úżô¤ÎÇŰÎó¤ňÂč2°ú żô¤Č¤ą¤ë·ÁĽ°¤ÇÍż¤¨¤é¤ě¤ë(Âč3°úżô¤Ďself)ˇĄargc¤¬-2¤Î»ţ, Âč1°ú -żô¤¬self, Âč2°úżô¤¬args(args¤Ď°úżô¤ň´Ţ¤ŕruby¤ÎÇŰÎó)¤Č¤¤¤¦·Á +żô¤¬self, Âč2°úżô¤¬args(args¤Ď°úżô¤ň´Ţ¤ŕRuby¤ÎÇŰÎó)¤Č¤¤¤¦·Á Ľ°¤ÇÍż¤¨¤é¤ě¤ëˇĄ rb_define_private_method(VALUE class, char *name, VALUE (*func)(), int argc) @@ -927,7 +895,7 @@ argc,argv żô¤ËÂбţ¤ą¤ë°úżô¤¬Íż¤¨¤é¤ě¤Ć¤¤¤Ę¤¤ľěąç¤ĎĘŃżô¤ËQnil¤¬ÂĺĆţ¤µ¤ě ¤ëˇĄ -** rubyĄáĄ˝ĄĂĄÉ¸Ć¤Ó˝Đ¤· +** RubyĄáĄ˝ĄĂĄÉ¸Ć¤Ó˝Đ¤· VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) @@ -939,7 +907,7 @@ argc,argv VALUE rb_eval_string(char *str) -ʸ»úÎó¤ňruby¤ČĄąĄŻĄęĄ×ĄČ¤·¤ĆĄłĄóĄŃĄ¤Ąëˇ¦ĽÂąÔ¤ą¤ëˇĄ +ʸ»úÎó¤ňRuby¤ČĄąĄŻĄęĄ×ĄČ¤·¤ĆĄłĄóĄŃĄ¤Ąëˇ¦ĽÂąÔ¤ą¤ëˇĄ ID rb_intern(char *name) @@ -959,7 +927,7 @@ class VALUE rb_iv_get(VALUE obj, char *name) obj¤ÎĄ¤ĄóĄąĄżĄóĄąĘŃżô¤ÎĂͤňĆŔ¤ëˇĄ`@'¤Ç»Ď¤Ţ¤é¤Ę¤¤Ą¤ĄóĄąĄżĄóĄą -ĘŃżô¤Ď rubyĄ×ĄíĄ°ĄéĄŕ¤«¤éĄ˘ĄŻĄ»Ąą¤Ç¤­¤Ę¤¤ˇÖ±Ł¤ě¤żˇ×Ą¤ĄóĄąĄż +ĘŃżô¤Ď RubyĄ×ĄíĄ°ĄéĄŕ¤«¤éĄ˘ĄŻĄ»Ąą¤Ç¤­¤Ę¤¤ˇÖ±Ł¤ě¤żˇ×Ą¤ĄóĄąĄż ĄóĄąĘŃżô¤Ë¤Ę¤ëˇĄ VALUE rb_iv_set(VALUE obj, char *name, VALUE val) @@ -993,69 +961,66 @@ val ** Îăł°ˇ¦Ą¨ĄéˇĽ - void Warning(char *fmt, ...) + void rb_warning(char *fmt, ...) -verbose»ţ¤Ëɸ˝ŕĄ¨ĄéˇĽ˝ĐÎϤ˷ٹđľđĘó¤ňÉ˝Ľ¨¤ą¤ëˇĄ°úżô¤Ďprintf()¤ČƱ¤¸ˇĄ +rb_verbose»ţ¤Ëɸ˝ŕĄ¨ĄéˇĽ˝ĐÎϤ˷ٹđľđĘó¤ňÉ˝Ľ¨¤ą¤ëˇĄ°úżô¤Ďprintf()¤ČƱ¤¸ˇĄ - void Fail(char *fmt, ...) + void rb_raise(rb_eRuntimeError, char *fmt, ...) Îăł°¤ňČŻŔ¸¤µ¤»¤ëˇĄ°úżô¤Ďprintf()¤ČƱ¤¸ˇĄ - void Fatal(char *fmt, ...) + void rb_fatal(char *fmt, ...) Ă×̿ŪÎăł°¤ňČŻŔ¸¤µ¤»¤ëˇĄÄĚľď¤ÎÎăł°˝čÍý¤ĎąÔ¤Ę¤ď¤ě¤ş, Ą¤ĄóĄżˇĽ Ą×ĄęĄż¤¬˝ŞÎ»¤ą¤ë(¤ż¤Ŕ¤·ensure¤Ç»ŘÄꤵ¤ě¤żĄłˇĽĄÉ¤Ď˝ŞÎ»Á°¤ËĽÂ ąÔ¤µ¤ě¤ë)ˇĄ - void Bug(char *fmt, ...) + void rb_bug(char *fmt, ...) Ą¤ĄóĄżˇĽĄ×ĄęĄż¤Ę¤ÉĄ×ĄíĄ°ĄéĄŕ¤ÎĄĐĄ°¤Ç¤·¤«ČŻŔ¸¤ą¤ë¤Ď¤ş¤Î¤Ę¤¤ľő ¶·¤Î»ţ¸Ć¤ÖˇĄĄ¤ĄóĄżˇĽĄ×ĄęĄż¤ĎĄłĄ˘ĄŔĄóĄ×¤·Äľ¤Á¤Ë˝ŞÎ»¤ą¤ëˇĄÎăł° ˝čÍý¤Ď°ěŔڹԤʤď¤ě¤Ę¤¤ˇĄ -** ruby¤Î˝é´ü˛˝ˇ¦ĽÂąÔ +** Initialize and Starts the Interpreter -ruby¤ňĄ˘Ą×ĄęĄ±ˇĽĄ·ĄçĄó¤ËËä¤áąţ¤ŕľěąç¤Ë¤Ď°Ę˛Ľ¤ÎĄ¤ĄóĄżĄŐĄ§ˇĽĄą -¤ň»Č¤¦ˇĄÄĚľď¤ÎłČÄĄĄâĄ¸ĄĺˇĽĄë¤Ë¤ĎɬÍפʤ¤ˇĄ +The embedding API are below (not needed for extension libraries): void ruby_init(int argc, char **argv, char **envp) -rubyĄ¤ĄóĄżĄ×ĄęĄż¤Î˝é´ü˛˝¤ňąÔ¤Ę¤¦ˇĄ +Initializes the interpreter. void ruby_run() -rubyĄ¤ĄóĄżĄ×ĄęĄż¤ňĽÂąÔ¤ą¤ëˇĄ +Starts execution of the interpreter. void ruby_script(char *name) -ruby¤ÎĄąĄŻĄęĄ×ĄČĚľ($0)¤ňŔßÄꤹ¤ëˇĄ +Specifies the name of the script ($0). -Appendix B. extconf.rb¤Ç»Č¤¨¤ë´Řżô¤ż¤Á +Appendix B. Functions Available in extconf.rb extconf.rb¤ÎĂć¤Ç¤ĎÍřÍѲÄÇ˝¤ĘĄłĄóĄŃĄ¤Ąëľň·ďĄÁĄ§ĄĂĄŻ¤Î´Řżô¤Ď°Ę ˛Ľ¤ÎÄ̤ę¤Ç¤˘¤ëˇĄ have_library(lib, func) -´Řżôfunc¤ňÄęµÁ¤·¤Ć¤¤¤ëĄéĄ¤ĄÖĄéĄęlib¤Î¸şß¤ňĄÁĄ§ĄĂĄŻ¤ą¤ëˇĄĄé -Ą¤ĄÖĄéĄę¤¬Â¸şß¤ą¤ë»ţˇ¤TRUE¤ňĘÖ¤ąˇĄ +Checks whether library which contains specified function exists. +Returns true if the library exists. have_func(func) -´Řżôfunc¤Î¸şß¤ňĄÁĄ§ĄĂĄŻ¤ą¤ëˇĄfunc¤¬É¸˝ŕ¤Ç¤ĎĄęĄóĄŻ¤µ¤ě¤Ę¤¤Ąé -Ą¤ĄÖĄéĄęĆâ¤Î¤â¤Î¤Ç¤˘¤ë»ţ¤Ë¤ĎŔč¤Ëhave_library¤Ç¤˝¤ÎĄéĄ¤ĄÖĄéĄę -¤ňĄÁĄ§ĄĂĄŻ¤·¤Ć¤Ş¤Ż»öˇĄ´Řżô¤¬Â¸şß¤ą¤ë»ţTRUE¤ňĘÖ¤ąˇĄ +Checks whether func exists. Returns true if the function exists. To +check functions in the additional library, you need to check that +library first using have_library(). have_header(header) -ĄŘĄĂĄŔĄŐĄˇĄ¤Ąë¤Î¸şß¤ňĄÁĄ§ĄĂĄŻ¤ą¤ëˇĄĄŘĄĂĄŔĄŐĄˇĄ¤Ąë¤¬Â¸şß¤ą¤ë -»ţTRUE¤ňĘÖ¤ąˇĄ +Checks for the header files. Returns true if the header file exists. create_makefile(target) -łČÄĄĄâĄ¸ĄĺˇĽĄëÍѤÎMakefile¤ňŔ¸Ŕ®¤ą¤ëˇĄ¤ł¤Î´Řżô¤ň¸Ć¤Đ¤Ę¤±¤ě¤Đ -¤˝¤ÎĄâĄ¸ĄĺˇĽĄë¤ĎĄłĄóĄŃĄ¤Ąë¤µ¤ě¤Ę¤¤ˇĄtarget¤ĎĄâĄ¸ĄĺˇĽĄëĚľ¤ňÉ˝ -¤ąˇĄ +Generates the Makefile for the extension library. If you don't invoke +this method, the compilation will not be done. /* * Local variables: diff --git a/README.jp b/README.jp index 00822a3658..d137a435d8 100644 --- a/README.jp +++ b/README.jp @@ -5,7 +5,7 @@ Ruby ¤ą¤«¤éˇ¤ĄŞĄÖĄ¸Ą§ĄŻĄČ»Ř¸ţĄ×ĄíĄ°ĄéĄßĄóĄ°¤ňĽę·Ú¤ËąÔ¤¦»ö¤¬˝ĐÍč¤Ţ ¤ąˇĄ¤â¤Á¤í¤óÄĚľď¤ÎĽęÂł¤­·ż¤ÎĄ×ĄíĄ°ĄéĄßĄóĄ°¤â˛ÄÇ˝¤Ç¤ąˇĄ -Ruby¤ĎĄĆĄ­ĄąĄČ˝čÍý´Ř·¸¤ÎÇ˝ÎϤʤɤËÍĄ¤ěˇ¤perl¤ČƱ¤¸¤Ż¤é¤¤¶ŻÎĎ +Ruby¤ĎĄĆĄ­ĄąĄČ˝čÍý´Ř·¸¤ÎÇ˝ÎϤʤɤËÍĄ¤ěˇ¤Perl¤ČƱ¤¸¤Ż¤é¤¤¶ŻÎĎ ¤Ç¤ąˇĄ¤µ¤é¤ËĄ·ĄóĄ×Ąë¤Ęʸˡ¤Čˇ¤Îăł°˝čÍý¤äĄ¤ĄĆĄěˇĽĄż¤Ę¤É¤Îµˇą˝ ¤Ë¤č¤Ă¤Ćˇ¤¤č¤ęʬ¤«¤ę¤ä¤ą¤¤Ą×ĄíĄ°ĄéĄßĄóĄ°¤¬˝ĐÍč¤Ţ¤ąˇĄ @@ -20,7 +20,8 @@ Ruby + Ą¤ĄĆĄěˇĽĄż¤ČĄŻĄíˇĽĄ¸Ąă + Ą¬ˇĽĄŮˇĽĄ¸ĄłĄěĄŻĄż + ĄŔĄ¤ĄĘĄßĄĂĄŻĄíˇĽĄÇĄŁĄóĄ° (Ą˘ˇĽĄ­ĄĆĄŻĄÁĄă¤Ë¤č¤ë) - + °Üż˘Ŕ­¤¬ąâ¤¤ˇĄÂż¤Ż¤ÎUNIXľĺ¤ÇĆ°¤Ż + + °Üż˘Ŕ­¤¬ąâ¤¤ˇĄÂż¤Ż¤ÎUNIXľĺ¤ÇĆ°¤Ż¤Ŕ¤±¤Ç¤Ę¤Żˇ¤DOS¤äWindowsˇ¤ + Macˇ¤BeOS¤Ę¤É¤Îľĺ¤Ç¤âĆ°¤Ż * ĆţĽęˡ @@ -41,14 +42,14 @@ Ruby ¤Ç¤ąˇĄ -* ĄáĄ¤ĄęĄóĄ°ĄęĄąĄČ +* ĄáˇĽĄęĄóĄ°ĄęĄąĄČ - Ruby¤Ë´Ř¤ď¤ëĎĂÂę¤Î¤ż¤á¤ÎĄáĄ¤ĄęĄóĄ°ĄęĄąĄČ¤ňł«Ŕߤ·¤Ţ¤·¤żˇĄĄ˘ + Ruby¤Ë´Ř¤ď¤ëĎĂÂę¤Î¤ż¤á¤ÎĄáˇĽĄęĄóĄ°ĄęĄąĄČ¤ňł«Ŕߤ·¤Ţ¤·¤żˇĄĄ˘ ĄÉĄěĄą¤Ď ruby-list@netlab.co.jp - ¤Ç¤ąˇĄ¤ł¤ÎĄ˘ĄÉĄěĄą¤ËĄáĄ¤Ąë¤ňÁ÷¤ě¤Đˇ¤Ľ«Ć°ĹޤËĹĐĎż¤µ¤ě¤Ţ¤ąˇĄ + ¤Ç¤ąˇĄ¤ł¤ÎĄ˘ĄÉĄěĄą¤ËĄáˇĽĄë¤ňÁ÷¤ě¤Đˇ¤Ľ«Ć°ĹޤËĹĐĎż¤µ¤ě¤Ţ¤ąˇĄ * ĄłĄóĄŃĄ¤Ąëˇ¦Ą¤ĄóĄąĄČˇĽĄë @@ -81,6 +82,8 @@ Ruby 6. make install + root¤Çşî¶Č¤ą¤ëɬÍפ¬¤˘¤ë¤«¤â¤·¤ě¤Ţ¤»¤óˇĄ + ¤â¤·ˇ¤ĄłĄóĄŃĄ¤Ąë»ţ¤ËĄ¨ĄéˇĽ¤¬ČŻŔ¸¤·¤żľěąç¤Ë¤ĎĄ¨ĄéˇĽ¤ÎĄíĄ°¤ČĄŢ Ą·Ąóˇ¤OS¤ÎĽďÎŕ¤ň´Ţ¤ŕ¤Ç¤­¤ë¤Ŕ¤±ľÜ¤·¤¤ĄěĄÝˇĽĄČ¤ňşîĽÔ¤ËÁ÷¤Ă¤Ć¤Ż ¤Ŕ¤µ¤ë¤ČÂľ¤ÎĘý¤Î¤ż¤á¤Ë¤â¤Ę¤ę¤Ţ¤ąˇĄ @@ -92,7 +95,7 @@ UNIX ¤ą¤¬ˇ¤»×¤ď¤Ě¸«Íî¤Č¤·¤¬¤˘¤Ă¤żľěąç(¤˘¤ë¤Ë°ă¤¤¤Ę¤¤)ˇ¤şîĽÔ¤Ë¤˝¤Î ¤ł¤Č¤ňĄěĄÝˇĽĄČ¤ą¤ě¤Đˇ¤˛ň·č¤Ç¤­¤ë¤«¤âĂΤě¤Ţ¤»¤óˇĄ -Ą˘ˇĽĄŻĄĆĄŻĄÁĄă¤Ë¤â¤Ă¤Č¤â°Í¸¤ą¤ë¤Î¤ĎGCÉô¤Ç¤ąˇĄRuby¤ÎGC¤ĎÂĐľÝ +Ą˘ˇĽĄ­ĄĆĄŻĄÁĄă¤Ë¤â¤Ă¤Č¤â°Í¸¤ą¤ë¤Î¤ĎGCÉô¤Ç¤ąˇĄRuby¤ÎGC¤ĎÂĐľÝ ¤ÎĄ˘ˇĽĄ­ĄĆĄŻĄÁĄă¤¬setjmp()¤Ë¤č¤Ă¤ĆÁ´¤Ć¤ÎĄěĄ¸ĄąĄż¤ň jmp_buf¤Ë łĘÇĽ¤ą¤ë¤ł¤Č¤Čˇ¤jmp_buf¤ČĄąĄżĄĂĄŻ¤¬32bitĄ˘ĄéĄ¤ĄóĄáĄóĄČ¤µ¤ě¤Ć ¤¤¤ë¤ł¤Č¤ň˛ľÄꤷ¤Ć¤¤¤Ţ¤ąˇĄĆäËÁ°ĽÔ¤¬Ŕ®Î©¤·¤Ę¤¤ľěąç¤ÎÂбţ¤ĎČó @@ -120,34 +123,37 @@ Licence) Íł¤ËĘŃąą¤Ç¤­¤Ţ¤ąˇĄ (a) ĄÍĄĂĄČĄËĄĺˇĽĄş¤ËĄÝĄąĄČ¤·¤ż¤ęˇ¤şîĽÔ¤ËĘŃąą¤ňÁ÷ÉŐ¤ą¤ë - ¤Ę¤É¤ÎĘýˡ¤Çˇ¤ĘŃąą¤ň¸řł«¤ą¤ë + ¤Ę¤É¤ÎĘýˡ¤Çˇ¤ĘŃąą¤ň¸řł«¤ą¤ëˇĄ - (b) ĘŃąą¤·¤żRuby¤ňĽ«Ę¬¤Î˝ę°¤ą¤ëÁČżĄĆâÉô¤Ŕ¤±¤Ç»Č¤¦ + (b) ĘŃąą¤·¤żRuby¤ňĽ«Ę¬¤Î˝ę°¤ą¤ëÁČżĄĆâÉô¤Ŕ¤±¤Ç»Č¤¦ˇĄ (c) ĘŃąąĹŔ¤ňĚŔĽ¨¤·¤ż¤¦¤¨ˇ¤Ą˝ĄŐĄČĄ¦Ą§Ą˘¤ÎĚľÁ°¤ňĘŃąą¤ą¤ëˇĄ - ¤˝¤ÎĄ˝ĄŐĄČĄ¦Ą§Ą˘¤ňÇŰÉۤą¤ë»ţ¤Ë¤Ď¤â¤Č¤ÎRuby¤âƱ»ţ¤Ë - ÇŰÉۤą¤ë + ¤˝¤ÎĄ˝ĄŐĄČĄ¦Ą§Ą˘¤ňÇŰÉۤą¤ë»ţ¤Ë¤ĎĘŃąąÁ°¤ÎRuby¤âƱ»ţ + ¤ËÇŰÉۤą¤ëˇĄ¤Ţ¤ż¤ĎĘŃąąÁ°¤ÎRuby¤ÎĄ˝ˇĽĄą¤ÎĆţĽęˡ¤ňĚŔ + Ľ¨¤ą¤ëˇĄ - (d) ¤˝¤ÎÂľ¤ÎĘŃąąľň·ď¤ňşîĽÔ¤Čąç°Ő¤ą¤ë + (d) ¤˝¤ÎÂľ¤ÎĘŃąąľň·ď¤ňşîĽÔ¤Čąç°Ő¤ą¤ëˇĄ 3. °Ę˛Ľ¤Îľň·ď¤Î¤¤¤ş¤ě¤«¤ňËţ¤ż¤ą»ţ¤ËRuby¤ňĄŞĄÖĄ¸Ą§ĄŻĄČĄłˇĽ ĄÉ¤äĽÂąÔ·ÁĽ°¤Ç¤âÇŰÉۤǤ­¤Ţ¤ąˇĄ - (a) ĄĐĄ¤ĄĘĄę¤ňĽő¤±Ľč¤Ă¤żżÍ¤¬Ą˝ˇĽĄą¤ňĆţĽę¤Ç¤­¤ë¤č¤¦¤ËĄ˝ˇĽ - Ąą¤ÎĆţĽęˡ¤ňĚŔĽ¨¤ą¤ë + (a) ĄĐĄ¤ĄĘĄę¤ňĽő¤±Ľč¤Ă¤żżÍ¤¬Ą˝ˇĽĄą¤ňĆţĽę¤Ç¤­¤ë¤č¤¦¤Ëˇ¤ + Ą˝ˇĽĄą¤ÎĆţĽęˡ¤ňĚŔĽ¨¤ą¤ëˇĄ - (b) µˇłŁ˛ÄĆɤʥ˝ˇĽĄąĄłˇĽĄÉ¤ňĹşÉŐ¤ą¤ë + (b) µˇłŁ˛ÄĆɤʥ˝ˇĽĄąĄłˇĽĄÉ¤ňĹşÉŐ¤ą¤ëˇĄ (c) ĘŃąą¤ňąÔ¤Ă¤żĄĐĄ¤ĄĘĄę¤ĎĚľÁ°¤ňĘŃąą¤·¤ż¤¦¤¨ˇ¤Ą˝ˇĽĄą¤Î - ĆţĽęˡ¤ňĚŔĽ¨¤ą¤ë + ĆţĽęˡ¤ňĚŔĽ¨¤ą¤ëˇĄ - (d) ¤˝¤ÎÂľ¤ÎÇŰÉŰľň·ď¤ňşîĽÔ¤Čąç°Ő¤ą¤ë + (d) ¤˝¤ÎÂľ¤ÎÇŰÉŰľň·ď¤ňşîĽÔ¤Čąç°Ő¤ą¤ëˇĄ 4. Âľ¤ÎĄ×ĄíĄ°ĄéĄŕ¤Ř¤Î°úÍѤϤ¤¤«¤Ę¤ëĚÜĹŞ¤Ç¤˘¤ěĽ«Íł¤Ç¤ąˇĄ¤ż ¤Ŕ¤·ˇ¤Ruby¤Ë´Ţ¤Ţ¤ě¤ëÂľ¤ÎşîĽÔ¤Ë¤č¤ëĄłˇĽĄÉ¤Ďˇ¤¤˝¤ě¤ľ¤ě¤Î şîĽÔ¤Î°Ő¸ţ¤Ë¤č¤ëŔ©¸Â¤¬˛Ă¤¨¤é¤ě¤Ţ¤ąˇĄ¶ńÂÎĹŞ¤Ë¤Ďgc.c(°ěÉô)ˇ¤ util.c(°ěÉô)ˇ¤st.[ch]ˇ¤regex.[ch], fnmatch.[ch], glob.c ¤Ş¤č¤Ó./missingĄÇĄŁĄěĄŻĄČĄę˛Ľ¤ÎĄŐĄˇĄ¤Ąë·˛¤¬łşĹö¤·¤Ţ¤ąˇĄ + ¤˝¤ě¤ľ¤ě¤ÎÇŰÉŰľň·ď¤Ę¤É¤ËÉŐ¤¤¤Ć¤ĎłĆĄŐĄˇĄ¤Ąë¤ň»˛ľČ¤·¤Ć¤Ż + ¤Ŕ¤µ¤¤ˇĄ 5. Ruby¤Ř¤ÎĆţÎϤȤʤ륹ĄŻĄęĄ×ĄČ¤Ş¤č¤Óˇ¤Ruby¤«¤é¤Î˝ĐÎϤθ˘ Íř¤ĎRuby¤ÎşîĽÔ¤Ç¤Ď¤Ę¤Żˇ¤¤˝¤ě¤ľ¤ě¤ÎĆţ˝ĐÎϤňŔ¸Ŕ®¤·¤żżÍ¤Ë diff --git a/ToDo b/ToDo index 3b6edee08f..3bc7887489 100644 --- a/ToDo +++ b/ToDo @@ -1,4 +1,37 @@ -* non-blocking open/write for thread -* ĄŃĄĂĄ±ˇĽĄ¸¤Ţ¤ż¤ĎÂç°čĘŃżô¤ÎĄ˘ĄŻĄ»ĄąŔ©¸ć -* formatµˇÇ˝ -* re-write regex code for speed and copyright +Language Spec. + +* package or access control for global variables +* named arguments like foo(nation:="german"). +* multiple return values, yield values. maybe imcompatible + +Hacking Interpreter + +* non-blocking open (e.g. named pipe) for thread +* avoid blocking with gethostbyname/gethostbyaddr +* objectify interpreters +* remove rb_eval() recursions +* syntax tree -> bytecode ??? +* scrambled script, or script filter +* regular expression bug /(?:\s+\d+){2}/ URGENT!! + +Extension Libraries + +* mod_ruby, FastCGI ruby +* InterBase module +* ptk.rb pTk wrapper that is compatible to tk.rb + +Ruby Libraries + +* CGI.rb +* httplib.rb, urllib.rb, nttplib.rb, etc. +* format like perl's + +Tools + +* extension library maker like XS or SWIG +* freeze or undump to bundle everything + +Misc + +* translate README.EXT fully into English +* publish Ruby books diff --git a/array.c b/array.c index 388fb05bd7..8f6c0c223f 100644 --- a/array.c +++ b/array.c @@ -6,41 +6,55 @@ $Date$ created at: Fri Aug 6 09:46:12 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" +#include "util.h" - -VALUE cArray; +VALUE rb_cArray; #define ARY_DEFAULT_SIZE 16 void -memclear(mem, size) +rb_mem_clear(mem, size) register VALUE *mem; - register int size; + register size_t size; { while (size--) { *mem++ = Qnil; } } +static void +memfill(mem, size, val) + register VALUE *mem; + register size_t size; + register VALUE val; +{ + while (size--) { + *mem++ = val; + } +} + #define ARY_FREEZE FL_USER1 +#define ARY_TMPLOCK FL_USER2 static void -ary_modify(ary) +rb_ary_modify(ary) VALUE ary; { - rb_secure(5); - if (FL_TEST(ary, ARY_FREEZE)) { - TypeError("can't modify frozen array"); - } + if (FL_TEST(ary, ARY_FREEZE)) + rb_raise(rb_eTypeError, "can't modify frozen array"); + if (FL_TEST(ary, ARY_TMPLOCK)) + rb_raise(rb_eTypeError, "can't modify array during sort"); + if (rb_safe_level() >= 4 && !FL_TEST(ary, FL_TAINT)) + rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } VALUE -ary_freeze(ary) +rb_ary_freeze(ary) VALUE ary; { FL_SET(ary, ARY_FREEZE); @@ -48,56 +62,68 @@ ary_freeze(ary) } static VALUE -ary_frozen_p(ary) +rb_ary_frozen_p(ary) VALUE ary; { - if (FL_TEST(ary, ARY_FREEZE)) - return TRUE; - return FALSE; + if (FL_TEST(ary, ARY_FREEZE|ARY_TMPLOCK)) + return Qtrue; + return Qfalse; } VALUE -ary_new2(len) - int len; +rb_ary_new2(len) + size_t len; { NEWOBJ(ary, struct RArray); - OBJSETUP(ary, cArray, T_ARRAY); + OBJSETUP(ary, rb_cArray, T_ARRAY); + if (len < 0) { + rb_raise(rb_eArgError, "negative array size (or size too big)"); + } + if (len > 0 && len*sizeof(VALUE) <= 0) { + rb_raise(rb_eArgError, "array size too big"); + } ary->len = 0; ary->capa = len; - if (len == 0) - ary->ptr = 0; - else { - ary->ptr = ALLOC_N(VALUE, len); - memclear(ary->ptr, len); - } + ary->ptr = 0; + ary->ptr = ALLOC_N(VALUE, len); return (VALUE)ary; } VALUE -ary_new() +rb_ary_new() { - return ary_new2(ARY_DEFAULT_SIZE); + return rb_ary_new2(ARY_DEFAULT_SIZE); } +#ifdef HAVE_STDARG_PROTOTYPES +#include +#define va_init_list(a,b) va_start(a,b) +#else #include +#define va_init_list(a,b) va_start(a) +#endif VALUE -ary_new3(n, va_alist) - int n; +#ifdef HAVE_STDARG_PROTOTYPES +rb_ary_new3(size_t n, ...) +#else +rb_ary_new3(n, va_alist) + size_t n; va_dcl +#endif { va_list ar; VALUE ary; - int i; + size_t i; if (n < 0) { - IndexError("Negative number of items(%d)", n); + rb_raise(rb_eIndexError, "negative number of items(%d)", n); } - ary = ary_new2(nptr[i] = va_arg(ar, VALUE); } @@ -108,26 +134,28 @@ ary_new3(n, va_alist) } VALUE -ary_new4(n, elts) - int n; +rb_ary_new4(n, elts) + size_t n; VALUE *elts; { VALUE ary; - ary = ary_new2(n); - MEMCPY(RARRAY(ary)->ptr, elts, VALUE, n); + ary = rb_ary_new2(n); + if (elts) { + MEMCPY(RARRAY(ary)->ptr, elts, VALUE, n); + } RARRAY(ary)->len = n; return ary; } VALUE -assoc_new(car, cdr) +rb_assoc_new(car, cdr) VALUE car, cdr; { VALUE ary; - ary = ary_new2(2); + ary = rb_ary_new2(2); RARRAY(ary)->ptr[0] = car; RARRAY(ary)->ptr[1] = cdr; RARRAY(ary)->len = 2; @@ -136,32 +164,49 @@ assoc_new(car, cdr) } static VALUE -ary_s_new(argc, argv, class) +rb_ary_s_new(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { - VALUE size; + size_t len = 0; + VALUE size, val; NEWOBJ(ary, struct RArray); - OBJSETUP(ary, class, T_ARRAY); + OBJSETUP(ary, klass, T_ARRAY); - rb_scan_args(argc, argv, "01", &size); ary->len = 0; - ary->capa = NIL_P(size)?ARY_DEFAULT_SIZE:NUM2INT(size); + ary->ptr = 0; + if (rb_scan_args(argc, argv, "02", &size, &val) == 0) { + ary->capa = ARY_DEFAULT_SIZE; + } + else { + size_t capa = NUM2UINT(size); + + if (capa < 0) { + rb_raise(rb_eArgError, "negative array size"); + } + if (capa > 0 && capa*sizeof(VALUE) <= 0) { + rb_raise(rb_eArgError, "array size too big"); + } + ary->capa = capa; + len = capa; + } ary->ptr = ALLOC_N(VALUE, ary->capa); - memclear(ary->ptr, ary->capa); + memfill(ary->ptr, len, val); + ary->len = len; + rb_obj_call_init((VALUE)ary); return (VALUE)ary; } static VALUE -ary_s_create(argc, argv, class) +rb_ary_s_create(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { NEWOBJ(ary, struct RArray); - OBJSETUP(ary, class, T_ARRAY); + OBJSETUP(ary, klass, T_ARRAY); ary->len = argc; ary->capa = argc; @@ -177,14 +222,17 @@ ary_s_create(argc, argv, class) } void -ary_store(ary, idx, val) +rb_ary_store(ary, idx, val) VALUE ary; - int idx; + size_t idx; VALUE val; { - ary_modify(ary); + rb_ary_modify(ary); if (idx < 0) { - IndexError("negative index for array"); + idx = RARRAY(ary)->len + idx; + if (idx < 0) { + rb_raise(rb_eIndexError, "negative index of array"); + } } if (idx >= RARRAY(ary)->capa) { @@ -192,7 +240,8 @@ ary_store(ary, idx, val) REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); } if (idx > RARRAY(ary)->len) { - memclear(RARRAY(ary)->ptr+RARRAY(ary)->len, idx-RARRAY(ary)->len+1); + rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, + idx-RARRAY(ary)->len+1); } if (idx >= RARRAY(ary)->len) { @@ -202,28 +251,28 @@ ary_store(ary, idx, val) } VALUE -ary_push(ary, item) +rb_ary_push(ary, item) VALUE ary; VALUE item; { - ary_store(ary, RARRAY(ary)->len, item); + rb_ary_store(ary, RARRAY(ary)->len, item); return ary; } static VALUE -ary_push_method(argc, argv, ary) +rb_ary_push_method(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { while (argc--) { - ary_store(ary, RARRAY(ary)->len, *argv++); + rb_ary_store(ary, RARRAY(ary)->len, *argv++); } return ary; } VALUE -ary_pop(ary) +rb_ary_pop(ary) VALUE ary; { if (RARRAY(ary)->len == 0) return Qnil; @@ -235,7 +284,7 @@ ary_pop(ary) } VALUE -ary_shift(ary) +rb_ary_shift(ary) VALUE ary; { VALUE top; @@ -256,10 +305,10 @@ ary_shift(ary) } VALUE -ary_unshift(ary, item) +rb_ary_unshift(ary, item) VALUE ary, item; { - ary_modify(ary); + rb_ary_modify(ary); if (RARRAY(ary)->len >= RARRAY(ary)->capa) { RARRAY(ary)->capa+=ARY_DEFAULT_SIZE; REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); @@ -269,13 +318,15 @@ ary_unshift(ary, item) MEMMOVE(RARRAY(ary)->ptr+1, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); RARRAY(ary)->len++; - return RARRAY(ary)->ptr[0] = item; + RARRAY(ary)->ptr[0] = item; + + return ary; } VALUE -ary_entry(ary, offset) +rb_ary_entry(ary, offset) VALUE ary; - int offset; + size_t offset; { if (RARRAY(ary)->len == 0) return Qnil; @@ -290,27 +341,27 @@ ary_entry(ary, offset) } static VALUE -ary_subseq(ary, beg, len) +rb_ary_subseq(ary, beg, len) VALUE ary; - int beg, len; + size_t beg, len; { VALUE ary2; - if (beg < 0) { - beg = RARRAY(ary)->len + beg; - if (beg < 0) beg = 0; - } - if (len < 0) { - IndexError("negative length %d", RARRAY(ary)->len); + if (len <= 0) { + return rb_ary_new2(0); } - if (len == 0) { - return ary_new2(0); + if (beg < 0) { + len += beg; + beg = 0; } if (beg + len > RARRAY(ary)->len) { len = RARRAY(ary)->len - beg; } + if (len < 0) { + len = 0; + } - ary2 = ary_new2(len); + ary2 = rb_ary_new2(len); MEMCPY(RARRAY(ary2)->ptr, RARRAY(ary)->ptr+beg, VALUE, len); RARRAY(ary2)->len = len; @@ -320,80 +371,74 @@ ary_subseq(ary, beg, len) static VALUE beg_len(range, begp, lenp, len) VALUE range; - int *begp, *lenp; - int len; + size_t *begp, *lenp; + size_t len; { - int beg, end; + size_t beg, end; + size_t b, e; - if (!range_beg_end(range, &beg, &end)) return FALSE; - - if ((beg > 0 && end > 0 || beg < 0 && end < 0) && beg > end) { - IndexError("end smaller than beg [%d..%d]", beg, end); - } + if (!rb_range_beg_end(range, &beg, &end)) return Qfalse; + b = beg; e = end; if (beg < 0) { beg = len + beg; - if (beg < 0) beg = 0; } + if (end < 0) { + end = len + end; + } + if (beg > end) { + rb_raise(rb_eIndexError, "end smaller than beg [%d..%d]", b, e); + } + *begp = beg; if (beg > len) { *lenp = 0; } else { - if (end < 0) { - end = len + end; - if (end < 0) end = -1; - } - if (beg > end) { - *lenp = 0; - } - else { - *lenp = end - beg +1; - } + len = end - beg +1; + *lenp = len; } - return TRUE; + return Qtrue; } VALUE -ary_aref(argc, argv, ary) +rb_ary_aref(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE arg1, arg2; - int beg, len; + size_t beg, len; if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) { - beg = NUM2INT(arg1); - len = NUM2INT(arg2); - if (len <= 0) { - return ary_new(); + beg = NUM2UINT(arg1); + len = NUM2UINT(arg2); + if (beg < 0) { + beg = RARRAY(ary)->len + beg; } - return ary_subseq(ary, beg, len); + return rb_ary_subseq(ary, beg, len); } /* special case - speeding up */ if (FIXNUM_P(arg1)) { - return ary_entry(ary, FIX2INT(arg1)); + return rb_ary_entry(ary, FIX2UINT(arg1)); } - else { - /* check if idx is Range */ - if (beg_len(arg1, &beg, &len, RARRAY(ary)->len)) { - return ary_subseq(ary, beg, len); - } + else if (TYPE(arg1) == T_BIGNUM) { + rb_raise(rb_eIndexError, "index too big"); } - if (TYPE(arg1) == T_BIGNUM) { - IndexError("index too big"); + else if (beg_len(arg1, &beg, &len, RARRAY(ary)->len)) { + /* check if idx is Range */ + return rb_ary_subseq(ary, beg, len); } - return ary_entry(ary, NUM2INT(arg1)); + return rb_ary_entry(ary, NUM2UINT(arg1)); } static VALUE -ary_index(ary, val) +rb_ary_index(ary, val) VALUE ary; VALUE val; { - int i; + size_t i; for (i=0; ilen; i++) { if (rb_equal(RARRAY(ary)->ptr[i], val)) @@ -403,59 +448,74 @@ ary_index(ary, val) } static VALUE -ary_indexes(ary, args) - VALUE ary, args; +rb_ary_rindex(ary, val) + VALUE ary; + VALUE val; { - VALUE *p, *pend; - VALUE new_ary; - int i = 0; + size_t i = RARRAY(ary)->len; - if (!args || NIL_P(args)) { - return ary_new2(0); + while (i--) { + if (rb_equal(RARRAY(ary)->ptr[i], val)) + return INT2FIX(i); } + return Qnil; +} - new_ary = ary_new2(RARRAY(args)->len); +static VALUE +rb_ary_indexes(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + VALUE new_ary; + size_t i; - p = RARRAY(args)->ptr; pend = p + RARRAY(args)->len; - while (p < pend) { - ary_store(new_ary, i++, ary_entry(ary, NUM2INT(*p))); - p++; + new_ary = rb_ary_new2(argc); + for (i=0; ilen + beg; - if (beg < 0) beg = 0; + len += beg; + beg = 0; } + + rb_ary_modify(ary); if (beg >= RARRAY(ary)->len) { len = beg + RARRAY(rpl)->len; if (len >= RARRAY(ary)->capa) { RARRAY(ary)->capa=len; REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); } - memclear(RARRAY(ary)->ptr+RARRAY(ary)->len, beg-RARRAY(ary)->len); + rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, beg-RARRAY(ary)->len); MEMCPY(RARRAY(ary)->ptr+beg, RARRAY(rpl)->ptr, VALUE, RARRAY(rpl)->len); RARRAY(ary)->len = len; } else { - int alen; + size_t alen; if (beg + len > RARRAY(ary)->len) { len = RARRAY(ary)->len - beg; } - if (len < 0) { - IndexError("negative length %d", RARRAY(ary)->len); - } alen = RARRAY(ary)->len + RARRAY(rpl)->len - len; if (alen >= RARRAY(ary)->capa) { @@ -473,48 +533,49 @@ ary_replace(ary, beg, len, rpl) } static VALUE -ary_aset(argc, argv, ary) +rb_ary_aset(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE arg1, arg2, arg3; - int offset; - int beg, len; + size_t offset; + size_t beg, len; if (rb_scan_args(argc, argv, "21", &arg1, &arg2, &arg3) == 3) { - beg = NUM2INT(arg1); - len = NUM2INT(arg2); - ary_replace(ary, beg, len, arg3); + beg = NUM2UINT(arg1); + len = NUM2UINT(arg2); + + if (beg < 0) { + beg = RARRAY(ary)->len + beg; + } + rb_ary_replace(ary, beg, len, arg3); return arg3; } else if (FIXNUM_P(arg1)) { - offset = FIX2INT(arg1); + offset = FIX2UINT(arg1); goto fixnum; } else if (beg_len(arg1, &beg, &len, RARRAY(ary)->len)) { /* check if idx is Range */ - ary_replace(ary, beg, len, arg2); + rb_ary_replace(ary, beg, len, arg2); return arg2; } if (TYPE(arg1) == T_BIGNUM) { - IndexError("index too big"); + rb_raise(rb_eIndexError, "index too big"); } - offset = NUM2INT(arg1); + offset = NUM2UINT(arg1); fixnum: - if (offset < 0) { - offset = RARRAY(ary)->len + offset; - } - ary_store(ary, offset, arg2); + rb_ary_store(ary, offset, arg2); return arg2; } VALUE -ary_each(ary) +rb_ary_each(ary) VALUE ary; { - int i; + size_t i; for (i=0; ilen; i++) { rb_yield(RARRAY(ary)->ptr[i]); @@ -523,10 +584,10 @@ ary_each(ary) } static VALUE -ary_each_index(ary) +rb_ary_each_index(ary) VALUE ary; { - int i; + size_t i; for (i=0; ilen; i++) { rb_yield(INT2FIX(i)); @@ -535,10 +596,10 @@ ary_each_index(ary) } static VALUE -ary_reverse_each(ary) +rb_ary_reverse_each(ary) VALUE ary; { - int len = RARRAY(ary)->len; + size_t len = RARRAY(ary)->len; while (len--) { rb_yield(RARRAY(ary)->ptr[len]); @@ -547,26 +608,26 @@ ary_reverse_each(ary) } static VALUE -ary_length(ary) +rb_ary_length(ary) VALUE ary; { return INT2FIX(RARRAY(ary)->len); } static VALUE -ary_empty_p(ary) +rb_ary_empty_p(ary) VALUE ary; { if (RARRAY(ary)->len == 0) - return TRUE; - return FALSE; + return Qtrue; + return Qfalse; } static VALUE -ary_clone(ary) +rb_ary_clone(ary) VALUE ary; { - VALUE ary2 = ary_new2(RARRAY(ary)->len); + VALUE ary2 = rb_ary_new2(RARRAY(ary)->len); CLONESETUP(ary2, ary); MEMCPY(RARRAY(ary2)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); @@ -575,32 +636,56 @@ ary_clone(ary) } static VALUE -ary_dup(ary) +rb_ary_dup(ary) VALUE ary; { - return ary_new4(RARRAY(ary)->len, RARRAY(ary)->ptr); + return rb_ary_new4(RARRAY(ary)->len, RARRAY(ary)->ptr); } -extern VALUE OFS; +static VALUE +to_ary(ary) + VALUE ary; +{ + return rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); +} -VALUE -ary_join(ary, sep) +extern VALUE rb_output_fs; + +static VALUE +inspect_join(ary, arg) VALUE ary; - VALUE sep; + VALUE *arg; { - int i; + return rb_ary_join(arg[0], arg[1]); +} + +VALUE +rb_ary_join(ary, sep) + VALUE ary, sep; +{ + size_t i; VALUE result, tmp; - if (RARRAY(ary)->len == 0) return str_new(0, 0); + if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); - switch (TYPE(RARRAY(ary)->ptr[0])) { + tmp = RARRAY(ary)->ptr[0]; + switch (TYPE(tmp)) { case T_STRING: - result = str_dup(RARRAY(ary)->ptr[0]); + result = rb_str_dup(tmp); break; case T_ARRAY: - result = ary_join(RARRAY(ary)->ptr[0], sep); + if (rb_inspecting_p(tmp)) { + result = rb_str_new2("[...]"); + } + else { + VALUE args[2]; + + args[0] = tmp; + args[1] = sep; + result = rb_protect_inspect(inspect_join, ary, (VALUE)args); + } break; default: - result = obj_as_string(RARRAY(ary)->ptr[0]); + result = rb_obj_as_string(tmp); break; } @@ -610,21 +695,30 @@ ary_join(ary, sep) case T_STRING: break; case T_ARRAY: - tmp = ary_join(tmp, sep); + if (rb_inspecting_p(tmp)) { + tmp = rb_str_new2("[...]"); + } + else { + VALUE args[2]; + + args[0] = tmp; + args[1] = sep; + tmp = rb_protect_inspect(inspect_join, ary, (VALUE)args); + } break; default: - tmp = obj_as_string(tmp); + tmp = rb_obj_as_string(tmp); } - if (!NIL_P(sep)) str_cat(result, RSTRING(sep)->ptr, RSTRING(sep)->len); - str_cat(result, RSTRING(tmp)->ptr, RSTRING(tmp)->len); - if (str_tainted(tmp)) str_taint(result); + if (!NIL_P(sep)) rb_str_concat(result, sep); + rb_str_cat(result, RSTRING(tmp)->ptr, RSTRING(tmp)->len); + if (OBJ_TAINTED(tmp)) OBJ_TAINT(result); } return result; } static VALUE -ary_join_method(argc, argv, ary) +rb_ary_join_method(argc, argv, ary) int argc; VALUE *argv; VALUE ary; @@ -632,57 +726,144 @@ ary_join_method(argc, argv, ary) VALUE sep; rb_scan_args(argc, argv, "01", &sep); - if (NIL_P(sep)) sep = OFS; - if (!NIL_P(sep)) Check_Type(sep, T_STRING); - - return ary_join(ary, sep); + if (NIL_P(sep)) sep = rb_output_fs; + return rb_ary_join(ary, sep); } VALUE -ary_to_s(ary) +rb_ary_to_s(ary) VALUE ary; { - VALUE str = ary_join(ary, OFS); - if (NIL_P(str)) return str_new(0, 0); + VALUE str; + + if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); + str = rb_ary_join(ary, rb_output_fs); + if (NIL_P(str)) return rb_str_new(0, 0); return str; } +#ifdef USE_THREAD +static ID inspect_key; +#else +static VALUE inspect_tbl; +#endif + +struct inspect_arg { + VALUE (*func)(); + VALUE arg1, arg2; +}; + +VALUE +inspect_call(arg) + struct inspect_arg *arg; +{ + return (*arg->func)(arg->arg1, arg->arg2); +} + static VALUE -ary_inspect(ary) +inspect_ensure(obj) + VALUE obj; +{ +#ifdef USE_THREAD + VALUE inspect_tbl; + + inspect_tbl = rb_thread_local_aref(rb_thread_current(), inspect_key); +#endif + rb_ary_pop(inspect_tbl); + return 0; +} + +VALUE +rb_protect_inspect(func, obj, arg) + VALUE (*func)(); + VALUE obj, arg; +{ + struct inspect_arg iarg; + +#ifdef USE_THREAD + VALUE inspect_tbl; + + if (!inspect_key) { + inspect_key = rb_intern("__inspect_key__"); + } + inspect_tbl = rb_thread_local_aref(rb_thread_current(), inspect_key); + if (NIL_P(inspect_tbl)) { + inspect_tbl = rb_ary_new(); + rb_thread_local_aset(rb_thread_current(), inspect_key, inspect_tbl); + } +#else + if (!inspect_tbl) { + inspect_tbl = rb_ary_new(); + rb_global_variable(&inspect_tbl); + } +#endif + rb_ary_push(inspect_tbl, obj); + iarg.func = func; + iarg.arg1 = obj; + iarg.arg2 = arg; + return rb_ensure(inspect_call, (VALUE)&iarg, inspect_ensure, obj); +} + +VALUE +rb_inspecting_p(obj) + VALUE obj; +{ +#ifdef USE_THREAD + VALUE inspect_tbl; + + if (!inspect_key) return Qfalse; + inspect_tbl = rb_thread_local_aref(rb_thread_current(), inspect_key); + if (NIL_P(inspect_tbl)) return Qfalse; +#else + if (!inspect_tbl) return Qnil; +#endif + return rb_ary_includes(inspect_tbl, obj); +} + +static VALUE +inspect_ary(ary) VALUE ary; { - int i, len; + size_t i = 0; VALUE s, str; - if (RARRAY(ary)->len == 0) return str_new2("[]"); - str = str_new2("["); - len = 1; + str = rb_str_new2("["); for (i=0; ilen; i++) { s = rb_inspect(RARRAY(ary)->ptr[i]); - if (i > 0) str_cat(str, ", ", 2); - str_cat(str, RSTRING(s)->ptr, RSTRING(s)->len); - len += RSTRING(s)->len + 2; + if (i > 0) rb_str_cat(str, ", ", 2); + rb_str_cat(str, RSTRING(s)->ptr, RSTRING(s)->len); } - str_cat(str, "]", 1); + rb_str_cat(str, "]", 1); return str; } static VALUE -ary_to_a(ary) +rb_ary_inspect(ary) + VALUE ary; +{ + if (RARRAY(ary)->len == 0) return rb_str_new2("[]"); + if (rb_inspecting_p(ary)) return rb_str_new2("[...]"); + return rb_protect_inspect(inspect_ary, ary, 0); +} + +static VALUE +rb_ary_to_a(ary) VALUE ary; { return ary; } VALUE -ary_reverse(ary) +rb_ary_reverse(ary) VALUE ary; { VALUE *p1, *p2; VALUE tmp; + if (RARRAY(ary)->len == 0) return ary; + p1 = RARRAY(ary)->ptr; p2 = p1 + RARRAY(ary)->len - 1; /* points last item */ @@ -697,10 +878,10 @@ ary_reverse(ary) } static VALUE -ary_reverse_method(ary) +rb_ary_reverse_method(ary) VALUE ary; { - return ary_reverse(ary_clone(ary)); + return rb_ary_reverse(rb_ary_dup(ary)); } static ID cmp; @@ -709,7 +890,7 @@ static int sort_1(a, b) VALUE *a, *b; { - VALUE retval = rb_yield(assoc_new(*a, *b)); + VALUE retval = rb_yield(rb_assoc_new(*a, *b)); return NUM2INT(retval); } @@ -722,38 +903,59 @@ sort_2(a, b) if (FIXNUM_P(*a)) { if (FIXNUM_P(*b)) return *a - *b; } - else if (TYPE(*a) == T_STRING) { - if (TYPE(*b) == T_STRING) return str_cmp(*a, *b); + else if (TYPE(*a) == T_STRING && TYPE(*b) == T_STRING) { + return rb_str_cmp(*a, *b); } retval = rb_funcall(*a, cmp, 1, *b); return NUM2INT(retval); } +static VALUE +sort_internal(ary) + VALUE ary; +{ + qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), + rb_iterator_p()?sort_1:sort_2); + return ary; +} + +static VALUE +sort_unlock(ary) + VALUE ary; +{ + FL_UNSET(ary, ARY_TMPLOCK); + return ary; +} + VALUE -ary_sort_bang(ary) +rb_ary_sort_bang(ary) VALUE ary; { - ary_modify(ary); - qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), iterator_p()?sort_1:sort_2); + if (RARRAY(ary)->len <= 1) return ary; + + rb_ary_modify(ary); + FL_SET(ary, ARY_TMPLOCK); /* prohibit modification during sort */ + rb_ensure(sort_internal, ary, sort_unlock, ary); return ary; } VALUE -ary_sort(ary) +rb_ary_sort(ary) VALUE ary; { - return ary_sort_bang(ary_clone(ary)); + if (RARRAY(ary)->len == 0) return ary; + return rb_ary_sort_bang(rb_ary_dup(ary)); } VALUE -ary_delete(ary, item) +rb_ary_delete(ary, item) VALUE ary; VALUE item; { - int i1, i2; + size_t i1, i2; - ary_modify(ary); + rb_ary_modify(ary); for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) { if (rb_equal(RARRAY(ary)->ptr[i1], item)) continue; if (i1 != i2) { @@ -762,7 +964,9 @@ ary_delete(ary, item) i2++; } if (RARRAY(ary)->len == i2) { - if (iterator_p()) rb_yield(item); + if (rb_iterator_p()) { + return rb_yield(item); + } return Qnil; } else { @@ -773,15 +977,15 @@ ary_delete(ary, item) } VALUE -ary_delete_at(ary, at) +rb_ary_delete_at(ary, at) VALUE ary; VALUE at; { - int i1, i2, pos; + size_t i1, i2, pos; VALUE del = Qnil; - ary_modify(ary); - pos = NUM2INT(at); + rb_ary_modify(ary); + pos = NUM2UINT(at); for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) { if (i1 == pos) { del = RARRAY(ary)->ptr[i1]; @@ -798,12 +1002,12 @@ ary_delete_at(ary, at) } static VALUE -ary_delete_if(ary) +rb_ary_delete_if(ary) VALUE ary; { - int i1, i2; + size_t i1, i2; - ary_modify(ary); + rb_ary_modify(ary); for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) { if (rb_yield(RARRAY(ary)->ptr[i1])) continue; if (i1 != i2) { @@ -816,23 +1020,30 @@ ary_delete_if(ary) return ary; } -#if 0 static VALUE -ary_replace(ary) +rb_ary_filter(ary) VALUE ary; { - int i; + size_t i; + rb_ary_modify(ary); for (i = 0; i < RARRAY(ary)->len; i++) { RARRAY(ary)->ptr[i] = rb_yield(RARRAY(ary)->ptr[i]); } + return ary; +} +static VALUE +rb_ary_replace_method(ary, ary2) + VALUE ary, ary2; +{ + ary2 = to_ary(ary2); + rb_ary_replace(ary, 0, RARRAY(ary2)->len, ary2); return ary; } -#endif static VALUE -ary_clear(ary) +rb_ary_clear(ary) VALUE ary; { RARRAY(ary)->len = 0; @@ -844,32 +1055,28 @@ ary_clear(ary) } static VALUE -ary_fill(argc, argv, ary) +rb_ary_fill(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE item, arg1, arg2; - int beg, len, end; + size_t beg, len, end; VALUE *p, *pend; - rb_scan_args(argc, argv, "12", &item, &arg1, &arg2); - if (NIL_P(arg2) && beg_len(arg1, &beg, &len, RARRAY(ary)->len)) { + if (rb_scan_args(argc, argv, "12", &item, &arg1, &arg2) == 2 && + beg_len(arg1, &beg, &len, RARRAY(ary)->len)) { /* beg and len set already */ } else { - beg = NUM2INT(arg1); + beg = NIL_P(arg1)?0:NUM2UINT(arg1); if (beg < 0) { beg = RARRAY(ary)->len + beg; if (beg < 0) beg = 0; } - if (!NIL_P(arg2)) { - len = NUM2INT(arg2); - } - else { - len = RARRAY(ary)->len - beg; - } + len = NIL_P(arg2)?RARRAY(ary)->len - beg:NUM2UINT(arg2); } + rb_ary_modify(ary); end = beg + len; if (end > RARRAY(ary)->len) { if (end >= RARRAY(ary)->capa) { @@ -877,7 +1084,7 @@ ary_fill(argc, argv, ary) REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); } if (beg > RARRAY(ary)->len) { - memclear(RARRAY(ary)->ptr+RARRAY(ary)->len, end-RARRAY(ary)->len); + rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len,end-RARRAY(ary)->len); } RARRAY(ary)->len = end; } @@ -890,16 +1097,16 @@ ary_fill(argc, argv, ary) } VALUE -ary_plus(x, y) +rb_ary_plus(x, y) VALUE x, y; { VALUE z; if (TYPE(y) != T_ARRAY) { - return ary_plus(x, rb_Array(y)); + return rb_ary_plus(x, rb_Array(y)); } - z = ary_new2(RARRAY(x)->len + RARRAY(y)->len); + z = rb_ary_new2(RARRAY(x)->len + RARRAY(y)->len); MEMCPY(RARRAY(z)->ptr, RARRAY(x)->ptr, VALUE, RARRAY(x)->len); MEMCPY(RARRAY(z)->ptr+RARRAY(x)->len, RARRAY(y)->ptr, VALUE, RARRAY(y)->len); RARRAY(z)->len = RARRAY(x)->len + RARRAY(y)->len; @@ -907,43 +1114,44 @@ ary_plus(x, y) } VALUE -ary_concat(x, y) +rb_ary_concat(x, y) VALUE x, y; { VALUE *p, *pend; if (TYPE(y) != T_ARRAY) { - return ary_concat(x, rb_Array(y)); + return rb_ary_concat(x, rb_Array(y)); } p = RARRAY(y)->ptr; pend = p + RARRAY(y)->len; while (p < pend) { - ary_store(x, RARRAY(x)->len, *p); + rb_ary_store(x, RARRAY(x)->len, *p); p++; } return x; } static VALUE -ary_times(ary, times) +rb_ary_times(ary, times) VALUE ary; VALUE times; { VALUE ary2; - int i, len; + size_t i, len; if (TYPE(times) == T_STRING) { - return ary_join(ary, times); + return rb_ary_join(ary, times); } - len = NUM2INT(times) * RARRAY(ary)->len; - ary2 = ary_new2(len); - RARRAY(ary2)->len = len; - + len = NUM2UINT(times); if (len < 0) { - ArgError("negative argument"); + rb_raise(rb_eArgError, "negative argument"); } + len *= RARRAY(ary)->len; + + ary2 = rb_ary_new2(len); + RARRAY(ary2)->len = len; for (i=0; ilen) { MEMCPY(RARRAY(ary2)->ptr+i, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); @@ -953,7 +1161,7 @@ ary_times(ary, times) } VALUE -ary_assoc(ary, key) +rb_ary_assoc(ary, key) VALUE ary; VALUE key; { @@ -971,7 +1179,7 @@ ary_assoc(ary, key) } VALUE -ary_rassoc(ary, value) +rb_ary_rassoc(ary, value) VALUE ary; VALUE value; { @@ -989,135 +1197,203 @@ ary_rassoc(ary, value) } static VALUE -ary_equal(ary1, ary2) +rb_ary_equal(ary1, ary2) VALUE ary1, ary2; { - int i; + size_t i; - if (TYPE(ary2) != T_ARRAY) return FALSE; - if (RARRAY(ary1)->len != RARRAY(ary2)->len) return FALSE; + if (TYPE(ary2) != T_ARRAY) return Qfalse; + if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse; for (i=0; ilen; i++) { if (!rb_equal(RARRAY(ary1)->ptr[i], RARRAY(ary2)->ptr[i])) - return FALSE; + return Qfalse; } - return TRUE; + return Qtrue; } static VALUE -ary_eql(ary1, ary2) +rb_ary_eql(ary1, ary2) VALUE ary1, ary2; { - int i; + size_t i; - if (TYPE(ary2) != T_ARRAY) return FALSE; + if (TYPE(ary2) != T_ARRAY) return Qfalse; if (RARRAY(ary1)->len != RARRAY(ary2)->len) - return FALSE; + return Qfalse; for (i=0; ilen; i++) { if (!rb_eql(RARRAY(ary1)->ptr[i], RARRAY(ary2)->ptr[i])) - return FALSE; + return Qfalse; } - return TRUE; + return Qtrue; } static VALUE -ary_hash(ary) +rb_ary_hash(ary) VALUE ary; { - int h, i; + size_t i; + int h; h = RARRAY(ary)->len; for (i=0; ilen; i++) { - h ^= rb_hash(RARRAY(ary)->ptr[i]); + int n = rb_hash(RARRAY(ary)->ptr[i]); + h ^= NUM2LONG(n); } return INT2FIX(h); } VALUE -ary_includes(ary, item) +rb_ary_includes(ary, item) VALUE ary; VALUE item; { - int i; + size_t i; for (i=0; ilen; i++) { if (rb_equal(RARRAY(ary)->ptr[i], item)) { - return TRUE; + return Qtrue; + } + } + return Qfalse; +} + +static VALUE +rb_ary_cmp(ary, ary2) + VALUE ary; + VALUE ary2; +{ + size_t i, len; + + ary2 = to_ary(ary2); + len = RARRAY(ary)->len; + if (len > RARRAY(ary2)->len) { + len = RARRAY(ary2)->len; + } + for (i=0; iptr[i],cmp,1,RARRAY(ary2)->ptr[i]); + if (v != INT2FIX(0)) { + return v; } } - return FALSE; + len = RARRAY(ary)->len - RARRAY(ary2)->len; + if (len == 0) return INT2FIX(0); + if (len > 0) return INT2FIX(1); + return INT2FIX(-1); } static VALUE -ary_diff(ary1, ary2) +rb_ary_diff(ary1, ary2) VALUE ary1, ary2; { VALUE ary3; - int i; + size_t i; - Check_Type(ary2, T_ARRAY); - ary3 = ary_new(); + ary2 = to_ary(ary2); + ary3 = rb_ary_new(); for (i=0; ilen; i++) { - if (ary_includes(ary2, RARRAY(ary1)->ptr[i])) continue; - if (ary_includes(ary3, RARRAY(ary1)->ptr[i])) continue; - ary_push(ary3, RARRAY(ary1)->ptr[i]); + if (rb_ary_includes(ary2, RARRAY(ary1)->ptr[i])) continue; + if (rb_ary_includes(ary3, RARRAY(ary1)->ptr[i])) continue; + rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); } return ary3; } static VALUE -ary_and(ary1, ary2) +rb_ary_and(ary1, ary2) VALUE ary1, ary2; { VALUE ary3; - int i; + size_t i; - Check_Type(ary2, T_ARRAY); - ary3 = ary_new(); + ary2 = to_ary(ary2); + ary3 = rb_ary_new(); for (i=0; ilen; i++) { - if (ary_includes(ary2, RARRAY(ary1)->ptr[i]) - && !ary_includes(ary3, RARRAY(ary1)->ptr[i])) { - ary_push(ary3, RARRAY(ary1)->ptr[i]); + if (rb_ary_includes(ary2, RARRAY(ary1)->ptr[i]) + && !rb_ary_includes(ary3, RARRAY(ary1)->ptr[i])) { + rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); } } return ary3; } static VALUE -ary_or(ary1, ary2) +rb_ary_or(ary1, ary2) VALUE ary1, ary2; { VALUE ary3; - int i; + size_t i; if (TYPE(ary2) != T_ARRAY) { - if (ary_includes(ary1, ary2)) return ary1; - else return ary_plus(ary1, ary2); + if (rb_ary_includes(ary1, ary2)) return ary1; + else return rb_ary_plus(ary1, ary2); } - ary3 = ary_new(); + ary3 = rb_ary_new(); for (i=0; ilen; i++) { - if (!ary_includes(ary3, RARRAY(ary1)->ptr[i])) - ary_push(ary3, RARRAY(ary1)->ptr[i]); + if (!rb_ary_includes(ary3, RARRAY(ary1)->ptr[i])) + rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); } for (i=0; ilen; i++) { - if (!ary_includes(ary3, RARRAY(ary2)->ptr[i])) - ary_push(ary3, RARRAY(ary2)->ptr[i]); + if (!rb_ary_includes(ary3, RARRAY(ary2)->ptr[i])) + rb_ary_push(ary3, RARRAY(ary2)->ptr[i]); } return ary3; } static VALUE -ary_compact_bang(ary) +rb_ary_uniq_bang(ary) + VALUE ary; +{ + VALUE *p, *q, *t, *end; + VALUE v; + + rb_ary_modify(ary); + p = RARRAY(ary)->ptr; + end = p + RARRAY(ary)->len; + + while (p < end) { + v = *p++; + q = t = p; + while (q < end) { + if (rb_equal(*q, v)) q++; + else *t++ = *q++; + } + end = t; + } + if (RARRAY(ary)->len == (end - RARRAY(ary)->ptr)) { + return Qnil; + } + + RARRAY(ary)->len = (end - RARRAY(ary)->ptr); + + return ary; +} + +static VALUE +rb_ary_uniq(ary) + VALUE ary; +{ + VALUE v = rb_ary_uniq_bang(rb_ary_dup(ary)); + + if (NIL_P(v)) return ary; + return v; +} + +static VALUE +rb_ary_compact_bang(ary) VALUE ary; { VALUE *p, *t, *end; - ary_modify(ary); + rb_ary_modify(ary); p = t = RARRAY(ary)->ptr; end = p + RARRAY(ary)->len; while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } + if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) { + return Qnil; + } RARRAY(ary)->len = RARRAY(ary)->capa = (p - RARRAY(ary)->ptr); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); @@ -1125,17 +1401,20 @@ ary_compact_bang(ary) } static VALUE -ary_compact(ary) +rb_ary_compact(ary) VALUE ary; { - return ary_compact_bang(ary_clone(ary)); + VALUE v = rb_ary_compact_bang(rb_ary_dup(ary)); + + if (NIL_P(v)) return ary; + return v; } static VALUE -ary_nitems(ary) +rb_ary_nitems(ary) VALUE ary; { - int n = 0; + size_t n = 0; VALUE *p, *pend; p = RARRAY(ary)->ptr; @@ -1147,74 +1426,108 @@ ary_nitems(ary) return INT2FIX(n); } -extern VALUE mEnumerable; - -void -Init_Array() +static VALUE +rb_ary_flatten_bang(ary) + VALUE ary; { - cArray = rb_define_class("Array", cObject); - rb_include_module(cArray, mEnumerable); - - rb_define_singleton_method(cArray, "new", ary_s_new, -1); - rb_define_singleton_method(cArray, "[]", ary_s_create, -1); - rb_define_method(cArray, "to_s", ary_to_s, 0); - rb_define_method(cArray, "inspect", ary_inspect, 0); - rb_define_method(cArray, "to_a", ary_to_a, 0); - - rb_define_method(cArray, "freeze", ary_freeze, 0); - rb_define_method(cArray, "frozen?", ary_frozen_p, 0); - - rb_define_method(cArray, "==", ary_equal, 1); - rb_define_method(cArray, "eql?", ary_eql, 1); - rb_define_method(cArray, "hash", ary_hash, 0); - - rb_define_method(cArray, "[]", ary_aref, -1); - rb_define_method(cArray, "[]=", ary_aset, -1); - rb_define_method(cArray, "concat", ary_concat, 1); - rb_define_method(cArray, "<<", ary_push, 1); - rb_define_method(cArray, "push", ary_push_method, -1); - rb_define_method(cArray, "pop", ary_pop, 0); - rb_define_method(cArray, "shift", ary_shift, 0); - rb_define_method(cArray, "unshift", ary_unshift, 1); - rb_define_method(cArray, "each", ary_each, 0); - rb_define_method(cArray, "each_index", ary_each_index, 0); - rb_define_method(cArray, "reverse_each", ary_reverse_each, 0); - rb_define_method(cArray, "length", ary_length, 0); - rb_define_alias(cArray, "size", "length"); - rb_define_method(cArray, "empty?", ary_empty_p, 0); - rb_define_method(cArray, "index", ary_index, 1); - rb_define_method(cArray, "indexes", ary_indexes, -2); - rb_define_method(cArray, "clone", ary_clone, 0); - rb_define_method(cArray, "dup", ary_dup, 0); - rb_define_method(cArray, "join", ary_join_method, -1); - rb_define_method(cArray, "reverse", ary_reverse_method, 0); - rb_define_method(cArray, "reverse!", ary_reverse, 0); - rb_define_method(cArray, "sort", ary_sort, 0); - rb_define_method(cArray, "sort!", ary_sort_bang, 0); - rb_define_method(cArray, "delete", ary_delete, 1); - rb_define_method(cArray, "delete_at", ary_delete_at, 1); - rb_define_method(cArray, "delete_if", ary_delete_if, 0); -#if 0 - rb_define_method(cArray, "replace", ary_replace, 0); -#endif - rb_define_method(cArray, "clear", ary_clear, 0); - rb_define_method(cArray, "fill", ary_fill, -1); - rb_define_method(cArray, "include?", ary_includes, 1); - rb_define_method(cArray, "===", ary_includes, 1); + size_t i; + int mod = 0; - rb_define_method(cArray, "assoc", ary_assoc, 1); - rb_define_method(cArray, "rassoc", ary_rassoc, 1); + rb_ary_modify(ary); + for (i=0; ilen; i++) { + VALUE ary2 = RARRAY(ary)->ptr[i]; + if (TYPE(ary2) == T_ARRAY) { + rb_ary_replace(ary, i--, 1, ary2); + mod = 1; + } + } + if (mod == 0) return Qnil; + return ary; +} - rb_define_method(cArray, "+", ary_plus, 1); - rb_define_method(cArray, "*", ary_times, 1); +static VALUE +rb_ary_flatten(ary) + VALUE ary; +{ + VALUE v = rb_ary_flatten_bang(rb_ary_dup(ary)); - rb_define_method(cArray, "-", ary_diff, 1); - rb_define_method(cArray, "&", ary_and, 1); - rb_define_method(cArray, "|", ary_or, 1); + if (NIL_P(v)) return ary; + return v; +} - rb_define_method(cArray, "compact", ary_compact, 0); - rb_define_method(cArray, "compact!", ary_compact_bang, 0); - rb_define_method(cArray, "nitems", ary_nitems, 0); +void +Init_Array() +{ + rb_cArray = rb_define_class("Array", rb_cObject); + rb_include_module(rb_cArray, rb_mEnumerable); + + rb_define_singleton_method(rb_cArray, "new", rb_ary_s_new, -1); + rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1); + rb_define_method(rb_cArray, "to_s", rb_ary_to_s, 0); + rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0); + rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0); + rb_define_method(rb_cArray, "to_ary", rb_ary_to_a, 0); + + rb_define_method(rb_cArray, "freeze", rb_ary_freeze, 0); + rb_define_method(rb_cArray, "frozen?", rb_ary_frozen_p, 0); + + rb_define_method(rb_cArray, "==", rb_ary_equal, 1); + rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1); + rb_define_method(rb_cArray, "hash", rb_ary_hash, 0); + rb_define_method(rb_cArray, "===", rb_ary_equal, 1); + + rb_define_method(rb_cArray, "[]", rb_ary_aref, -1); + rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1); + rb_define_method(rb_cArray, "concat", rb_ary_concat, 1); + rb_define_method(rb_cArray, "<<", rb_ary_push, 1); + rb_define_method(rb_cArray, "push", rb_ary_push_method, -1); + rb_define_method(rb_cArray, "pop", rb_ary_pop, 0); + rb_define_method(rb_cArray, "shift", rb_ary_shift, 0); + rb_define_method(rb_cArray, "unshift", rb_ary_unshift, 1); + rb_define_method(rb_cArray, "each", rb_ary_each, 0); + rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0); + rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0); + rb_define_method(rb_cArray, "length", rb_ary_length, 0); + rb_define_alias(rb_cArray, "size", "length"); + rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0); + rb_define_method(rb_cArray, "index", rb_ary_index, 1); + rb_define_method(rb_cArray, "rindex", rb_ary_rindex, 1); + rb_define_method(rb_cArray, "indexes", rb_ary_indexes, -1); + rb_define_method(rb_cArray, "indices", rb_ary_indexes, -1); + rb_define_method(rb_cArray, "clone", rb_ary_clone, 0); + rb_define_method(rb_cArray, "dup", rb_ary_dup, 0); + rb_define_method(rb_cArray, "join", rb_ary_join_method, -1); + rb_define_method(rb_cArray, "reverse", rb_ary_reverse_method, 0); + rb_define_method(rb_cArray, "reverse!", rb_ary_reverse, 0); + rb_define_method(rb_cArray, "sort", rb_ary_sort, 0); + rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0); + rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); + rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at, 1); + rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0); + rb_define_method(rb_cArray, "filter", rb_ary_filter, 0); + rb_define_method(rb_cArray, "replace", rb_ary_replace_method, 1); + rb_define_method(rb_cArray, "clear", rb_ary_clear, 0); + rb_define_method(rb_cArray, "fill", rb_ary_fill, -1); + rb_define_method(rb_cArray, "include?", rb_ary_includes, 1); + rb_define_method(rb_cArray, "<=>", rb_ary_cmp, 1); + + rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1); + rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1); + + rb_define_method(rb_cArray, "+", rb_ary_plus, 1); + rb_define_method(rb_cArray, "*", rb_ary_times, 1); + + rb_define_method(rb_cArray, "-", rb_ary_diff, 1); + rb_define_method(rb_cArray, "&", rb_ary_and, 1); + rb_define_method(rb_cArray, "|", rb_ary_or, 1); + + rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0); + rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0); + rb_define_method(rb_cArray, "compact", rb_ary_compact, 0); + rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0); + rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); + rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, 0); + rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0); cmp = rb_intern("<=>"); } diff --git a/bignum.c b/bignum.c index 17d9c839c5..770e86ad80 100644 --- a/bignum.c +++ b/bignum.c @@ -9,28 +9,28 @@ ************************************************/ #include "ruby.h" -#include #include +#include -extern VALUE cInteger; -VALUE cBignum; +VALUE rb_cBignum; +typedef unsigned short USHORT; #define BDIGITS(x) RBIGNUM(x)->digits -#define BITSPERDIG (sizeof(USHORT)*CHAR_BIT) +#define BITSPERDIG (sizeof(short)*CHAR_BIT) #define BIGRAD (1L << BITSPERDIG) -#define DIGSPERINT ((UINT)(sizeof(INT)/sizeof(USHORT))) -#define BIGUP(x) ((UINT)(x) << BITSPERDIG) -#define BIGDN(x) ((x) >> BITSPERDIG) -#define BIGLO(x) ((x) & (BIGRAD-1)) +#define DIGSPERINT ((unsigned int)(sizeof(long)/sizeof(short))) +#define BIGUP(x) ((unsigned long)(x) << BITSPERDIG) +#define BIGDN(x) (((x)<0) ? ~((~(x))>>BITSPERDIG) : (x)>>BITSPERDIG) +#define BIGLO(x) ((USHORT)((x) & (BIGRAD-1))) static VALUE -bignew_1(class, len, sign) - VALUE class; - UINT len; +bignew_1(klass, len, sign) + VALUE klass; + size_t len; char sign; { NEWOBJ(big, struct RBignum); - OBJSETUP(big, cBignum, T_BIGNUM); + OBJSETUP(big, klass, T_BIGNUM); big->sign = sign; big->len = len; BDIGITS(big) = ALLOC_N(USHORT, len); @@ -38,10 +38,10 @@ bignew_1(class, len, sign) return (VALUE)big; } -#define bignew(len,sign) bignew_1(cBignum,len,sign) +#define bignew(len,sign) bignew_1(rb_cBignum,len,sign) VALUE -big_clone(x) +rb_big_clone(x) VALUE x; { VALUE z = bignew_1(CLASS_OF(x), RBIGNUM(x)->len, RBIGNUM(x)->sign); @@ -51,22 +51,22 @@ big_clone(x) } void -big_2comp(x) /* get 2's complement */ +rb_big_2comp(x) /* get 2's complement */ VALUE x; { - UINT i = RBIGNUM(x)->len; + int i = RBIGNUM(x)->len; USHORT *ds = BDIGITS(x); long num; while (i--) ds[i] = ~ds[i]; i = 0; num = 1; do { - num += (long)ds[i]; + num += ds[i]; ds[i++] = BIGLO(num); num = BIGDN(num); } while (i < RBIGNUM(x)->len); if (ds[0] == 1 || ds[0] == 0) { - for (i=1;ilen;i++) { + for (i=1; ilen; i++) { if (ds[i] != 0) return; } REALLOC_N(BDIGITS(x), USHORT, RBIGNUM(x)->len++); @@ -79,39 +79,39 @@ static VALUE bignorm(x) VALUE x; { - UINT len = RBIGNUM(x)->len; + size_t len = RBIGNUM(x)->len; USHORT *ds = BDIGITS(x); while (len-- && !ds[len]) ; RBIGNUM(x)->len = ++len; - if (len*sizeof(USHORT) < sizeof(VALUE) || - (len*sizeof(USHORT) == sizeof(VALUE) && - ds[sizeof(VALUE)/sizeof(USHORT)-1] <= 0x3fff)) { + if (len*sizeof(USHORT) <= sizeof(VALUE)) { long num = 0; while (len--) { num = BIGUP(num) + ds[len]; } - if (RBIGNUM(x)->sign) { - if (POSFIXABLE(num)) return INT2FIX(num); + if (num >= 0) { + if (RBIGNUM(x)->sign) { + if (POSFIXABLE(num)) return INT2FIX(num); + } + else if (NEGFIXABLE(-(long)num)) return INT2FIX(-(long)num); } - else if (NEGFIXABLE(-num)) return INT2FIX(-num); } return x; } VALUE -big_norm(x) +rb_big_norm(x) VALUE x; { - return bignorm(RBIGNUM(x)); + return bignorm(x); } VALUE -uint2big(n) - UINT n; +rb_uint2big(n) + unsigned long n; { - UINT i = 0; + unsigned int i = 0; USHORT *digits; VALUE big; @@ -130,17 +130,17 @@ uint2big(n) } VALUE -int2big(n) - INT n; +rb_int2big(n) + long n; { - INT neg = 0; + long neg = 0; VALUE big; if (n < 0) { n = -n; neg = 1; } - big = uint2big(n); + big = rb_uint2big(n); if (neg) { RBIGNUM(big)->sign = 0; } @@ -148,34 +148,39 @@ int2big(n) } VALUE -uint2inum(n) - UINT n; +rb_uint2inum(n) + unsigned long n; { if (POSFIXABLE(n)) return INT2FIX(n); - return uint2big(n); + return rb_uint2big(n); } VALUE -int2inum(n) - INT n; +rb_int2inum(n) + long n; { if (FIXABLE(n)) return INT2FIX(n); - return int2big(n); + return rb_int2big(n); } VALUE -str2inum(str, base) - UCHAR *str; +rb_str2inum(str, base) + char *str; int base; { char sign = 1, c; unsigned long num; - UINT len, blen = 1, i; + size_t len, blen = 1; + int i; VALUE z; USHORT *zds; - while (isspace(*str)) str++; - if (*str == '-') { + while (ISSPACE(*str)) str++; + + if (*str == '+') { + str++; + } + else if (*str == '-') { str++; sign = 0; } @@ -195,26 +200,30 @@ str2inum(str, base) base = 10; } } - len = strlen(str); if (base == 8) { - len = 3*len*sizeof(char); + while (str[0] == '0') str++; + len = 3*strlen(str)*sizeof(char); } else { /* base == 10 or 16 */ - len = 4*len*sizeof(char); + if (base == 16 && str[0] == '0' && (str[1] == 'x'||str[1] == 'X')) { + str += 2; + } + while (str[0] == '0') str++; + len = 4*strlen(str)*sizeof(char); } if (len <= (sizeof(VALUE)*CHAR_BIT)) { - UINT val = strtoul((char*)str, 0, base); + unsigned int val = strtoul((char*)str, 0, base); if (POSFIXABLE(val)) { if (sign) return INT2FIX(val); else { - INT result = -(INT)val; + long result = -(long)val; return INT2FIX(result); } } else { - VALUE big = uint2big(val); + VALUE big = rb_uint2big(val); RBIGNUM(big)->sign = sign; return big; } @@ -263,21 +272,21 @@ str2inum(str, base) static char hexmap[] = "0123456789abcdef"; VALUE -big2str(x, base) +rb_big2str(x, base) VALUE x; int base; { VALUE t; USHORT *ds; - UINT i, j, hbase; + unsigned int i, j, hbase; VALUE ss; - UCHAR *s, c; + char *s, c; if (FIXNUM_P(x)) { - return fix2str(x, base); + return rb_fix2str(x, base); } i = RBIGNUM(x)->len; - if (i == 0) return str_new2("0"); + if (i == 0) return rb_str_new2("0"); if (base == 10) { j = (sizeof(USHORT)/sizeof(char)*CHAR_BIT*i*241L)/800+2; hbase = 10000; @@ -297,12 +306,12 @@ big2str(x, base) else { j = 0; hbase = 0; - Fail("bignum cannot treat base %d", base); + rb_raise(rb_eArgError, "bignum cannot treat base %d", base); } - t = big_clone(x); + t = rb_big_clone(x); ds = BDIGITS(t); - ss = str_new(0, j); + ss = rb_str_new(0, j); s = RSTRING(ss)->ptr; s[0] = RBIGNUM(x)->sign ? '+' : '-'; @@ -311,13 +320,13 @@ big2str(x, base) unsigned long num = 0; while (k--) { num = BIGUP(num) + ds[k]; - ds[k] = num / hbase; + ds[k] = (USHORT)(num / hbase); num %= hbase; } if (ds[i-1] == 0) i--; k = 4; while (k--) { - c = num % base; + c = (char)(num % base); s[--j] = hexmap[(int)c]; num /= base; if (i == 0 && num == 0) break; @@ -332,44 +341,56 @@ big2str(x, base) } static VALUE -big_to_s(x) +rb_big_to_s(x) VALUE x; { - return big2str(x, 10); + return rb_big2str(x, 10); } -INT -big2int(x) +unsigned long +rb_big2ulong(x) VALUE x; { - UINT num; - UINT len = RBIGNUM(x)->len; + unsigned long num; + size_t len = RBIGNUM(x)->len; USHORT *ds; if (len > sizeof(long)/sizeof(USHORT)) - ArgError("Bignum too big to convert into fixnum"); + rb_raise(rb_eArgError, "bignum too big to convert into `uint'"); ds = BDIGITS(x); num = 0; while (len--) { num = BIGUP(num); num += ds[len]; } - if (!RBIGNUM(x)->sign) return -num; return num; } -VALUE -big_to_i(x) +long +rb_big2long(x) + VALUE x; +{ + unsigned long num = rb_big2ulong(x); + + if ((long)num < 0) { + rb_raise(rb_eArgError, "bignum too big to convert into `int'"); + } + if (!RBIGNUM(x)->sign) return -(long)num; + return num; +} + +static VALUE +rb_big_to_i(x) VALUE x; { return bignorm(x); } VALUE -dbl2big(d) +rb_dbl2big(d) double d; { - UINT i = 0; + unsigned int i = 0; long c; USHORT *digits; VALUE z; @@ -385,18 +406,18 @@ dbl2big(d) u *= BIGRAD; c = (long)u; u -= c; - digits[i] = c; + digits[i] = (USHORT)c; } return bignorm(z); } double -big2dbl(x) +rb_big2dbl(x) VALUE x; { double d = 0.0; - UINT i = RBIGNUM(x)->len; + size_t i = RBIGNUM(x)->len; USHORT *ds = BDIGITS(x); while (i--) { @@ -406,29 +427,29 @@ big2dbl(x) return d; } -VALUE -big_to_f(x) +static VALUE +rb_big_to_f(x) VALUE x; { - return float_new(big2dbl(x)); + return rb_float_new(rb_big2dbl(x)); } static VALUE -big_cmp(x, y) +rb_big_cmp(x, y) VALUE x, y; { - int xlen = RBIGNUM(x)->len; + size_t xlen = RBIGNUM(x)->len; switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } if (RBIGNUM(x)->sign > RBIGNUM(y)->sign) return INT2FIX(1); @@ -446,18 +467,18 @@ big_cmp(x, y) } static VALUE -big_eq(x, y) +rb_big_eq(x, y) VALUE x, y; { - if (big_cmp(x, y) == INT2FIX(0)) return TRUE; - return FALSE; + if (rb_big_cmp(x, y) == INT2FIX(0)) return Qtrue; + return Qfalse; } static VALUE -big_uminus(x) +rb_big_uminus(x) VALUE x; { - VALUE z = big_clone(x); + VALUE z = rb_big_clone(x); RBIGNUM(z)->sign = !RBIGNUM(x)->sign; @@ -465,16 +486,16 @@ big_uminus(x) } static VALUE -big_neg(x) +rb_big_neg(x) VALUE x; { - VALUE z = big_clone(x); - UINT i = RBIGNUM(x)->len; + VALUE z = rb_big_clone(x); + size_t i = RBIGNUM(x)->len; USHORT *ds = BDIGITS(z); - if (!RBIGNUM(x)->sign) big_2comp(z); + if (!RBIGNUM(x)->sign) rb_big_2comp(z); while (i--) ds[i] = ~ds[i]; - if (RBIGNUM(x)->sign) big_2comp(z); + if (RBIGNUM(x)->sign) rb_big_2comp(z); RBIGNUM(z)->sign = !RBIGNUM(z)->sign; return bignorm(z); @@ -487,7 +508,7 @@ bigsub(x, y) VALUE z = 0; USHORT *zds; long num; - UINT i; + size_t i; i = RBIGNUM(x)->len; /* if x is larger than y, swap */ @@ -535,10 +556,11 @@ bigadd(x, y, sign) { VALUE z; long num; - UINT i, len; + size_t i, len; - if (RBIGNUM(x)->sign == (RBIGNUM(y)->sign ^ sign)) { - if (RBIGNUM(y)->sign == sign) return bigsub(y, x); + sign = (sign == RBIGNUM(y)->sign); + if (RBIGNUM(x)->sign != sign) { + if (sign) return bigsub(y, x); return bigsub(x, y); } @@ -549,11 +571,11 @@ bigadd(x, y, sign) else { len = RBIGNUM(y)->len + 1; } - z = bignew(len, sign==RBIGNUM(y)->sign); + z = bignew(len, sign); len = RBIGNUM(x)->len; for (i = 0, num = 0; i < len; i++) { - num += (long)(BDIGITS(x)[i] + BDIGITS(y)[i]); + num += BDIGITS(x)[i] + BDIGITS(y)[i]; BDIGITS(z)[i] = BIGLO(num); num = BIGDN(num); } @@ -567,72 +589,72 @@ bigadd(x, y, sign) BDIGITS(z)[i] = BDIGITS(y)[i]; i++; } - BDIGITS(z)[i] = num; + BDIGITS(z)[i] = (USHORT)num; return bignorm(z); } VALUE -big_plus(x, y) +rb_big_plus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); /* fall through */ case T_BIGNUM: return bigadd(x, y, 1); case T_FLOAT: - return float_new(big2dbl(x) + RFLOAT(y)->value); + return rb_float_new(rb_big2dbl(x) + RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } VALUE -big_minus(x, y) +rb_big_minus(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); /* fall through */ case T_BIGNUM: return bigadd(x, y, 0); case T_FLOAT: - return float_new(big2dbl(x) - RFLOAT(y)->value); + return rb_float_new(rb_big2dbl(x) - RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } VALUE -big_mul(x, y) +rb_big_mul(x, y) VALUE x, y; { - UINT i = 0, j; + size_t i, j; unsigned long n = 0; VALUE z; USHORT *zds; - if (FIXNUM_P(x)) x = int2big(FIX2INT(x)); + if (FIXNUM_P(x)) x = rb_int2big(FIX2LONG(x)); switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: - return float_new(big2dbl(x) * RFLOAT(y)->value); + return rb_float_new(rb_big2dbl(x) * RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } j = RBIGNUM(x)->len + RBIGNUM(y)->len + 1; @@ -658,19 +680,21 @@ big_mul(x, y) } static void -bigdivmod(x, y, div, mod) +bigdivmod(x, y, div, mod, modulo) VALUE x, y; VALUE *div, *mod; + int modulo; { - UINT nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len, i, j; - VALUE z; + size_t nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len; + int i, j; + VALUE yy, z; USHORT *xds, *yds, *zds, *tds; - unsigned long t2; + size_t t2; long num; USHORT dd, q; yds = BDIGITS(y); - if (ny == 0 && yds[0] == 0) num_zerodiv(); + if (ny == 0 && yds[0] == 0) rb_num_zerodiv(); if (nx < ny || nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1]) { if (div) *div = INT2FIX(0); if (mod) *mod = bignorm(x); @@ -679,17 +703,17 @@ bigdivmod(x, y, div, mod) xds = BDIGITS(x); if (ny == 1) { dd = yds[0]; - z = big_clone(x); + z = rb_big_clone(x); zds = BDIGITS(z); t2 = 0; i = nx; while (i--) { t2 = BIGUP(t2) + zds[i]; - zds[i] = t2 / dd; + zds[i] = (USHORT)(t2 / dd); t2 %= dd; } if (div) *div = bignorm(z); if (mod) { - if (!RBIGNUM(y)->sign) t2 = -t2; + if (!RBIGNUM(y)->sign) t2 = -(long)t2; *mod = INT2FIX(t2); } return; @@ -699,12 +723,12 @@ bigdivmod(x, y, div, mod) if (nx==ny) zds[nx+1] = 0; while (!yds[ny-1]) ny--; if ((dd = BIGRAD/(int)(yds[ny-1]+1)) != 1) { - y = big_clone(y); - tds = BDIGITS(y); + yy = rb_big_clone(y); + tds = BDIGITS(yy); j = 0; num = 0; while (j= ny); if (div) { /* move quotient down in z */ - *div = big_clone(z); + *div = rb_big_clone(z); zds = BDIGITS(*div); j = (nx==ny ? nx+2 : nx+1) - ny; for (i = 0;i < j;i++) zds[i] = zds[i+ny]; @@ -761,105 +785,130 @@ bigdivmod(x, y, div, mod) *div = bignorm(*div); } if (mod) { /* just normalize remainder */ - *mod = big_clone(z); + *mod = rb_big_clone(z); if (dd) { zds = BDIGITS(*mod); t2 = 0; i = ny; while(i--) { t2 = BIGUP(t2) + zds[i]; - zds[i] = t2 / dd; + zds[i] = (USHORT)(t2 / dd); t2 %= dd; } } RBIGNUM(*mod)->len = ny; - RBIGNUM(*mod)->sign = RBIGNUM(y)->sign; + RBIGNUM(*mod)->sign = RBIGNUM(x)->sign; + if (modulo && RBIGNUM(x)->sign != RBIGNUM(y)->sign) { + size_t len = ny; + zds = BDIGITS(*mod); + while (len-- && !zds[len]); + if (len > 0) { + *mod = bigadd(*mod, y, 1); + return; + } + } *mod = bignorm(*mod); } } static VALUE -big_div(x, y) +rb_big_div(x, y) VALUE x, y; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: - return float_new(big2dbl(x) / RFLOAT(y)->value); + return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } - bigdivmod(x, y, &z, 0); + bigdivmod(x, y, &z, 0, 0); return z; } + static VALUE -big_mod(x, y) +rb_big_modulo(x, y, modulo) VALUE x, y; + int modulo; { VALUE z; switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); break; case T_BIGNUM: break; case T_FLOAT: - y = dbl2big(RFLOAT(y)->value); + y = rb_dbl2big(RFLOAT(y)->value); break; default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } - bigdivmod(x, y, 0, &z); + bigdivmod(x, y, 0, &z, modulo); return z; } static VALUE -big_divmod(x, y) +rb_big_mod(x, y) + VALUE x, y; +{ + return rb_big_modulo(x, y, 1); +} + +static VALUE +rb_big_remainder(x, y) + VALUE x, y; +{ + return rb_big_modulo(x, y, 0); +} + +static VALUE +rb_big_divmod(x, y) VALUE x, y; { VALUE div, mod; switch (TYPE(y)) { case T_FIXNUM: - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); break; case T_FLOAT: - y = dbl2big(RFLOAT(y)->value); + y = rb_dbl2big(RFLOAT(y)->value); break; case T_BIGNUM: break; default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } - bigdivmod(x, y, &div, &mod); + bigdivmod(x, y, &div, &mod, 1); - return assoc_new(div, mod);; + return rb_assoc_new(div, mod);; } VALUE -big_pow(x, y) +rb_big_pow(x, y) VALUE x, y; { double d; - VALUE z; + long yy; if (y == INT2FIX(0)) return INT2FIX(1); switch (TYPE(y)) { @@ -868,57 +917,59 @@ big_pow(x, y) break; case T_BIGNUM: - if (RBIGNUM(y)->sign) goto pos_big; - d = big2dbl(y); + rb_warn("in a**b, b may be too big"); + d = rb_big2dbl(y); break; case T_FIXNUM: - if (FIX2INT(y) > 0) goto pos_big; - d = (double)FIX2INT(y); + yy = NUM2LONG(y); + if (yy > 0) { + VALUE z; + + z = x; + for (;;) { + yy = yy - 1; + if (yy == 0) break; + while (yy % 2 == 0) { + yy = yy / 2; + x = rb_big_mul(x, x); + } + z = rb_big_mul(z, x); + } + return z; + } + d = (double)yy; break; default: - return num_coerce_bin(x, y); - } - return float_new(pow(big2dbl(x), d)); - - pos_big: - z = x; - for (;;) { - y = rb_funcall(y, '-', 1, INT2FIX(1)); - if (y == INT2FIX(0)) break; - while (rb_funcall(y, '%', 1, INT2FIX(2)) == INT2FIX(0)) { - y = rb_funcall(y, '/', 1, INT2FIX(2)); - x = big_mul(x, x); - } - z = big_mul(z, x); + return rb_num_coerce_bin(x, y); } - return z; + return rb_float_new(pow(rb_big2dbl(x), d)); } VALUE -big_and(x, y) +rb_big_and(x, y) VALUE x, y; { VALUE z; USHORT *ds1, *ds2, *zds; - UINT i, l1, l2; + size_t i, l1, l2; char sign; if (FIXNUM_P(y)) { - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); } else { Check_Type(y, T_BIGNUM); } if (!RBIGNUM(y)->sign) { - y = big_clone(y); - big_2comp(y); + y = rb_big_clone(y); + rb_big_2comp(y); } if (!RBIGNUM(x)->sign) { - x = big_clone(x); - big_2comp(x); + x = rb_big_clone(x); + rb_big_2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; @@ -943,33 +994,33 @@ big_and(x, y) for (; isign) big_2comp(z); + if (!RBIGNUM(z)->sign) rb_big_2comp(z); return bignorm(z); } VALUE -big_or(x, y) +rb_big_or(x, y) VALUE x, y; { VALUE z; USHORT *ds1, *ds2, *zds; - UINT i, l1, l2; + unsigned int i, l1, l2; char sign; if (FIXNUM_P(y)) { - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); } else { Check_Type(y, T_BIGNUM); } if (!RBIGNUM(y)->sign) { - y = big_clone(y); - big_2comp(y); + y = rb_big_clone(y); + rb_big_2comp(y); } if (!RBIGNUM(x)->sign) { - x = big_clone(x); - big_2comp(x); + x = rb_big_clone(x); + rb_big_2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; @@ -994,34 +1045,34 @@ big_or(x, y) for (; isign) big_2comp(z); + if (!RBIGNUM(z)->sign) rb_big_2comp(z); return bignorm(z); } VALUE -big_xor(x, y) +rb_big_xor(x, y) VALUE x, y; { VALUE z; USHORT *ds1, *ds2, *zds; - UINT i, l1, l2; + unsigned int i, l1, l2; char sign; if (FIXNUM_P(y)) { - y = int2big(FIX2INT(y)); + y = rb_int2big(FIX2LONG(y)); } else { Check_Type(y, T_BIGNUM); } if (!RBIGNUM(y)->sign) { - y = big_clone(y); - big_2comp(y); + y = rb_big_clone(y); + rb_big_2comp(y); } if (!RBIGNUM(x)->sign) { - x = big_clone(x); - big_2comp(x); + x = rb_big_clone(x); + rb_big_2comp(x); } if (RBIGNUM(x)->len > RBIGNUM(y)->len) { l1 = RBIGNUM(y)->len; @@ -1048,26 +1099,26 @@ big_xor(x, y) for (; isign) big_2comp(z); + if (!RBIGNUM(z)->sign) rb_big_2comp(z); return bignorm(z); } -static VALUE big_rshift(); +static VALUE rb_big_rshift _((VALUE,VALUE)); VALUE -big_lshift(x, y) +rb_big_lshift(x, y) VALUE x, y; { USHORT *xds, *zds; int shift = NUM2INT(y); - UINT s1 = shift/BITSPERDIG; - UINT s2 = shift%BITSPERDIG; + size_t s1 = shift/BITSPERDIG; + size_t s2 = shift%BITSPERDIG; VALUE z; unsigned long num = 0; - UINT len, i; + size_t len, i; - if (shift < 0) return big_rshift(x, INT2FIX(-shift)); + if (shift < 0) return rb_big_rshift(x, INT2FIX(-shift)); xds = BDIGITS(x); len = RBIGNUM(x)->len; z = bignew(len+s1+1, RBIGNUM(x)->sign); @@ -1085,19 +1136,19 @@ big_lshift(x, y) } static VALUE -big_rshift(x, y) +rb_big_rshift(x, y) VALUE x, y; { USHORT *xds, *zds; int shift = NUM2INT(y); - UINT s1 = shift/BITSPERDIG; - UINT s2 = shift%BITSPERDIG; + size_t s1 = shift/BITSPERDIG; + size_t s2 = shift%BITSPERDIG; VALUE z; unsigned long num = 0; - UINT i = RBIGNUM(x)->len; - UINT j; + size_t i = RBIGNUM(x)->len; + size_t j; - if (shift < 0) return big_lshift(x, INT2FIX(-shift)); + if (shift < 0) return rb_big_lshift(x, INT2FIX(-shift)); if (s1 > RBIGNUM(x)->len) { if (RBIGNUM(x)->sign) return INT2FIX(0); @@ -1117,12 +1168,12 @@ big_rshift(x, y) } static VALUE -big_aref(x, y) +rb_big_aref(x, y) VALUE x, y; { USHORT *xds; int shift = NUM2INT(y); - UINT s1, s2; + size_t s1, s2; if (shift < 0) return INT2FIX(0); s1 = shift/BITSPERDIG; @@ -1130,8 +1181,8 @@ big_aref(x, y) if (!RBIGNUM(x)->sign) { if (s1 >= RBIGNUM(x)->len) return INT2FIX(1); - x = big_clone(x); - big_2comp(x); + x = rb_big_clone(x); + rb_big_2comp(x); } else { if (s1 >= RBIGNUM(x)->len) return INT2FIX(0); @@ -1143,10 +1194,11 @@ big_aref(x, y) } static VALUE -big_hash(x) +rb_big_hash(x) VALUE x; { - int i, len, key; + size_t i, len; + int key; USHORT *digits; key = 0; digits = BDIGITS(x); @@ -1157,27 +1209,29 @@ big_hash(x) } static VALUE -big_coerce(x, y) +rb_big_coerce(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - return assoc_new(int2big(FIX2INT(y)), x); + return rb_assoc_new(rb_int2big(FIX2LONG(y)), x); } else { - TypeError("can't coerce %s to Bignum", rb_class2name(CLASS_OF(y))); + rb_raise(rb_eTypeError, "can't coerce %s to Bignum", + rb_class2name(CLASS_OF(y))); } /* not reached */ + return Qnil; } static VALUE -big_abs(x) +rb_big_abs(x) VALUE x; { if (!RBIGNUM(x)->sign) { - x = big_clone(x); + x = rb_big_clone(x); RBIGNUM(x)->sign = 1; } - return (VALUE)x; + return x; } /* !!!warnig!!!! @@ -1185,11 +1239,11 @@ big_abs(x) */ VALUE -big_rand(max) +rb_big_rand(max) VALUE max; { struct RBignum *v; - int len; + size_t len; len = RBIGNUM(max)->len; v = RBIGNUM(bignew(len,1)); @@ -1201,47 +1255,57 @@ big_rand(max) #endif } - return big_mod(v, max); + return rb_big_mod((VALUE)v, max); } static VALUE -big_size(big) +rb_big_size(big) VALUE big; { return INT2FIX(RBIGNUM(big)->len*sizeof(USHORT)); } +static VALUE +rb_big_zero_p(big) + VALUE big; +{ + return Qfalse; +} + void Init_Bignum() { - cBignum = rb_define_class("Bignum", cInteger); - - rb_undef_method(CLASS_OF(cBignum), "new"); - - rb_define_method(cBignum, "to_s", big_to_s, 0); - rb_define_method(cBignum, "coerce", big_coerce, 1); - rb_define_method(cBignum, "-@", big_uminus, 0); - rb_define_method(cBignum, "+", big_plus, 1); - rb_define_method(cBignum, "-", big_minus, 1); - rb_define_method(cBignum, "*", big_mul, 1); - rb_define_method(cBignum, "/", big_div, 1); - rb_define_method(cBignum, "%", big_mod, 1); - rb_define_method(cBignum, "divmod", big_divmod, 1); - rb_define_method(cBignum, "**", big_pow, 1); - rb_define_method(cBignum, "&", big_and, 1); - rb_define_method(cBignum, "|", big_or, 1); - rb_define_method(cBignum, "^", big_xor, 1); - rb_define_method(cBignum, "~", big_neg, 0); - rb_define_method(cBignum, "<<", big_lshift, 1); - rb_define_method(cBignum, ">>", big_rshift, 1); - rb_define_method(cBignum, "[]", big_aref, 1); - - rb_define_method(cBignum, "<=>", big_cmp, 1); - rb_define_method(cBignum, "==", big_eq, 1); - rb_define_method(cBignum, "eql?", big_eq, 1); - rb_define_method(cBignum, "hash", big_hash, 0); - rb_define_method(cBignum, "to_i", big_to_i, 0); - rb_define_method(cBignum, "to_f", big_to_f, 0); - rb_define_method(cBignum, "abs", big_abs, 0); - rb_define_method(cBignum, "size", big_size, 0); + rb_cBignum = rb_define_class("Bignum", rb_cInteger); + + rb_undef_method(CLASS_OF(rb_cBignum), "new"); + + rb_define_method(rb_cBignum, "to_s", rb_big_to_s, 0); + rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1); + rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0); + rb_define_method(rb_cBignum, "+", rb_big_plus, 1); + rb_define_method(rb_cBignum, "-", rb_big_minus, 1); + rb_define_method(rb_cBignum, "*", rb_big_mul, 1); + rb_define_method(rb_cBignum, "/", rb_big_div, 1); + rb_define_method(rb_cBignum, "%", rb_big_mod, 1); + rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1); + rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1); + rb_define_method(rb_cBignum, "**", rb_big_pow, 1); + rb_define_method(rb_cBignum, "&", rb_big_and, 1); + rb_define_method(rb_cBignum, "|", rb_big_or, 1); + rb_define_method(rb_cBignum, "^", rb_big_xor, 1); + rb_define_method(rb_cBignum, "~", rb_big_neg, 0); + rb_define_method(rb_cBignum, "<<", rb_big_lshift, 1); + rb_define_method(rb_cBignum, ">>", rb_big_rshift, 1); + rb_define_method(rb_cBignum, "[]", rb_big_aref, 1); + + rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1); + rb_define_method(rb_cBignum, "==", rb_big_eq, 1); + rb_define_method(rb_cBignum, "===", rb_big_eq, 1); + rb_define_method(rb_cBignum, "eql?", rb_big_eq, 1); + rb_define_method(rb_cBignum, "hash", rb_big_hash, 0); + rb_define_method(rb_cBignum, "to_i", rb_big_to_i, 0); + rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0); + rb_define_method(rb_cBignum, "abs", rb_big_abs, 0); + rb_define_method(rb_cBignum, "size", rb_big_size, 0); + rb_define_method(rb_cBignum, "zero?", rb_big_zero_p, 0); } diff --git a/class.c b/class.c index 13c9298c1c..86ac8c5ae7 100644 --- a/class.c +++ b/class.c @@ -6,40 +6,41 @@ $Date$ created at: Tue Aug 10 15:05:44 JST 1993 - Copyright (C) 1993-1995 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "node.h" #include "st.h" +#include -struct st_table *new_idhash(); -extern st_table *rb_class_tbl; +#ifdef USE_CWGUSI +#include +#endif -extern VALUE cClass; -extern VALUE cModule; +extern st_table *rb_class_tbl; VALUE -class_new(super) +rb_class_new(super) VALUE super; { NEWOBJ(klass, struct RClass); - OBJSETUP(klass, cClass, T_CLASS); + OBJSETUP(klass, rb_cClass, T_CLASS); klass->super = super; klass->iv_tbl = 0; klass->m_tbl = 0; /* safe GC */ - klass->m_tbl = new_idhash(); + klass->m_tbl = st_init_numtable(); return (VALUE)klass; } VALUE -singleton_class_new(super) +rb_singleton_class_new(super) VALUE super; { - VALUE klass = class_new(super); + VALUE klass = rb_class_new(super); FL_SET(klass, FL_SINGLETON); return klass; @@ -56,7 +57,7 @@ clone_method(mid, body, tbl) } VALUE -singleton_class_clone(klass) +rb_singleton_class_clone(klass) VALUE klass; { if (!FL_TEST(klass, FL_SINGLETON)) @@ -69,7 +70,7 @@ singleton_class_clone(klass) clone->super = RCLASS(klass)->super; clone->iv_tbl = 0; clone->m_tbl = 0; - clone->m_tbl = new_idhash(); + clone->m_tbl = st_init_numtable(); st_foreach(RCLASS(klass)->m_tbl, clone_method, clone->m_tbl); FL_SET(clone, FL_SINGLETON); return (VALUE)clone; @@ -77,7 +78,7 @@ singleton_class_clone(klass) } void -singleton_class_attached(klass, obj) +rb_singleton_class_attached(klass, obj) VALUE klass, obj; { if (FL_TEST(klass, FL_SINGLETON)) @@ -91,15 +92,15 @@ rb_define_class_id(id, super) { VALUE klass; - if (!super) super = cObject; - klass = class_new(super); + if (!super) super = rb_cObject; + klass = rb_class_new(super); rb_name_class(klass, id); /* make metaclass */ - RBASIC(klass)->class = singleton_class_new(RBASIC(super)->class); - singleton_class_attached(RBASIC(klass)->class, klass); + RBASIC(klass)->klass = rb_singleton_class_new(RBASIC(super)->klass); + rb_singleton_class_attached(RBASIC(klass)->klass, klass); rb_funcall(super, rb_intern("inherited"), 1, klass); - return (VALUE)klass; + return klass; } VALUE @@ -112,14 +113,15 @@ rb_define_class(name, super) id = rb_intern(name); klass = rb_define_class_id(id, super); + st_add_direct(rb_class_tbl, id, klass); return klass; } VALUE -rb_define_class_under(under, name, super) - VALUE under; +rb_define_class_under(outer, name, super) + VALUE outer; char *name; VALUE super; { @@ -128,22 +130,22 @@ rb_define_class_under(under, name, super) id = rb_intern(name); klass = rb_define_class_id(id, super); - rb_const_set(under, id, klass); - rb_set_class_path(klass, under, name); + rb_const_set(outer, id, klass); + rb_set_class_path(klass, outer, name); return klass; } VALUE -module_new() +rb_module_new() { NEWOBJ(mdl, struct RClass); - OBJSETUP(mdl, cModule, T_MODULE); + OBJSETUP(mdl, rb_cModule, T_MODULE); mdl->super = 0; mdl->iv_tbl = 0; mdl->m_tbl = 0; - mdl->m_tbl = new_idhash(); + mdl->m_tbl = st_init_numtable(); return (VALUE)mdl; } @@ -152,9 +154,9 @@ VALUE rb_define_module_id(id) ID id; { - extern st_table *rb_class_tbl; - VALUE mdl = module_new(); + VALUE mdl; + mdl = rb_module_new(); rb_name_class(mdl, id); return mdl; @@ -175,8 +177,8 @@ rb_define_module(name) } VALUE -rb_define_module_under(under, name) - VALUE under; +rb_define_module_under(outer, name) + VALUE outer; char *name; { VALUE module; @@ -184,8 +186,8 @@ rb_define_module_under(under, name) id = rb_intern(name); module = rb_define_module_id(id); - rb_const_set(under, id, module); - rb_set_class_path(module, under, name); + rb_const_set(outer, id, module); + rb_set_class_path(module, outer, name); return module; } @@ -195,16 +197,16 @@ include_class_new(module, super) VALUE module, super; { NEWOBJ(klass, struct RClass); - OBJSETUP(klass, cClass, T_ICLASS); + OBJSETUP(klass, rb_cClass, T_ICLASS); klass->m_tbl = RCLASS(module)->m_tbl; klass->iv_tbl = RCLASS(module)->iv_tbl; klass->super = super; if (TYPE(module) == T_ICLASS) { - RBASIC(klass)->class = RBASIC(module)->class; + RBASIC(klass)->klass = RBASIC(module)->klass; } else { - RBASIC(klass)->class = module; + RBASIC(klass)->klass = module; } return (VALUE)klass; @@ -217,61 +219,66 @@ rb_include_module(klass, module) VALUE p; if (NIL_P(module)) return; + if (klass == module) return; switch (TYPE(module)) { case T_MODULE: case T_CLASS: + case T_ICLASS: break; default: Check_Type(module, T_MODULE); } - if (klass == module) return; - rb_clear_cache(); - while (module) { /* ignore if the module included already in superclasses */ for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) { if (BUILTIN_TYPE(p) == T_ICLASS && - RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) + RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { + if (RCLASS(module)->super) { + rb_include_module(p, RCLASS(module)->super); + } return; + } } - RCLASS(klass)->super = include_class_new(module, RCLASS(klass)->super); klass = RCLASS(klass)->super; module = RCLASS(module)->super; } + rb_clear_cache(); } VALUE -mod_included_modules(mod) +rb_mod_included_modules(mod) VALUE mod; { - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); VALUE p; for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { if (BUILTIN_TYPE(p) == T_ICLASS) { - ary_push(ary, RBASIC(p)->class); + rb_ary_push(ary, RBASIC(p)->klass); } } return ary; } VALUE -mod_ancestors(mod) +rb_mod_ancestors(mod) VALUE mod; { - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); VALUE p; for (p = mod; p; p = RCLASS(p)->super) { + if (FL_TEST(p, FL_SINGLETON)) + continue; if (BUILTIN_TYPE(p) == T_ICLASS) { - ary_push(ary, RBASIC(p)->class); + rb_ary_push(ary, RBASIC(p)->klass); } else { - ary_push(ary, p); + rb_ary_push(ary, p); } } return ary; @@ -283,19 +290,43 @@ ins_methods_i(key, body, ary) NODE *body; VALUE ary; { - if (!body->nd_noex) { - VALUE name = str_new2(rb_id2name(key)); + if ((body->nd_noex&(NOEX_PRIVATE|NOEX_PROTECTED)) == 0) { + VALUE name = rb_str_new2(rb_id2name(key)); - if (!ary_includes(ary, name)) { + if (!rb_ary_includes(ary, name)) { if (!body->nd_body) { - ary_push(ary, Qnil); + rb_ary_push(ary, Qnil); } - ary_push(ary, name); + rb_ary_push(ary, name); + } + } + else if (body->nd_body && nd_type(body->nd_body) == NODE_ZSUPER) { + rb_ary_push(ary, Qnil); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); + } + return ST_CONTINUE; +} + +static int +ins_methods_prot_i(key, body, ary) + ID key; + NODE *body; + VALUE ary; +{ + if (!body->nd_body) { + rb_ary_push(ary, Qnil); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); + } + else if (body->nd_noex & NOEX_PROTECTED) { + VALUE name = rb_str_new2(rb_id2name(key)); + + if (!rb_ary_includes(ary, name)) { + rb_ary_push(ary, name); } } else if (nd_type(body->nd_body) == NODE_ZSUPER) { - ary_push(ary, Qnil); - ary_push(ary, str_new2(rb_id2name(key))); + rb_ary_push(ary, Qnil); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); } return ST_CONTINUE; } @@ -307,19 +338,19 @@ ins_methods_priv_i(key, body, ary) VALUE ary; { if (!body->nd_body) { - ary_push(ary, Qnil); - ary_push(ary, str_new2(rb_id2name(key))); + rb_ary_push(ary, Qnil); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); } - else if (body->nd_noex) { - VALUE name = str_new2(rb_id2name(key)); + else if (body->nd_noex & NOEX_PRIVATE) { + VALUE name = rb_str_new2(rb_id2name(key)); - if (!ary_includes(ary, name)) { - ary_push(ary, name); + if (!rb_ary_includes(ary, name)) { + rb_ary_push(ary, name); } } else if (nd_type(body->nd_body) == NODE_ZSUPER) { - ary_push(ary, Qnil); - ary_push(ary, str_new2(rb_id2name(key))); + rb_ary_push(ary, Qnil); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); } return ST_CONTINUE; } @@ -334,7 +365,7 @@ method_list(mod, option, func) VALUE klass; VALUE *p, *q, *pend; - ary = ary_new(); + ary = rb_ary_new(); for (klass = mod; klass; klass = RCLASS(klass)->super) { st_foreach(RCLASS(klass)->m_tbl, func, ary); if (!option) break; @@ -352,7 +383,7 @@ method_list(mod, option, func) } VALUE -class_instance_methods(argc, argv, mod) +rb_class_instance_methods(argc, argv, mod) int argc; VALUE *argv; VALUE mod; @@ -364,7 +395,19 @@ class_instance_methods(argc, argv, mod) } VALUE -class_private_instance_methods(argc, argv, mod) +rb_class_protected_instance_methods(argc, argv, mod) + int argc; + VALUE *argv; + VALUE mod; +{ + VALUE option; + + rb_scan_args(argc, argv, "01", &option); + return method_list(mod, RTEST(option), ins_methods_prot_i); +} + +VALUE +rb_class_private_instance_methods(argc, argv, mod) int argc; VALUE *argv; VALUE mod; @@ -376,14 +419,14 @@ class_private_instance_methods(argc, argv, mod) } VALUE -obj_singleton_methods(obj) +rb_obj_singleton_methods(obj) VALUE obj; { VALUE ary; VALUE klass; VALUE *p, *q, *pend; - ary = ary_new(); + ary = rb_ary_new(); klass = CLASS_OF(obj); while (klass && FL_TEST(klass, FL_SINGLETON)) { st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary); @@ -409,7 +452,7 @@ rb_define_method_id(klass, name, func, argc) VALUE (*func)(); int argc; { - rb_add_method(klass, name, NEW_CFUNC(func, argc), NOEX_PUBLIC); + rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC|NOEX_CFUNC); } void @@ -419,15 +462,22 @@ rb_define_method(klass, name, func, argc) VALUE (*func)(); int argc; { - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PUBLIC); + ID id = rb_intern(name); + + rb_add_method(klass, id, NEW_CFUNC(func, argc), + ((name[0] == 'i' && id == rb_intern("initialize"))? + NOEX_PRIVATE:NOEX_PUBLIC)|NOEX_CFUNC); } void -rb_undef_method(klass, name) +rb_define_protected_method(klass, name, func, argc) VALUE klass; char *name; + VALUE (*func)(); + int argc; { - rb_add_method(klass, rb_intern(name), 0, NOEX_PUBLIC); + rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), + NOEX_PROTECTED|NOEX_CFUNC); } void @@ -437,7 +487,16 @@ rb_define_private_method(klass, name, func, argc) VALUE (*func)(); int argc; { - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PRIVATE); + rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), + NOEX_PRIVATE|NOEX_CFUNC); +} + +void +rb_undef_method(klass, name) + VALUE klass; + char *name; +{ + rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF); } VALUE @@ -445,14 +504,14 @@ rb_singleton_class(obj) VALUE obj; { if (rb_special_const_p(obj)) { - TypeError("cannot define singleton"); + rb_raise(rb_eTypeError, "cannot define singleton"); } - if (FL_TEST(RBASIC(obj)->class, FL_SINGLETON)) { - return (VALUE)RBASIC(obj)->class; + if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON)) { + return RBASIC(obj)->klass; } - RBASIC(obj)->class = singleton_class_new(RBASIC(obj)->class); - singleton_class_attached(RBASIC(obj)->class, obj); - return RBASIC(obj)->class; + RBASIC(obj)->klass = rb_singleton_class_new(RBASIC(obj)->klass); + rb_singleton_class_attached(RBASIC(obj)->klass, obj); + return RBASIC(obj)->klass; } void @@ -476,15 +535,13 @@ rb_define_module_function(module, name, func, argc) rb_define_singleton_method(module, name, func, argc); } -extern VALUE mKernel; - void rb_define_global_function(name, func, argc) char *name; VALUE (*func)(); int argc; { - rb_define_private_method(mKernel, name, func, argc); + rb_define_module_function(rb_mKernel, name, func, argc); } void @@ -496,57 +553,50 @@ rb_define_alias(klass, name1, name2) } void -rb_define_attr(klass, id, read, write) +rb_define_attr(klass, name, read, write) VALUE klass; - ID id; + char *name; int read, write; { - char *name; - char *buf; - ID attr, attreq, attriv; - - name = rb_id2name(id); - attr = rb_intern(name); - buf = ALLOCA_N(char,strlen(name)+2); - sprintf(buf, "%s=", name); - attreq = rb_intern(buf); - sprintf(buf, "@%s", name); - attriv = rb_intern(buf); - if (read) { - rb_add_method(klass, attr, NEW_IVAR(attriv), 0); - } - if (write) { - rb_add_method(klass, attreq, NEW_ATTRSET(attriv), 0); - } + rb_attr(klass, rb_intern(name), read, write, Qfalse); } +#ifdef HAVE_STDARG_PROTOTYPES +#include +#define va_init_list(a,b) va_start(a,b) +#else #include -#include +#define va_init_list(a,b) va_start(a) +#endif int +#ifdef HAVE_STDARG_PROTOTYPES +rb_scan_args(int argc, VALUE *argv, char *fmt, ...) +#else rb_scan_args(argc, argv, fmt, va_alist) int argc; VALUE *argv; char *fmt; va_dcl +#endif { int n, i; char *p = fmt; VALUE *var; va_list vargs; - va_start(vargs); + va_init_list(vargs, fmt); if (*p == '*') { var = va_arg(vargs, VALUE*); - *var = ary_new4(argc, argv); + *var = rb_ary_new4(argc, argv); return argc; } - if (isdigit(*p)) { + if (ISDIGIT(*p)) { n = *p - '0'; if (n > argc) - ArgError("Wrong # of arguments (%d for %d)", argc, n); + rb_raise(rb_eArgError, "Wrong # of arguments (%d for %d)", argc, n); for (i=0; i i) { - *var = ary_new4(argc-i, argv+i); + *var = rb_ary_new4(argc-i, argv+i); } else { - *var = ary_new(); + *var = rb_ary_new(); } } else if (*p == '\0') { if (argc > i) { - ArgError("Wrong # of arguments(%d for %d)", argc, i); + rb_raise(rb_eArgError, "Wrong # of arguments(%d for %d)", argc, i); } } else { @@ -593,6 +643,6 @@ rb_scan_args(argc, argv, fmt, va_alist) return argc; error: - Fatal("bad scan arg format: %s", fmt); + rb_fatal("bad scan arg format: %s", fmt); return 0; } diff --git a/compar.c b/compar.c index e852fb1e49..a6212a86bb 100644 --- a/compar.c +++ b/compar.c @@ -6,13 +6,13 @@ $Date$ created at: Thu Aug 26 14:39:48 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" -VALUE mComparable; +VALUE rb_mComparable; static ID cmp; @@ -23,8 +23,8 @@ cmp_eq(x, y) VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t == 0) return TRUE; - return FALSE; + if (t == 0) return Qtrue; + return Qfalse; } static VALUE @@ -34,8 +34,8 @@ cmp_gt(x, y) VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t > 0) return TRUE; - return FALSE; + if (t > 0) return Qtrue; + return Qfalse; } static VALUE @@ -45,8 +45,8 @@ cmp_ge(x, y) VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t >= 0) return TRUE; - return FALSE; + if (t >= 0) return Qtrue; + return Qfalse; } static VALUE @@ -56,8 +56,8 @@ cmp_lt(x, y) VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t < 0) return TRUE; - return FALSE; + if (t < 0) return Qtrue; + return Qfalse; } static VALUE @@ -67,8 +67,8 @@ cmp_le(x, y) VALUE c = rb_funcall(x, cmp, 1, y); int t = NUM2INT(c); - if (t <= 0) return TRUE; - return FALSE; + if (t <= 0) return Qtrue; + return Qfalse; } static VALUE @@ -76,25 +76,25 @@ cmp_between(x, min, max) VALUE x, min, max; { VALUE c = rb_funcall(x, cmp, 1, min); - int t = NUM2INT(c); - if (t < 0) return FALSE; + long t = NUM2LONG(c); + if (t < 0) return Qfalse; c = rb_funcall(x, cmp, 1, max); - t = NUM2INT(c); - if (t > 0) return FALSE; - return TRUE; + t = NUM2LONG(c); + if (t > 0) return Qfalse; + return Qtrue; } void Init_Comparable() { - mComparable = rb_define_module("Comparable"); - rb_define_method(mComparable, "==", cmp_eq, 1); - rb_define_method(mComparable, ">", cmp_gt, 1); - rb_define_method(mComparable, ">=", cmp_ge, 1); - rb_define_method(mComparable, "<", cmp_lt, 1); - rb_define_method(mComparable, "<=", cmp_le, 1); - rb_define_method(mComparable, "between?", cmp_between, 2); + rb_mComparable = rb_define_module("Comparable"); + rb_define_method(rb_mComparable, "==", cmp_eq, 1); + rb_define_method(rb_mComparable, ">", cmp_gt, 1); + rb_define_method(rb_mComparable, ">=", cmp_ge, 1); + rb_define_method(rb_mComparable, "<", cmp_lt, 1); + rb_define_method(rb_mComparable, "<=", cmp_le, 1); + rb_define_method(rb_mComparable, "between?", cmp_between, 2); cmp = rb_intern("<=>"); } diff --git a/config.guess b/config.guess index 91dad5ee6a..042d209871 100644 --- a/config.guess +++ b/config.guess @@ -1,6 +1,6 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc. +# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -63,11 +63,53 @@ trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'` + cat <dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 @@ -78,17 +120,54 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in amiga:NetBSD:*:*) echo m68k-cbm-netbsd${UNAME_RELEASE} exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; - Pyramid*:OSx*:*:*) + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; - sun4*:SunOS:5.*:*) + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) @@ -112,25 +191,84 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; atari*:NetBSD:*:*) echo m68k-atari-netbsd${UNAME_RELEASE} exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; sun3*:NetBSD:*:*) echo m68k-sun-netbsd${UNAME_RELEASE} exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; mac68k:NetBSD:*:*) echo m68k-apple-netbsd${UNAME_RELEASE} exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + macppc:NetBSD:*:*) + echo powerpc-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; - mips:*:4*:UMIPS) - echo mips-mips-riscos4sysv + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; - mips:*:5*:RISCos) + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Night_Hawk:Power_UNIX:*:*) @@ -174,10 +312,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i[34]86:AIX:*:*) + i?86:AIX:*:*) echo i386-ibm-aix exit 0 ;; *:AIX:2:3) @@ -203,7 +341,8 @@ EOF fi exit 0 ;; *:AIX:*:4) - if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc @@ -236,12 +375,44 @@ EOF hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; - 9000/[3478]??:HP-UX:*:*) + 9000/[34678]??:HP-UX:*:*) case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;; - 9000/8?? ) HP_ARCH=hppa1.0 ;; + 9000/6?? | 9000/7?? | 9000/80[24] | 9000/8?[13679] | 9000/892 ) + sed 's/^ //' << EOF >dummy.c + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (${CC-cc} dummy.c -o dummy 2>/dev/null ) && HP_ARCH=`./dummy` + rm -f dummy.c dummy esac HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -288,6 +459,13 @@ EOF hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; @@ -315,18 +493,40 @@ EOF CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} exit 0 ;; - CRAY*C90:*:*:*) - echo c90-cray-unicos${UNAME_RELEASE} + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} exit 0 ;; CRAY-2:*:*:*) echo cray2-cray-unicos exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; hp3[0-9][05]:NetBSD:*:*) echo m68k-hp-netbsd${UNAME_RELEASE} exit 0 ;; - i[34]86:BSD/386:*:* | *:BSD/OS:*:*) + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | i?86:BSD/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; @@ -340,33 +540,142 @@ EOF echo i386-pc-bow exit 0 ;; i*:CYGWIN*:*) - echo i386-pc-cygwin32 + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin32 + echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) - echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; *:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux - exit 0 ;; + # uname on the ARM produces all sorts of strangeness, and we need to + # filter it out. + case "$UNAME_MACHINE" in + arm* | sa110*) UNAME_MACHINE="arm" ;; + esac + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-aout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-coff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-aout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-aout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + echo ${UNAME_MACHINE}-${VENDOR}-linux + exit 0 + fi ;; # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions # are messed up and put the nodename in both sysname and nodename. - i[34]86:DYNIX/ptx:4*:*) + i?86:DYNIX/ptx:4*:*) echo i386-sequent-sysv4 exit 0 ;; - i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*) + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} fi exit 0 ;; - i[34]86:*:3.2:*) + i?86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + fi + echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION} + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; @@ -397,28 +718,36 @@ EOF # "miniframe" echo m68010-convergent-sysv exit 0 ;; - M680[234]0:*:R3V[567]*:*) + M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; - 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0) - uname -p 2>/dev/null | grep 86 >/dev/null \ - && echo i486-ncr-sysv4.3 && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - uname -p 2>/dev/null | grep 86 >/dev/null \ + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; - m680[234]0:LynxOS:2.[23]*:*) - echo m68k-lynx-lynxos${UNAME_RELEASE} + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; - i[34]86:LynxOS:2.[23]*:*) - echo i386-lynx-lynxos${UNAME_RELEASE} + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; - TSUNAMI:LynxOS:2.[23]*:*) - echo sparc-lynx-lynxos${UNAME_RELEASE} + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; - rs6000:LynxOS:2.[23]*:*) - echo rs6000-lynx-lynxos${UNAME_RELEASE} + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 @@ -431,42 +760,58 @@ EOF echo ns32k-sni-sysv fi exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; - X680[02346]0:Human68k:*:*) - echo m68k-sharp-human + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 exit 0 ;; - R[34]000:*System_V*:*:*) + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv`echo ${UNAME_RELEASE} | sed -n 's/\([.0-9]*\).*/\1/p'` else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; - R[34]???:UNIX_SV:4.?MP:*) - if [ -x /sbin/uversion ]; then - UVERSION_RELEASE=`(/sbin/uversion -r) 2>/dev/null` \ - || UVERSION_RELEASE=unknown - UVERSION_SYSTEM=`(/sbin/uversion -s) 2>/dev/null` \ - || UVERSION_SYSTEM=unknown - case "${UVERSION_RELEASE}:${UVERSION_SYSTEM}" in - Release*:EWS4800/*) - suffix=`echo ${UNAME_RELEASE} | tr '[A-Z]' '[a-z]'` - suffix=${suffix}r`echo ${UVERSION_RELEASE} | \ - sed -e 's/Release//' -e 's/ Rev.*$//'` - echo mips-nec-sysv${suffix} - exit 0 ;; - esac - fi;; - *:machten:*:*) - echo ${UNAME_MACHINE}-apple-machten - exit 0 ;; - powerpc:JCC_BSD+:*:*) - echo powerpc-jcc-bsd4.4 - exit 0 ;; DS/90*:*:*:V20*) - echo sparc-fujitsu-uxpds + echo sparc-fujitsu-uxpds + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + + *:Rhapsody:*:*) + arch=`/usr/bin/arch` + case "$arch" in + ppc) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + ;; + i[3456]86) + echo i386-apple-rhapsody${UNAME_RELEASE} + ;; + *) + echo $arch-apple-rhapsody${UNAME_RELEASE} + ;; + esac exit 0 ;; esac @@ -511,7 +856,11 @@ main () #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3"); + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); #endif @@ -567,16 +916,12 @@ main () printf ("i860-alliant-bsd\n"); exit (0); #endif -#if defined (__human68k__) || defined (HUMAN68K) - printf ("m68k-sharp-human\n"); exit (0); -#endif - exit (1); } EOF -${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm -f dummy.c dummy.x dummy && exit 0 -rm -f dummy.c dummy.x dummy +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy # Apollos put the system type in the environment. diff --git a/config.sub b/config.sub index 002d408812..858aba7aa5 100644 --- a/config.sub +++ b/config.sub @@ -1,6 +1,6 @@ #! /bin/sh # Configuration validation subroutine script, version 1.1. -# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. +# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc. # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. @@ -149,35 +149,43 @@ esac case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. - tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \ - | arme[lb] | pyramid \ - | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \ - | alpha | we32k | ns16k | clipper | i370 | sh \ - | powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \ - | pdp11 | mips64el | mips64orion | mips64orionel \ - | sparc | sparclet | sparclite | sparc64) - basic_machine=$basic_machine-unknown - ;; + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. - i[3456]86) + i[34567]86) basic_machine=$basic_machine-pc ;; + i[3456]86-TOWNS*) + basic_machine=`echo $basic_machine | sed -e 's/-TOWNS.*/-TOWNS/'` + ;; # Object if more than one company name word. *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 ;; # Recognize the basic CPU types with company name. - vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \ - | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \ - | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \ - | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \ - | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \ - | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \ - | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \ - | mips64el-* | mips64orion-* | mips64orionel-*) + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. @@ -204,9 +212,9 @@ case $basic_machine in amiga | amiga-*) basic_machine=m68k-cbm ;; - amigados) + amigaos | amigados) basic_machine=m68k-cbm - os=-amigados + os=-amigaos ;; amigaunix | amix) basic_machine=m68k-cbm @@ -292,10 +300,6 @@ case $basic_machine in encore | umax | mmax) basic_machine=ns32k-encore ;; - ews4800) - basic_machine=mips-nec - os=-sysv4 - ;; fx2800) basic_machine=i860-alliant ;; @@ -341,24 +345,27 @@ case $basic_machine in hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; + hppa-next) + os=-nextstep3 + ;; i370-ibm* | ibm*) basic_machine=i370-ibm os=-mvs ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? - i[3456]86v32) + i[34567]86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; - i[3456]86v4*) + i[34567]86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; - i[3456]86v) + i[34567]86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; - i[3456]86sol2) + i[34567]86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; @@ -390,6 +397,14 @@ case $basic_machine in miniframe) basic_machine=m68000-convergent ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux + ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; @@ -457,25 +472,23 @@ case $basic_machine in pc532 | pc532-*) basic_machine=ns32k-pc532 ;; - pentium | p5) - basic_machine=i586-intel + pentium | p5 | k5 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | k6 | 6x86) + basic_machine=i686-pc ;; - pentiumpro | p6) - basic_machine=i686-intel + pentiumii | pentium2) + basic_machine=i786-pc ;; - pentium-* | p5-*) + pentium-* | p5-* | k5-* | nexen-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - pentiumpro-* | p6-*) + pentiumpro-* | p6-* | k6-* | 6x86-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - k5) - # We don't have specific support for AMD's K5 yet, so just call it a Pentium - basic_machine=i586-amd - ;; - nexen) - # We don't have specific support for Nexgen yet, so just call it a Pentium - basic_machine=i586-nexgen + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould @@ -559,6 +572,12 @@ case $basic_machine in basic_machine=i386-sequent os=-dynix ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; tower | tower-32) basic_machine=m68k-ncr ;; @@ -578,6 +597,9 @@ case $basic_machine in basic_machine=vax-dec os=-vms ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; vxworks960) basic_machine=i960-wrs os=-vxworks @@ -605,7 +627,11 @@ case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. mips) - basic_machine=mips-mips + if [ x$os = x-linux ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi ;; romp) basic_machine=romp-ibm @@ -634,10 +660,6 @@ case $basic_machine in orion105) basic_machine=clipper-highlevel ;; - human) - basic_machine=m68k-sharp - os=-human - ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 @@ -652,6 +674,10 @@ case $basic_machine in *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; + human) + basic_machine=m68k-sharp + os=-human + ;; *) ;; esac @@ -670,9 +696,12 @@ case $os in -solaris) os=-solaris2 ;; - -unixware* | svr4*) + -svr4*) os=-sysv4 ;; + -unixware*) + os=-sysv4.2uw + ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; @@ -683,15 +712,16 @@ case $os in -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \ - | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \ - | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -cygwin32* | -pe* | -psos* | -moss* | -proelf* \ - | -linux* | -bow*) + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux* | -uxpv* | -beos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -sunos5*) @@ -754,6 +784,9 @@ case $os in ;; -human) ;; + -beos) + os=-beos + ;; -none) ;; *) @@ -806,6 +839,9 @@ case $basic_machine in sparc-* | *-sun) os=-sunos4.1.1 ;; + *-be) + os=-beos + ;; *-ibm) os=-aix ;; @@ -819,7 +855,7 @@ case $basic_machine in os=-sysv ;; *-cbm) - os=-amigados + os=-amigaos ;; *-dg) os=-dgux @@ -869,6 +905,9 @@ case $basic_machine in *-masscomp) os=-rtu ;; + f301-fujitsu) + os=-uxpv + ;; *) os=-none ;; @@ -887,9 +926,6 @@ case $basic_machine in -sunos*) vendor=sun ;; - -lynxos*) - vendor=lynx - ;; -aix*) vendor=ibm ;; @@ -917,7 +953,7 @@ case $basic_machine in -ptx*) vendor=sequent ;; - -vxworks*) + -vxsim* | -vxworks*) vendor=wrs ;; -aux*) diff --git a/configure b/configure index dd18efc8b4..31a40f05e8 100644 --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated automatically using autoconf version 2.12 +# Generated automatically using autoconf version 2.12.2 # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation @@ -16,7 +16,7 @@ ac_help="$ac_help ac_help="$ac_help --disable-thread never use user-level thread" ac_help="$ac_help ---enable-fat-binary build a NeXT Multi Architecture Binary. " +--enable-fat-binary build a NeXT/Apple Multi Architecture Binary. " ac_help="$ac_help --with-dln-a-out use dln_a_out if possible" ac_help="$ac_help @@ -59,6 +59,7 @@ mandir='${prefix}/man' # Initialize some other variables. subdirs= MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. ac_max_here_lines=12 @@ -342,7 +343,7 @@ EOF verbose=yes ;; -version | --version | --versio | --versi | --vers) - echo "configure generated by autoconf version 2.12" + echo "configure generated by autoconf version 2.12.2" exit 0 ;; -with-* | --with-*) @@ -512,9 +513,11 @@ ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross +ac_exeext= +ac_objext=o if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then @@ -562,7 +565,7 @@ fi if test $rb_thread = yes; then cat >> confdefs.h <<\EOF -#define THREAD 1 +#define USE_THREAD 1 EOF fi @@ -588,33 +591,32 @@ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # Make sure we can run config.sub. -if $ac_config_sub sun4 >/dev/null 2>&1; then : +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:597: checking host system type" >&5 +echo "configure:600: checking host system type" >&5 host_alias=$host case "$host_alias" in NONE) case $nonopt in NONE) - if host_alias=`$ac_config_guess`; then : + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } fi ;; *) host_alias=$nonopt ;; esac ;; esac -host=`$ac_config_sub $host_alias` +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 - fat_binary=no # Check whether --enable-fat-binary or --disable-fat-binary was given. if test "${enable_fat_binary+set}" = set; then @@ -622,18 +624,38 @@ if test "${enable_fat_binary+set}" = set; then fat_binary=$enableval fi -if test "$fat_binary" = yes ; then + if test "$fat_binary" = yes ; then echo $ac_n "checking target architecture ""... $ac_c" 1>&6 -echo "configure:629: checking target architecture " >&5 +echo "configure:631: checking target architecture " >&5 - if test "$TARGET_ARCHS" = "" ; then - if test `/usr/bin/arch` = "m68k" ; then - TARGET_ARCHS="m68k i486" + case "$host_os" in + rhapsody*) + echo -n "MacOS X Server: " + if test "$TARGET_ARCHS" = "" ; then + TARGET_ARCHS="ppc i386" + fi + ;; + nextstep*|openstep*) + echo -n "NeXTSTEP/OPENSTEP: " + + if test "$host_os" = "rhapsody" ; then + echo -n "Rhapsody: " + if test "$TARGET_ARCHS" = "" ; then + TARGET_ARCHS="ppc i486" + fi else - TARGET_ARCHS="m68k `/usr/bin/arch`" + echo -n "NeXTSTEP/OPENSTEP: " + if test "$TARGET_ARCHS" = "" ; then + if test `/usr/bin/arch` = "m68k" ; then + TARGET_ARCHS="m68k i486" + else # Black and Native one + TARGET_ARCHS="m68k `/usr/bin/arch`" + fi + fi fi - fi + ;; + esac # /usr/lib/arch_tool -archify_list $TARGET_ARCHS for archs in $TARGET_ARCHS do @@ -647,7 +669,6 @@ EOF echo "." fi - if test "$program_transform_name" = s,x,x,; then program_transform_name= else @@ -671,15 +692,16 @@ test "$program_transform_name" = "" && program_transform_name="s,x,x," # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:675: checking for $ac_word" >&5 +echo "configure:696: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" @@ -700,16 +722,17 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:704: checking for $ac_word" >&5 +echo "configure:726: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" ac_prog_rejected=no - for ac_dir in $PATH; do + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then @@ -744,25 +767,61 @@ else echo "$ac_t""no" 1>&6 fi + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:777: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:752: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:809: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' -ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' cross_compiling=$ac_cv_prog_cc_cross -cat > conftest.$ac_ext < conftest.$ac_ext << EOF + +#line 820 "configure" #include "confdefs.h" + main(){return(0);} EOF -if { (eval echo configure:766: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:825: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -776,18 +835,24 @@ else ac_cv_prog_cc_works=no fi rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:786: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:851: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:791: checking whether we are using GNU C" >&5 +echo "configure:856: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -796,7 +861,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:800: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:865: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -807,11 +872,15 @@ echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes - ac_test_CFLAGS="${CFLAGS+set}" - ac_save_CFLAGS="$CFLAGS" - CFLAGS= - echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:815: checking whether ${CC-cc} accepts -g" >&5 +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:884: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -826,20 +895,24 @@ rm -f conftest* fi echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 - if test "$ac_test_CFLAGS" = set; then - CFLAGS="$ac_save_CFLAGS" - elif test $ac_cv_prog_cc_g = yes; then +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then CFLAGS="-g -O2" else - CFLAGS="-O2" + CFLAGS="-g" fi else - GCC= - test "${CFLAGS+set}" = set || CFLAGS="-g" + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:843: checking how to run the C preprocessor" >&5 +echo "configure:916: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -854,14 +927,14 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:864: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` +{ (eval echo configure:937: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else @@ -871,14 +944,31 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:881: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` +{ (eval echo configure:954: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:971: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : else @@ -890,6 +980,8 @@ else fi rm -f conftest* fi +rm -f conftest* +fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi @@ -901,13 +993,13 @@ echo "$ac_t""$CPP" 1>&6 if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 -echo "configure:905: checking whether ${CC-cc} needs -traditional" >&5 +echo "configure:997: checking whether ${CC-cc} needs -traditional" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext < Autoconf TIOCGETP @@ -925,7 +1017,7 @@ rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext < Autoconf TCGETA @@ -951,15 +1043,16 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:955: checking for $ac_word" >&5 +echo "configure:1047: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_YACC="$ac_prog" @@ -983,15 +1076,16 @@ test -n "$YACC" || YACC="yacc" # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:987: checking for $ac_word" >&5 +echo "configure:1080: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" @@ -1015,15 +1109,16 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1019: checking for $ac_word" >&5 +echo "configure:1113: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" - for ac_dir in $PATH; do + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_AR="$ac_prog" @@ -1051,28 +1146,30 @@ test -n "$AR" || AR="ar" # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1059: checking for a BSD compatible install" >&5 +echo "configure:1155: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else - IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. - for ac_prog in ginstall installbsd scoinst install; do + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. - # OSF/1 installbsd also uses dspmsg, but is usable. : else ac_cv_path_install="$ac_dir/$ac_prog -c" @@ -1102,10 +1199,12 @@ echo "$ac_t""$INSTALL" 1>&6 # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:1109: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:1208: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1135,18 +1234,18 @@ fi # checks for UNIX variants that set C preprocessor variables ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 -echo "configure:1139: checking for minix/config.h" >&5 +echo "configure:1238: checking for minix/config.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1149: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` +{ (eval echo configure:1248: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" @@ -1183,13 +1282,243 @@ EOF fi +echo $ac_n "checking size of int""... $ac_c" 1>&6 +echo "configure:1287: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int)); + exit(0); +} +EOF +if { (eval echo configure:1306: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1326: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long)); + exit(0); +} +EOF +if { (eval echo configure:1345: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1365: checking size of void*" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_voidp'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(void*)); + exit(0); +} +EOF +if { (eval echo configure:1384: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_voidp=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_voidp=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_voidp" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1405: checking for prototypes" >&5 +if eval "test \"`echo '$''{'rb_cv_have_prototypes'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + rb_cv_have_prototypes=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + rb_cv_have_prototypes=no +fi +rm -f conftest* +fi + +echo "$ac_t""$rb_cv_have_prototypes" 1>&6 +if test "$rb_cv_have_prototypes" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_PROTOTYPES 1 +EOF + +fi + +echo $ac_n "checking for variable length prototypes and stdarg.h""... $ac_c" 1>&6 +echo "configure:1438: checking for variable length prototypes and stdarg.h" >&5 +if eval "test \"`echo '$''{'rb_cv_stdarg'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int foo(int x, ...) { + va_list va; + va_start(va, x); + va_arg(va, int); + va_arg(va, char *); + va_arg(va, double); + return 0; +} + +int main() { +return foo(10, "", 3.14); +; return 0; } +EOF +if { (eval echo configure:1460: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + rb_cv_stdarg=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + rb_cv_stdarg=no +fi +rm -f conftest* +fi + +echo "$ac_t""$rb_cv_stdarg" 1>&6 +if test "$rb_cv_stdarg" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_STDARG_PROTOTYPES 1 +EOF + +fi + +echo $ac_n "checking for gcc attribute noreturn""... $ac_c" 1>&6 +echo "configure:1481: checking for gcc attribute noreturn" >&5 +if eval "test \"`echo '$''{'rb_cv_have_attr_noreturn'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + rb_cv_have_attr_noreturn=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + rb_cv_have_attr_noreturn=no +fi +rm -f conftest* +fi + +echo "$ac_t""$rb_cv_have_attr_noreturn" 1>&6 +if test "$rb_cv_have_attr_noreturn" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ATTR_NORETURN 1 +EOF + +fi + case "$host_os" in nextstep*) ;; +openstep*) ;; +rhapsody*) ;; human*) ;; +beos*) ;; *) LIBS="-lm $LIBS";; esac echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 -echo "configure:1193: checking for crypt in -lcrypt" >&5 +echo "configure:1522: checking for crypt in -lcrypt" >&5 ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1197,7 +1526,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lcrypt $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1541: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1236,7 +1565,7 @@ else fi echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:1240: checking for dlopen in -ldl" >&5 +echo "configure:1569: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1244,7 +1573,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1283,7 +1612,7 @@ else fi # Dynamic linking for SunOS/Solaris and SYSV echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 -echo "configure:1287: checking for shl_load in -ldld" >&5 +echo "configure:1616: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1291,7 +1620,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1635: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1329,18 +1658,65 @@ else echo "$ac_t""no" 1>&6 fi # Dynamic linking for HP-UX +echo $ac_n "checking for setlocale in -lxpg4""... $ac_c" 1>&6 +echo "configure:1663: checking for setlocale in -lxpg4" >&5 +ac_lib_var=`echo xpg4'_'setlocale | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lxpg4 $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo xpg4 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + # FreeBSD needs this ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 -echo "configure:1339: checking for $ac_hdr that defines DIR" >&5 +echo "configure:1715: checking for $ac_hdr that defines DIR" >&5 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_hdr> @@ -1348,7 +1724,7 @@ int main() { DIR *dirp = 0; ; return 0; } EOF -if { (eval echo configure:1352: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1728: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else @@ -1373,7 +1749,7 @@ done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 -echo "configure:1377: checking for opendir in -ldir" >&5 +echo "configure:1753: checking for opendir in -ldir" >&5 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1381,7 +1757,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1414,7 +1790,7 @@ fi else echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 -echo "configure:1418: checking for opendir in -lx" >&5 +echo "configure:1794: checking for opendir in -lx" >&5 ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1422,7 +1798,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lx $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:1813: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1456,12 +1832,12 @@ fi fi echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:1460: checking for ANSI C header files" >&5 +echo "configure:1836: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1469,8 +1845,8 @@ else #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1473: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` +{ (eval echo configure:1849: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes @@ -1486,7 +1862,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1504,7 +1880,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF @@ -1525,7 +1901,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -1536,7 +1912,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:1540: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1916: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -1561,22 +1937,22 @@ fi for ac_hdr in stdlib.h unistd.h limits.h sys/file.h sys/ioctl.h pwd.h \ sys/select.h sys/time.h sys/times.h sys/param.h sys/wait.h\ - syscall.h a.out.h string.h utime.h memory.h + syscall.h a.out.h string.h utime.h memory.h direct.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1569: checking for $ac_hdr" >&5 +echo "configure:1945: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1579: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` +{ (eval echo configure:1955: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" @@ -1603,12 +1979,12 @@ done echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:1607: checking for uid_t in sys/types.h" >&5 +echo "configure:1983: checking for uid_t in sys/types.h" >&5 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF @@ -1637,12 +2013,12 @@ EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 -echo "configure:1641: checking for size_t" >&5 +echo "configure:2017: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -1651,7 +2027,7 @@ else #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else @@ -1670,12 +2046,12 @@ EOF fi echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 -echo "configure:1674: checking for st_blksize in struct stat" >&5 +echo "configure:2050: checking for st_blksize in struct stat" >&5 if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -1683,7 +2059,7 @@ int main() { struct stat s; s.st_blksize; ; return 0; } EOF -if { (eval echo configure:1687: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2063: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_st_blksize=yes else @@ -1705,236 +2081,79 @@ fi save_LIBOJBS="$LIBOBJS" echo $ac_n "checking for st_blocks in struct stat""... $ac_c" 1>&6 -echo "configure:1709: checking for st_blocks in struct stat" >&5 -if eval "test \"`echo '$''{'ac_cv_struct_st_blocks'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#include -int main() { -struct stat s; s.st_blocks; -; return 0; } -EOF -if { (eval echo configure:1722: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_struct_st_blocks=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_struct_st_blocks=no -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_struct_st_blocks" 1>&6 -if test $ac_cv_struct_st_blocks = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_ST_BLOCKS 1 -EOF - -else - LIBOBJS="$LIBOBJS fileblocks.o" -fi - -LIBOBJS="$save_LIBOBJS" -echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6 -echo "configure:1746: checking for st_rdev in struct stat" >&5 -if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#include -int main() { -struct stat s; s.st_rdev; -; return 0; } -EOF -if { (eval echo configure:1759: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - ac_cv_struct_st_rdev=yes -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - ac_cv_struct_st_rdev=no -fi -rm -f conftest* -fi - -echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6 -if test $ac_cv_struct_st_rdev = yes; then - cat >> confdefs.h <<\EOF -#define HAVE_ST_RDEV 1 -EOF - -fi - - -echo $ac_n "checking size of short""... $ac_c" 1>&6 -echo "configure:1781: checking size of short" >&5 -if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else - cat > conftest.$ac_ext < -main() -{ - FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof(short)); - exit(0); -} -EOF -if { (eval echo configure:1800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_sizeof_short=`cat conftestval` -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_sizeof_short=0 -fi -rm -fr conftest* -fi - -fi -echo "$ac_t""$ac_cv_sizeof_short" 1>&6 -cat >> confdefs.h <&6 -echo "configure:1820: checking size of int" >&5 -if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } -else - cat > conftest.$ac_ext < -main() -{ - FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof(int)); - exit(0); -} -EOF -if { (eval echo configure:1839: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_sizeof_int=`cat conftestval` -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_sizeof_int=0 -fi -rm -fr conftest* -fi - -fi -echo "$ac_t""$ac_cv_sizeof_int" 1>&6 -cat >> confdefs.h <&6 -echo "configure:1859: checking size of long" >&5 -if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +echo "configure:2085: checking for st_blocks in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blocks'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < -main() -{ - FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof(long)); - exit(0); -} +#include +#include +int main() { +struct stat s; s.st_blocks; +; return 0; } EOF -if { (eval echo configure:1878: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_sizeof_long=`cat conftestval` +if { (eval echo configure:2098: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blocks=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_sizeof_long=0 + rm -rf conftest* + ac_cv_struct_st_blocks=no fi -rm -fr conftest* +rm -f conftest* fi -fi -echo "$ac_t""$ac_cv_sizeof_long" 1>&6 -cat >> confdefs.h <&6 +if test $ac_cv_struct_st_blocks = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLOCKS 1 EOF +else + LIBOBJS="$LIBOBJS fileblocks.${ac_objext}" +fi -echo $ac_n "checking size of void*""... $ac_c" 1>&6 -echo "configure:1898: checking size of void*" >&5 -if eval "test \"`echo '$''{'ac_cv_sizeof_voidp'+set}'`\" = set"; then +LIBOBJS="$save_LIBOBJS" +echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6 +echo "configure:2122: checking for st_rdev in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 -else - if test "$cross_compiling" = yes; then - { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < -main() -{ - FILE *f=fopen("conftestval", "w"); - if (!f) exit(1); - fprintf(f, "%d\n", sizeof(void*)); - exit(0); -} +#include +#include +int main() { +struct stat s; s.st_rdev; +; return 0; } EOF -if { (eval echo configure:1917: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null -then - ac_cv_sizeof_voidp=`cat conftestval` +if { (eval echo configure:2135: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_rdev=yes else echo "configure: failed program was:" >&5 cat conftest.$ac_ext >&5 - rm -fr conftest* - ac_cv_sizeof_voidp=0 + rm -rf conftest* + ac_cv_struct_st_rdev=no fi -rm -fr conftest* +rm -f conftest* fi -fi -echo "$ac_t""$ac_cv_sizeof_voidp" 1>&6 -cat >> confdefs.h <&6 +if test $ac_cv_struct_st_rdev = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_RDEV 1 EOF +fi echo $ac_n "checking type of array argument to getgroups""... $ac_c" 1>&6 -echo "configure:1938: checking type of array argument to getgroups" >&5 +echo "configure:2157: checking type of array argument to getgroups" >&5 if eval "test \"`echo '$''{'ac_cv_type_getgroups'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1942,7 +2161,7 @@ else ac_cv_type_getgroups=cross else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2190: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_type_getgroups=gid_t else @@ -1981,7 +2200,7 @@ fi if test $ac_cv_type_getgroups = cross; then cat > conftest.$ac_ext < EOF @@ -2005,12 +2224,12 @@ EOF echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 -echo "configure:2009: checking return type of signal handlers" >&5 +echo "configure:2228: checking return type of signal handlers" >&5 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -2027,7 +2246,7 @@ int main() { int i; ; return 0; } EOF -if { (eval echo configure:2031: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2250: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else @@ -2048,19 +2267,19 @@ EOF # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:2052: checking for working alloca.h" >&5 +echo "configure:2271: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:2064: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2283: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_header_alloca_h=yes else @@ -2081,25 +2300,30 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:2085: checking for alloca" >&5 +echo "configure:2304: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < +# ifdef _MSC_VER +# include +# define alloca _alloca # else -# ifdef _AIX - #pragma alloca +# if HAVE_ALLOCA_H +# include # else -# ifndef alloca /* predefined by HP cc +Olibcalls */ +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); +# endif # endif # endif # endif @@ -2109,7 +2333,7 @@ int main() { char *p = (char *) alloca(1); ; return 0; } EOF -if { (eval echo configure:2113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2337: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_alloca_works=yes else @@ -2134,19 +2358,19 @@ if test $ac_cv_func_alloca_works = no; then # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. - ALLOCA=alloca.o + ALLOCA=alloca.${ac_objext} cat >> confdefs.h <<\EOF #define C_ALLOCA 1 EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:2145: checking whether alloca needs Cray hooks" >&5 +echo "configure:2369: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2175: checking for $ac_func" >&5 +echo "configure:2399: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2427: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2226,7 +2450,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:2230: checking stack direction for C alloca" >&5 +echo "configure:2454: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2234,7 +2458,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2481: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else @@ -2275,12 +2499,12 @@ EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&6 -echo "configure:2279: checking for pid_t" >&5 +echo "configure:2503: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS @@ -2289,7 +2513,7 @@ else #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_pid_t=yes else @@ -2309,18 +2533,18 @@ fi ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for vfork.h""... $ac_c" 1>&6 -echo "configure:2313: checking for vfork.h" >&5 +echo "configure:2537: checking for vfork.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2323: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } -ac_err=`grep -v '^ *+' conftest.out` +{ (eval echo configure:2547: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" @@ -2344,18 +2568,18 @@ else fi echo $ac_n "checking for working vfork""... $ac_c" 1>&6 -echo "configure:2348: checking for working vfork" >&5 +echo "configure:2572: checking for working vfork" >&5 if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then echo $ac_n "checking for vfork""... $ac_c" 1>&6 -echo "configure:2354: checking for vfork" >&5 +echo "configure:2578: checking for vfork" >&5 if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2606: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_vfork=yes" else @@ -2397,9 +2621,10 @@ else echo "$ac_t""no" 1>&6 fi +ac_cv_func_vfork_works=$ac_cv_func_vfork else cat > conftest.$ac_ext < @@ -2494,7 +2719,7 @@ main() { } } EOF -if { (eval echo configure:2498: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:2723: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_vfork_works=yes else @@ -2516,16 +2741,52 @@ EOF fi -for ac_func in dup2 setenv memmove mkdir strcasecmp strerror strftime\ - strstr strtoul strdup crypt flock +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:2746: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +for ac_func in dup2 memmove mkdir strcasecmp strerror strftime\ + strchr strstr strtoul strdup crypt flock vsnprintf do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2524: checking for $ac_func" >&5 +echo "configure:2785: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2813: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2569,24 +2830,24 @@ EOF else echo "$ac_t""no" 1>&6 -LIBOBJS="$LIBOBJS ${ac_func}.o" +LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" fi done -for ac_func in fmod killpg random wait4 waitpid syscall getcwd\ +for ac_func in fmod killpg drand48 random wait4 waitpid syscall getcwd\ truncate chsize times utimes fcntl lockf setitimer\ setruid seteuid setreuid setrgid setegid setregid\ - setpgrp2 getpgid getgroups getpriority\ - dlopen sigprocmask sigaction _setjmp + setpgrp2 getpgid setpgid getgroups getpriority\ + dlopen sigprocmask sigaction _setjmp setpgrp setsid do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:2585: checking for $ac_func" >&5 +echo "configure:2846: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2874: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -2635,12 +2896,12 @@ done if test "$ac_cv_func_strftime" = no; then echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 -echo "configure:2639: checking whether struct tm is in sys/time.h or time.h" >&5 +echo "configure:2900: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include @@ -2648,7 +2909,7 @@ int main() { struct tm *tp; tp->tm_sec; ; return 0; } EOF -if { (eval echo configure:2652: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2913: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else @@ -2669,12 +2930,12 @@ EOF fi echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 -echo "configure:2673: checking for tm_zone in struct tm" >&5 +echo "configure:2934: checking for tm_zone in struct tm" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> @@ -2682,7 +2943,7 @@ int main() { struct tm tm; tm.tm_zone; ; return 0; } EOF -if { (eval echo configure:2686: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2947: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else @@ -2702,12 +2963,12 @@ EOF else echo $ac_n "checking for tzname""... $ac_c" 1>&6 -echo "configure:2706: checking for tzname" >&5 +echo "configure:2967: checking for tzname" >&5 if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ @@ -2717,7 +2978,7 @@ int main() { atoi(*tzname); ; return 0; } EOF -if { (eval echo configure:2721: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:2982: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_var_tzname=yes else @@ -2739,14 +3000,14 @@ EOF fi cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3011: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_DAYLIGHT 1 @@ -2766,7 +3027,7 @@ EOF else echo $ac_n "checking for BSD signal semantics""... $ac_c" 1>&6 -echo "configure:2770: checking for BSD signal semantics" >&5 +echo "configure:3031: checking for BSD signal semantics" >&5 if eval "test \"`echo '$''{'rb_cv_bsd_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2774,7 +3035,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < @@ -2796,7 +3057,7 @@ main() } EOF -if { (eval echo configure:2800: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3061: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then rb_cv_bsd_signal=yes else @@ -2830,19 +3091,19 @@ EOF else echo $ac_n "checking whether getpgrp() has arg""... $ac_c" 1>&6 -echo "configure:2834: checking whether getpgrp() has arg" >&5 +echo "configure:3095: checking whether getpgrp() has arg" >&5 if eval "test \"`echo '$''{'rb_cv_bsdgetpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { getpgrp(0); ; return 0; } EOF -if { (eval echo configure:2846: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3107: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_bsdgetpgrp=yes else @@ -2863,19 +3124,19 @@ EOF fi echo $ac_n "checking whether setpgrp() has args""... $ac_c" 1>&6 -echo "configure:2867: checking whether setpgrp() has args" >&5 +echo "configure:3128: checking whether setpgrp() has args" >&5 if eval "test \"`echo '$''{'rb_cv_bsdsetpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { setpgrp(1, 1); ; return 0; } EOF -if { (eval echo configure:2879: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3140: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_bsdsetpgrp=yes else @@ -2897,14 +3158,14 @@ EOF fi echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 -echo "configure:2901: checking whether byte ordering is bigendian" >&5 +echo "configure:3162: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include @@ -2915,11 +3176,11 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:2919: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3180: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include @@ -2930,7 +3191,7 @@ int main() { #endif ; return 0; } EOF -if { (eval echo configure:2934: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3195: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else @@ -2950,7 +3211,7 @@ if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3228: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else @@ -2987,14 +3248,14 @@ EOF fi echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6 -echo "configure:2991: checking whether char is unsigned" >&5 +echo "configure:3252: checking whether char is unsigned" >&5 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3291: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_char_unsigned=yes else @@ -3050,20 +3311,68 @@ EOF fi +echo $ac_n "checking whether right shift preserve sign bit""... $ac_c" 1>&6 +echo "configure:3316: checking whether right shift preserve sign bit" >&5 +if eval "test \"`echo '$''{'rb_cv_rshift_sign'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <>1)) + return 0; + return 1; +} + +EOF +if { (eval echo configure:3336: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + rb_cv_rshift_sign=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + rb_cv_rshift_sign=no +fi +rm -fr conftest* +fi + +fi + + echo "$ac_t""$rb_cv_rshift_sign" 1>&6 +if test "$rb_cv_rshift_sign" = yes; then + cat >> confdefs.h <<\EOF +#define RSHIFT(x,y) ((x)>>y) +EOF + +else + cat >> confdefs.h <<\EOF +#define RSHIFT(x,y) (((x)<0) ? ~((~(x))>>y) : (x)>>y) +EOF + +fi + echo $ac_n "checking count field in FILE structures""... $ac_c" 1>&6 -echo "configure:3055: checking count field in FILE structures" >&5 +echo "configure:3364: checking count field in FILE structures" >&5 if eval "test \"`echo '$''{'rb_cv_fcnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { FILE *f = stdin; f->_cnt = 0; ; return 0; } EOF -if { (eval echo configure:3067: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3376: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_fcnt="_cnt" else @@ -3073,14 +3382,14 @@ fi rm -f conftest* if test "$rb_cv_fcnt" = ""; then cat > conftest.$ac_ext < int main() { FILE *f = stdin; f->__cnt = 0; ; return 0; } EOF -if { (eval echo configure:3084: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3393: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_fcnt="__cnt" else @@ -3091,14 +3400,14 @@ rm -f conftest* fi if test "$rb_cv_fcnt" = ""; then cat > conftest.$ac_ext < int main() { FILE *f = stdin; f->_r = 0; ; return 0; } EOF -if { (eval echo configure:3102: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3411: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_fcnt="_r" else @@ -3109,14 +3418,14 @@ rm -f conftest* fi if test "$rb_cv_fcnt" = ""; then cat > conftest.$ac_ext < int main() { FILE *f = stdin; f->readCount = 0; ; return 0; } EOF -if { (eval echo configure:3120: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3429: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_fcnt="readCount" else @@ -3139,102 +3448,6 @@ EOF fi -if test "$ac_cv_func_getpwent" = yes; then - echo $ac_n "checking struct passwd""... $ac_c" 1>&6 -echo "configure:3145: checking struct passwd" >&5 - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pw_change" >/dev/null 2>&1; then - rm -rf conftest* - cat >> confdefs.h <<\EOF -#define PW_CHANGE 1 -EOF - -fi -rm -f conftest* - - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pw_quota" >/dev/null 2>&1; then - rm -rf conftest* - cat >> confdefs.h <<\EOF -#define PW_QUOTA 1 -EOF - -fi -rm -f conftest* - - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pw_age" >/dev/null 2>&1; then - rm -rf conftest* - cat >> confdefs.h <<\EOF -#define PW_AGE 1 -EOF - -fi -rm -f conftest* - - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pw_class" >/dev/null 2>&1; then - rm -rf conftest* - cat >> confdefs.h <<\EOF -#define PW_CLASS 1 -EOF - -fi -rm -f conftest* - - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pw_comment" >/dev/null 2>&1; then - rm -rf conftest* - cat >> confdefs.h <<\EOF -#define PW_COMMENT 1 -EOF - -fi -rm -f conftest* - - cat > conftest.$ac_ext < -EOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "pw_expire" >/dev/null 2>&1; then - rm -rf conftest* - cat >> confdefs.h <<\EOF -#define PW_EXPIRE 1 -EOF - -fi -rm -f conftest* - - echo "$ac_t""done" 1>&6 -fi - # Check whether --with-dln-a-out or --without-dln-a-out was given. if test "${with_dln_a_out+set}" = set; then withval="$with_dln_a_out" @@ -3251,7 +3464,7 @@ fi case "$host_os" in linux*) echo $ac_n "checking whether ELF binaries are produced""... $ac_c" 1>&6 -echo "configure:3255: checking whether ELF binaries are produced" >&5 +echo "configure:3468: checking whether ELF binaries are produced" >&5 if eval "test \"`echo '$''{'rb_cv_linux_elf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3259,7 +3472,7 @@ else : else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3496: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then rb_cv_linux_elf=yes else @@ -3309,11 +3522,14 @@ STATIC= if test "$with_dln_a_out" != yes; then rb_cv_dlopen=unknown echo $ac_n "checking whether OS depend dynamic link works""... $ac_c" 1>&6 -echo "configure:3313: checking whether OS depend dynamic link works" >&5 +echo "configure:3526: checking whether OS depend dynamic link works" >&5 if test "$GCC" = yes; then case "$host_os" in nextstep*) ;; + openstep*) ;; + rhapsody*) ;; human*) ;; + cygwin*) CCDLFLAGS=-DDLLIMPORT;; *) CCDLFLAGS=-fpic;; esac else @@ -3343,21 +3559,44 @@ echo "configure:3313: checking whether OS depend dynamic link works" >&5 rb_cv_dlopen=yes ;; linux*) LDSHARED="gcc -shared" rb_cv_dlopen=yes ;; + freebsd3*) LDSHARED="ld -Bshareable" + LDFLAGS="-rdynamic" + rb_cv_dlopen=yes ;; freebsd*) LDSHARED="ld -Bshareable" rb_cv_dlopen=yes ;; netbsd*) LDSHARED="ld -Bshareable" rb_cv_dlopen=yes ;; - openbsd*) LDSHARED="ld -Bshareable" + openbsd*) LDSHARED="ld -Bforcearchive -Bshareable" + CCDLFLAGS=-fPIC rb_cv_dlopen=yes ;; nextstep*) LDSHARED='cc -r' LDFLAGS="-u libsys_s" DLDFLAGS="$ARCH_FLAG" rb_cv_dlopen=yes ;; + openstep*) LDSHARED='cc -dynamic -bundle -undefined suppress' + LDFLAGS="" + DLDFLAGS="$ARCH_FLAG" + rb_cv_dlopen=yes ;; + rhapsody*) LDSHARED='cc -dynamic -bundle -undefined suppress' + LDFLAGS="" + DLDFLAGS="$ARCH_FLAG" + rb_cv_dlopen=yes ;; aix*) LDSHARED='../../miniruby ../aix_ld.rb $(TARGET)' rb_cv_dlopen=yes ;; human*) DLDFLAGS='' LDSHARED='' LDFLAGS='' ;; + beos*) LDSHARED="ld -xms" + case "$host_cpu" in + powerpc*) + DLDFLAGS="-f ruby.exp -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o" + ;; + *) + DLDFLAGS="ruby.def -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o" + ;; + esac + rb_cv_dlopen=yes ;; + cygwin*) LDSHARED='../../miniruby ../cygwin32_ld.rb' ;; *) LDSHARED='ld' ;; esac echo "$ac_t""$rb_cv_dlopen" 1>&6 @@ -3367,13 +3606,13 @@ dln_a_out_works=no if test "$ac_cv_header_a_out_h" = yes; then if test "$with_dln_a_out" = yes || test "$rb_cv_dlopen" = unknown; then echo $ac_n "checking whether matz's dln works""... $ac_c" 1>&6 -echo "configure:3371: checking whether matz's dln works" >&5 +echo "configure:3610: checking whether matz's dln works" >&5 cat confdefs.h > config.h if eval "test \"`echo '$''{'rb_cv_dln_a_out'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:3626: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* rb_cv_dln_a_out=yes else @@ -3429,6 +3668,21 @@ EOF cat >> confdefs.h <<\EOF #define DLEXT ".o" EOF +;; + openstep*) DLEXT=bundle + cat >> confdefs.h <<\EOF +#define DLEXT ".bundle" +EOF +;; + rhapsody*) DLEXT=bundle + cat >> confdefs.h <<\EOF +#define DLEXT ".bundle" +EOF +;; + cygwin*) DLEXT=dll + cat >> confdefs.h <<\EOF +#define DLEXT ".dll" +EOF ;; *) DLEXT=so cat >> confdefs.h <<\EOF @@ -3449,6 +3703,10 @@ case "$host_os" in STRIP='strip -S -x';; nextstep*) STRIP='strip -A -n';; + openstep*) + STRIP='strip -A -n';; + rhapsody*) + STRIP='strip -A -n';; esac EXTSTATIC= @@ -3466,7 +3724,7 @@ fi case "$host_os" in human*) echo $ac_n "checking for _harderr in -lsignal""... $ac_c" 1>&6 -echo "configure:3470: checking for _harderr in -lsignal" >&5 +echo "configure:3728: checking for _harderr in -lsignal" >&5 ac_lib_var=`echo signal'_'_harderr | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3474,7 +3732,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lsignal $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3513,7 +3771,7 @@ else fi echo $ac_n "checking for hmemset in -lhmem""... $ac_c" 1>&6 -echo "configure:3517: checking for hmemset in -lhmem" >&5 +echo "configure:3775: checking for hmemset in -lhmem" >&5 ac_lib_var=`echo hmem'_'hmemset | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -3521,7 +3779,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lhmem $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -3562,12 +3820,12 @@ fi for ac_func in select do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:3566: checking for $ac_func" >&5 +echo "configure:3824: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then +if { (eval echo configure:3852: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -3615,7 +3873,7 @@ fi done echo $ac_n "checking whether PD libc _dtos18 fail to convert big number""... $ac_c" 1>&6 -echo "configure:3619: checking whether PD libc _dtos18 fail to convert big number" >&5 +echo "configure:3877: checking whether PD libc _dtos18 fail to convert big number" >&5 if eval "test \"`echo '$''{'rb_cv_missing__dtos18'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3623,7 +3881,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < @@ -3635,7 +3893,7 @@ main () } EOF -if { (eval echo configure:3639: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3897: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then rb_cv_missing__dtos18=yes else @@ -3657,7 +3915,7 @@ EOF fi echo $ac_n "checking whether PD libc fconvert fail to round""... $ac_c" 1>&6 -echo "configure:3661: checking whether PD libc fconvert fail to round" >&5 +echo "configure:3919: checking whether PD libc fconvert fail to round" >&5 if eval "test \"`echo '$''{'rb_cv_missing_fconvert'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3665,7 +3923,7 @@ else { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < @@ -3678,7 +3936,7 @@ main () } EOF -if { (eval echo configure:3682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +if { (eval echo configure:3940: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then rb_cv_missing_fconvert=yes else @@ -3704,6 +3962,10 @@ EOF binsuffix=.x setup=Setup.x68 ;; + cygwin*) + binsuffix=.exe + setup=Setup + ;; *) binsuffix= setup=Setup @@ -3712,16 +3974,76 @@ esac + + + if test "$prefix" = NONE; then prefix=$ac_default_prefix fi if test "$fat_binary" = yes ; then - CFLAGS="$CFLAGS -pipe $ARCH_FLAG" + CFLAGS="$CFLAGS $ARCH_FLAG" +fi + +LIBRUBY='libruby.a' +LIBRUBYARG='libruby.a' +SOLIBS= +if test "$host_os" = "beos"; then + CFLAGS="$CFLAGS -relax_pointers" + LIBRUBY='libruby.so' + LIBRUBYARG='-lruby' + SOLIBS='-lnet' + echo creating ruby.def + case "$host_cpu" in + powerpc*) + cp beos/ruby.def.in ruby.exp + ;; + *) + echo EXPORTS > ruby.def + cat beos/ruby.def.in >> ruby.def + ;; + esac +fi + +if test "$enable_shared" = 'yes'; then + LIBRUBY='libruby.so' + LIBRUBYARG='-L./ -lruby' fi +case "$host_os" in + nextstep*) + CFLAGS="$CFLAGS -pipe" + ;; + openstep*) + CFLAGS="$CFLAGS -pipe" + ;; + rhasody*) + CFLAGS="$CFLAGS -pipe -no-precomp" + ;; + *) + ;; +esac + + + + + + +ri_prefix= +test "$program_prefix" != NONE && + ri_prefix=$program_prefix + +ri_suffix= +test "$program_suffix" != NONE && + ri_suffix=$program_suffix + +RUBY_INSTALL_NAME="${ri_prefix}ruby${ri_suffix}" +cat >> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <> confdefs.h <&1 | - case `(ac_space=' '; set) 2>&1` in + case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote substitution # turns \\\\ into \\, and sed turns \\ into \). @@ -3858,7 +4193,7 @@ do echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) - echo "$CONFIG_STATUS generated by autoconf version 2.12" + echo "$CONFIG_STATUS generated by autoconf version 2.12.2" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; @@ -3878,9 +4213,11 @@ sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF $ac_vpsub $extrasub +s%@SHELL@%$SHELL%g s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g @@ -3910,6 +4247,7 @@ s%@YACC@%$YACC%g s%@RANLIB@%$RANLIB%g s%@AR@%$AR%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@SET_MAKE@%$SET_MAKE%g s%@LIBOBJS@%$LIBOBJS%g @@ -3923,6 +4261,9 @@ s%@STRIP@%$STRIP%g s%@EXTSTATIC@%$EXTSTATIC%g s%@binsuffix@%$binsuffix%g s%@setup@%$setup%g +s%@LIBRUBY@%$LIBRUBY%g +s%@LIBRUBYARG@%$LIBRUBYARG%g +s%@SOLIBS@%$SOLIBS%g s%@arch@%$arch%g CEOF diff --git a/configure.bat b/configure.bat index 35f9d4893d..093d43549d 100644 --- a/configure.bat +++ b/configure.bat @@ -2,4 +2,5 @@ sed -f top.sed Makefile.in >Makefile sed -f top.sed ext/extmk.rb.in > ext\extmk.rb copy ext\Setup.dj ext\Setup -copy config.dj config.h +copy config_h.dj config.h +copy config_s.dj config.status diff --git a/configure.in b/configure.in index 567e58cc3e..0477ade03e 100644 --- a/configure.in +++ b/configure.in @@ -24,28 +24,47 @@ AC_ARG_ENABLE(thread, [--disable-thread never use user-level thread], [ rb_thread=$enableval ]) if test $rb_thread = yes; then - AC_DEFINE(THREAD) + AC_DEFINE(USE_THREAD) fi AC_CANONICAL_HOST - dnl checks for fat-binary fat_binary=no AC_ARG_ENABLE( fat-binary, - [--enable-fat-binary build a NeXT Multi Architecture Binary. ], + [--enable-fat-binary build a NeXT/Apple Multi Architecture Binary. ], [ fat_binary=$enableval ] ) -if test "$fat_binary" = yes ; then + if test "$fat_binary" = yes ; then AC_MSG_CHECKING( target architecture ) - if test "$TARGET_ARCHS" = "" ; then - if test `/usr/bin/arch` = "m68k" ; then - TARGET_ARCHS="m68k i486" + case "$host_os" in + rhapsody*) + echo -n "MacOS X Server: " + if test "$TARGET_ARCHS" = "" ; then + TARGET_ARCHS="ppc i386" + fi + ;; + nextstep*|openstep*) + echo -n "NeXTSTEP/OPENSTEP: " + + if test "$host_os" = "rhapsody" ; then + echo -n "Rhapsody: " + if test "$TARGET_ARCHS" = "" ; then + TARGET_ARCHS="ppc i486" + fi else - TARGET_ARCHS="m68k `/usr/bin/arch`" + echo -n "NeXTSTEP/OPENSTEP: " + if test "$TARGET_ARCHS" = "" ; then + if test `/usr/bin/arch` = "m68k" ; then + TARGET_ARCHS="m68k i486" + else # Black and Native one + TARGET_ARCHS="m68k `/usr/bin/arch`" + fi + fi fi - fi + ;; + esac # /usr/lib/arch_tool -archify_list $TARGET_ARCHS for archs in $TARGET_ARCHS do @@ -56,7 +75,6 @@ if test "$fat_binary" = yes ; then echo "." fi - AC_ARG_PROGRAM dnl Checks for programs. @@ -72,22 +90,70 @@ AC_PROG_MAKE_SET # checks for UNIX variants that set C preprocessor variables AC_MINIX +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(void*) + +AC_MSG_CHECKING(for prototypes) +AC_CACHE_VAL(rb_cv_have_prototypes, + [AC_TRY_COMPILE([int foo(int x) { return 0; }], [return foo(10);], + rb_cv_have_prototypes=yes, + rb_cv_have_prototypes=no)]) +AC_MSG_RESULT($rb_cv_have_prototypes) +if test "$rb_cv_have_prototypes" = yes; then + AC_DEFINE(HAVE_PROTOTYPES) +fi + +AC_MSG_CHECKING(for variable length prototypes and stdarg.h) +AC_CACHE_VAL(rb_cv_stdarg, + [AC_TRY_COMPILE([ +#include +int foo(int x, ...) { + va_list va; + va_start(va, x); + va_arg(va, int); + va_arg(va, char *); + va_arg(va, double); + return 0; +} +], [return foo(10, "", 3.14);], + rb_cv_stdarg=yes, + rb_cv_stdarg=no)]) +AC_MSG_RESULT($rb_cv_stdarg) +if test "$rb_cv_stdarg" = yes; then + AC_DEFINE(HAVE_STDARG_PROTOTYPES) +fi + +AC_MSG_CHECKING(for gcc attribute noreturn) +AC_CACHE_VAL(rb_cv_have_attr_noreturn, + [AC_TRY_COMPILE([void exit(int x) __attribute__ ((noreturn));], [], + rb_cv_have_attr_noreturn=yes, + rb_cv_have_attr_noreturn=no)]) +AC_MSG_RESULT($rb_cv_have_attr_noreturn) +if test "$rb_cv_have_attr_noreturn" = yes; then + AC_DEFINE(HAVE_ATTR_NORETURN) +fi + dnl Checks for libraries. case "$host_os" in nextstep*) ;; +openstep*) ;; +rhapsody*) ;; human*) ;; +beos*) ;; *) LIBS="-lm $LIBS";; esac AC_CHECK_LIB(crypt, crypt) AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX +AC_CHECK_LIB(xpg4, setlocale) # FreeBSD needs this dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_CHECK_HEADERS(stdlib.h unistd.h limits.h sys/file.h sys/ioctl.h pwd.h \ sys/select.h sys/time.h sys/times.h sys/param.h sys/wait.h\ - syscall.h a.out.h string.h utime.h memory.h) + syscall.h a.out.h string.h utime.h memory.h direct.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_TYPE_UID_T @@ -98,23 +164,19 @@ AC_STRUCT_ST_BLOCKS LIBOBJS="$save_LIBOBJS" AC_STRUCT_ST_RDEV -AC_CHECK_SIZEOF(short) -AC_CHECK_SIZEOF(int) -AC_CHECK_SIZEOF(long) -AC_CHECK_SIZEOF(void*) - dnl Checks for library functions. AC_TYPE_GETGROUPS AC_TYPE_SIGNAL AC_FUNC_ALLOCA AC_FUNC_VFORK -AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strcasecmp strerror strftime\ - strstr strtoul strdup crypt flock) -AC_CHECK_FUNCS(fmod killpg random wait4 waitpid syscall getcwd\ +AC_FUNC_MEMCMP +AC_REPLACE_FUNCS(dup2 memmove mkdir strcasecmp strerror strftime\ + strchr strstr strtoul strdup crypt flock vsnprintf) +AC_CHECK_FUNCS(fmod killpg drand48 random wait4 waitpid syscall getcwd\ truncate chsize times utimes fcntl lockf setitimer\ setruid seteuid setreuid setrgid setegid setregid\ - setpgrp2 getpgid getgroups getpriority\ - dlopen sigprocmask sigaction _setjmp) + setpgrp2 getpgid setpgid getgroups getpriority\ + dlopen sigprocmask sigaction _setjmp setpgrp setsid) if test "$ac_cv_func_strftime" = no; then AC_STRUCT_TIMEZONE AC_TRY_LINK([], @@ -181,6 +243,26 @@ fi AC_C_BIGENDIAN AC_CHAR_UNSIGNED +AC_MSG_CHECKING(whether right shift preserve sign bit) +AC_CACHE_VAL(rb_cv_rshift_sign, + [AC_TRY_RUN([ +int +main() +{ + if (-1==(-1>>1)) + return 0; + return 1; +} +], + rb_cv_rshift_sign=yes, + rb_cv_rshift_sign=no)]) + AC_MSG_RESULT($rb_cv_rshift_sign) +if test "$rb_cv_rshift_sign" = yes; then + AC_DEFINE(RSHIFT(x,y), ((x)>>y)) +else + AC_DEFINE(RSHIFT(x,y), (((x)<0) ? ~((~(x))>>y) : (x)>>y)) +fi + AC_MSG_CHECKING([count field in FILE structures]) AC_CACHE_VAL(rb_cv_fcnt, [AC_TRY_COMPILE([#include ], @@ -205,17 +287,6 @@ else AC_DEFINE_UNQUOTED(FILE_COUNT, $rb_cv_fcnt) fi -if test "$ac_cv_func_getpwent" = yes; then - AC_MSG_CHECKING(struct passwd) - AC_EGREP_HEADER(pw_change, pwd.h, AC_DEFINE(PW_CHANGE)) - AC_EGREP_HEADER(pw_quota, pwd.h, AC_DEFINE(PW_QUOTA)) - AC_EGREP_HEADER(pw_age, pwd.h, AC_DEFINE(PW_AGE)) - AC_EGREP_HEADER(pw_class, pwd.h, AC_DEFINE(PW_CLASS)) - AC_EGREP_HEADER(pw_comment, pwd.h, AC_DEFINE(PW_COMMENT)) - AC_EGREP_HEADER(pw_expire, pwd.h, AC_DEFINE(PW_EXPIRE)) - AC_MSG_RESULT(done) -fi - dnl wheather use dln_a_out ot not AC_ARG_WITH(dln-a-out, [--with-dln-a-out use dln_a_out if possible], [ case $withval in @@ -271,7 +342,10 @@ if test "$with_dln_a_out" != yes; then if test "$GCC" = yes; then case "$host_os" in nextstep*) ;; + openstep*) ;; + rhapsody*) ;; human*) ;; + cygwin*) CCDLFLAGS=-DDLLIMPORT;; *) CCDLFLAGS=-fpic;; esac else @@ -301,21 +375,44 @@ if test "$with_dln_a_out" != yes; then rb_cv_dlopen=yes ;; linux*) LDSHARED="gcc -shared" rb_cv_dlopen=yes ;; + freebsd3*) LDSHARED="ld -Bshareable" + LDFLAGS="-rdynamic" + rb_cv_dlopen=yes ;; freebsd*) LDSHARED="ld -Bshareable" rb_cv_dlopen=yes ;; netbsd*) LDSHARED="ld -Bshareable" rb_cv_dlopen=yes ;; - openbsd*) LDSHARED="ld -Bshareable" + openbsd*) LDSHARED="ld -Bforcearchive -Bshareable" + CCDLFLAGS=-fPIC rb_cv_dlopen=yes ;; nextstep*) LDSHARED='cc -r' LDFLAGS="-u libsys_s" DLDFLAGS="$ARCH_FLAG" rb_cv_dlopen=yes ;; + openstep*) LDSHARED='cc -dynamic -bundle -undefined suppress' + LDFLAGS="" + DLDFLAGS="$ARCH_FLAG" + rb_cv_dlopen=yes ;; + rhapsody*) LDSHARED='cc -dynamic -bundle -undefined suppress' + LDFLAGS="" + DLDFLAGS="$ARCH_FLAG" + rb_cv_dlopen=yes ;; aix*) LDSHARED='../../miniruby ../aix_ld.rb $(TARGET)' rb_cv_dlopen=yes ;; human*) DLDFLAGS='' LDSHARED='' LDFLAGS='' ;; + beos*) LDSHARED="ld -xms" + case "$host_cpu" in + powerpc*) + DLDFLAGS="-f ruby.exp -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o" + ;; + *) + DLDFLAGS="ruby.def -lbe -lroot glue-noinit.a init_term_dyn.o start_dyn.o" + ;; + esac + rb_cv_dlopen=yes ;; + cygwin*) LDSHARED='../../miniruby ../cygwin32_ld.rb' ;; *) LDSHARED='ld' ;; esac AC_MSG_RESULT($rb_cv_dlopen) @@ -357,6 +454,12 @@ else AC_DEFINE(DLEXT, ".sl");; nextstep*) DLEXT=o AC_DEFINE(DLEXT, ".o");; + openstep*) DLEXT=bundle + AC_DEFINE(DLEXT, ".bundle");; + rhapsody*) DLEXT=bundle + AC_DEFINE(DLEXT, ".bundle");; + cygwin*) DLEXT=dll + AC_DEFINE(DLEXT, ".dll");; *) DLEXT=so AC_DEFINE(DLEXT, ".so");; esac @@ -374,6 +477,10 @@ case "$host_os" in STRIP='strip -S -x';; nextstep*) STRIP='strip -A -n';; + openstep*) + STRIP='strip -A -n';; + rhapsody*) + STRIP='strip -A -n';; esac EXTSTATIC= @@ -435,11 +542,18 @@ rb_cv_missing_fconvert=yes, rb_cv_missing_fconvert=no)]) binsuffix=.x setup=Setup.x68 ;; + cygwin*) + binsuffix=.exe + setup=Setup + ;; *) binsuffix= setup=Setup ;; esac + + + AC_SUBST(binsuffix) AC_SUBST(setup) @@ -448,23 +562,82 @@ if test "$prefix" = NONE; then fi if test "$fat_binary" = yes ; then - CFLAGS="$CFLAGS -pipe $ARCH_FLAG" + CFLAGS="$CFLAGS $ARCH_FLAG" +fi + +LIBRUBY='libruby.a' +LIBRUBYARG='libruby.a' +SOLIBS= +if test "$host_os" = "beos"; then + CFLAGS="$CFLAGS -relax_pointers" + LIBRUBY='libruby.so' + LIBRUBYARG='-lruby' + SOLIBS='-lnet' + echo creating ruby.def + case "$host_cpu" in + powerpc*) + cp beos/ruby.def.in ruby.exp + ;; + *) + echo EXPORTS > ruby.def + cat beos/ruby.def.in >> ruby.def + ;; + esac fi -AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby") +if test "$enable_shared" = 'yes'; then + LIBRUBY='libruby.so' + LIBRUBYARG='-L./ -lruby' +fi + +case "$host_os" in + nextstep*) + CFLAGS="$CFLAGS -pipe" + ;; + openstep*) + CFLAGS="$CFLAGS -pipe" + ;; + rhasody*) + CFLAGS="$CFLAGS -pipe -no-precomp" + ;; + *) + ;; +esac + + +AC_SUBST(LIBRUBY) +AC_SUBST(LIBRUBYARG) +AC_SUBST(SOLIBS) + +ri_prefix= +test "$program_prefix" != NONE && + ri_prefix=$program_prefix + +ri_suffix= +test "$program_suffix" != NONE && + ri_suffix=$program_suffix + +RUBY_INSTALL_NAME="${ri_prefix}ruby${ri_suffix}" +AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/${RUBY_INSTALL_NAME}") +AC_DEFINE_UNQUOTED(RUBY_SITE_LIB, "${prefix}/lib/${RUBY_INSTALL_NAME}/site_ruby") AC_SUBST(arch)dnl if test "$fat_binary" = yes ; then arch="fat-${host_os}" AC_DEFINE_UNQUOTED(RUBY_THIN_ARCHLIB, - "${prefix}/lib/ruby/" __ARCHITECTURE__ "-${host_os}" ) + "${prefix}/lib/${RUBY_INSTALL_NAME}/" __ARCHITECTURE__ "-${host_os}" ) + + AC_DEFINE_UNQUOTED(RUBY_SITE_THIN_ARCHLIB, + "${prefix}/lib/${RUBY_INSTALL_NAME}/" __ARCHITECTURE__ "-${host_os}" ) - AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/ruby/${arch}") + AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/${RUBY_INSTALL_NAME}/${arch}") + AC_DEFINE_UNQUOTED(RUBY_SITE_ARCHLIB, "${prefix}/lib/${RUBY_INSTALL_NAME}/site_ruby/${arch}") AC_DEFINE_UNQUOTED(RUBY_PLATFORM, __ARCHITECTURE__ "-${host_os}" ) else arch="${host_cpu}-${host_os}" - AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/ruby/${arch}") + AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/${RUBY_INSTALL_NAME}/${arch}") + AC_DEFINE_UNQUOTED(RUBY_SITE_ARCHLIB, "${prefix}/lib/${RUBY_INSTALL_NAME}/site_ruby/${arch}") AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "${arch}") fi diff --git a/defines.h b/defines.h index a24f9ebff7..fb10d628b4 100644 --- a/defines.h +++ b/defines.h @@ -12,18 +12,20 @@ #define RUBY -/* define EUC/SJIS for default kanji-code */ -#if defined(MSDOS) || defined(__CYGWIN32__) || defined(__human68k__) -#undef EUC -#define SJIS +/* define RUBY_USE_EUC/SJIS for default kanji-code */ +#if defined(MSDOS) || defined(__CYGWIN32__) || defined(__human68k__) || defined(__MACOS__) +#undef RUBY_USE_EUC +#define RUBY_USE_SJIS #else -#define EUC -#undef SJIS +#define RUBY_USE_EUC +#undef RUBY_USE_SJIS #endif #ifdef NeXT #define DYNAMIC_ENDIAN /* determine endian at runtime */ +#ifndef __APPLE__ #define S_IXUSR _S_IXUSR /* execute/search permission, owner */ +#endif #define S_IXGRP 0000010 /* execute/search permission, group */ #define S_IXOTH 0000001 /* execute/search permission, other */ #endif /* NeXT */ @@ -32,12 +34,22 @@ #include "missing/nt.h" #endif +#ifndef EXTERN +#define EXTERN extern +#endif + #ifdef sparc #define FLUSH_REGISTER_WINDOWS asm("ta 3") #else #define FLUSH_REGISTER_WINDOWS /* empty */ #endif +#if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__MACOS__) +#define RUBY_PATH_SEP ";" +#else +#define RUBY_PATH_SEP ":" +#endif + #if defined(__human68k__) || defined(__CYGWIN32__) #undef HAVE_RANDOM #undef HAVE_SETITIMER diff --git a/dir.c b/dir.c index 29ce261272..51d7f9e344 100644 --- a/dir.c +++ b/dir.c @@ -6,7 +6,7 @@ $Date$ created at: Wed Jan 5 09:51:01 JST 1994 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -27,6 +27,9 @@ #if HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) +#elif HAVE_DIRECT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen @@ -39,7 +42,7 @@ # if HAVE_NDIR_H # include # endif -# ifdef NT +# if defined(NT) && defined(_MSC_VER) # include "missing/dir.h" # endif #endif @@ -50,7 +53,11 @@ char *getenv(); #endif -static VALUE cDir; +#ifdef USE_CWGUSI +# include +#endif + +VALUE rb_cDir; static void free_dir(dir) @@ -59,6 +66,8 @@ free_dir(dir) if (dir) closedir(dir); } +static VALUE dir_close _((VALUE)); + static VALUE dir_s_open(dir_class, dirname) VALUE dir_class, dirname; @@ -71,7 +80,7 @@ dir_s_open(dir_class, dirname) dirp = opendir(RSTRING(dirname)->ptr); if (dirp == NULL) { if (errno == EMFILE || errno == ENFILE) { - gc_gc(); + rb_gc(); dirp = opendir(RSTRING(dirname)->ptr); } if (dirp == NULL) { @@ -81,13 +90,17 @@ dir_s_open(dir_class, dirname) obj = Data_Wrap_Struct(dir_class, 0, free_dir, dirp); + if (rb_iterator_p()) { + return rb_ensure(rb_yield, obj, dir_close, obj); + } + return obj; } static void dir_closed() { - Fail("closed directory"); + rb_raise(rb_eIOError, "closed directory"); } #define GetDIR(obj, dirp) {\ @@ -95,6 +108,27 @@ dir_closed() if (dirp == NULL) dir_closed();\ } +static VALUE +dir_read(dir) + VALUE dir; +{ + DIR *dirp; + struct dirent *dp; + + GetDIR(dir, dirp); + errno = 0; + dp = readdir(dirp); + if (dp) + return rb_tainted_str_new(dp->d_name, NAMLEN(dp)); + else if (errno == 0) { /* end of stream */ + return Qnil; + } + else { + rb_sys_fail(0); + } + return Qnil; /* not reached */ +} + static VALUE dir_each(dir) VALUE dir; @@ -105,7 +139,7 @@ dir_each(dir) GetDIR(dir, dirp); for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - file = str_taint(str_new(dp->d_name, NAMLEN(dp))); + file = rb_tainted_str_new(dp->d_name, NAMLEN(dp)); rb_yield(file); } return dir; @@ -118,10 +152,10 @@ dir_tell(dir) DIR *dirp; int pos; -#if !defined(__CYGWIN32__) +#if !defined(__CYGWIN32__) && !defined(__BEOS__) GetDIR(dir, dirp); pos = telldir(dirp); - return int2inum(pos); + return rb_int2inum(pos); #else rb_notimplement(); #endif @@ -133,7 +167,7 @@ dir_seek(dir, pos) { DIR *dirp; -#if !defined(__CYGWIN32__) +#if !defined(__CYGWIN32__) && !defined(__BEOS__) GetDIR(dir, dirp); seekdir(dirp, NUM2INT(pos)); return dir; @@ -177,8 +211,7 @@ dir_s_chdir(argc, argv, obj) char *dist = ""; rb_secure(2); - rb_scan_args(argc, argv, "01", &path); - if (!NIL_P(path)) { + if (rb_scan_args(argc, argv, "01", &path) == 1) { Check_SafeStr(path); dist = RSTRING(path)->ptr; } @@ -190,7 +223,7 @@ dir_s_chdir(argc, argv, obj) } if (chdir(dist) < 0) - rb_sys_fail(0); + rb_sys_fail(dist); return INT2FIX(0); } @@ -199,32 +232,33 @@ static VALUE dir_s_getwd(dir) VALUE dir; { - extern char *getwd(); char path[MAXPATHLEN]; #ifdef HAVE_GETCWD if (getcwd(path, sizeof(path)) == 0) rb_sys_fail(path); #else + extern char *getwd(); if (getwd(path) == 0) rb_sys_fail(path); #endif - return str_taint(str_new2(path)); + return rb_tainted_str_new2(path); } static VALUE dir_s_chroot(dir, path) VALUE dir, path; { -#if !defined(DJGPP) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__) +#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__) && !defined(USE_CWGUSI) && !defined(__BEOS__) rb_secure(2); Check_SafeStr(path); if (chroot(RSTRING(path)->ptr) == -1) - rb_sys_fail(0); + rb_sys_fail(RSTRING(path)->ptr); return INT2FIX(0); #else rb_notimplement(); + return Qnil; /* not reached */ #endif } @@ -246,7 +280,7 @@ dir_s_mkdir(argc, argv, obj) } Check_SafeStr(path); -#ifndef NT +#if !defined(NT) && !defined(USE_CWGUSI) if (mkdir(RSTRING(path)->ptr, mode) == -1) rb_sys_fail(RSTRING(path)->ptr); #else @@ -266,7 +300,7 @@ dir_s_rmdir(obj, dir) if (rmdir(RSTRING(dir)->ptr) < 0) rb_sys_fail(RSTRING(dir)->ptr); - return TRUE; + return Qtrue; } #define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0') @@ -285,7 +319,7 @@ push_globs(ary, s) if (fnames == (char**)-1) rb_sys_fail(s); ff = fnames; while (*ff) { - ary_push(ary, str_taint(str_new2(*ff))); + rb_ary_push(ary, rb_tainted_str_new2(*ff)); free(*ff); ff++; } @@ -341,22 +375,24 @@ push_braces(ary, s) } static VALUE -dir_s_glob(dir, vstr) - VALUE dir, vstr; +dir_s_glob(dir, str) + VALUE dir, str; { char *p, *pend; char buf[MAXPATHLEN]; char *t, *t0; int nest; VALUE ary; - struct RString *str; - Check_SafeStr(vstr); - str = RSTRING(vstr); - ary = ary_new(); + Check_SafeStr(str); + if (RSTRING(str)->len > MAXPATHLEN) { + rb_raise(rb_eArgError, "pathname too long (%d bytes)", + RSTRING(str)->len); + } + ary = rb_ary_new(); - p = str->ptr; - pend = p + str->len; + p = RSTRING(str)->ptr; + pend = p + RSTRING(str)->len; while (p < pend) { t = buf; @@ -389,37 +425,48 @@ dir_foreach(io, dirname) { VALUE dir; - dir = dir_s_open(cDir, dirname); + dir = rb_funcall(rb_cDir, rb_intern("open"), 1, dirname); return rb_ensure(dir_each, dir, dir_close, dir); } -void -Init_Dir() +static VALUE +dir_entries(io, dirname) + VALUE io, dirname; { - extern VALUE mEnumerable; - - cDir = rb_define_class("Dir", cObject); - - rb_include_module(cDir, mEnumerable); - - rb_define_singleton_method(cDir, "open", dir_s_open, 1); - rb_define_singleton_method(cDir, "foreach", dir_foreach, 1); - - rb_define_method(cDir,"each", dir_each, 0); - rb_define_method(cDir,"rewind", dir_rewind, 0); - rb_define_method(cDir,"tell", dir_tell, 0); - rb_define_method(cDir,"seek", dir_seek, 1); - rb_define_method(cDir,"close", dir_close, 0); + VALUE dir; - rb_define_singleton_method(cDir,"chdir", dir_s_chdir, -1); - rb_define_singleton_method(cDir,"getwd", dir_s_getwd, 0); - rb_define_singleton_method(cDir,"pwd", dir_s_getwd, 0); - rb_define_singleton_method(cDir,"chroot", dir_s_chroot, 1); - rb_define_singleton_method(cDir,"mkdir", dir_s_mkdir, -1); - rb_define_singleton_method(cDir,"rmdir", dir_s_rmdir, 1); - rb_define_singleton_method(cDir,"delete", dir_s_rmdir, 1); - rb_define_singleton_method(cDir,"unlink", dir_s_rmdir, 1); + dir = rb_funcall(rb_cDir, rb_intern("open"), 1, dirname); + return rb_ensure(rb_Array, dir, dir_close, dir); +} - rb_define_singleton_method(cDir,"glob", dir_s_glob, 1); - rb_define_singleton_method(cDir,"[]", dir_s_glob, 1); +void +Init_Dir() +{ + rb_cDir = rb_define_class("Dir", rb_cObject); + + rb_include_module(rb_cDir, rb_mEnumerable); + + rb_define_singleton_method(rb_cDir, "new", dir_s_open, 1); + rb_define_singleton_method(rb_cDir, "open", dir_s_open, 1); + rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, 1); + rb_define_singleton_method(rb_cDir, "entries", dir_entries, 1); + + rb_define_method(rb_cDir,"read", dir_read, 0); + rb_define_method(rb_cDir,"each", dir_each, 0); + rb_define_method(rb_cDir,"rewind", dir_rewind, 0); + rb_define_method(rb_cDir,"tell", dir_tell, 0); + rb_define_method(rb_cDir,"seek", dir_seek, 1); + rb_define_method(rb_cDir,"close", dir_close, 0); + + rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1); + rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0); + rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0); + rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1); + rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1); + rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1); + rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1); + rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1); + + rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, 1); + rb_define_singleton_method(rb_cDir,"[]", dir_s_glob, 1); } diff --git a/dln.c b/dln.c index f4ab012021..858291d5b7 100644 --- a/dln.c +++ b/dln.c @@ -6,20 +6,20 @@ $Date$ created at: Tue Jan 18 17:05:06 JST 1994 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ -#ifdef _AIX -#pragma alloca -#endif - #include "config.h" #include "defines.h" #include "dln.h" char *dln_argv0; +#ifdef _AIX +#pragma alloca +#endif + #if defined(HAVE_ALLOCA_H) && !defined(__GNUC__) #include #endif @@ -36,7 +36,9 @@ void *xrealloc(); #include #ifndef NT -#include +# ifndef USE_CWGUSI +# include +# endif #else #include "missing/file.h" #endif @@ -58,15 +60,25 @@ char *strdup(); char *getenv(); #endif +#ifdef __MACOS__ +# include +# include +# include +#endif + +#ifdef __BEOS__ +# include +#endif + int eaccess(); -#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) +#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(__CYGWIN32__) && !defined(_AIX) /* dynamic load with dlopen() */ # define USE_DLN_DLOPEN #endif #ifndef FUNCNAME_PATTERN -# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__) || defined(NeXT) +# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(NeXT) || defined(__WATCOMC__) # define FUNCNAME_PATTERN "_Init_%.200s" # else # define FUNCNAME_PATTERN "Init_%.200s" @@ -81,7 +93,11 @@ init_funcname(buf, file) /* Load the file as an object one */ for (p = file, slash = p-1; *p; p++) /* Find position of last '/' */ +#ifdef __MACOS__ + if (*p == ':') slash = p; +#else if (*p == '/') slash = p; +#endif sprintf(buf, FUNCNAME_PATTERN, slash + 1); for (p = buf; *p; p++) { /* Delete suffix it it exists */ @@ -407,7 +423,7 @@ load_text_data(fd, hdrp, bss, disp) } static int -undef_print(key, value) +underb_f_print(key, value) char *key, *value; { fprintf(stderr, " %s\n", key); @@ -418,7 +434,7 @@ static void dln_print_undef() { fprintf(stderr, " Undefined symbols:\n"); - st_foreach(undef_tbl, undef_print, NULL); + st_foreach(undef_tbl, underb_f_print, NULL); } static void @@ -814,7 +830,7 @@ load_1(fd, disp, need_init) for (sym = syms; symn_un.n_name; if (name[0] == '_' && sym->n_value >= block) { - if (strcmp(name+1, "libs_to_be_linked") == 0) { + if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { libs_to_be_linked = (char**)sym->n_value; } else if (strcmp(name+1, buf) == 0) { @@ -869,11 +885,11 @@ search_undef(key, value, lib_tbl) } struct symdef { - int str_index; + int rb_str_index; int lib_offset; }; -char *dln_library_path = DLN_DEFAULT_LIB_PATH; +char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; static int load_lib(lib) @@ -904,10 +920,10 @@ load_lib(lib) /* library search path: */ /* look for environment variable DLN_LIBRARY_PATH first. */ - /* then variable dln_library_path. */ + /* then variable dln_librrb_ary_path. */ /* if path is still NULL, use "." for path. */ path = getenv("DLN_LIBRARY_PATH"); - if (path == NULL) path = dln_library_path; + if (path == NULL) path = dln_librrb_ary_path; file = dln_find_file(lib, path); fd = open(file, O_RDONLY); @@ -936,7 +952,7 @@ load_lib(lib) base = (struct symdef*)(data + 1); name_base = (char*)(base + nsym) + sizeof(int); while (nsym > 0) { - char *name = name_base + base->str_index; + char *name = name_base + base->rb_str_index; st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); nsym--; @@ -1065,14 +1081,18 @@ dln_sym(name) #include "dl.h" #endif -#ifdef _AIX +#if defined(_AIX) #include /* for isdigit() */ #include /* for global errno */ #include #endif #ifdef NeXT -/*#include */ +#if NS_TARGET_MAJOR < 4 +#include +#else +#include +#endif #endif #ifdef _WIN32 @@ -1109,21 +1129,28 @@ dln_strerror() #ifdef _WIN32 static char message[1024]; + int error = GetLastError(); + char *p = message; + p += sprintf(message, "%d: ", error); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, - GetLastError(), - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - message, - sizeof message, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + p, + sizeof message - strlen(message), NULL); + for (p = message; *p; p++) { + if (*p == '\n' || *p == '\r') + *p = ' '; + } return message; #endif } -#ifdef _AIX +#if defined(_AIX) static void aix_loaderror(char *pathname) { @@ -1166,7 +1193,7 @@ aix_loaderror(char *pathname) ERRBUF_APPEND("\n"); } errbuf[strlen(errbuf)-1] = '\0'; /* trim off last newline */ - LoadError(errbuf); + rb_loaderror(errbuf); return; } #endif @@ -1193,7 +1220,7 @@ dln_load(file) /* Load file */ if ((handle = LoadLibraryExA(winfile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) { - printf("LoadLibraryExA\n"); + printf("LoadLibraryExA: %s\n", winfile); goto failed; } @@ -1229,15 +1256,15 @@ dln_load(file) void *handle; void (*init_fct)(); -# ifndef RTLD_LAZY -# define RTLD_LAZY 1 -# endif -# ifndef RTLD_GLOBAL -# define RTLD_GLOBAL 0 -# endif +#ifndef RTLD_LAZY +# define RTLD_LAZY 1 +#endif +#ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +#endif /* Load file */ - if ((handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { + if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) { goto failed; } @@ -1260,15 +1287,15 @@ dln_load(file) flags = BIND_DEFERRED; lib = shl_load(file, flags, 0); if (lib == NULL) { - rb_sys_fail(file); + extern int errno; + rb_loaderror("%s - %s", strerror(errno), file); } shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct); if (init_fct == NULL) { shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct); if (init_fct == NULL) { - extern int errno; errno = ENOSYM; - rb_sys_fail(file); + rb_loaderror("%s - %s", strerror(ENOSYM), file); } } (*init_fct)(); @@ -1276,7 +1303,7 @@ dln_load(file) } #endif /* hpux */ -#ifdef _AIX +#if defined(_AIX) #define DLN_DEFINED { void (*init_fct)(); @@ -1300,6 +1327,7 @@ dln_load(file) Mi hisho@tasihara.nest.or.jp, and... Miss ARAI Akino(^^;) ----------------------------------------------------*/ +#if NS_TARGET_MAJOR < 4 /* NeXTSTEP rld functions */ { unsigned long init_address; char *object_files[2] = {NULL, NULL}; @@ -1310,12 +1338,12 @@ dln_load(file) /* Load object file, if return value ==0 , load failed*/ if(rld_load(NULL, NULL, object_files, NULL) == 0) { - LoadError("Failed to load %.200s", file); + rb_loaderror("Failed to load %.200s", file); } /* lookup the initial function */ if(rld_lookup(NULL, buf, &init_address) == 0) { - LoadError("Failed to lookup Init function %.200s",file); + rb_loaderror("Failed to lookup Init function %.200s", file); } /* Cannot call *init_address directory, so copy this value to @@ -1325,8 +1353,133 @@ dln_load(file) (*init_fct)(); return ; } +#else/* OPENSTEP dyld functions */ + { + int dyld_result ; + NSObjectFileImage obj_file ; /* handle, but not use it */ + /* "file" is module file name . + "buf" is initial function name with "_" . */ + + void (*init_fct)(); + + + dyld_result = NSCreateObjectFileImageFromFile( file, &obj_file ); + + if (dyld_result != NSObjectFileImageSuccess) { + rb_loaderror("Failed to load %.200s", file); + } + + NSLinkModule(obj_file, file, TRUE); + + /* lookup the initial function */ + /*NSIsSymbolNameDefined require function name without "_" */ + if( NSIsSymbolNameDefined( buf + 1 ) ) { + rb_loaderror("Failed to lookup Init function %.200s",file); + } + + /* NSLookupAndBindSymbol require function name with "_" !! */ + init_fct = NSAddressOfSymbol( NSLookupAndBindSymbol( buf ) ); + (*init_fct)(); + + return ; + } +#endif /* rld or dyld */ #endif +#ifdef __BEOS__ +# define DLN_DEFINED + { + status_t err_stat; /* BeOS error status code */ + image_id img_id; /* extention module unique id */ + void (*init_fct)(); /* initialize function for extention module */ + + /* load extention module */ + img_id = load_add_on(file); + if (img_id <= 0) { + rb_loaderror("Failed to load %.200s", file); + } + + /* find symbol for module initialize function. */ + /* The Be Book KernelKit Images section described to use + B_SYMBOL_TYPE_TEXT for symbol of function, not + B_SYMBOL_TYPE_CODE. Why ? */ + /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */ + /* "__Fv" dont need! The Be Book Bug ? */ + err_stat = get_image_symbol(img_id, buf, + B_SYMBOL_TYPE_TEXT, &init_fct); + + if (err_stat != B_NO_ERROR) { + char real_name[1024]; + strcpy(real_name, buf); + strcat(real_name, "__Fv"); + err_stat = get_image_symbol(img_id, real_name, + B_SYMBOL_TYPE_TEXT, &init_fct); + } + + if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) { + unload_add_on(img_id); + rb_loaderror("Failed to lookup Init function %.200s", file); + } + else if (B_NO_ERROR != err_stat) { + char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)"; + unload_add_on(img_id); + rb_loaderror(errmsg, strerror(err_stat), buf); + } + + /* call module initialize function. */ + (*init_fct)(); + return; + } +#endif /* __BEOS__*/ + +#ifdef __MACOS__ +# define DLN_DEFINED + { + OSErr err; + FSSpec libspec; + CFragConnectionID connID; + Ptr mainAddr; + char errMessage[1024]; + Boolean isfolder, didsomething; + Str63 fragname; + Ptr symAddr; + CFragSymbolClass class; + void (*init_fct)(); + char fullpath[MAXPATHLEN]; + + strcpy(fullpath, file); + + /* resolve any aliases to find the real file */ + c2pstr(fullpath); + (void)FSMakeFSSpec(0, 0, fullpath, &libspec); + err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething); + if ( err ) { + rb_loaderror("Unresolved Alias - %s", file); + } + + /* Load the fragment (or return the connID if it is already loaded */ + fragname[0] = 0; + err = GetDiskFragment(&libspec, 0, 0, fragname, + kLoadCFrag, &connID, &mainAddr, + errMessage); + if ( err ) { + p2cstr(errMessage); + rb_loaderror("%s - %s",errMessage , file); + } + + /* Locate the address of the correct init function */ + c2pstr(buf); + err = FindSymbol(connID, buf, &symAddr, &class); + if ( err ) { + rb_loaderror("Unresolved symbols - %s" , file); + } + + init_fct = (void (*)())symAddr; + (*init_fct)(); + return; + } +#endif /* __MACOS__ */ + #ifndef DLN_DEFINED rb_notimplement("dynamic link not supported"); #endif @@ -1335,7 +1488,7 @@ dln_load(file) #endif #if !defined(_AIX) && !defined(NeXT) failed: - LoadError("%s - %s", dln_strerror(), file); + rb_loaderror("%s - %s", dln_strerror(), file); #endif } @@ -1346,15 +1499,21 @@ dln_find_exe(fname, path) char *fname; char *path; { + if (!path) { #if defined(__human68k__) - if (!path) path = getenv("path"); - if (!path) - path = "/usr/local/bin;/usr/usb;/usr/bin;/bin;."; #else - if (!path) path = getenv("PATH"); - if (!path) path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:."; + path = getenv("PATH"); #endif + } + + if (!path) { +#if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__MACOS__) + path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;."; +#else + path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:."; +#endif + } return dln_find_1(fname, path, 1); } @@ -1367,6 +1526,30 @@ dln_find_file(fname, path) return dln_find_1(fname, path, 0); } +#if defined(__CYGWIN32__) +char * +conv_to_posix_path(win32, posix) + char *win32; + char *posix; +{ + char *first = win32; + char *p = win32; + char *dst = posix; + + for (p = win32; *p; p++) + if (*p == ';') { + *p = 0; + cygwin32_conv_to_posix_path(first, posix); + posix += strlen(posix); + *posix++ = ':'; + first = p + 1; + *p = ';'; + } + cygwin32_conv_to_posix_path(first, posix); + return dst; +} +#endif + static char fbuf[MAXPATHLEN]; static char * @@ -1380,15 +1563,24 @@ dln_find_1(fname, path, exe_flag) register char *bp; struct stat st; +#if defined(__CYGWIN32__) + char rubypath[MAXPATHLEN]; + conv_to_posix_path(path, rubypath); + path = rubypath; +#endif +#ifndef __MACOS__ if (fname[0] == '/') return fname; if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0) return fname; + if (exe_flag && strchr(fname, '/')) return fname; #if defined(MSDOS) || defined(NT) || defined(__human68k__) if (fname[0] == '\\') return fname; - if (fname[1] == ':') return fname; + if (strlen(fname) > 2 && fname[1] == ':') return fname; if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0) return fname; + if (exe_flag && strchr(fname, '\\')) return fname; #endif +#endif /* __MACOS__ */ for (dp = path;; dp = ++ep) { register int l; @@ -1396,11 +1588,7 @@ dln_find_1(fname, path, exe_flag) int fspace; /* extract a component */ -#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__) - ep = strchr(dp, ':'); -#else - ep = strchr(dp, ';'); -#endif + ep = strchr(dp, RUBY_PATH_SEP[0]); if (ep == NULL) ep = dp+strlen(dp); @@ -1417,7 +1605,11 @@ dln_find_1(fname, path, exe_flag) ** take the path literally. */ - if (*dp == '~' && (l == 1 || dp[1] == '/')) { + if (*dp == '~' && (l == 1 || +#if defined(MSDOS) || defined(NT) || defined(__human68k__) + dp[1] == '\\' || +#endif + dp[1] == '/')) { char *home; home = getenv("HOME"); @@ -1440,7 +1632,11 @@ dln_find_1(fname, path, exe_flag) /* add a "/" between directory and filename */ if (ep[-1] != '/') +#ifdef __MACOS__ + *bp++ = ':'; +#else *bp++ = '/'; +#endif } /* now append the file name */ diff --git a/dln.h b/dln.h index 0e16170a02..7af1f63a9d 100644 --- a/dln.h +++ b/dln.h @@ -11,12 +11,20 @@ #ifndef DLN_H #define DLN_H -char *dln_find_exe(); -char *dln_find_file(); +#ifndef _ +#ifndef __STDC__ +# define _(args) () +#else +# define _(args) args +#endif +#endif + +char *dln_find_exe _((char*,char*)); +char *dln_find_file _((char*,char*)); #ifdef USE_DLN_A_OUT extern char *dln_argv0; #endif -void dln_load(); +void dln_load _((char*)); #endif diff --git a/enum.c b/enum.c index d8e2fcdc8b..2b4b904018 100644 --- a/enum.c +++ b/enum.c @@ -6,13 +6,13 @@ $Date$ created at: Fri Oct 1 15:15:19 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" -VALUE mEnumerable; +VALUE rb_mEnumerable; static ID id_each, id_eqq, id_cmp; VALUE @@ -27,7 +27,7 @@ grep_i(i, arg) VALUE i, *arg; { if (RTEST(rb_funcall(arg[0], id_eqq, 1, i))) { - ary_push(arg[1], i); + rb_ary_push(arg[1], i); } return Qnil; } @@ -46,14 +46,14 @@ static VALUE enum_grep(obj, pat) VALUE obj, pat; { - if (iterator_p()) { + if (rb_iterator_p()) { rb_iterate(rb_each, obj, grep_iter_i, pat); return obj; } else { VALUE tmp, arg[2]; - arg[0] = pat; arg[1] = tmp = ary_new(); + arg[0] = pat; arg[1] = tmp = rb_ary_new(); rb_iterate(rb_each, obj, grep_i, (VALUE)arg); return tmp; @@ -71,7 +71,7 @@ find_i(i, arg) struct find_arg *arg; { if (RTEST(rb_yield(i))) { - arg->found = TRUE; + arg->found = Qtrue; arg->val = i; rb_iter_break(); } @@ -88,7 +88,7 @@ enum_find(argc, argv, obj) VALUE if_none; rb_scan_args(argc, argv, "01", &if_none); - arg.found = FALSE; + arg.found = Qfalse; rb_iterate(rb_each, obj, find_i, (VALUE)&arg); if (arg.found) { return arg.val; @@ -104,7 +104,7 @@ find_all_i(i, tmp) VALUE i, tmp; { if (RTEST(rb_yield(i))) { - ary_push(tmp, i); + rb_ary_push(tmp, i); } return Qnil; } @@ -115,7 +115,7 @@ enum_find_all(obj) { VALUE tmp; - tmp = ary_new(); + tmp = rb_ary_new(); rb_iterate(rb_each, obj, find_all_i, tmp); return tmp; @@ -125,12 +125,7 @@ static VALUE collect_i(i, tmp) VALUE i, tmp; { - VALUE retval; - - retval = rb_yield(i); - if (RTEST(retval)) { - ary_push(tmp, retval); - } + rb_ary_push(tmp, rb_yield(i)); return Qnil; } @@ -140,37 +135,17 @@ enum_collect(obj) { VALUE tmp; - tmp = ary_new(); + tmp = rb_ary_new(); rb_iterate(rb_each, obj, collect_i, tmp); return tmp; } -static VALUE -reverse_i(i, tmp) - VALUE i, tmp; -{ - ary_unshift(tmp, i); - return Qnil; -} - -static VALUE -enum_reverse(obj) - VALUE obj; -{ - VALUE tmp; - - tmp = ary_new(); - rb_iterate(rb_each, obj, reverse_i, tmp); - - return tmp; -} - static VALUE enum_all(i, ary) VALUE i, ary; { - ary_push(ary, i); + rb_ary_push(ary, i); return Qnil; } @@ -180,7 +155,7 @@ enum_to_a(obj) { VALUE ary; - ary = ary_new(); + ary = rb_ary_new(); rb_iterate(rb_each, obj, enum_all, ary); return ary; @@ -190,7 +165,7 @@ static VALUE enum_sort(obj) VALUE obj; { - return ary_sort(enum_to_a(obj)); + return rb_ary_sort(enum_to_a(obj)); } static VALUE @@ -203,7 +178,7 @@ min_i(i, min) *min = i; else { cmp = rb_funcall(i, id_cmp, 1, *min); - if (FIX2INT(cmp) < 0) + if (FIX2LONG(cmp) < 0) *min = i; } return Qnil; @@ -218,8 +193,8 @@ min_ii(i, min) if (NIL_P(*min)) *min = i; else { - cmp = rb_yield(assoc_new(i, *min)); - if (FIX2INT(cmp) < 0) + cmp = rb_yield(rb_assoc_new(i, *min)); + if (FIX2LONG(cmp) < 0) *min = i; } return Qnil; @@ -231,7 +206,7 @@ enum_min(obj) { VALUE min = Qnil; - rb_iterate(rb_each, obj, iterator_p()?min_ii:min_i, (VALUE)&min); + rb_iterate(rb_each, obj, rb_iterator_p()?min_ii:min_i, (VALUE)&min); return min; } @@ -245,7 +220,7 @@ max_i(i, max) *max = i; else { cmp = rb_funcall(i, id_cmp, 1, *max); - if (FIX2INT(cmp) > 0) + if (FIX2LONG(cmp) > 0) *max = i; } return Qnil; @@ -260,8 +235,8 @@ max_ii(i, max) if (NIL_P(*max)) *max = i; else { - cmp = rb_yield(assoc_new(i, *max)); - if (FIX2INT(cmp) > 0) + cmp = rb_yield(rb_assoc_new(i, *max)); + if (FIX2LONG(cmp) > 0) *max = i; } return Qnil; @@ -273,7 +248,7 @@ enum_max(obj) { VALUE max = Qnil; - rb_iterate(rb_each, obj, iterator_p()?max_ii:max_i, (VALUE)&max); + rb_iterate(rb_each, obj, rb_iterator_p()?max_ii:max_i, (VALUE)&max); return max; } @@ -333,8 +308,8 @@ enum_member(obj, val) iv.i = 0; iv.v = val; rb_iterate(rb_each, obj, member_i, (VALUE)&iv); - if (iv.i) return TRUE; - return FALSE; + if (iv.i) return Qtrue; + return Qfalse; } static VALUE @@ -346,7 +321,7 @@ length_i(i, length) return Qnil; } -VALUE +static VALUE enum_length(obj) VALUE obj; { @@ -356,26 +331,58 @@ enum_length(obj) return INT2FIX(length); } +VALUE +rb_enum_length(obj) + VALUE obj; +{ + return enum_length(obj); +} + +static VALUE +each_with_index_i(val, indexp) + VALUE val; + int *indexp; +{ +#if 1 + rb_yield(rb_assoc_new(val, INT2FIX(*indexp))); +#else + rb_yield(rb_ary_concat(rb_Array(val), INT2FIX(*indexp))); +#endif + (*indexp)++; + return Qnil; +} + +static VALUE +enum_each_with_index(obj) + VALUE obj; +{ + int index = 0; + + rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&index); + return Qnil; +} + void Init_Enumerable() { - mEnumerable = rb_define_module("Enumerable"); - - rb_define_method(mEnumerable,"to_a", enum_to_a, 0); - - rb_define_method(mEnumerable,"sort", enum_sort, 0); - rb_define_method(mEnumerable,"grep", enum_grep, 1); - rb_define_method(mEnumerable,"find", enum_find, -1); - rb_define_method(mEnumerable,"find_all", enum_find_all, 0); - rb_define_method(mEnumerable,"collect", enum_collect, 0); - rb_define_method(mEnumerable,"reverse", enum_reverse, 0); - rb_define_method(mEnumerable,"min", enum_min, 0); - rb_define_method(mEnumerable,"max", enum_max, 0); - rb_define_method(mEnumerable,"index", enum_index, 1); - rb_define_method(mEnumerable,"member?", enum_member, 1); - rb_define_method(mEnumerable,"include?", enum_member, 1); - rb_define_method(mEnumerable,"length", enum_length, 0); - rb_define_method(mEnumerable,"size", enum_length, 0); + rb_mEnumerable = rb_define_module("Enumerable"); + + rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0); + rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0); + + rb_define_method(rb_mEnumerable,"sort", enum_sort, 0); + rb_define_method(rb_mEnumerable,"grep", enum_grep, 1); + rb_define_method(rb_mEnumerable,"find", enum_find, -1); + rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0); + rb_define_method(rb_mEnumerable,"collect", enum_collect, 0); + rb_define_method(rb_mEnumerable,"min", enum_min, 0); + rb_define_method(rb_mEnumerable,"max", enum_max, 0); + rb_define_method(rb_mEnumerable,"index", enum_index, 1); + rb_define_method(rb_mEnumerable,"member?", enum_member, 1); + rb_define_method(rb_mEnumerable,"include?", enum_member, 1); + rb_define_method(rb_mEnumerable,"length", enum_length, 0); + rb_define_method(rb_mEnumerable,"size", enum_length, 0); + rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0); id_eqq = rb_intern("==="); id_each = rb_intern("each"); diff --git a/env.h b/env.h index ebcfcc5d31..79fdfc2bef 100644 --- a/env.h +++ b/env.h @@ -12,6 +12,7 @@ #define ENV_H extern struct FRAME { + VALUE self; int argc; VALUE *argv; ID last_func; @@ -21,16 +22,16 @@ extern struct FRAME { char *file; int line; int iter; -} *the_frame; +} *ruby_frame; -void gc_mark_frame _((struct FRAME *)); +void rb_gc_mark_frame _((struct FRAME *)); extern struct SCOPE { struct RBasic super; ID *local_tbl; VALUE *local_vars; int flag; -} *the_scope; +} *ruby_scope; #define SCOPE_ALLOCA 0 #define SCOPE_MALLOC 1 @@ -38,7 +39,7 @@ extern struct SCOPE { extern int rb_in_eval; -extern VALUE the_class; +extern VALUE ruby_class; struct RVarmap { struct RBasic super; @@ -46,6 +47,6 @@ struct RVarmap { VALUE val; struct RVarmap *next; }; -extern struct RVarmap *the_dyna_vars; +extern struct RVarmap *ruby_dyna_vars; #endif /* ENV_H */ diff --git a/error.c b/error.c index 7163f62609..44ca067472 100644 --- a/error.c +++ b/error.c @@ -6,56 +6,46 @@ $Date$ created at: Mon Aug 9 16:11:34 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "env.h" #include +#ifdef HAVE_STDARG_PROTOTYPES +#include +#define va_init_list(a,b) va_start(a,b) +#else #include +#define va_init_list(a,b) va_start(a) +#endif -extern char *sourcefile; -extern int sourceline; +#ifdef USE_CWGUSI +#include +int sys_nerr = 256; +#endif -int nerrs; +int ruby_nerrs; static void -err_sprintf(buf, fmt, args) +err_snprintf(buf, len, fmt, args) char *buf, *fmt; + int len; va_list args; { - if (!sourcefile) { - vsprintf(buf, fmt, args); + if (!ruby_sourcefile) { + vsnprintf(buf, len, fmt, args); } else { - sprintf(buf, "%s:%d: ", sourcefile, sourceline); - vsprintf((char*)buf+strlen(buf), fmt, args); - } -} - -static void -err_append(s) - char *s; -{ - extern VALUE errinfo; - - if (rb_in_eval) { - if (NIL_P(errinfo)) { - errinfo = str_new2(s); + int n = snprintf(buf, len, "%s:%d: ", ruby_sourcefile, ruby_sourceline); + if (len > n) { + vsnprintf((char*)buf+n, len-n, fmt, args); } - else { - str_cat(errinfo, "\n", 1); - str_cat(errinfo, s, strlen(s)); - } - } - else { - fputs(s, stderr); - fputs("\n", stderr); - fflush(stderr); } } +static void err_append _((char*)); static void err_print(fmt, args) char *fmt; @@ -63,66 +53,102 @@ err_print(fmt, args) { char buf[BUFSIZ]; - err_sprintf(buf, fmt, args); + err_snprintf(buf, BUFSIZ, fmt, args); err_append(buf); } void -Error(fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_compile_error(char *fmt, ...) +#else +rb_compile_error(fmt, va_alist) char *fmt; va_dcl +#endif { va_list args; - va_start(args); + va_init_list(args, fmt); err_print(fmt, args); va_end(args); - nerrs++; + ruby_nerrs++; } void -Error_Append(fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_compile_error_append(char *fmt, ...) +#else +rb_compile_error_append(fmt, va_alist) char *fmt; va_dcl +#endif { va_list args; char buf[BUFSIZ]; - va_start(args); - vsprintf(buf, fmt, args); + va_init_list(args, fmt); + vsnprintf(buf, BUFSIZ, fmt, args); va_end(args); err_append(buf); } void -Warning(fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_warn(char *fmt, ...) +#else +rb_warn(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + char buf[BUFSIZ]; + va_list args; + + snprintf(buf, BUFSIZ, "warning: %s", fmt); + + va_init_list(args, fmt); + err_print(buf, args); + va_end(args); +} + +/* rb_warning() reports only in verbose mode */ +void +#ifdef HAVE_STDARG_PROTOTYPES +rb_warning(char *fmt, ...) +#else +rb_warning(fmt, va_alist) char *fmt; va_dcl +#endif { char buf[BUFSIZ]; va_list args; - if (!RTEST(verbose)) return; + if (!RTEST(rb_verbose)) return; - sprintf(buf, "warning: %s", fmt); + snprintf(buf, BUFSIZ, "warning: %s", fmt); - va_start(args); + va_init_list(args, fmt); err_print(buf, args); va_end(args); } void -Bug(fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_bug(char *fmt, ...) +#else +rb_bug(fmt, va_alist) char *fmt; va_dcl +#endif { char buf[BUFSIZ]; va_list args; - sprintf(buf, "[BUG] %s", fmt); + snprintf(buf, BUFSIZ, "[BUG] %s", fmt); rb_in_eval = 0; - va_start(args); + va_init_list(args, fmt); err_print(buf, args); va_end(args); abort(); @@ -156,94 +182,133 @@ static struct types { -1, 0, }; -extern void TypeError(); - void rb_check_type(x, t) VALUE x; int t; { struct types *type = builtin_types; + int tt = TYPE(x); - if (TYPE(x)!=(t)) { + if (tt != t) { while (type->type >= 0) { if (type->type == t) { - TypeError("wrong argument type %s (expected %s)", - rb_class2name(CLASS_OF(x)), type->name); + char *etype; + + if (NIL_P(x)) { + etype = "nil"; + } + else if (FIXNUM_P(x)) { + etype = "Fixnum"; + } + else if (rb_special_const_p(x)) { + etype = RSTRING(rb_obj_as_string(x))->ptr; + } + else { + etype = rb_class2name(CLASS_OF(x)); + } + rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", + etype, type->name); } type++; } - Bug("unknown type 0x%x", t); + rb_bug("unknown type 0x%x", t); } } /* exception classes */ -#include "errno.h" - -extern VALUE cString; -VALUE eGlobalExit, eException; -VALUE eSystemExit, eInterrupt, eFatal; -VALUE eRuntimeError; -VALUE eSyntaxError; -VALUE eTypeError; -VALUE eArgError; -VALUE eNameError; -VALUE eIndexError; -VALUE eNotImpError; -VALUE eLoadError; -VALUE eSecurityError; - -VALUE eSystemCallError; -VALUE mErrno; +#include + +VALUE rb_eException; +VALUE rb_eSystemExit, rb_eInterrupt, rb_eFatal; +VALUE rb_eStandardError; +VALUE rb_eRuntimeError; +VALUE rb_eSyntaxError; +VALUE rb_eTypeError; +VALUE rb_eArgError; +VALUE rb_eNameError; +VALUE rb_eIndexError; +VALUE rb_eLoadError; +VALUE rb_eSecurityError; +VALUE rb_eNotImpError; + +VALUE rb_eSystemCallError; +VALUE rb_mErrno; VALUE -exc_new(etype, ptr, len) +rb_exc_new(etype, ptr, len) VALUE etype; char *ptr; - UINT len; + int len; { - NEWOBJ(exc, struct RString); - OBJSETUP(exc, etype, T_STRING); - - exc->len = len; - exc->orig = 0; - exc->ptr = ALLOC_N(char,len+1); - if (ptr) { - memcpy(exc->ptr, ptr, len); - } - exc->ptr[len] = '\0'; - return (VALUE)exc; + VALUE exc = rb_obj_alloc(etype); + + rb_iv_set(exc, "mesg", rb_str_new(ptr, len)); + return exc; } VALUE -exc_new2(etype, s) +rb_exc_new2(etype, s) VALUE etype; char *s; { - return exc_new(etype, s, strlen(s)); + return rb_exc_new(etype, s, strlen(s)); } VALUE -exc_new3(etype, str) +rb_exc_new3(etype, str) VALUE etype, str; { - Check_Type(str, T_STRING); - return exc_new(etype, RSTRING(str)->ptr, RSTRING(str)->len); + char *s; + int len; + + s = str2cstr(str, &len); + return rb_exc_new(etype, s, len); } static VALUE -exc_s_new(argc, argv, etype) +exc_initialize(argc, argv, exc) int argc; VALUE *argv; - VALUE etype; + VALUE exc; { - VALUE arg; + VALUE mesg; - if (rb_scan_args(argc, argv, "01", &arg) == 0) { - return exc_new(etype, 0, 0); + if (rb_scan_args(argc, argv, "01", &mesg) == 1) { + STR2CSTR(mesg); /* ensure mesg can be converted to String */ } - Check_Type(arg, T_STRING); - return exc_new3(etype, arg); + rb_iv_set(exc, "mesg", mesg); + + return exc; +} + +static VALUE +exc_new(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + VALUE etype, exc; + + if (argc == 1 && self == argv[0]) return self; + etype = CLASS_OF(self); + while (FL_TEST(etype, FL_SINGLETON)) { + etype = RCLASS(etype)->super; + } + exc = rb_obj_alloc(etype); + rb_obj_call_init(exc); + + return exc; +} + +static VALUE +exc_to_s(exc) + VALUE exc; +{ + VALUE mesg = rb_iv_get(exc, "mesg"); + + if (NIL_P(mesg)) return rb_class_path(CLASS_OF(exc)); + return mesg; } static VALUE @@ -253,185 +318,314 @@ exc_inspect(exc) VALUE str, klass; klass = CLASS_OF(exc); + exc = rb_obj_as_string(exc); if (RSTRING(exc)->len == 0) { - return rb_class_path(klass); + return rb_str_dup(rb_class_path(klass)); } - str = str_new2("#<"); + str = rb_str_new2("#<"); klass = rb_class_path(klass); - str_cat(str, RSTRING(klass)->ptr, RSTRING(klass)->len); - str_cat(str, ":", 1); - str_cat(str, RSTRING(exc)->ptr, RSTRING(exc)->len); - str_cat(str, ">", 1); + rb_str_concat(str, klass); + rb_str_cat(str, ":", 1); + rb_str_concat(str, exc); + rb_str_cat(str, ">", 1); return str; } +static VALUE +exc_backtrace(exc) + VALUE exc; +{ + return rb_iv_get(exc, "bt"); +} + +static VALUE +check_backtrace(bt) + VALUE bt; +{ + int i; + static char *err = "backtrace must be Array of String"; + + if (!NIL_P(bt)) { + int t = TYPE(bt); + + if (t == T_STRING) return rb_ary_new3(1, bt); + if (t != T_ARRAY) { + rb_raise(rb_eTypeError, err); + } + for (i=0;ilen;i++) { + if (TYPE(RARRAY(bt)->ptr[i]) != T_STRING) { + rb_raise(rb_eTypeError, err); + } + } + } + return bt; +} + +static VALUE +exc_set_backtrace(exc, bt) + VALUE exc; +{ + return rb_iv_set(exc, "bt", check_backtrace(bt)); +} + static VALUE exception(argc, argv) int argc; VALUE *argv; { - void ArgError(); VALUE v = Qnil; + VALUE etype = rb_eStandardError; int i; ID id; if (argc == 0) { - ArgError("wrong # of arguments"); + rb_raise(rb_eArgError, "wrong # of arguments"); + } + rb_warn("Exception() is now obsolete"); + if (TYPE(argv[argc-1]) == T_CLASS) { + etype = argv[argc-1]; + argc--; + if (!rb_funcall(etype, '<', 1, rb_eException)) { + rb_raise(rb_eTypeError, "exception should be subclass of Exception"); + } } for (i=0; i> 12) & 0xf; + offset = (i >> 8) & 0xf; + if (offset < syserr_index[ix].n) { + ix = syserr_index[ix].ix; + if ((i & 0xff) < syserr_list[ix + offset].n) { + list = syserr_list[ix + offset].list; + list[i & 0xff] = error; + rb_global_variable(&list[i & 0xff]); + } + } +#else if (i <= sys_nerr) { - syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError); - rb_global_variable(&syserr_list[i]); + syserr_list[i] = error; } +#endif + return error; } -static void init_syserr(); +static VALUE +syserr_errno(self) + VALUE self; +{ + return rb_iv_get(self, "errno"); +} + +#ifdef __BEOS__ +static VALUE +get_syserr(int i) +{ + VALUE *list; + int ix, offset; + + i -= B_GENERAL_ERROR_BASE; + ix = (i >> 12) & 0xf; + offset = (i >> 8) & 0xf; + if (offset < syserr_index[ix].n) { + ix = syserr_index[ix].ix; + if ((i & 0xff) < syserr_list[ix + offset].n) { + list = syserr_list[ix + offset].list; + return list[i & 0xff]; + } + } + return 0; +} +#endif /* __BEOS__ */ + +static void init_syserr _((void)); void Init_Exception() { - eGlobalExit = rb_define_class("GlobalExit", cString); - rb_define_singleton_method(eGlobalExit, "new", exc_s_new, -1); - rb_define_method(eGlobalExit, "inspect", exc_inspect, 0); - - eSystemExit = rb_define_class("SystemExit", eGlobalExit); - eFatal = rb_define_class("fatal", eGlobalExit); - eInterrupt = rb_define_class("Interrupt", eGlobalExit); - - eException = rb_define_class("Exception", eGlobalExit); - eSyntaxError = rb_define_class("SyntaxError", eException); - eTypeError = rb_define_class("TypeError", eException); - eArgError = rb_define_class("ArgumentError", eException); - eNameError = rb_define_class("NameError", eException); - eIndexError = rb_define_class("IndexError", eException); - eNotImpError = rb_define_class("NotImplementError", eException); - eLoadError = rb_define_class("LoadError", eException); - - eRuntimeError = rb_define_class("RuntimeError", eException); - eSecurityError = rb_define_class("SecurityError", eException); + rb_eException = rb_define_class("Exception", rb_cObject); + rb_define_method(rb_eException, "new", exc_new, -1); + rb_define_method(rb_eException, "initialize", exc_initialize, -1); + rb_define_method(rb_eException, "to_s", exc_to_s, 0); + rb_define_method(rb_eException, "to_str", exc_to_s, 0); + rb_define_method(rb_eException, "message", exc_to_s, 0); + rb_define_method(rb_eException, "inspect", exc_inspect, 0); + rb_define_method(rb_eException, "backtrace", exc_backtrace, 0); + rb_define_method(rb_eException, "set_backtrace", exc_set_backtrace, 1); + + rb_eSystemExit = rb_define_class("SystemExit", rb_eException); + rb_eFatal = rb_define_class("fatal", rb_eException); + rb_eInterrupt = rb_define_class("Interrupt", rb_eException); + + rb_eStandardError = rb_define_class("StandardError", rb_eException); + rb_eSyntaxError = rb_define_class("SyntaxError", rb_eStandardError); + rb_eTypeError = rb_define_class("TypeError", rb_eStandardError); + rb_eArgError = rb_define_class("ArgumentError", rb_eStandardError); + rb_eNameError = rb_define_class("NameError", rb_eStandardError); + rb_eIndexError = rb_define_class("IndexError", rb_eStandardError); + rb_eLoadError = rb_define_class("LoadError", rb_eStandardError); + + rb_eRuntimeError = rb_define_class("RuntimeError", rb_eStandardError); + rb_eSecurityError = rb_define_class("SecurityError", rb_eStandardError); + rb_eNotImpError = rb_define_class("NotImplementError", rb_eException); init_syserr(); rb_define_global_function("Exception", exception, -1); } -#define RAISE_ERROR(class) {\ - va_list args;\ - char buf[BUFSIZ];\ -\ - va_start(args);\ - vsprintf(buf, fmt, args);\ - va_end(args);\ -\ - rb_raise(exc_new2(class, buf));\ -} - void -Raise(exc, fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_raise(VALUE exc, char *fmt, ...) +#else +rb_raise(exc, fmt, va_alist) VALUE exc; char *fmt; va_dcl +#endif { - RAISE_ERROR(exc); -} - -void -TypeError(fmt, va_alist) - char *fmt; - va_dcl -{ - RAISE_ERROR(eTypeError); -} - -void -ArgError(fmt, va_alist) - char *fmt; - va_dcl -{ - RAISE_ERROR(eArgError); -} + va_list args; + char buf[BUFSIZ]; -void -NameError(fmt, va_alist) - char *fmt; - va_dcl -{ - RAISE_ERROR(eNameError); + va_init_list(args,fmt); + vsnprintf(buf, BUFSIZ, fmt, args); + va_end(args); + rb_exc_raise(rb_exc_new2(exc, buf)); } void -IndexError(fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_loaderror(char *fmt, ...) +#else +rb_loaderror(fmt, va_alist) char *fmt; va_dcl +#endif { - RAISE_ERROR(eIndexError); -} + va_list args; + char buf[BUFSIZ]; -void -Fail(fmt, va_alist) - char *fmt; - va_dcl -{ - RAISE_ERROR(eRuntimeError); + va_init_list(args, fmt); + vsnprintf(buf, BUFSIZ, fmt, args); + va_end(args); + rb_exc_raise(rb_exc_new2(rb_eLoadError, buf)); } void rb_notimplement() { - Raise(eNotImpError, - "The %s() function is unimplemented on this machine", - rb_id2name(the_frame->last_func)); + rb_raise(rb_eNotImpError, + "The %s() function is unimplemented on this machine", + rb_id2name(ruby_frame->last_func)); } void -LoadError(fmt, va_alist) - char *fmt; - va_dcl -{ - RAISE_ERROR(eLoadError); -} - -void -Fatal(fmt, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_fatal(char *fmt, ...) +#else +rb_fatal(fmt, va_alist) char *fmt; va_dcl +#endif { va_list args; char buf[BUFSIZ]; - va_start(args); - vsprintf(buf, fmt, args); + va_init_list(args, fmt); + vsnprintf(buf, BUFSIZ, fmt, args); va_end(args); rb_in_eval = 0; - rb_fatal(exc_new2(eFatal, buf)); + rb_exc_fatal(rb_exc_new2(rb_eFatal, buf)); } void @@ -441,32 +635,79 @@ rb_sys_fail(mesg) #ifndef NT char *strerror(); #endif - char buf[BUFSIZ]; + char *err; + char *buf; extern int errno; int n = errno; + VALUE ee; - if (RTEST(mesg)) - sprintf(buf, "%s - %s", strerror(errno), mesg); - else - sprintf(buf, "%s", strerror(errno)); + err = strerror(errno); + if (mesg) { + buf = ALLOCA_N(char, strlen(err)+strlen(mesg)+4); + sprintf(buf, "%s - %s", err, mesg); + } + else { + buf = ALLOCA_N(char, strlen(err)+1); + strcpy(buf, err); + } errno = 0; +#ifdef __BEOS__ + ee = get_syserr(n); + if (!ee) { + char name[6]; + + sprintf(name, "E%03d", n); + ee = set_syserr(n, name); + } +#else +# ifdef USE_CWGUSI + if (n < 0) { + int macoserr_index = sys_nerr - 1; + if (!syserr_list[macoserr_index]) { + char name[6]; + sprintf(name, "E%03d", macoserr_index); + ee = set_syserr(macoserr_index, name); + } + } + else +#endif /* USE_CWGUSI */ if (n > sys_nerr || !syserr_list[n]) { char name[6]; sprintf(name, "E%03d", n); - set_syserr(n, name); + ee = set_syserr(n, name); + } + else { + ee = syserr_list[n]; } - rb_raise(exc_new2(syserr_list[n], buf)); + ee = rb_exc_new2(ee, buf); +#endif + rb_iv_set(ee, "errno", INT2FIX(n)); + rb_exc_raise(ee); } static void init_syserr() { - eSystemCallError = rb_define_class("SystemCallError", eException); - mErrno = rb_define_module("Errno"); +#ifdef __BEOS__ + int i, ix, offset; +#endif + rb_eSystemCallError = rb_define_class("SystemCallError", rb_eStandardError); + rb_define_method(rb_eSystemCallError, "errno", syserr_errno, 0); + + rb_mErrno = rb_define_module("Errno"); +#ifdef __BEOS__ + for (i = 0; syserr_index[i].n != 0; i++) { + ix = syserr_index[i].ix; + for (offset = 0; offset < syserr_index[i].n; offset++) { + MEMZERO(syserr_list[ix + offset].list, VALUE, syserr_list[ix + offset].n); + } + } +#else syserr_list = ALLOC_N(VALUE, sys_nerr+1); MEMZERO(syserr_list, VALUE, sys_nerr+1); +#endif #ifdef EPERM set_syserr(EPERM, "EPERM"); @@ -835,3 +1076,28 @@ init_syserr() set_syserr(EDQUOT, "EDQUOT"); #endif } + +static void +err_append(s) + char *s; +{ + extern VALUE rb_errinfo; + + if (rb_in_eval) { + if (NIL_P(rb_errinfo)) { + rb_errinfo = rb_exc_new2(rb_eSyntaxError, s); + } + else { + VALUE str = rb_str_to_str(rb_errinfo); + + rb_str_cat(str, "\n", 1); + rb_str_cat(str, s, strlen(s)); + rb_errinfo = rb_exc_new3(rb_eSyntaxError, str); + } + } + else { + fputs(s, stderr); + fputs("\n", stderr); + fflush(stderr); + } +} diff --git a/eval.c b/eval.c index 42617c2b27..a7da313fbe 100644 --- a/eval.c +++ b/eval.c @@ -6,14 +6,14 @@ $Date$ created at: Thu Jun 10 14:22:17 JST 1993 - Copyright (C) 1993-1997 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "node.h" #include "env.h" -#include "sig.h" +#include "rubysig.h" #include #include @@ -21,13 +21,23 @@ #include "dln.h" #ifndef HAVE_STRING_H -char *strrchr(); +char *strrchr _((char*,char)); #endif #ifdef HAVE_UNISTD_H #include #endif +#ifdef __BEOS__ +#include +#endif + +#ifdef USE_CWGUSI +#include +#include +#include +#endif + #ifndef setjmp #ifdef HAVE__SETJMP #define setjmp(env) _setjmp(env) @@ -35,23 +45,33 @@ char *strrchr(); #endif #endif -extern VALUE cData; - -VALUE cProc; +VALUE rb_cProc; +static VALUE rb_cBinding; static VALUE proc_call _((VALUE,VALUE)); -static VALUE f_binding _((VALUE)); -static void f_END _((void)); - -#define SCOPE_PRIVATE FL_USER4 - -#define CACHE_SIZE 0x200 -#define CACHE_MASK 0x1ff -#define EXPR1(c,m) ((((int)(c)>>3)^(m))&CACHE_MASK) +static VALUE rb_f_binding _((VALUE)); +static void rb_f_END _((void)); +static VALUE rb_f_iterator_p _((void)); +static VALUE block_pass _((VALUE,NODE*)); +static VALUE rb_cMethod; +static VALUE method_proc _((VALUE)); + +static int scope_vmode; +#define SCOPE_PUBLIC 0 +#define SCOPE_PRIVATE 1 +#define SCOPE_PROTECTED 2 +#define SCOPE_MODFUNC 5 +#define SCOPE_MASK 7 +#define SCOPE_SET(f) do {scope_vmode=(f);} while(0) +#define SCOPE_TEST(f) (scope_vmode&(f)) + +#define CACHE_SIZE 0x800 +#define CACHE_MASK 0x7ff +#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK) struct cache_entry { /* method hash table. */ ID mid; /* method's id */ ID mid0; /* method's original id */ - VALUE class; /* receiver's class */ + VALUE klass; /* receiver's class */ VALUE origin; /* where method defined */ NODE *method; int noex; @@ -87,80 +107,69 @@ rb_clear_cache_by_id(id) } void -rb_add_method(class, mid, node, noex) - VALUE class; +rb_add_method(klass, mid, node, noex) + VALUE klass; ID mid; NODE *node; int noex; { NODE *body; - if (NIL_P(class)) class = cObject; - body = NEW_METHOD(node, noex); - st_insert(RCLASS(class)->m_tbl, mid, body); -} - -void -rb_remove_method(class, mid) - VALUE class; - ID mid; -{ - NODE *body; - - if (!st_delete(RCLASS(class)->m_tbl, &mid, &body)) { - NameError("method `%s' not defined in %s", - rb_id2name(mid), rb_class2name(class)); + if (NIL_P(klass)) klass = rb_cObject; + if (klass == rb_cObject) { + rb_secure(4); } - rb_clear_cache_by_id(mid); + body = NEW_METHOD(node, noex); + st_insert(RCLASS(klass)->m_tbl, mid, body); } static NODE* -search_method(class, id, origin) - VALUE class, *origin; +search_method(klass, id, origin) + VALUE klass, *origin; ID id; { NODE *body; - while (!st_lookup(RCLASS(class)->m_tbl, id, &body)) { - class = (VALUE)RCLASS(class)->super; - if (!class) return 0; + while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) { + klass = RCLASS(klass)->super; + if (!klass) return 0; } - if (origin) *origin = class; + if (origin) *origin = klass; return body; } static NODE* -rb_get_method_body(classp, idp, noexp) - VALUE *classp; +rb_get_method_body(klassp, idp, noexp) + VALUE *klassp; ID *idp; int *noexp; { ID id = *idp; - VALUE class = *classp; + VALUE klass = *klassp; VALUE origin; - NODE *body; + NODE * volatile body; struct cache_entry *ent; - if ((body = search_method(class, id, &origin)) == 0) { + if ((body = search_method(klass, id, &origin)) == 0) { return 0; } if (!body->nd_body) return 0; /* store in cache */ - ent = cache + EXPR1(class, id); - ent->class = class; + ent = cache + EXPR1(klass, id); + ent->klass = klass; ent->noex = body->nd_noex; body = body->nd_body; if (nd_type(body) == NODE_FBODY) { ent->mid = id; - *classp = body->nd_orig; + *klassp = body->nd_orig; ent->origin = body->nd_orig; *idp = ent->mid0 = body->nd_mid; body = ent->method = body->nd_head; } else { - *classp = (VALUE)origin; + *klassp = origin; ent->origin = origin; ent->mid = ent->mid0 = id; ent->method = body; @@ -171,23 +180,26 @@ rb_get_method_body(classp, idp, noexp) } void -rb_alias(class, name, def) - VALUE class; +rb_alias(klass, name, def) + VALUE klass; ID name, def; { VALUE origin; NODE *orig, *body; if (name == def) return; - orig = search_method(class, def, &origin); + if (klass == rb_cObject) { + rb_secure(4); + } + orig = search_method(klass, def, &origin); if (!orig || !orig->nd_body) { - if (TYPE(class) == T_MODULE) { - orig = search_method(cObject, def, &origin); + if (TYPE(klass) == T_MODULE) { + orig = search_method(rb_cObject, def, &origin); } } if (!orig || !orig->nd_body) { - NameError("undefined method `%s' for `%s'", - rb_id2name(def), rb_class2name((VALUE)class)); + rb_raise(rb_eNameError, "undefined method `%s' for `%s'", + rb_id2name(def), rb_class2name(klass)); } body = orig->nd_body; if (nd_type(body) == NODE_FBODY) { /* was alias */ @@ -196,101 +208,194 @@ rb_alias(class, name, def) origin = body->nd_orig; } - st_insert(RCLASS(class)->m_tbl, name, + st_insert(RCLASS(klass)->m_tbl, name, NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)); } static void -rb_export_method(class, name, noex) - VALUE class; +remove_method(klass, mid) + VALUE klass; + ID mid; +{ + NODE *body; + + if (klass == rb_cObject) { + rb_secure(4); + } + if (!st_delete(RCLASS(klass)->m_tbl, &mid, &body)) { + rb_raise(rb_eNameError, "method `%s' not defined in %s", + rb_id2name(mid), rb_class2name(klass)); + } + rb_clear_cache_by_id(mid); +} + +void +rb_remove_method(klass, name) + VALUE klass; + char *name; +{ + remove_method(klass, rb_intern(name)); +} + +void +rb_disable_super(klass, name) + VALUE klass; + char *name; +{ + VALUE origin; + NODE *body; + ID mid = rb_intern(name); + + body = search_method(klass, mid, &origin); + if (!body || !body->nd_body) { + rb_raise(rb_eNameError, "undefined method `%s' for `%s'", + rb_id2name(mid), rb_class2name(klass)); + } + if (origin == klass) { + body->nd_noex |= NOEX_UNDEF; + } + else { + rb_clear_cache_by_id(mid); + rb_add_method(ruby_class, mid, 0, NOEX_UNDEF); + } +} + +void +rb_enable_super(klass, name) + VALUE klass; + char *name; +{ + VALUE origin; + NODE *body; + ID mid = rb_intern(name); + + body = search_method(klass, mid, &origin); + if (!body || !body->nd_body || origin != klass) { + rb_raise(rb_eNameError, "undefined method `%s' for `%s'", + rb_id2name(mid), rb_class2name(klass)); + } + body->nd_noex &= ~NOEX_UNDEF; +} + +static void +rb_export_method(klass, name, noex) + VALUE klass; ID name; - int noex; + ID noex; { NODE *body; - struct RClass *origin; + VALUE origin; - body = search_method(class, name, &origin); - if (!body && TYPE(class) == T_MODULE) { - body = search_method(cObject, name, &origin); + if (klass == rb_cObject) { + rb_secure(4); + } + body = search_method(klass, name, &origin); + if (!body && TYPE(klass) == T_MODULE) { + body = search_method(rb_cObject, name, &origin); } if (!body) { - NameError("undefined method `%s' for `%s'", - rb_id2name(name), rb_class2name(class)); + rb_raise(rb_eNameError, "undefined method `%s' for `%s'", + rb_id2name(name), rb_class2name(klass)); } if (body->nd_noex != noex) { - if (class == (VALUE)origin) { + if (klass == origin) { body->nd_noex = noex; } else { rb_clear_cache_by_id(name); - rb_add_method(class, name, NEW_ZSUPER(), noex); + rb_add_method(klass, name, NEW_ZSUPER(), noex); } } } -static VALUE -method_boundp(class, id, ex) - VALUE class; +int +rb_method_boundp(klass, id, ex) + VALUE klass; ID id; int ex; { int noex; - if (rb_get_method_body(&class, &id, &noex)) { - if (ex && noex == NOEX_PRIVATE) - return FALSE; - return TRUE; + if (rb_get_method_body(&klass, &id, &noex)) { + if (ex && noex & NOEX_PRIVATE) + return Qfalse; + return Qtrue; } - return FALSE; + return Qfalse; } -int -rb_method_boundp(class, id, ex) - VALUE class; +void +rb_attr(klass, id, read, write, ex) + VALUE klass; ID id; - int ex; + int read, write, ex; { - if (method_boundp(class, id, ex)) - return TRUE; - return FALSE; + char *name; + char *buf; + ID attriv; + int noex; + + if (!ex) noex = NOEX_PUBLIC; + else { + if (SCOPE_TEST(SCOPE_PRIVATE)) { + noex = NOEX_PRIVATE; + rb_warning("private attribute?"); + } + else if (SCOPE_TEST(SCOPE_PROTECTED)) { + noex = NOEX_PROTECTED; + } + else { + noex = NOEX_PUBLIC; + } + } + + name = rb_id2name(id); + if (!name) { + rb_raise(rb_eArgError, "argument needs to be symbol or string"); + } + buf = ALLOCA_N(char,strlen(name)+2); + sprintf(buf, "@%s", name); + attriv = rb_intern(buf); + if (read) { + rb_add_method(klass, id, NEW_IVAR(attriv), noex); + } + sprintf(buf, "%s=", name); + id = rb_intern(buf); + if (write) { + rb_add_method(klass, id, NEW_ATTRSET(attriv), noex); + } } static ID init, eqq, each, aref, aset, match; -VALUE errinfo = Qnil, errat = Qnil; -extern NODE *eval_tree0; -extern NODE *eval_tree; -extern int nerrs; - -extern VALUE mKernel; -extern VALUE cModule; -extern VALUE cClass; -extern VALUE eFatal; -extern VALUE eGlobalExit; -extern VALUE eInterrupt; -extern VALUE eSystemExit; -extern VALUE eException; -extern VALUE eRuntimeError; -extern VALUE eSyntaxError; -static VALUE eLocalJumpError; -extern VALUE eSecurityError; - -extern VALUE TopSelf; - -struct FRAME *the_frame; -struct SCOPE *the_scope; +VALUE rb_errinfo = Qnil; +extern NODE *ruby_eval_tree_begin; +extern NODE *ruby_eval_tree; +extern int ruby_nerrs; + +static VALUE rb_eLocalJumpError; +static VALUE rb_eSysStackError; + +extern VALUE ruby_top_self; + +struct FRAME *ruby_frame; +struct SCOPE *ruby_scope; static struct FRAME *top_frame; static struct SCOPE *top_scope; #define PUSH_FRAME() { \ - struct FRAME *_frame = ALLOCA_N(struct FRAME,1);\ - _frame->prev = the_frame; \ - _frame->file = sourcefile; \ - _frame->line = sourceline; \ - _frame->iter = the_iter->iter; \ - _frame->cbase = the_frame->cbase; \ - the_frame = _frame; \ - -#define POP_FRAME() the_frame = _frame->prev; } + struct FRAME _frame; \ + _frame.prev = ruby_frame; \ + _frame.file = ruby_sourcefile; \ + _frame.line = ruby_sourceline; \ + _frame.iter = ruby_iter->iter; \ + _frame.cbase = ruby_frame->cbase; \ + _frame.argc = 0; \ + ruby_frame = &_frame; \ + +#define POP_FRAME() \ + ruby_sourcefile = _frame.file; \ + ruby_sourceline = _frame.line; \ + ruby_frame = _frame.prev; } struct BLOCK { NODE *var; @@ -298,70 +403,95 @@ struct BLOCK { VALUE self; struct FRAME frame; struct SCOPE *scope; - VALUE class; + VALUE klass; struct tag *tag; int iter; + int vmode; struct RVarmap *d_vars; -#ifdef THREAD +#ifdef USE_THREAD VALUE orig_thread; #endif struct BLOCK *prev; -} *the_block; +}; +static struct BLOCK *ruby_block; +static struct BLOCK *ruby_calling_block; #define PUSH_BLOCK(v,b) { \ - struct BLOCK *_block = ALLOCA_N(struct BLOCK,1);\ - _block->tag = prot_tag; \ - _block->var = v; \ - _block->body = b; \ - _block->self = self; \ - _block->frame = *the_frame; \ - _block->class = the_class; \ - _block->frame.file = sourcefile; \ - _block->frame.line = sourceline; \ - _block->scope = the_scope; \ - _block->d_vars = the_dyna_vars; \ - _block->prev = the_block; \ - _block->iter = the_iter->iter; \ - the_block = _block; + struct BLOCK _block; \ + _block.tag = prot_tag; \ + _block.var = v; \ + _block.body = b; \ + _block.self = self; \ + _block.frame = *ruby_frame; \ + _block.klass = ruby_class; \ + _block.frame.file = ruby_sourcefile;\ + _block.frame.line = ruby_sourceline;\ + _block.scope = ruby_scope; \ + _block.d_vars = ruby_dyna_vars; \ + _block.prev = ruby_block; \ + _block.iter = ruby_iter->iter; \ + _block.vmode = scope_vmode; \ + ruby_block = &_block; + +#define POP_BLOCK() \ + ruby_block = _block.prev; \ +} #define PUSH_BLOCK2(b) { \ - struct BLOCK *_block = ALLOCA_N(struct BLOCK,1);\ - *_block = *b; \ - _block->prev = the_block; \ - the_block = _block; + struct BLOCK * volatile _old; \ + struct BLOCK * volatile _old_call; \ + _old = ruby_block; \ + _old_call = ruby_calling_block; \ + ruby_calling_block = b; \ + ruby_block = b; -#define POP_BLOCK() \ - the_block = the_block->prev; \ +#define POP_BLOCK2() \ + ruby_calling_block = _old_call; \ + ruby_block = _old; \ } -struct RVarmap *the_dyna_vars; +struct RVarmap *ruby_dyna_vars; #define PUSH_VARS() { \ - struct RVarmap *_old; \ - _old = the_dyna_vars; \ - the_dyna_vars = 0; + struct RVarmap * volatile _oldvmap; \ + _oldvmap = ruby_dyna_vars; \ + ruby_dyna_vars = 0; #define POP_VARS() \ - the_dyna_vars = _old; \ + ruby_dyna_vars = _oldvmap; \ +} + +static struct RVarmap* +new_dvar(id, value) + ID id; + VALUE value; +{ + NEWOBJ(vars, struct RVarmap); + OBJSETUP(vars, 0, T_VARMAP); + vars->id = id; + vars->val = value; + vars->next = ruby_dyna_vars; + + return vars; } VALUE -dyna_var_defined(id) +rb_dvar_defined(id) ID id; { - struct RVarmap *vars = the_dyna_vars; + struct RVarmap *vars = ruby_dyna_vars; while (vars) { - if (vars->id == id) return TRUE; + if (vars->id == id) return Qtrue; vars = vars->next; } - return FALSE; + return Qfalse; } VALUE -dyna_var_ref(id) +rb_dvar_ref(id) ID id; { - struct RVarmap *vars = the_dyna_vars; + struct RVarmap *vars = ruby_dyna_vars; while (vars) { if (vars->id == id) { @@ -372,35 +502,48 @@ dyna_var_ref(id) return Qnil; } -VALUE -dyna_var_asgn(id, value) +void +rb_dvar_push(id, value) + ID id; + VALUE value; +{ + ruby_dyna_vars = new_dvar(id, value); +} + +void +rb_dvar_asgn(id, value) ID id; VALUE value; { - struct RVarmap *vars = the_dyna_vars; + struct RVarmap *vars = ruby_dyna_vars; while (vars) { if (vars->id == id) { vars->val = value; - return value; + return; } vars = vars->next; } - { - NEWOBJ(_vars, struct RVarmap); - OBJSETUP(_vars, 0, T_VARMAP); - _vars->id = id; - _vars->val = value; - _vars->next = the_dyna_vars; - the_dyna_vars = _vars; + rb_dvar_push(id, value); + return; +} + +static void +dvar_asgn_push(id, value) + ID id; + VALUE value; +{ + rb_dvar_asgn(id, value); + if (ruby_calling_block) { + ruby_calling_block->d_vars = ruby_dyna_vars; } - return value; } -static struct iter { +struct iter { int iter; struct iter *prev; -} *the_iter; +}; +static struct iter *ruby_iter; #define ITER_NOT 0 #define ITER_PRE 1 @@ -408,46 +551,35 @@ static struct iter { #define PUSH_ITER(i) { \ struct iter _iter; \ - _iter.prev = the_iter; \ + _iter.prev = ruby_iter; \ _iter.iter = (i); \ - the_iter = &_iter; \ + ruby_iter = &_iter; \ #define POP_ITER() \ - the_iter = _iter.prev; \ + ruby_iter = _iter.prev; \ } -#ifdef C_ALLOCA -/* need to protect retval in struct tag from GC. */ -#define tag_retval_dcl VALUE *dd_retval -#define tag_retval_init VALUE _tag_retval = Qnil;\ - _tag->dd_retval = &_tag_retval; -#define tag_retval dd_retval[0] -#else -#define tag_retval_dcl VALUE retval -#define tag_retval_init _tag->retval = Qnil -#define tag_retval retval -#endif - -static struct tag { +struct tag { jmp_buf buf; struct FRAME *frame; struct iter *iter; ID tag; - tag_retval_dcl; - ID dst; + VALUE retval; + int dst; struct tag *prev; -} *prot_tag; +}; +static struct tag *prot_tag; #define PUSH_TAG(ptag) { \ - struct tag *_tag = ALLOCA_N(struct tag,1);\ - tag_retval_init; \ - _tag->frame = the_frame; \ - _tag->iter = the_iter; \ - _tag->prev = prot_tag; \ - _tag->tag_retval = Qnil; \ - _tag->tag = ptag; \ - _tag->dst = 0; \ - prot_tag = _tag; + struct tag _tag; \ + _tag.retval = Qnil; \ + _tag.frame = ruby_frame; \ + _tag.iter = ruby_iter; \ + _tag.prev = prot_tag; \ + _tag.retval = Qnil; \ + _tag.tag = ptag; \ + _tag.dst = 0; \ + prot_tag = &_tag; #define PROT_NONE 0 #define PROT_FUNC -1 @@ -456,13 +588,15 @@ static struct tag { #define EXEC_TAG() setjmp(prot_tag->buf) #define JUMP_TAG(st) { \ - the_frame = prot_tag->frame; \ - the_iter = prot_tag->iter; \ + ruby_frame = prot_tag->frame; \ + ruby_iter = prot_tag->iter; \ longjmp(prot_tag->buf,(st)); \ } #define POP_TAG() \ - prot_tag = _tag->prev; \ + if (_tag.prev) \ + _tag.prev->retval = _tag.retval;\ + prot_tag = _tag.prev; \ } #define TAG_RETURN 0x1 @@ -475,57 +609,68 @@ static struct tag { #define TAG_FATAL 0x8 #define TAG_MASK 0xf -VALUE the_class; +VALUE ruby_class; +static VALUE ruby_wrapper; /* security wrapper */ #define PUSH_CLASS() { \ - VALUE _class = the_class; \ + VALUE _class = ruby_class; \ -#define POP_CLASS() the_class = _class; } +#define POP_CLASS() ruby_class = _class; } #define PUSH_SCOPE() { \ - struct SCOPE *_old; \ + volatile int _vmode = scope_vmode; \ + struct SCOPE * volatile _old; \ NEWOBJ(_scope, struct SCOPE); \ OBJSETUP(_scope, 0, T_SCOPE); \ _scope->local_tbl = 0; \ _scope->local_vars = 0; \ _scope->flag = 0; \ - _old = the_scope; \ - the_scope = _scope; \ + _old = ruby_scope; \ + ruby_scope = _scope; \ + scope_vmode = SCOPE_PUBLIC; + +#define SCOPE_DONT_RECYCLE FL_USER2 + +static void scope_dup(struct SCOPE *); #define POP_SCOPE() \ - if (the_scope->flag == SCOPE_ALLOCA) {\ - the_scope->local_vars = 0;\ - the_scope->local_tbl = 0;\ - if (the_scope != top_scope)\ - gc_force_recycle(the_scope);\ + if (ruby_scope->flag == SCOPE_ALLOCA) {\ + if (FL_TEST(ruby_scope, SCOPE_DONT_RECYCLE)) {\ + scope_dup(ruby_scope);\ + FL_SET(_old, SCOPE_DONT_RECYCLE);\ + }\ + else {\ + ruby_scope->local_vars = 0;\ + ruby_scope->local_tbl = 0;\ + if (ruby_scope != top_scope)\ + rb_gc_force_recycle((VALUE)ruby_scope);\ + }\ }\ else {\ - the_scope->flag |= SCOPE_NOSTACK;\ + ruby_scope->flag |= SCOPE_NOSTACK;\ }\ - the_scope = _old;\ + ruby_scope = _old;\ + scope_vmode = _vmode;\ } -static VALUE rb_eval(); -static VALUE eval(); -static NODE *compile(); - -static VALUE rb_call(); -VALUE rb_apply(); -VALUE rb_funcall2(); +static VALUE rb_eval _((VALUE,NODE*)); +static VALUE eval _((VALUE,VALUE,VALUE,char*,int)); +static NODE *compile _((VALUE,char*)); +static VALUE rb_yield_0 _((VALUE, VALUE, VALUE)); -static VALUE module_setup(); +static VALUE rb_call _((VALUE,VALUE,ID,int,VALUE*,int)); +static VALUE module_setup _((VALUE,NODE*)); -static VALUE massign(); -static void assign(); +static VALUE massign _((VALUE,NODE*,VALUE)); +static void assign _((VALUE,NODE*,VALUE)); static int safe_level = 0; /* safe-level: 0 - strings from streams/environment/ARGV are tainted (default) 1 - no dangerous operation by tainted string - 2 - some process operations prohibited + 2 - process/file operations prohibited 3 - all genetated strings are tainted - 4 - no global variable value modification/no direct output - 5 - no instance variable value modification + 4 - no global (non-tainted) variable modification/no direct output */ int @@ -556,8 +701,8 @@ safe_setter(val) int level = NUM2INT(val); if (level < safe_level) { - Raise(eSecurityError, "tried to downgrade safe level from %d to %d", - safe_level, level); + rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", + safe_level, level); } safe_level = level; } @@ -567,12 +712,14 @@ rb_check_safe_str(x) VALUE x; { if (TYPE(x)!= T_STRING) { - TypeError("wrong argument type %s (expected String)", - rb_class2name(CLASS_OF(x))); + rb_raise(rb_eTypeError, "wrong argument type %s (expected String)", + rb_class2name(CLASS_OF(x))); } - if (rb_safe_level() > 0 && str_tainted(x)) { - Raise(eSecurityError, "Insecure operation - %s", - rb_id2name(the_frame->last_func)); + if (OBJ_TAINTED(x)) { + if (safe_level > 0){ + rb_raise(rb_eSecurityError, "Insecure operation - %s", + rb_id2name(ruby_frame->last_func)); + } } } @@ -581,87 +728,95 @@ rb_secure(level) int level; { if (level <= safe_level) { - Raise(eSecurityError, "Insecure operation `%s' for level %d", - rb_id2name(the_frame->last_func), level); + rb_raise(rb_eSecurityError, "Insecure operation `%s' for level %d", + rb_id2name(ruby_frame->last_func), safe_level); } } -extern int sourceline; -extern char *sourcefile; - static VALUE trace_func = 0; -static void call_trace_func(); +static void call_trace_func _((char*,char*,int,VALUE,ID,VALUE)); static void error_pos() { - if (sourcefile) { - if (the_frame->last_func) { - fprintf(stderr, "%s:%d:in `%s'", sourcefile, sourceline, - rb_id2name(the_frame->last_func)); + if (ruby_sourcefile) { + if (ruby_frame->last_func) { + fprintf(stderr, "%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline, + rb_id2name(ruby_frame->last_func)); } else { - fprintf(stderr, "%s:%d", sourcefile, sourceline); + fprintf(stderr, "%s:%d", ruby_sourcefile, ruby_sourceline); } } } +static VALUE +get_backtrace(info) + VALUE info; +{ + if (NIL_P(info)) return Qnil; + return rb_funcall(info, rb_intern("backtrace"), 0); +} + +static void +set_backtrace(info, bt) + VALUE info, bt; +{ + rb_funcall(info, rb_intern("set_backtrace"), 1, bt); +} + static void error_print() { + VALUE errat; VALUE eclass; + VALUE einfo; + volatile int safe = safe_level; - if (NIL_P(errinfo)) return; + if (NIL_P(rb_errinfo)) return; + errat = get_backtrace(rb_errinfo); if (!NIL_P(errat)) { - VALUE mesg = Qnil; + VALUE mesg = RARRAY(errat)->ptr[0]; - switch (TYPE(errat)) { - case T_STRING: - mesg = errat; - errat = Qnil; - break; - case T_ARRAY: - mesg = RARRAY(errat)->ptr[0]; - break; - } if (NIL_P(mesg)) error_pos(); else { fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr); } } - eclass = CLASS_OF(errinfo); - if (eclass == eRuntimeError && RSTRING(errinfo)->len == 0) { + eclass = CLASS_OF(rb_errinfo); + einfo = rb_obj_as_string(rb_errinfo); + if (eclass == rb_eRuntimeError && RSTRING(einfo)->len == 0) { fprintf(stderr, ": unhandled exception\n"); } else { VALUE epath; epath = rb_class_path(eclass); - if (RSTRING(errinfo)->len == 0) { + if (RSTRING(einfo)->len == 0) { fprintf(stderr, ": "); fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr); putc('\n', stderr); } else { - unsigned char *tail = 0; - int len = RSTRING(errinfo)->len; + char *tail = 0; + int len = RSTRING(einfo)->len; if (RSTRING(epath)->ptr[0] == '#') epath = 0; - if (tail = strchr(RSTRING(errinfo)->ptr, '\n')) { - len = tail - RSTRING(errinfo)->ptr; + if (tail = strchr(RSTRING(einfo)->ptr, '\n')) { + len = tail - RSTRING(einfo)->ptr; tail++; /* skip newline */ } fprintf(stderr, ": "); - fwrite(RSTRING(errinfo)->ptr, 1, len, stderr); + fwrite(RSTRING(einfo)->ptr, 1, len, stderr); if (epath) { fprintf(stderr, " ("); fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr); fprintf(stderr, ")\n"); } if (tail) { - fwrite(tail, 1, RSTRING(errinfo)->len-len-1, stderr); + fwrite(tail, 1, RSTRING(einfo)->len-len-1, stderr); putc('\n', stderr); } } @@ -677,7 +832,9 @@ error_print() ep = RARRAY(errat); for (i=1; ilen; i++) { - fprintf(stderr, "\tfrom %s\n", RSTRING(ep->ptr[i])->ptr); + if (TYPE(ep->ptr[i]) == T_STRING) { + fprintf(stderr, "\tfrom %s\n", RSTRING(ep->ptr[i])->ptr); + } if (i == TRACE_HEAD && ep->len > TRACE_MAX) { fprintf(stderr, "\t ... %d levels...\n", ep->len - TRACE_HEAD - TRACE_TAIL); @@ -685,18 +842,18 @@ error_print() } } } + safe_level = safe; } -#ifndef NT +#if !defined(NT) && !defined(__MACOS__) extern char **environ; #endif -char **origenviron; +char **rb_origenviron; void rb_call_inits _((void)); -void init_stack _((void)); -void init_heap _((void)); +void Init_stack _((void)); +void Init_heap _((void)); void Init_ext _((void)); -void gc_call_finalizer_at_exit _((void)); void ruby_init() @@ -705,31 +862,36 @@ ruby_init() static struct iter iter; int state; - the_frame = top_frame = &frame; - the_iter = &iter; + ruby_frame = top_frame = &frame; + ruby_iter = &iter; - origenviron = environ; +#ifdef __MACOS__ + rb_origenviron = 0; +#else + rb_origenviron = environ; +#endif - init_heap(); + Init_heap(); PUSH_SCOPE(); - the_scope->local_vars = 0; - the_scope->local_tbl = 0; - top_scope = the_scope; + ruby_scope->local_vars = 0; + ruby_scope->local_tbl = 0; + top_scope = ruby_scope; /* default visibility is private at toplevel */ - FL_SET(top_scope, SCOPE_PRIVATE); + SCOPE_SET(SCOPE_PRIVATE); PUSH_TAG(PROT_NONE) if ((state = EXEC_TAG()) == 0) { rb_call_inits(); - the_class = cObject; - the_frame->cbase = (VALUE)node_newnode(NODE_CREF,cObject,0,0); - rb_define_global_const("TOPLEVEL_BINDING", f_binding(TopSelf)); + ruby_class = rb_cObject; + ruby_frame->self = ruby_top_self; + ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,rb_cObject,0,0); + rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self)); ruby_prog_init(); } POP_TAG(); if (state) error_print(); POP_SCOPE(); - the_scope = top_scope; + ruby_scope = top_scope; } static int ext_init = 0; @@ -746,15 +908,14 @@ ruby_options(argc, argv) NODE *save; ruby_process_options(argc, argv); - save = eval_tree; - eval_tree = 0; - Init_ext(); - ext_init = 1; - rb_require_modules(); - eval_tree = save; + ext_init = 1; /* Init_ext() called in ruby_process_options */ + save = ruby_eval_tree; + ruby_require_modules(); + ruby_eval_tree = save; } POP_TAG(); if (state) { + trace_func = 0; error_print(); exit(1); } @@ -767,16 +928,16 @@ eval_node(self) VALUE result = Qnil; NODE *tree; - if (eval_tree0) { - tree = eval_tree0; - eval_tree0 = 0; + if (ruby_eval_tree_begin) { + tree = ruby_eval_tree_begin; + ruby_eval_tree_begin = 0; rb_eval(self, tree); } - if (!eval_tree) return Qnil; + if (!ruby_eval_tree) return Qnil; - tree = eval_tree; - eval_tree = 0; + tree = ruby_eval_tree; + ruby_eval_tree = 0; result = rb_eval(self, tree); return result; @@ -784,15 +945,14 @@ eval_node(self) int rb_in_eval; -#ifdef THREAD -static void thread_cleanup(); -static void thread_wait_other_threads(); -static VALUE thread_current(); +#ifdef USE_THREAD +static void rb_thread_cleanup _((void)); +static void rb_thread_wait_other_threads _((void)); #endif static int exit_status; -static void exec_end_proc(); +static void exec_end_proc _((void)); void ruby_run() @@ -800,16 +960,15 @@ ruby_run() int state; static int ex; - if (nerrs > 0) exit(nerrs); + if (ruby_nerrs > 0) exit(ruby_nerrs); - init_stack(); - errat = Qnil; /* clear for execution */ + Init_stack(); PUSH_TAG(PROT_NONE); PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { if (!ext_init) Init_ext(); - eval_node(TopSelf); + eval_node(ruby_top_self); } POP_ITER(); POP_TAG(); @@ -819,12 +978,10 @@ ruby_run() PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { rb_trap_exit(); -#ifdef THREAD - thread_cleanup(); - thread_wait_other_threads(); +#ifdef USE_THREAD + rb_thread_cleanup(); + rb_thread_wait_other_threads(); #endif - exec_end_proc(); - gc_call_finalizer_at_exit(); } else { ex = state; @@ -834,63 +991,69 @@ ruby_run() switch (ex & 0xf) { case 0: - exit(0); + ex = 0; + break; case TAG_RETURN: error_pos(); - fprintf(stderr, "unexpected return\n"); - exit(1); + fprintf(stderr, ": unexpected return\n"); + ex = 1; break; case TAG_NEXT: error_pos(); - fprintf(stderr, "unexpected next\n"); - exit(1); + fprintf(stderr, ": unexpected next\n"); + ex = 1; break; case TAG_BREAK: error_pos(); - fprintf(stderr, "unexpected break\n"); - exit(1); + fprintf(stderr, ": unexpected break\n"); + ex = 1; break; case TAG_REDO: error_pos(); - fprintf(stderr, "unexpected redo\n"); - exit(1); + fprintf(stderr, ": unexpected redo\n"); + ex = 1; break; case TAG_RETRY: error_pos(); - fprintf(stderr, "retry outside of rescue clause\n"); - exit(1); + fprintf(stderr, ": retry outside of rescue clause\n"); + ex = 1; break; case TAG_RAISE: case TAG_FATAL: - if (obj_is_kind_of(errinfo, eSystemExit)) { + if (rb_obj_is_kind_of(rb_errinfo, rb_eSystemExit)) { exit(exit_status); } error_print(); - exit(1); + ex = 1; break; default: - Bug("Unknown longjmp status %d", ex); + rb_bug("Unknown longjmp status %d", ex); break; } + exec_end_proc(); + rb_gc_call_finalizer_at_exit(); + exit(ex); } static void compile_error(at) char *at; { - VALUE mesg; + VALUE str; + char *mesg; + int len; - mesg = errinfo; - nerrs = 0; - errinfo = exc_new2(eSyntaxError, "compile error"); + mesg = str2cstr(rb_errinfo, &len); + ruby_nerrs = 0; + str = rb_str_new2("compile error"); if (at) { - str_cat(errinfo, " in ", 4); - str_cat(errinfo, at, strlen(at)); + rb_str_cat(str, " in ", 4); + rb_str_cat(str, at, strlen(at)); } - str_cat(errinfo, "\n", 1); - str_cat(errinfo, RSTRING(mesg)->ptr, RSTRING(mesg)->len); - rb_raise(errinfo); + rb_str_cat(str, "\n", 1); + rb_str_cat(str, mesg, len); + rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str)); } VALUE @@ -898,45 +1061,67 @@ rb_eval_string(str) char *str; { VALUE v; - char *oldsrc = sourcefile; + char *oldsrc = ruby_sourcefile; - sourcefile = "(eval)"; - v = eval(TopSelf, str_new2(str), Qnil); - sourcefile = oldsrc; + ruby_sourcefile = "(eval)"; + v = eval(ruby_top_self, rb_str_new2(str), Qnil, 0, 0); + ruby_sourcefile = oldsrc; return v; } -void +VALUE +rb_eval_string_protect(str, state) + char *str; + int *state; +{ + VALUE result; /* OK */ + int status; + + PUSH_TAG(PROT_NONE); + if ((status = EXEC_TAG()) == 0) { + result = rb_eval_string(str); + } + POP_TAG(); + if (state) { + *state = status; + } + if (status != 0) { + return Qnil; + } + + return result; +} + +VALUE rb_eval_cmd(cmd, arg) VALUE cmd, arg; { int state; + VALUE val; /* OK */ struct SCOPE *saved_scope; - volatile int safe = rb_safe_level(); + volatile int safe = safe_level; if (TYPE(cmd) != T_STRING) { - Check_Type(arg, T_ARRAY); - rb_funcall2(cmd, rb_intern("call"), - RARRAY(arg)->len, RARRAY(arg)->ptr); - return; + return rb_funcall2(cmd, rb_intern("call"), + RARRAY(arg)->len, RARRAY(arg)->ptr); } PUSH_CLASS(); PUSH_TAG(PROT_NONE); - saved_scope = the_scope; - the_scope = top_scope; + saved_scope = ruby_scope; + ruby_scope = top_scope; - the_class = cObject; - if (str_tainted(cmd)) { - safe_level = 5; + ruby_class = rb_cObject; + if (OBJ_TAINTED(cmd)) { + safe_level = 4; } if ((state = EXEC_TAG()) == 0) { - eval(TopSelf, cmd, Qnil); + val = eval(ruby_top_self, cmd, Qnil, 0, 0); } - the_scope = saved_scope; + ruby_scope = saved_scope; safe_level = safe; POP_TAG(); POP_CLASS(); @@ -945,42 +1130,45 @@ rb_eval_cmd(cmd, arg) case 0: break; case TAG_RETURN: - Raise(eLocalJumpError, "unexpected return"); + rb_raise(rb_eLocalJumpError, "unexpected return"); break; case TAG_NEXT: - Raise(eLocalJumpError, "unexpected next"); + rb_raise(rb_eLocalJumpError, "unexpected next"); break; case TAG_BREAK: - Raise(eLocalJumpError, "unexpected break"); + rb_raise(rb_eLocalJumpError, "unexpected break"); break; case TAG_REDO: - Raise(eLocalJumpError, "unexpected redo"); + rb_raise(rb_eLocalJumpError, "unexpected redo"); break; case TAG_RETRY: - Raise(eLocalJumpError, "retry outside of rescue clause"); + rb_raise(rb_eLocalJumpError, "retry outside of rescue clause"); break; default: JUMP_TAG(state); break; } + return val; } -void +VALUE rb_trap_eval(cmd, sig) VALUE cmd; int sig; { int state; + VALUE val; /* OK */ PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - rb_eval_cmd(cmd, ary_new3(1, INT2FIX(sig))); + val = rb_eval_cmd(cmd, rb_ary_new3(1, INT2FIX(sig))); } POP_TAG(); if (state) { - trap_immediate = 0; + rb_trap_immediate = 0; JUMP_TAG(state); } + return val; } static VALUE @@ -988,7 +1176,7 @@ superclass(self, node) VALUE self; NODE *node; { - VALUE val = 0; /* OK */ + VALUE val; /* OK */ int state; PUSH_TAG(PROT_NONE); @@ -996,21 +1184,23 @@ superclass(self, node) val = rb_eval(self, node); } POP_TAG(); - if (state == TAG_RAISE) { + if (state) { superclass_error: switch (nd_type(node)) { case NODE_COLON2: - TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid)); + rb_raise(rb_eTypeError, "undefined superclass `%s'", + rb_id2name(node->nd_mid)); case NODE_CVAR: - TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid)); + rb_raise(rb_eTypeError, "undefined superclass `%s'", + rb_id2name(node->nd_vid)); default: - TypeError("superclass undefined"); + rb_raise(rb_eTypeError, "superclass undefined"); } JUMP_TAG(state); } if (TYPE(val) != T_CLASS) goto superclass_error; if (FL_TEST(val, FL_SINGLETON)) { - TypeError("can't make subclass of virtual class"); + rb_raise(rb_eTypeError, "can't make subclass of virtual class"); } return val; @@ -1023,12 +1213,12 @@ ev_const_defined(cref, id) { NODE *cbase = cref; - while (cbase && cbase->nd_clss != cObject) { - struct RClass *class = RCLASS(cbase->nd_clss); + while (cbase && cbase->nd_clss != rb_cObject) { + struct RClass *klass = RCLASS(cbase->nd_clss); - if (class->iv_tbl && - st_lookup(class->iv_tbl, id, 0)) { - return TRUE; + if (klass->iv_tbl && + st_lookup(klass->iv_tbl, id, 0)) { + return Qtrue; } cbase = cbase->nd_next; } @@ -1043,11 +1233,11 @@ ev_const_get(cref, id) NODE *cbase = cref; VALUE result; - while (cbase && cbase->nd_clss != cObject) { - struct RClass *class = RCLASS(cbase->nd_clss); + while (cbase && cbase->nd_clss != rb_cObject) { + struct RClass *klass = RCLASS(cbase->nd_clss); - if (class->iv_tbl && - st_lookup(class->iv_tbl, id, &result)) { + if (klass->iv_tbl && + st_lookup(klass->iv_tbl, id, &result)) { return result; } cbase = cbase->nd_next; @@ -1056,43 +1246,43 @@ ev_const_get(cref, id) } static VALUE -mod_nesting() +rb_mod_nesting() { - NODE *cbase = (NODE*)the_frame->cbase; - VALUE ary = ary_new(); + NODE *cbase = (NODE*)ruby_frame->cbase; + VALUE ary = rb_ary_new(); - while (cbase && cbase->nd_clss != cObject) { - ary_push(ary, cbase->nd_clss); + while (cbase && cbase->nd_clss != rb_cObject) { + rb_ary_push(ary, cbase->nd_clss); cbase = cbase->nd_next; } return ary; } static VALUE -mod_s_constants() +rb_mod_s_constants() { - NODE *cbase = (NODE*)the_frame->cbase; - VALUE ary = ary_new(); + NODE *cbase = (NODE*)ruby_frame->cbase; + VALUE ary = rb_ary_new(); - while (cbase && cbase->nd_clss != cObject) { - mod_const_at(cbase->nd_clss, ary); + while (cbase && cbase->nd_clss != rb_cObject) { + rb_mod_const_at(cbase->nd_clss, ary); cbase = cbase->nd_next; } - mod_const_of(((NODE*)the_frame->cbase)->nd_clss, ary); + rb_mod_const_of(((NODE*)ruby_frame->cbase)->nd_clss, ary); return ary; } static VALUE -mod_remove_method(mod, name) +rb_mod_remove_method(mod, name) VALUE mod, name; { - rb_remove_method(mod, rb_to_id(name)); + remove_method(mod, rb_to_id(name)); return mod; } static VALUE -mod_undef_method(mod, name) +rb_mod_undef_method(mod, name) VALUE mod, name; { ID id = rb_to_id(name); @@ -1103,16 +1293,27 @@ mod_undef_method(mod, name) } static VALUE -mod_alias_method(mod, new, old) - VALUE mod, new, old; +rb_mod_alias_method(mod, newname, oldname) + VALUE mod, newname, oldname; { - ID id = rb_to_id(new); + ID id = rb_to_id(newname); - rb_alias(mod, id, rb_to_id(old)); + rb_alias(mod, id, rb_to_id(oldname)); rb_clear_cache_by_id(id); return mod; } +#ifdef C_ALLOCA +# define TMP_PROTECT NODE * volatile __protect_tmp=0 +# define TMP_ALLOC(n) \ + (__protect_tmp = rb_node_newnode(NODE_ALLOCA, \ + ALLOC_N(VALUE,n),__protect_tmp,n), \ + (void*)__protect_tmp->nd_head) +#else +# define TMP_PROTECT typedef int foobazzz +# define TMP_ALLOC(n) ALLOCA_N(VALUE,n) +#endif + #define SETUP_ARGS(anode) {\ NODE *n = anode;\ if (!n) {\ @@ -1122,17 +1323,17 @@ mod_alias_method(mod, new, old) else if (nd_type(n) == NODE_ARRAY) {\ argc=n->nd_alen;\ if (argc > 0) {\ - char *file = sourcefile;\ - int line = sourceline;\ + char *file = ruby_sourcefile;\ + int line = ruby_sourceline;\ int i;\ n = anode;\ - argv = ALLOCA_N(VALUE,argc);\ + argv = TMP_ALLOC(argc);\ for (i=0;ind_head);\ n=n->nd_next;\ }\ - sourcefile = file;\ - sourceline = line;\ + ruby_sourcefile = file;\ + ruby_sourceline = line;\ }\ else {\ argc = 0;\ @@ -1141,19 +1342,31 @@ mod_alias_method(mod, new, old) }\ else {\ VALUE args = rb_eval(self,n);\ - char *file = sourcefile;\ - int line = sourceline;\ + char *file = ruby_sourcefile;\ + int line = ruby_sourceline;\ if (TYPE(args) != T_ARRAY)\ args = rb_Array(args);\ argc = RARRAY(args)->len;\ argv = ALLOCA_N(VALUE, argc);\ MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\ - sourcefile = file;\ - sourceline = line;\ + ruby_sourcefile = file;\ + ruby_sourceline = line;\ + }\ +} + +#define BEGIN_CALLARGS {\ + struct BLOCK *tmp_block = ruby_block;\ + if (ruby_iter->iter == ITER_PRE) {\ + ruby_block = ruby_block->prev;\ }\ + PUSH_ITER(ITER_NOT); + +#define END_CALLARGS \ + ruby_block = tmp_block;\ + POP_ITER();\ } -#define MATCH_DATA the_scope->local_vars[node->nd_cnt] +#define MATCH_DATA ruby_scope->local_vars[node->nd_cnt] static char* is_defined _((VALUE, NODE*, char*)); @@ -1196,9 +1409,9 @@ is_defined(self, node, buf) switch (nd_type(node)) { case NODE_SUPER: case NODE_ZSUPER: - if (the_frame->last_func == 0) return 0; - else if (method_boundp(RCLASS(the_frame->last_class)->super, - the_frame->last_func, 1)) { + if (ruby_frame->last_func == 0) return 0; + else if (rb_method_boundp(RCLASS(ruby_frame->last_class)->super, + ruby_frame->last_func, 1)) { if (nd_type(node) == NODE_SUPER) { return arg_defined(self, node->nd_args, buf, "super"); } @@ -1206,8 +1419,8 @@ is_defined(self, node, buf) } break; - case NODE_FCALL: case NODE_VCALL: + case NODE_FCALL: val = CLASS_OF(self); goto check_bound; @@ -1219,11 +1432,9 @@ is_defined(self, node, buf) val = CLASS_OF(val); } POP_TAG(); - if (state) { - return 0; - } + if (state) return 0; check_bound: - if (method_boundp(val, node->nd_mid, nd_type(node)== NODE_CALL)) { + if (rb_method_boundp(val, node->nd_mid, nd_type(node)== NODE_CALL)) { return arg_defined(self, node->nd_args, buf, "method"); } break; @@ -1233,7 +1444,7 @@ is_defined(self, node, buf) return "method"; case NODE_YIELD: - if (iterator_p()) { + if (rb_iterator_p()) { return "yield"; } break; @@ -1256,14 +1467,16 @@ is_defined(self, node, buf) case NODE_MASGN: case NODE_LASGN: case NODE_DASGN: + case NODE_DASGN_PUSH: case NODE_GASGN: case NODE_IASGN: case NODE_CASGN: return "assignment"; case NODE_LVAR: - case NODE_DVAR: return "local-variable"; + case NODE_DVAR: + return "local-variable(in-block)"; case NODE_GVAR: if (rb_gvar_defined(node->nd_entry)) { @@ -1278,7 +1491,7 @@ is_defined(self, node, buf) break; case NODE_CVAR: - if (ev_const_defined(the_frame->cbase, node->nd_vid)) { + if (ev_const_defined((NODE*)ruby_frame->cbase, node->nd_vid)) { return "constant"; } break; @@ -1289,28 +1502,30 @@ is_defined(self, node, buf) val = rb_eval(self, node->nd_head); } POP_TAG(); - if (state) { - return 0; - } + if (state) return 0; else { switch (TYPE(val)) { case T_CLASS: case T_MODULE: if (rb_const_defined_at(val, node->nd_mid)) return "constant"; + default: + if (rb_method_boundp(val, node->nd_mid, 1)) { + return "method"; + } } } break; case NODE_NTH_REF: - if (reg_nth_defined(node->nd_nth, MATCH_DATA)) { + if (rb_reg_nth_defined(node->nd_nth, MATCH_DATA)) { sprintf(buf, "$%d", node->nd_nth); return buf; } break; case NODE_BACK_REF: - if (reg_nth_defined(0, MATCH_DATA)) { + if (rb_reg_nth_defined(0, MATCH_DATA)) { sprintf(buf, "$%c", node->nd_nth); return buf; } @@ -1330,11 +1545,30 @@ is_defined(self, node, buf) return 0; } -static int handle_rescue(); -VALUE rb_yield_0(); +static int handle_rescue _((VALUE,NODE*)); static void blk_free(); +static VALUE +rb_obj_is_block(block) + VALUE block; +{ + if (TYPE(block) == T_DATA && RDATA(block)->dfree == blk_free) { + return Qtrue; + } + return Qfalse; +} + +static VALUE +rb_obj_is_proc(proc) + VALUE proc; +{ + if (rb_obj_is_block(proc) && rb_obj_is_kind_of(proc, rb_cProc)) { + return Qtrue; + } + return Qfalse; +} + static VALUE set_trace_func(obj, trace) VALUE obj, trace; @@ -1343,58 +1577,73 @@ set_trace_func(obj, trace) trace_func = 0; return Qnil; } - if (TYPE(trace) != T_DATA || RDATA(trace)->dfree != blk_free) { - TypeError("trace_func needs to be Proc"); + if (!rb_obj_is_proc(trace)) { + rb_raise(rb_eTypeError, "trace_func needs to be Proc"); } return trace_func = trace; } static void -call_trace_func(event, file, line, self, id) +call_trace_func(event, file, line, self, id, klass) char *event; char *file; int line; VALUE self; ID id; + VALUE klass; /* OK */ { int state; volatile VALUE trace; struct FRAME *prev; + char *file_save = ruby_sourcefile; + int line_save = ruby_sourceline; if (!trace_func) return; trace = trace_func; trace_func = 0; -#ifdef THREAD - thread_critical++; +#ifdef USE_THREAD + rb_thread_critical++; #endif - prev = the_frame; + prev = ruby_frame; PUSH_FRAME(); - *the_frame = *_frame->prev; - the_frame->prev = prev; + *ruby_frame = *_frame.prev; + ruby_frame->prev = prev; - the_frame->line = sourceline = line; - the_frame->file = sourcefile = file; + if (file) { + ruby_frame->line = ruby_sourceline = line; + ruby_frame->file = ruby_sourcefile = file; + } + if (klass) { + if (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) { + klass = self; + } + } PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - proc_call(trace, ary_new3(5, str_new2(event), - str_new2(sourcefile), - INT2FIX(sourceline), - INT2FIX(id), - self?f_binding(self):Qnil)); + proc_call(trace, rb_ary_new3(6, rb_str_new2(event), + rb_str_new2(ruby_sourcefile), + INT2FIX(ruby_sourceline), + INT2FIX(id), + self?rb_f_binding(self):Qnil, + klass)); } POP_TAG(); POP_FRAME(); -#ifdef THREAD - thread_critical--; +#ifdef USE_THREAD + rb_thread_critical--; #endif if (!trace_func) trace_func = trace; + ruby_sourceline = line_save; + ruby_sourcefile = file_save; if (state) JUMP_TAG(state); } -static void return_value _((VALUE val)); +static void return_check _((void)); +#define return_value(v) prot_tag->retval = (v) + static VALUE rb_eval(self, node) VALUE self; @@ -1402,6 +1651,10 @@ rb_eval(self, node) { int state; volatile VALUE result = Qnil; +#ifdef NOBLOCK_RECUR + NODE * volatile next = 0; + NODE * volatile nstack = 0; +#endif #define RETURN(v) { result = (v); goto finish; } @@ -1410,14 +1663,26 @@ rb_eval(self, node) switch (nd_type(node)) { case NODE_BLOCK: +#ifndef NOBLOCK_RECUR + if (!node->nd_next) { + node = node->nd_head; + goto again; + } while (node) { result = rb_eval(self, node->nd_head); node = node->nd_next; } break; - +#else + if (next) { + nstack = rb_node_newnode(NODE_CREF,next,0,nstack); + } + next = node->nd_next; + node = node->nd_head; + goto again; +#endif case NODE_POSTEXE: - f_END(); + rb_f_END(); nd_set_type(node, NODE_NIL); /* exec just once */ result = Qnil; break; @@ -1429,12 +1694,12 @@ rb_eval(self, node) /* nodes for speed-up(default match) */ case NODE_MATCH: - result = reg_match2(node->nd_head->nd_lit); + result = rb_reg_match2(node->nd_head->nd_lit); break; /* nodes for speed-up(literal match) */ case NODE_MATCH2: - result = reg_match(rb_eval(self,node->nd_recv), + result = rb_reg_match(rb_eval(self,node->nd_recv), rb_eval(self,node->nd_value)); break; @@ -1444,7 +1709,7 @@ rb_eval(self, node) VALUE r = rb_eval(self,node->nd_recv); VALUE l = rb_eval(self,node->nd_value); if (TYPE(r) == T_STRING) { - result = reg_match(l, r); + result = rb_reg_match(l, r); } else { result = rb_funcall(r, match, 1, l); @@ -1454,7 +1719,7 @@ rb_eval(self, node) /* nodes for speed-up(top-level loop for -n/-p) */ case NODE_OPT_N: - while (!NIL_P(f_gets())) { + while (!NIL_P(rb_gets())) { rb_eval(self, node->nd_body); } RETURN(Qnil); @@ -1466,14 +1731,18 @@ rb_eval(self, node) RETURN(Qnil); case NODE_TRUE: - RETURN(TRUE); + RETURN(Qtrue); case NODE_FALSE: - RETURN(FALSE); + RETURN(Qfalse); case NODE_IF: - sourceline = nd_line(node); + ruby_sourceline = nd_line(node); +#ifdef NOBLOCK_RECUR + if (RTEST(result)){ +#else if (RTEST(rb_eval(self, node->nd_cond))) { +#endif node = node->nd_body; } else { @@ -1485,7 +1754,11 @@ rb_eval(self, node) { VALUE val; +#ifdef NOBLOCK_RECUR + val = result; +#else val = rb_eval(self, node->nd_head); +#endif node = node->nd_body; while (node) { NODE *tag; @@ -1497,10 +1770,25 @@ rb_eval(self, node) while (tag) { if (trace_func) { call_trace_func("line", tag->nd_file, nd_line(tag), - self, the_frame->last_func); + self, ruby_frame->last_func, 0); } - sourceline = nd_line(tag); - if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head),eqq,1,&val))){ + ruby_sourcefile = tag->nd_file; + ruby_sourceline = nd_line(tag); + if (nd_type(tag->nd_head) == NODE_WHEN) { + VALUE v = rb_eval(self, tag->nd_head->nd_head); + int i; + + if (TYPE(v) != T_ARRAY) v = rb_Array(v); + for (i=0; ilen; i++) { + if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){ + node = node->nd_body; + goto again; + } + } + tag = tag->nd_next; + continue; + } + if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) { node = node->nd_body; goto again; } @@ -1515,7 +1803,7 @@ rb_eval(self, node) PUSH_TAG(PROT_NONE); switch (state = EXEC_TAG()) { case 0: - sourceline = nd_line(node); + ruby_sourceline = nd_line(node); if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond))) goto while_out; do { @@ -1539,9 +1827,7 @@ rb_eval(self, node) } while_out: POP_TAG(); - if (state) { - JUMP_TAG(state); - } + if (state) JUMP_TAG(state); RETURN(Qnil); case NODE_UNTIL: @@ -1571,11 +1857,13 @@ rb_eval(self, node) } until_out: POP_TAG(); - if (state) { - JUMP_TAG(state); - } + if (state) JUMP_TAG(state); RETURN(Qnil); + case NODE_BLOCK_PASS: + result = block_pass(self, node); + break; + case NODE_ITER: case NODE_FOR: { @@ -1592,21 +1880,21 @@ rb_eval(self, node) } else { VALUE recv; - char *file = sourcefile; - int line = sourceline; + char *file = ruby_sourcefile; + int line = ruby_sourceline; recv = rb_eval(self, node->nd_iter); PUSH_ITER(ITER_PRE); - sourcefile = file; - sourceline = line; + ruby_sourcefile = file; + ruby_sourceline = line; result = rb_call(CLASS_OF(recv),recv,each,0,0,0); POP_ITER(); } } - else if (the_block->tag->dst == state) { + else if (_block.tag->dst == state) { state &= TAG_MASK; if (state == TAG_RETURN) { - result = prot_tag->tag_retval; + result = prot_tag->retval; } } POP_TAG(); @@ -1646,14 +1934,32 @@ rb_eval(self, node) JUMP_TAG(TAG_RETRY); break; + case NODE_RESTARGS: + result = rb_eval(self, node->nd_head); + if (TYPE(result) != T_ARRAY) { + result = rb_Array(result); + } + break; + case NODE_YIELD: - result = rb_yield_0(rb_eval(self, node->nd_stts), 0); + if (node->nd_stts) { + result = rb_eval(self, node->nd_stts); + if (nd_type(node->nd_stts) == NODE_RESTARGS && + RARRAY(result)->len == 1) + { + result = RARRAY(result)->ptr[0]; + } + } + else { + result = Qnil; + } + result = rb_yield_0(result, 0, 0); break; case NODE_RESCUE: retry_entry: { - volatile VALUE e_info = errinfo, e_at = errat; + volatile VALUE e_info = rb_errinfo; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { @@ -1662,6 +1968,7 @@ rb_eval(self, node) POP_TAG(); if (state == TAG_RAISE) { NODE * volatile resq = node->nd_resq; + while (resq) { if (handle_rescue(self, resq)) { state = 0; @@ -1671,8 +1978,7 @@ rb_eval(self, node) } POP_TAG(); if (state == 0) { - errinfo = e_info; - errat = e_at; + rb_errinfo = e_info; } else if (state == TAG_RETRY) { state = 0; @@ -1683,8 +1989,9 @@ rb_eval(self, node) resq = resq->nd_head; /* next rescue */ } } - if (state) { - JUMP_TAG(state); + if (state) JUMP_TAG(state); + if (node->nd_else) { /* no exception raised, else clause given */ + result = rb_eval(self, node->nd_else); } } break; @@ -1695,10 +2002,13 @@ rb_eval(self, node) result = rb_eval(self, node->nd_head); } POP_TAG(); - rb_eval(self, node->nd_ensr); - if (state) { - JUMP_TAG(state); + if (node->nd_ensr) { + VALUE retval = prot_tag->retval; /* save retval */ + + rb_eval(self, node->nd_ensr); + return_value(retval); } + if (state) JUMP_TAG(state); break; case NODE_AND: @@ -1714,45 +2024,65 @@ rb_eval(self, node) goto again; case NODE_NOT: - if (RTEST(rb_eval(self, node->nd_body))) result = FALSE; - else result = TRUE; + if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse; + else result = Qtrue; break; case NODE_DOT2: case NODE_DOT3: - RETURN(range_new(rb_eval(self, node->nd_beg), rb_eval(self, node->nd_end))); + result = rb_range_new(rb_eval(self, node->nd_beg), rb_eval(self, node->nd_end)); +#if 0 + break; +#else + result = rb_range_new(rb_eval(self, node->nd_beg), rb_eval(self, node->nd_end)); + if (node->nd_state) break; + if (nd_type(node->nd_beg) == NODE_LIT && FIXNUM_P(node->nd_beg->nd_lit) && + nd_type(node->nd_end) == NODE_LIT && FIXNUM_P(node->nd_end->nd_lit)) + { + nd_set_type(node, NODE_LIT); + node->nd_lit = result; + } + else { + node->nd_state = 1; + } +#endif + break; case NODE_FLIP2: /* like AWK */ - if (node->nd_state == 0) { + if (ruby_scope->local_vars == 0) { + rb_bug("unexpected local variable"); + } + if (!RTEST(ruby_scope->local_vars[node->nd_cnt])) { if (RTEST(rb_eval(self, node->nd_beg))) { - node->nd_state = rb_eval(self, node->nd_end)?0:1; - result = TRUE; + ruby_scope->local_vars[node->nd_cnt] = + RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue; + result = Qtrue; } else { - result = FALSE; + result = Qfalse; } } else { if (RTEST(rb_eval(self, node->nd_end))) { - node->nd_state = 0; + ruby_scope->local_vars[node->nd_cnt] = Qfalse; } - result = TRUE; + result = Qtrue; } break; case NODE_FLIP3: /* like SED */ - if (node->nd_state == 0) { - if (RTEST(rb_eval(self, node->nd_beg))) { - node->nd_state = 1; - result = TRUE; - } - result = FALSE; + if (ruby_scope->local_vars == 0) { + rb_bug("unexpected local variable"); + } + if (!RTEST(ruby_scope->local_vars[node->nd_cnt])) { + result = RTEST(rb_eval(self, node->nd_beg)); + ruby_scope->local_vars[node->nd_cnt] = result; } else { if (RTEST(rb_eval(self, node->nd_end))) { - node->nd_state = 0; + ruby_scope->local_vars[node->nd_cnt] = Qfalse; } - result = TRUE; + result = Qtrue; } break; @@ -1760,18 +2090,32 @@ rb_eval(self, node) if (node->nd_stts) { return_value(rb_eval(self, node->nd_stts)); } + return_check(); JUMP_TAG(TAG_RETURN); break; + case NODE_ARGSCAT: + result = rb_ary_concat(rb_eval(self, node->nd_head), + rb_eval(self, node->nd_body)); + break; + case NODE_CALL: { VALUE recv; int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; - PUSH_ITER(ITER_NOT); + BEGIN_CALLARGS; +#ifdef NOBLOCK_RECUR_incomplete + printf("mid %s recv: ", rb_id2name(node->nd_mid)); + rb_p(result); + recv = result; +#else recv = rb_eval(self, node->nd_recv); +#endif SETUP_ARGS(node->nd_args); - POP_ITER(); + END_CALLARGS; + result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0); } break; @@ -1779,10 +2123,12 @@ rb_eval(self, node) case NODE_FCALL: { int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; - PUSH_ITER(ITER_NOT); + BEGIN_CALLARGS; SETUP_ARGS(node->nd_args); - POP_ITER(); + END_CALLARGS; + result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1); } break; @@ -1795,48 +2141,54 @@ rb_eval(self, node) case NODE_ZSUPER: { int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; + if (ruby_frame->last_class == 0) { + rb_raise(rb_eNameError, "superclass method `%s' disabled", + rb_id2name(ruby_frame->last_func)); + } if (nd_type(node) == NODE_ZSUPER) { - argc = the_frame->argc; - argv = the_frame->argv; + argc = ruby_frame->argc; + argv = ruby_frame->argv; } else { - PUSH_ITER(ITER_NOT); + BEGIN_CALLARGS; SETUP_ARGS(node->nd_args); - POP_ITER(); + END_CALLARGS; } - PUSH_ITER(the_iter->iter?ITER_PRE:ITER_NOT); - result = rb_call(RCLASS(the_frame->last_class)->super, self, - the_frame->last_func, argc, argv, 1); + PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT); + result = rb_call(RCLASS(ruby_frame->last_class)->super, + ruby_frame->self, ruby_frame->last_func, + argc, argv, 3); POP_ITER(); } break; case NODE_SCOPE: { - VALUE save = the_frame->cbase; + VALUE save = ruby_frame->cbase; PUSH_SCOPE(); PUSH_TAG(PROT_NONE); - if (node->nd_rval) the_frame->cbase = (VALUE)node->nd_rval; + if (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; - the_scope->local_vars = vars; - memclear(the_scope->local_vars, node->nd_tbl[0]); - the_scope->local_tbl = node->nd_tbl; + ruby_scope->local_vars = vars; + rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); + ruby_scope->local_tbl = node->nd_tbl; } else { - the_scope->local_vars = 0; - the_scope->local_tbl = 0; + ruby_scope->local_vars = 0; + ruby_scope->local_tbl = 0; } if ((state = EXEC_TAG()) == 0) { - result = rb_eval(self, node->nd_body); + result = rb_eval(self, node->nd_next); } POP_TAG(); POP_SCOPE(); - the_frame->cbase = save; + ruby_frame->cbase = save; if (state) JUMP_TAG(state); } break; @@ -1846,12 +2198,23 @@ rb_eval(self, node) int argc; VALUE *argv; /* used in SETUP_ARGS */ VALUE recv, val; NODE *rval; + TMP_PROTECT; recv = rb_eval(self, node->nd_recv); rval = node->nd_args->nd_head; SETUP_ARGS(node->nd_args->nd_next); val = rb_funcall2(recv, aref, argc-1, argv); - val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval)); + if (node->nd_mid == 0) { /* OR */ + if (RTEST(val)) break; + val = rb_eval(self, rval); + } + else if (node->nd_mid == 1) { /* AND */ + if (!RTEST(val)) break; + val = rb_eval(self, rval); + } + else { + val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval)); + } argv[argc-1] = val; val = rb_funcall2(recv, aset, argc, argv); result = val; @@ -1865,75 +2228,94 @@ rb_eval(self, node) recv = rb_eval(self, node->nd_recv); val = rb_funcall(recv, id, 0); + if (node->nd_next->nd_mid == 0) { /* OR */ + if (RTEST(val)) break; + val = rb_eval(self, node->nd_value); + } + else if (node->nd_next->nd_mid == 1) { /* AND */ + if (!RTEST(val)) break; + val = rb_eval(self, node->nd_value); + } + else { + val = rb_funcall(val, node->nd_next->nd_mid, 1, + rb_eval(self, node->nd_value)); + } - val = rb_funcall(val, node->nd_next->nd_mid, 1, - rb_eval(self, node->nd_value)); - - rb_funcall2(recv, id_attrset(id), 1, &val); + rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); result = val; } break; + case NODE_OP_ASGN_AND: + result = rb_eval(self, node->nd_head); + if (RTEST(result)) { + result = rb_eval(self, node->nd_value); + } + break; + + case NODE_OP_ASGN_OR: + result = rb_eval(self, node->nd_head); + if (!RTEST(result)) { + result = rb_eval(self, node->nd_value); + } + break; + case NODE_MASGN: result = massign(self, node, rb_eval(self, node->nd_value)); break; case NODE_LASGN: - if (the_scope->local_vars == 0) - Bug("unexpected local variable assignment"); - the_scope->local_vars[node->nd_cnt] = rb_eval(self, node->nd_value); - result = the_scope->local_vars[node->nd_cnt]; + if (ruby_scope->local_vars == 0) + rb_bug("unexpected local variable assignment"); + result = rb_eval(self, node->nd_value); + ruby_scope->local_vars[node->nd_cnt] = result; break; case NODE_DASGN: - result = dyna_var_asgn(node->nd_vid, rb_eval(self, node->nd_value)); + result = rb_eval(self, node->nd_value); + rb_dvar_asgn(node->nd_vid, result); break; - case NODE_GASGN: - { - VALUE val; + case NODE_DASGN_PUSH: + result = rb_eval(self, node->nd_value); + dvar_asgn_push(node->nd_vid, result); + break; - val = rb_eval(self, node->nd_value); - rb_gvar_set(node->nd_entry, val); - result = val; - } + case NODE_GASGN: + result = rb_eval(self, node->nd_value); + rb_gvar_set(node->nd_entry, result); break; case NODE_IASGN: - { - VALUE val; - - val = rb_eval(self, node->nd_value); - rb_ivar_set(self, node->nd_vid, val); - result = val; - } + result = rb_eval(self, node->nd_value); + rb_ivar_set(self, node->nd_vid, result); break; case NODE_CASGN: - { - VALUE val; - - val = rb_eval(self, node->nd_value); - /* check for static scope constants */ - if (RTEST(verbose) && - ev_const_defined(the_frame->cbase, node->nd_vid)) { - Warning("already initialized constant %s", - rb_id2name(node->nd_vid)); + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no class/module to define constant"); + } + result = rb_eval(self, node->nd_value); + /* check for static scope constants */ + if (RTEST(rb_verbose) && + ev_const_defined((NODE*)ruby_frame->cbase, node->nd_vid)) { + if (RTEST(rb_verbose)) { + rb_warning("already initialized constant %s", + rb_id2name(node->nd_vid)); } - rb_const_set(the_class, node->nd_vid, val); - result = val; } + rb_const_set(ruby_class, node->nd_vid, result); break; case NODE_LVAR: - if (the_scope->local_vars == 0) { - Bug("unexpected local variable"); + if (ruby_scope->local_vars == 0) { + rb_bug("unexpected local variable"); } - result = the_scope->local_vars[node->nd_cnt]; + result = ruby_scope->local_vars[node->nd_cnt]; break; case NODE_DVAR: - result = dyna_var_ref(node->nd_vid); + result = rb_dvar_ref(node->nd_vid); break; case NODE_GVAR: @@ -1945,53 +2327,68 @@ rb_eval(self, node) break; case NODE_CVAR: - result = ev_const_get(the_frame->cbase, node->nd_vid); + result = ev_const_get((NODE*)ruby_frame->cbase, node->nd_vid); + break; + + case NODE_BLOCK_ARG: + if (ruby_scope->local_vars == 0) + rb_bug("unexpected block argument"); + if (rb_iterator_p()) { + result = rb_f_lambda(); + ruby_scope->local_vars[node->nd_cnt] = result; + } + else { + result = Qnil; + } break; case NODE_COLON2: { - VALUE cls; + VALUE klass; - cls = rb_eval(self, node->nd_head); - switch (TYPE(cls)) { + klass = rb_eval(self, node->nd_head); + switch (TYPE(klass)) { case T_CLASS: case T_MODULE: break; default: - Check_Type(cls, T_CLASS); - break; + return rb_funcall(klass, node->nd_mid, 0, 0); } - result = rb_const_get_at(cls, node->nd_mid); + result = rb_const_get_at(klass, node->nd_mid); } break; + case NODE_COLON3: + result = rb_const_get_at(rb_cObject, node->nd_mid); + break; + case NODE_NTH_REF: - result = reg_nth_match(node->nd_nth, MATCH_DATA); + result = rb_reg_nth_match(node->nd_nth, MATCH_DATA); break; case NODE_BACK_REF: switch (node->nd_nth) { case '&': - result = reg_last_match(MATCH_DATA); + result = rb_reg_last_match(MATCH_DATA); break; case '`': - result = reg_match_pre(MATCH_DATA); + result = rb_reg_match_pre(MATCH_DATA); break; case '\'': - result = reg_match_post(MATCH_DATA); + result = rb_reg_match_post(MATCH_DATA); break; case '+': - result = reg_match_last(MATCH_DATA); + result = rb_reg_match_last(MATCH_DATA); break; default: - Bug("unexpected back-ref"); + rb_bug("unexpected back-ref"); } break; case NODE_HASH: { NODE *list; - VALUE hash = hash_new(); + VALUE hash = rb_hash_new(); VALUE key, val; list = node->nd_head; @@ -1999,17 +2396,17 @@ rb_eval(self, node) key = rb_eval(self, list->nd_head); list = list->nd_next; if (list == 0) - Bug("odd number list for Hash"); + rb_bug("odd number list for Hash"); val = rb_eval(self, list->nd_head); list = list->nd_next; - hash_aset(hash, key, val); + rb_hash_aset(hash, key, val); } result = hash; } break; case NODE_ZARRAY: /* zero length list */ - result = ary_new(); + result = rb_ary_new(); break; case NODE_ARRAY: @@ -2018,7 +2415,7 @@ rb_eval(self, node) int i; i = node->nd_alen; - ary = ary_new2(i); + ary = rb_ary_new2(i); for (i=0;node;node=node->nd_next) { RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head); RARRAY(ary)->len = i; @@ -2029,7 +2426,7 @@ rb_eval(self, node) break; case NODE_STR: - result = str_new3(node->nd_lit); + result = rb_str_new3(node->nd_lit); break; case NODE_DSTR: @@ -2040,36 +2437,39 @@ rb_eval(self, node) VALUE str, str2; NODE *list = node->nd_next; - str = str_new3(node->nd_lit); + str = rb_str_new3(node->nd_lit); while (list) { - if (nd_type(list->nd_head) == NODE_STR) { - str2 = list->nd_head->nd_lit; - } - else { - if (nd_type(list->nd_head) == NODE_EVSTR) { + if (list->nd_head) { + switch (nd_type(list->nd_head)) { + case NODE_STR: + str2 = list->nd_head->nd_lit; + break; + case NODE_EVSTR: rb_in_eval++; - eval_tree = 0; - list->nd_head = compile(list->nd_head->nd_lit); + list->nd_head = compile(list->nd_head->nd_lit,0); + ruby_eval_tree = 0; rb_in_eval--; - if (nerrs > 0) { - compile_error("string expand"); + if (ruby_nerrs > 0) { + compile_error("string expansion"); } + /* fall through */ + default: + str2 = rb_eval(self, list->nd_head); + str2 = rb_obj_as_string(str2); + break; } - str2 = rb_eval(self, list->nd_head); - str2 = obj_as_string(str2); - } - if (str2) { - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + if (OBJ_TAINTED(str2)) OBJ_TAINT(str); } list = list->nd_next; } switch (nd_type(node)) { case NODE_DREGX: - result = reg_new(RSTRING(str)->ptr, RSTRING(str)->len, + result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, node->nd_cflag); break; case NODE_DREGX_ONCE: /* regexp expand once */ - result = reg_new(RSTRING(str)->ptr, RSTRING(str)->len, + result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, node->nd_cflag); nd_set_type(node, NODE_LIT); node->nd_lit = result; @@ -2093,9 +2493,10 @@ rb_eval(self, node) break; case NODE_ATTRSET: - if (the_frame->argc != 1) - ArgError("Wrong # of arguments(%d for 1)", the_frame->argc); - result = rb_ivar_set(self, node->nd_vid, the_frame->argv[0]); + if (ruby_frame->argc != 1) + rb_raise(rb_eArgError, "Wrong # of arguments(%d for 1)", + ruby_frame->argc); + result = rb_ivar_set(self, node->nd_vid, ruby_frame->argv[0]); break; case NODE_DEFN: @@ -2104,28 +2505,51 @@ rb_eval(self, node) VALUE origin; int noex; - body = search_method(the_class, node->nd_mid, &origin); + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no class to add method"); + } + if (ruby_class == rb_cObject && node->nd_mid == init) { + rb_warn("re-defining Object#initialize may cause infinite loop"); + } + body = search_method(ruby_class, node->nd_mid, &origin); if (body) { - if (origin == (VALUE)the_class) { - Warning("discarding old %s", rb_id2name(node->nd_mid)); + if (origin == ruby_class) { + if (safe_level >= 3) { + rb_raise(rb_eSecurityError, "re-defining method prohibited"); + } + if (RTEST(rb_verbose)) { + rb_warning("discarding old %s", rb_id2name(node->nd_mid)); + } } rb_clear_cache_by_id(node->nd_mid); } - if (FL_TEST(the_scope,SCOPE_PRIVATE)) { + if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) { noex = NOEX_PRIVATE; } + else if (SCOPE_TEST(SCOPE_PROTECTED)) { + noex = NOEX_PROTECTED; + } else { noex = NOEX_PUBLIC; } - rb_add_method(the_class, node->nd_mid, node->nd_defn, noex); - if (FL_TEST(the_class, FL_SINGLETON)) { - VALUE recv = rb_iv_get(the_class, "__attached__"); - rb_funcall(recv, rb_intern("singleton_method_added"), + 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); + if (scope_vmode == SCOPE_MODFUNC) { + rb_add_method(rb_singleton_class(ruby_class), + node->nd_mid, node->nd_defn, NOEX_PUBLIC); + rb_funcall(ruby_class, rb_intern("singleton_method_added"), + 1, INT2FIX(node->nd_mid)); + } + if (FL_TEST(ruby_class, FL_SINGLETON)) { + rb_funcall(rb_iv_get(ruby_class, "__attached__"), + rb_intern("singleton_method_added"), 1, INT2FIX(node->nd_mid)); } else { - rb_funcall(the_class, rb_intern("method_added"), + rb_funcall(ruby_class, rb_intern("method_added"), 1, INT2FIX(node->nd_mid)); } result = Qnil; @@ -2135,28 +2559,38 @@ rb_eval(self, node) case NODE_DEFS: if (node->nd_defn) { VALUE recv = rb_eval(self, node->nd_recv); - VALUE class; - NODE *body; + VALUE klass; + NODE *body = 0; if (FIXNUM_P(recv)) { - TypeError("Can't define method \"%s\" for Fixnum", - rb_id2name(node->nd_mid)); + rb_raise(rb_eTypeError, "Can't define method \"%s\" for Fixnum", + rb_id2name(node->nd_mid)); } if (NIL_P(recv)) { - TypeError("Can't define method \"%s\" for nil", - rb_id2name(node->nd_mid)); + rb_raise(rb_eTypeError, "Can't define method \"%s\" for nil", + rb_id2name(node->nd_mid)); } if (rb_special_const_p(recv)) { - TypeError("Can't define method \"%s\" for special constants", - rb_id2name(node->nd_mid)); + rb_raise(rb_eTypeError, + "Can't define method \"%s\" for special constants", + rb_id2name(node->nd_mid)); } - class = rb_singleton_class(recv); - if (st_lookup(RCLASS(class)->m_tbl, node->nd_mid, &body)) { - Warning("redefine %s", rb_id2name(node->nd_mid)); + if (rb_safe_level() >= 4 && !FL_TEST(recv, FL_TAINT)) { + rb_raise(rb_eSecurityError, "can't define singleton method"); + } + klass = rb_singleton_class(recv); + if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &body)) { + if (safe_level >= 3) { + rb_raise(rb_eSecurityError, "re-defining method prohibited"); + } + if (RTEST(rb_verbose)) { + rb_warning("redefine %s", rb_id2name(node->nd_mid)); + } } rb_clear_cache_by_id(node->nd_mid); - rb_add_method(class, node->nd_mid, node->nd_defn, NOEX_PUBLIC); + rb_add_method(klass, node->nd_mid, node->nd_defn, + NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); rb_funcall(recv, rb_intern("singleton_method_added"), 1, INT2FIX(node->nd_mid)); result = Qnil; @@ -2168,20 +2602,41 @@ rb_eval(self, node) VALUE origin; NODE *body; - body = search_method(the_class, node->nd_mid, &origin); + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no class to undef method"); + } + if (ruby_class == rb_cObject) { + rb_secure(4); + } + body = search_method(ruby_class, node->nd_mid, &origin); if (!body || !body->nd_body) { - NameError("undefined method `%s' for class `%s'", - rb_id2name(node->nd_mid), rb_class2name((VALUE)the_class)); + char *s0 = " class"; + VALUE klass = ruby_class; + + if (FL_TEST(ruby_class, FL_SINGLETON)) { + VALUE obj = rb_iv_get(ruby_class, "__attached__"); + switch (TYPE(obj)) { + case T_MODULE: + case T_CLASS: + klass = obj; + s0 = ""; + } + } + rb_raise(rb_eNameError, "undefined method `%s' for%s `%s'", + rb_id2name(node->nd_mid),s0,rb_class2name(klass)); } rb_clear_cache_by_id(node->nd_mid); - rb_add_method(the_class, node->nd_mid, 0, NOEX_PUBLIC); + rb_add_method(ruby_class, node->nd_mid, 0, NOEX_PUBLIC); result = Qnil; } break; case NODE_ALIAS: - rb_alias(the_class, node->nd_new, node->nd_old); - rb_funcall(the_class, rb_intern("method_added"), + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no class to make alias"); + } + rb_alias(ruby_class, node->nd_new, node->nd_old); + rb_funcall(ruby_class, rb_intern("method_added"), 1, INT2FIX(node->nd_mid)); result = Qnil; break; @@ -2193,8 +2648,11 @@ rb_eval(self, node) case NODE_CLASS: { - VALUE super, class, tmp; + VALUE super, klass, tmp; + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no outer class/module"); + } if (node->nd_super) { super = superclass(self, node->nd_super); } @@ -2202,16 +2660,21 @@ rb_eval(self, node) super = 0; } - if (rb_const_defined_at(the_class, node->nd_cname) && - ((VALUE)the_class != cObject || - !rb_autoload_defined(node->nd_cname))) { - - class = rb_const_get_at(the_class, node->nd_cname); - if (TYPE(class) != T_CLASS) { - TypeError("%s is not a class", rb_id2name(node->nd_cname)); + klass = 0; + if (rb_const_defined_at(ruby_class, node->nd_cname) && + (ruby_class != rb_cObject || !rb_autoload_defined(node->nd_cname))) { + klass = rb_const_get_at(ruby_class, node->nd_cname); + } + if (ruby_wrapper && rb_const_defined_at(rb_cObject, node->nd_cname)) { + klass = rb_const_get_at(rb_cObject, node->nd_cname); + } + if (klass) { + if (TYPE(klass) != T_CLASS) { + rb_raise(rb_eTypeError, "%s is not a class", + rb_id2name(node->nd_cname)); } if (super) { - tmp = RCLASS(class)->super; + tmp = RCLASS(klass)->super; if (FL_TEST(tmp, FL_SINGLETON)) { tmp = RCLASS(tmp)->super; } @@ -2219,23 +2682,28 @@ rb_eval(self, node) tmp = RCLASS(tmp)->super; } if (tmp != super) { - TypeError("superclass mismatch for %s", - rb_id2name(node->nd_cname)); + rb_raise(rb_eTypeError, "superclass mismatch for %s", + rb_id2name(node->nd_cname)); } } - if (safe_level >= 4) { - Raise(eSecurityError, "extending class prohibited"); + if (safe_level >= 3) { + rb_raise(rb_eSecurityError, "extending class prohibited"); } rb_clear_cache(); } else { - if (!super) super = cObject; - class = rb_define_class_id(node->nd_cname, super); - rb_const_set(the_class, node->nd_cname, class); - rb_set_class_path(class,the_class,rb_id2name(node->nd_cname)); + if (!super) super = rb_cObject; + klass = rb_define_class_id(node->nd_cname, super); + rb_const_set(ruby_class, node->nd_cname, klass); + rb_set_class_path(klass,ruby_class,rb_id2name(node->nd_cname)); + rb_obj_call_init(klass); + } + if (ruby_wrapper) { + rb_extend_object(klass, ruby_wrapper); + rb_include_module(klass, ruby_wrapper); } - return module_setup(class, node->nd_body); + result = module_setup(klass, node->nd_body); } break; @@ -2243,22 +2711,36 @@ rb_eval(self, node) { VALUE module; - if (rb_const_defined_at(the_class, node->nd_cname) && - ((VALUE)the_class != cObject || + if (NIL_P(ruby_class)) { + rb_raise(rb_eTypeError, "no outer class/module"); + } + module = 0; + if (rb_const_defined_at(ruby_class, node->nd_cname) && + (ruby_class != rb_cObject || !rb_autoload_defined(node->nd_cname))) { - - module = rb_const_get_at(the_class, node->nd_cname); + module = rb_const_get_at(ruby_class, node->nd_cname); + } + if (ruby_wrapper && rb_const_defined_at(rb_cObject, node->nd_cname)) { + module = rb_const_get_at(rb_cObject, node->nd_cname); + } + if (module) { if (TYPE(module) != T_MODULE) { - TypeError("%s is not a module", rb_id2name(node->nd_cname)); + rb_raise(rb_eTypeError, "%s is not a module", + rb_id2name(node->nd_cname)); } - if (safe_level >= 4) { - Raise(eSecurityError, "extending module prohibited"); + if (safe_level >= 3) { + rb_raise(rb_eSecurityError, "extending module prohibited"); } } else { module = rb_define_module_id(node->nd_cname); - rb_const_set(the_class, node->nd_cname, module); - rb_set_class_path(module,the_class,rb_id2name(node->nd_cname)); + rb_const_set(ruby_class, node->nd_cname, module); + rb_set_class_path(module,ruby_class,rb_id2name(node->nd_cname)); + rb_obj_call_init(module); + } + if (ruby_wrapper) { + rb_extend_object(module, ruby_wrapper); + rb_include_module(module, ruby_wrapper); } result = module_setup(module, node->nd_body); @@ -2267,24 +2749,28 @@ rb_eval(self, node) case NODE_SCLASS: { - VALUE class; + VALUE klass; - class = rb_eval(self, node->nd_recv); - if (FIXNUM_P(class)) { - TypeError("No virtual class for Fixnums"); + klass = rb_eval(self, node->nd_recv); + if (FIXNUM_P(klass)) { + rb_raise(rb_eTypeError, "No virtual class for Fixnums"); } - if (NIL_P(class)) { - TypeError("No virtual class for nil"); + if (NIL_P(klass)) { + rb_raise(rb_eTypeError, "No virtual class for nil"); } - if (rb_special_const_p(class)) { - TypeError("No virtual class for special constants"); + if (rb_special_const_p(klass)) { + rb_raise(rb_eTypeError, "No virtual class for special constants"); } - if (FL_TEST(CLASS_OF(class), FL_SINGLETON)) { + if (FL_TEST(CLASS_OF(klass), FL_SINGLETON)) { rb_clear_cache(); - class = rb_singleton_class(class); } - - result = module_setup(class, node->nd_body); + klass = rb_singleton_class(klass); + if (ruby_wrapper) { + rb_extend_object(klass, ruby_wrapper); + rb_include_module(klass, ruby_wrapper); + } + + result = module_setup(klass, node->nd_body); } break; @@ -2293,26 +2779,38 @@ rb_eval(self, node) char buf[20]; char *desc = is_defined(self, node->nd_head, buf); - if (desc) result = str_new2(desc); - else result = FALSE; + if (desc) result = rb_str_new2(desc); + else result = Qfalse; } break; case NODE_NEWLINE: - sourcefile = node->nd_file; - sourceline = node->nd_nth; + ruby_sourcefile = node->nd_file; + ruby_sourceline = node->nd_nth; if (trace_func) { - call_trace_func("line", sourcefile, sourceline, - self, the_frame->last_func); + call_trace_func("line", ruby_sourcefile, ruby_sourceline, + self, ruby_frame->last_func, 0); } node = node->nd_next; goto again; default: - Bug("unknown node type %d", nd_type(node)); + rb_bug("unknown node type %d", nd_type(node)); } finish: CHECK_INTS; +#ifdef NOBLOCK_RECUR + if (next) { + node = next; + next = 0; + goto again; + } + if (nstack) { + node = nstack->nd_head; + nstack = nstack->nd_next; + goto again; + } +#endif return result; } @@ -2322,47 +2820,48 @@ module_setup(module, node) NODE * volatile node; { int state; - VALUE save = the_frame->cbase; + VALUE save = ruby_frame->cbase; VALUE result; /* OK */ - char *file = sourcefile; - int line = sourceline; + char *file = ruby_sourcefile; + int line = ruby_sourceline; + TMP_PROTECT; /* fill c-ref */ node->nd_clss = module; node = node->nd_body; PUSH_CLASS(); - the_class = module; + ruby_class = module; PUSH_SCOPE(); - if (node->nd_rval) the_frame->cbase = node->nd_rval; + if (node->nd_rval) ruby_frame->cbase = node->nd_rval; if (node->nd_tbl) { - VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); + VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1); *vars++ = (VALUE)node; - the_scope->local_vars = vars; - memclear(the_scope->local_vars, node->nd_tbl[0]); - the_scope->local_tbl = node->nd_tbl; + ruby_scope->local_vars = vars; + rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); + ruby_scope->local_tbl = node->nd_tbl; } else { - the_scope->local_vars = 0; - the_scope->local_tbl = 0; + ruby_scope->local_vars = 0; + ruby_scope->local_tbl = 0; } PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { if (trace_func) { call_trace_func("class", file, line, - the_class, the_frame->last_func); + ruby_class, ruby_frame->last_func, 0); } - result = rb_eval((VALUE)the_class, node->nd_body); + result = rb_eval(ruby_class, node->nd_next); } POP_TAG(); POP_SCOPE(); POP_CLASS(); - the_frame->cbase = save; + ruby_frame->cbase = save; if (trace_func) { - call_trace_func("end", file, line, 0, the_frame->last_func); + call_trace_func("end", file, line, 0, ruby_frame->last_func, 0); } if (state) JUMP_TAG(state); @@ -2375,13 +2874,13 @@ rb_respond_to(obj, id) ID id; { if (rb_method_boundp(CLASS_OF(obj), id, 0)) { - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } static VALUE -obj_respond_to(argc, argv, obj) +rb_obj_respond_to(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -2392,19 +2891,19 @@ obj_respond_to(argc, argv, obj) rb_scan_args(argc, argv, "11", &mid, &priv); id = rb_to_id(mid); if (rb_method_boundp(CLASS_OF(obj), id, !RTEST(priv))) { - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } static VALUE -mod_method_defined(mod, mid) +rb_mod_method_defined(mod, mid) VALUE mod, mid; { if (rb_method_boundp(mod, rb_to_id(mid), 1)) { - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } void @@ -2413,20 +2912,20 @@ rb_exit(status) { if (prot_tag) { exit_status = status; - rb_raise(exc_new(eSystemExit, 0, 0)); + rb_exc_raise(rb_exc_new(rb_eSystemExit, 0, 0)); } exit(status); } static VALUE -f_exit(argc, argv, obj) +rb_f_exit(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { VALUE status; - rb_secure(2); + rb_secure(4); if (rb_scan_args(argc, argv, "01", &status) == 1) { status = NUM2INT(status); } @@ -2434,18 +2933,24 @@ f_exit(argc, argv, obj) status = 0; } rb_exit(status); - /* not reached */ + return Qnil; /* not reached */ } -static VALUE -f_abort() +static void +rb_abort() { - rb_secure(2); - if (errinfo) { + if (rb_errinfo) { error_print(); } rb_exit(1); - /* not reached */ +} + +static VALUE +rb_f_abort() +{ + rb_secure(4); + rb_abort(); + return Qnil; /* not reached */ } void @@ -2454,143 +2959,135 @@ rb_iter_break() JUMP_TAG(TAG_BREAK); } -#ifdef __GNUC__ -static volatile voidfn rb_longjmp; -#endif - -static VALUE make_backtrace(); - -static VALUE -check_errat(val) - VALUE val; -{ - int i; - static char *err = "value of $@ must be Array of String"; - - if (!NIL_P(val)) { - int t = TYPE(val); - - if (t == T_STRING) return ary_new3(1, val); - if (t != T_ARRAY) { - TypeError(err); - } - for (i=0;ilen;i++) { - if (TYPE(RARRAY(val)->ptr[i]) != T_STRING) { - TypeError(err); - } - } - } - return val; -} +static void rb_longjmp _((int, VALUE)) NORETURN; +static VALUE make_backtrace _((void)); static void -rb_longjmp(tag, mesg, at) +rb_longjmp(tag, mesg) int tag; - VALUE mesg, at; + VALUE mesg; { - if (NIL_P(errinfo) && NIL_P(mesg)) { - errinfo = exc_new(eRuntimeError, 0, 0); + VALUE at; + + if (NIL_P(mesg)) mesg = rb_errinfo; + if (NIL_P(mesg)) { + mesg = rb_exc_new(rb_eRuntimeError, 0, 0); } - if (!NIL_P(at)) { - errat = check_errat(at); + if (ruby_sourcefile && !NIL_P(mesg)) { + at = get_backtrace(mesg); + if (NIL_P(at)) { + at = make_backtrace(); + set_backtrace(mesg, at); + } } - else if (sourcefile && (NIL_P(errat) || !NIL_P(mesg))) { - errat = make_backtrace(); + if (!NIL_P(mesg)) { + rb_errinfo = mesg; } - if (!NIL_P(mesg)) { - if (obj_is_kind_of(mesg, eGlobalExit)) { - errinfo = mesg; - } - else { - errinfo = exc_new3(eRuntimeError, mesg); - } - str_freeze(errinfo); + if (RTEST(rb_debug) && !NIL_P(rb_errinfo) + && !rb_obj_is_kind_of(rb_errinfo, rb_eSystemExit)) { + fprintf(stderr, "Exception `%s' at %s:%d\n", + rb_class2name(CLASS_OF(rb_errinfo)), + ruby_sourcefile, ruby_sourceline); } + rb_trap_restore_mask(); + if (trace_func && tag != TAG_FATAL) { + call_trace_func("raise", ruby_sourcefile, ruby_sourceline, + ruby_frame->self, ruby_frame->last_func, 0); + } + if (!prot_tag) { + error_print(); + } JUMP_TAG(tag); } void -rb_raise(mesg) +rb_exc_raise(mesg) VALUE mesg; { - rb_longjmp(TAG_RAISE, mesg, Qnil); + rb_longjmp(TAG_RAISE, mesg); } void -rb_fatal(mesg) +rb_exc_fatal(mesg) VALUE mesg; { - rb_longjmp(TAG_FATAL, mesg, Qnil); + rb_longjmp(TAG_FATAL, mesg); } void rb_interrupt() { - Raise(eInterrupt, ""); + rb_raise(rb_eInterrupt, ""); } static VALUE -f_raise(argc, argv) +rb_f_raise(argc, argv) int argc; VALUE *argv; { VALUE arg1, arg2, arg3; - VALUE etype, mesg; + VALUE mesg; int n; - etype = eRuntimeError; mesg = Qnil; switch (n = rb_scan_args(argc, argv, "03", &arg1, &arg2, &arg3)) { case 1: mesg = arg1; break; - case 2: case 3: - etype = arg1; - if (obj_is_kind_of(etype, eGlobalExit)) { - etype = CLASS_OF(etype); - } - else { - Check_Type(etype, T_CLASS); - } + case 2: mesg = arg2; break; } if (!NIL_P(mesg)) { - Check_Type(mesg, T_STRING); - if (n == 2 || !obj_is_kind_of(mesg, eException)) { - mesg = exc_new3(etype, mesg); + if (n == 1 && TYPE(mesg) == T_STRING) { + mesg = rb_exc_new3(rb_eRuntimeError, mesg); + } + else { + mesg = rb_funcall(arg1, rb_intern("new"), 1, mesg); + } + if (!rb_obj_is_kind_of(mesg, rb_eException)) { + rb_raise(rb_eTypeError, "exception object expected"); } + set_backtrace(mesg, arg3); } PUSH_FRAME(); /* fake frame */ - *the_frame = *_frame->prev->prev; - rb_longjmp(TAG_RAISE, mesg, arg3); + *ruby_frame = *_frame.prev->prev; + rb_longjmp(TAG_RAISE, mesg); POP_FRAME(); + + return Qnil; /* not reached */ +} + +void +rb_jump_tag(tag) + int tag; +{ + JUMP_TAG(tag); } int -iterator_p() +rb_iterator_p() { - if (the_frame->iter) return TRUE; - return FALSE; + if (ruby_frame->iter) return Qtrue; + return Qfalse; } static VALUE -f_iterator_p() +rb_f_iterator_p() { - if (the_frame->prev && the_frame->prev->iter) return TRUE; - return FALSE; + if (ruby_frame->prev && ruby_frame->prev->iter) return Qtrue; + return Qfalse; } -VALUE -rb_yield_0(val, self) - VALUE val; - volatile VALUE self; +static VALUE +rb_yield_0(val, self, klass) + VALUE val, self, klass; /* OK */ { NODE *node; volatile VALUE result = Qnil; @@ -2598,23 +3095,23 @@ rb_yield_0(val, self) struct SCOPE *old_scope; struct FRAME frame; int state; - static USHORT serial = 1; + static unsigned serial = 1; - if (!iterator_p()) { - Raise(eLocalJumpError, "yield called out of iterator"); + if (!ruby_frame->iter || !ruby_block) { + rb_raise(rb_eLocalJumpError, "yield called out of iterator"); } PUSH_VARS(); PUSH_CLASS(); - block = the_block; + block = ruby_block; frame = block->frame; - frame.prev = the_frame; - the_frame = &(frame); - old_scope = the_scope; - the_scope = block->scope; - the_block = block->prev; - the_dyna_vars = block->d_vars; - the_class = block->class; + frame.prev = ruby_frame; + ruby_frame = &(frame); + old_scope = ruby_scope; + ruby_scope = block->scope; + ruby_block = block->prev; + ruby_dyna_vars = block->d_vars; + ruby_class = klass?klass:block->klass; if (!self) self = block->self; node = block->body; if (block->var) { @@ -2660,9 +3157,11 @@ rb_yield_0(val, self) POP_ITER(); POP_CLASS(); POP_VARS(); - the_block = block; - the_frame = the_frame->prev; - the_scope = old_scope; + ruby_block = block; + ruby_frame = ruby_frame->prev; + if (FL_TEST(ruby_scope, SCOPE_DONT_RECYCLE)) + FL_SET(old_scope, SCOPE_DONT_RECYCLE); + ruby_scope = old_scope; if (state) JUMP_TAG(state); return result; } @@ -2671,13 +3170,13 @@ VALUE rb_yield(val) VALUE val; { - return rb_yield_0(val, 0); + return rb_yield_0(val, 0, 0); } static VALUE -f_loop() +rb_f_loop() { - for (;;) { rb_yield(Qnil); } + for (;;) { rb_yield_0(Qnil, 0, 0); } } static VALUE @@ -2702,10 +3201,10 @@ massign(self, node, val) } if (node->nd_args) { if (!list && ind_args, ary_new4(len-i, RARRAY(val)->ptr+i)); + assign(self, node->nd_args, rb_ary_new4(len-i, RARRAY(val)->ptr+i)); } else { - assign(self, node->nd_args, ary_new2(0)); + assign(self, node->nd_args, rb_ary_new2(0)); } } } @@ -2735,17 +3234,25 @@ assign(self, lhs, val) break; case NODE_LASGN: - if (the_scope->local_vars == 0) - Bug("unexpected iterator variable assignment"); - the_scope->local_vars[lhs->nd_cnt] = val; + if (ruby_scope->local_vars == 0) + rb_bug("unexpected iterator variable assignment"); + ruby_scope->local_vars[lhs->nd_cnt] = val; break; case NODE_DASGN: - dyna_var_asgn(lhs->nd_vid, val); + rb_dvar_asgn(lhs->nd_vid, val); + break; + + case NODE_DASGN_PUSH: + dvar_asgn_push(lhs->nd_vid, val); break; case NODE_CASGN: - rb_const_set(the_class, lhs->nd_vid, val); + rb_const_set(ruby_class, lhs->nd_vid, val); + break; + + case NODE_MASGN: + massign(self, lhs, val); break; case NODE_CALL: @@ -2754,7 +3261,7 @@ assign(self, lhs, val) recv = rb_eval(self, lhs->nd_recv); if (!lhs->nd_args->nd_head) { /* attr set */ - rb_funcall2(recv, lhs->nd_mid, 1, &val); + rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, 0); } else { /* array set */ @@ -2762,13 +3269,14 @@ assign(self, lhs, val) args = rb_eval(self, lhs->nd_args); RARRAY(args)->ptr[RARRAY(args)->len-1] = val; - rb_apply(recv, lhs->nd_mid, args); + rb_call(CLASS_OF(recv), recv, lhs->nd_mid, + RARRAY(args)->len, RARRAY(args)->ptr, 0); } } break; default: - Bug("bug in variable assignment"); + rb_bug("bug in variable assignment"); break; } } @@ -2781,7 +3289,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) int state; volatile VALUE retval = Qnil; NODE *node = NEW_CFUNC(bl_proc, data2); - VALUE self = TopSelf; + VALUE self = ruby_top_self; iter_retry: PUSH_ITER(ITER_PRE); @@ -2792,10 +3300,10 @@ rb_iterate(it_proc, data1, bl_proc, data2) if (state == 0) { retval = (*it_proc)(data1); } - if (the_block->tag->dst == state) { + if (ruby_block->tag->dst == state) { state &= TAG_MASK; if (state == TAG_RETURN) { - retval = prot_tag->tag_retval; + retval = prot_tag->retval; } } POP_TAG(); @@ -2828,19 +3336,21 @@ handle_rescue(self, node) NODE *node; { int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; if (!node->nd_args) { - return obj_is_kind_of(errinfo, eException); + return rb_obj_is_kind_of(rb_errinfo, rb_eStandardError); } - PUSH_ITER(ITER_NOT); + BEGIN_CALLARGS; SETUP_ARGS(node->nd_args); - POP_ITER(); + END_CALLARGS; + while (argc--) { - if (!obj_is_kind_of(argv[0], cModule)) { - TypeError("class or module required for rescue clause"); + if (!rb_obj_is_kind_of(argv[0], rb_cModule)) { + rb_raise(rb_eTypeError, "class or module required for rescue clause"); } - if (obj_is_kind_of(errinfo, argv[0])) return 1; + if (rb_obj_is_kind_of(rb_errinfo, argv[0])) return 1; argv++; } return 0; @@ -2853,17 +3363,18 @@ rb_rescue(b_proc, data1, r_proc, data2) { int state; volatile VALUE result; + volatile VALUE e_info = rb_errinfo; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { retry_entry: result = (*b_proc)(data1); } - else if (state == TAG_RAISE && obj_is_kind_of(errinfo, eException)) { + else if (state == TAG_RAISE && rb_obj_is_kind_of(rb_errinfo, rb_eStandardError)) { if (r_proc) { PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - result = (*r_proc)(data2, errinfo); + result = (*r_proc)(data2, rb_errinfo); } POP_TAG(); if (state == TAG_RETRY) { @@ -2876,7 +3387,7 @@ rb_rescue(b_proc, data1, r_proc, data2) state = 0; } if (state == 0) { - errat = Qnil; + rb_errinfo = e_info; } } POP_TAG(); @@ -2885,43 +3396,70 @@ rb_rescue(b_proc, data1, r_proc, data2) return result; } +VALUE +rb_protect(proc, data, state) + VALUE (*proc)(); + VALUE data; + int *state; +{ + VALUE result; /* OK */ + int status; + + PUSH_TAG(PROT_NONE); + if ((status = EXEC_TAG()) == 0) { + result = (*proc)(data); + } + POP_TAG(); + if (state) { + *state = status; + } + if (status != 0) { + return Qnil; + } + + return result; +} + VALUE rb_ensure(b_proc, data1, e_proc, data2) VALUE (*b_proc)(); - void (*e_proc)(); + VALUE (*e_proc)(); VALUE data1, data2; { int state; volatile VALUE result = Qnil; + VALUE retval; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { result = (*b_proc)(data1); } POP_TAG(); - + retval = prot_tag->retval; /* save retval */ (*e_proc)(data2); - if (state) { - JUMP_TAG(state); - } + return_value(retval); + + if (state) JUMP_TAG(state); return result; } static int last_call_status; -#define CSTAT_NOEX 1 -#define CSTAT_VCALL 2 + +#define CSTAT_PRIV 1 +#define CSTAT_PROT 2 +#define CSTAT_VCALL 4 static VALUE -f_missing(argc, argv, obj) +rb_f_missing(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { - VALUE desc = 0; ID id; + VALUE desc = 0; char *format = 0; - char *file = sourcefile; - int line = sourceline; + char *file = ruby_sourcefile; + int line = ruby_sourceline; id = FIX2INT(argv[0]); argc--; argv++; @@ -2931,23 +3469,26 @@ f_missing(argc, argv, obj) format = "undefined method `%s' for nil"; break; case T_TRUE: - format = "undefined method `%s' for TRUE"; + format = "undefined method `%s' for Qtrue"; break; case T_FALSE: - format = "undefined method `%s' for FALSE"; + format = "undefined method `%s' for Qfalse"; break; case T_OBJECT: - desc = obj_as_string(obj); + desc = rb_any_to_s(obj); break; default: desc = rb_inspect(obj); break; } if (desc) { - if (last_call_status & CSTAT_NOEX) { + if (last_call_status & CSTAT_PRIV) { format = "private method `%s' called for %s"; } - else if (iterator_p()) { + if (last_call_status & CSTAT_PROT) { + format = "protected method `%s' called for %s"; + } + else if (rb_iterator_p()) { format = "undefined iterator `%s' for %s"; } else if (last_call_status & CSTAT_VCALL) { @@ -2961,18 +3502,18 @@ f_missing(argc, argv, obj) format = "undefined method `%s' for %s"; } if (RSTRING(desc)->len > 65) { - desc = any_to_s(obj); + desc = rb_any_to_s(obj); } } - sourcefile = file; - sourceline = line; + ruby_sourcefile = file; + ruby_sourceline = line; PUSH_FRAME(); /* fake frame */ - *the_frame = *_frame->prev->prev; + *ruby_frame = *_frame.prev->prev; - NameError(format, - rb_id2name(id), - desc?(char*)RSTRING(desc)->ptr:""); + rb_raise(rb_eNameError, format, + rb_id2name(id), + desc?(char*)RSTRING(desc)->ptr:""); POP_FRAME(); return Qnil; /* not reached */ @@ -3004,58 +3545,127 @@ rb_undefined(obj, id, argc, argv, call_status) extern int _stacksize; # define STACK_LEVEL_MAX (_stacksize - 4096) #else -# define STACK_LEVEL_MAX 655350 +# define STACK_LEVEL_MAX 655300 #endif #endif -extern VALUE *gc_stack_start; +extern VALUE *rb_gc_stack_start; static int stack_length() { VALUE pos; #ifdef sparc - return gc_stack_start - &pos + 0x80; + return rb_gc_stack_start - &pos + 0x80; #else - return (&pos < gc_stack_start) ? gc_stack_start - &pos - : &pos - gc_stack_start; + return (&pos < rb_gc_stack_start) ? rb_gc_stack_start - &pos + : &pos - rb_gc_stack_start; #endif } static VALUE -rb_call(class, recv, mid, argc, argv, scope) - VALUE class, recv; - ID mid; +call_cfunc(func, recv, len, argc, argv) + VALUE (*func)(); + VALUE recv; + int len, argc; + VALUE *argv; +{ + if (len >= 0 && argc != len) { + rb_raise(rb_eArgError, "Wrong # of arguments(%d for %d)", + argc, len); + } + + switch (len) { + case -2: + return (*func)(recv, rb_ary_new4(argc, argv)); + break; + case -1: + return (*func)(argc, argv, recv); + break; + case 0: + return (*func)(recv); + break; + case 1: + return (*func)(recv, argv[0]); + break; + case 2: + return (*func)(recv, argv[0], argv[1]); + break; + case 3: + return (*func)(recv, argv[0], argv[1], argv[2]); + break; + case 4: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3]); + break; + case 5: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4]); + break; + case 6: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); + break; + case 7: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6]); + break; + case 8: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7]); + break; + case 9: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8]); + break; + case 10: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9]); + break; + case 11: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]); + break; + case 12: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], + argv[10], argv[11]); + break; + case 13: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], + argv[11], argv[12]); + break; + case 14: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], + argv[11], argv[12], argv[13]); + break; + case 15: + return (*func)(recv, argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], + argv[11], argv[12], argv[13], argv[14]); + break; + default: + rb_raise(rb_eArgError, "too many arguments(%d)", len); + break; + } + return Qnil; /* not reached */ +} + +static VALUE +rb_call0(klass, recv, id, argc, argv, body, nosuper) + VALUE klass, recv; + ID id; int argc; /* OK */ VALUE *argv; /* OK */ - int scope; + NODE *body; /* OK */ + int nosuper; { - NODE *body, *b2; /* OK */ - int noex; - ID id = mid; - struct cache_entry *ent; + NODE *b2; /* OK */ volatile VALUE result = Qnil; int itr; - enum node_type type; static int tick; + TMP_PROTECT; - again: - /* is it in the method cache? */ - ent = cache + EXPR1(class, mid); - if (ent->mid == mid && ent->class == class) { - class = ent->origin; - id = ent->mid0; - noex = ent->noex; - body = ent->method; - } - else if ((body = rb_get_method_body(&class, &id, &noex)) == 0) { - return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0); - } - - /* receiver specified form for private method */ - if (noex == NOEX_PRIVATE && scope == 0) - return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX); - - switch (the_iter->iter) { + switch (ruby_iter->iter) { case ITER_PRE: itr = ITER_CUR; break; @@ -3065,151 +3675,57 @@ rb_call(class, recv, mid, argc, argv, scope) break; } - type = nd_type(body); - if (type == NODE_ZSUPER) { - /* for re-scoped/renamed method */ - mid = id; - if (scope == 0) scope = 1; - if (RCLASS(class)->super == 0) { - /* origin is the Module, so need to scan superclass hierarchy. */ - struct RClass *cl = RCLASS(class); - - class = RBASIC(recv)->class; - while (class) { - if (RCLASS(class)->m_tbl == cl->m_tbl) - break; - class = RCLASS(class)->super; - } - } - else { - class = RCLASS(class)->super; + if ((++tick & 0x3ff) == 0) { + CHECK_INTS; /* better than nothing */ + if (stack_length() > STACK_LEVEL_MAX) { + rb_raise(rb_eSysStackError, "stack level too deep"); } - goto again; } - if ((++tick & 0xfff) == 0 && stack_length() > STACK_LEVEL_MAX) - Fatal("stack level too deep"); - PUSH_ITER(itr); PUSH_FRAME(); - the_frame->last_func = id; - the_frame->last_class = class; - the_frame->argc = argc; - the_frame->argv = argv; - switch (type) { + ruby_frame->last_func = id; + ruby_frame->last_class = nosuper?0:klass; + ruby_frame->self = recv; + ruby_frame->argc = argc; + ruby_frame->argv = argv; + + switch (nd_type(body)) { case NODE_CFUNC: { int len = body->nd_argc; - if (len >= 0 && argc != len) { - ArgError("Wrong # of arguments(%d for %d)", argc, len); + if (len < -2) { + rb_bug("bad argc(%d) specified for `%s(%s)'", + len, rb_class2name(klass), rb_id2name(id)); } + if (trace_func) { + int state; + char *file = ruby_frame->prev->file; + int line = ruby_frame->prev->line; + if (!file) { + file = ruby_sourcefile; + line = ruby_sourceline; + } - switch (len) { - case -2: - result = (*body->nd_cfnc)(recv, ary_new4(argc, argv)); - break; - case -1: - result = (*body->nd_cfnc)(argc, argv, recv); - break; - case 0: - result = (*body->nd_cfnc)(recv); - break; - case 1: - result = (*body->nd_cfnc)(recv, argv[0]); - break; - case 2: - result = (*body->nd_cfnc)(recv, argv[0], argv[1]); - break; - case 3: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2]); - break; - case 4: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3]); - break; - case 5: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4]); - break; - case 6: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5]); - break; - case 7: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6]); - break; - case 8: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7]); - break; - case 9: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8]); - break; - case 10: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8], - argv[6], argv[7], argv[8], - argv[9]); - break; - case 11: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8], - argv[6], argv[7], argv[8], - argv[9], argv[10]); - break; - case 12: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8], - argv[6], argv[7], argv[8], - argv[9], argv[10], argv[11]); - break; - case 13: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8], - argv[6], argv[7], argv[8], - argv[9], argv[10], argv[11], - argv[12]); - break; - case 14: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8], - argv[6], argv[7], argv[8], - argv[9], argv[10], argv[11], - argv[12], argv[13]); - break; - case 15: - result = (*body->nd_cfnc)(recv, argv[0], argv[1], argv[2], - argv[3], argv[4], argv[5], - argv[6], argv[7], argv[8], - argv[6], argv[7], argv[8], - argv[9], argv[10], argv[11], - argv[12], argv[13], argv[14]); - break; - default: - if (len < 0) { - Bug("bad argc(%d) specified for `%s(%s)'", - len, rb_class2name((VALUE)class), rb_id2name(mid)); + call_trace_func("c-call", 0, 0, 0, id, 0); + PUSH_TAG(PROT_FUNC); + if ((state = EXEC_TAG()) == 0) { + result = call_cfunc(body->nd_cfnc, recv, len, argc, argv); } - else { - ArgError("too many arguments(%d)", len); - } - break; + POP_TAG(); + call_trace_func("c-return", 0, 0, recv, id, klass); + if (state) JUMP_TAG(state); + } + else { + result = call_cfunc(body->nd_cfnc, recv, len, argc, argv); } } break; + /* for re-scoped/renamed method */ + case NODE_ZSUPER: /* for attr get/set */ case NODE_ATTRSET: case NODE_IVAR: @@ -3223,36 +3739,44 @@ rb_call(class, recv, mid, argc, argv, scope) PUSH_SCOPE(); - if (body->nd_rval) the_frame->cbase = body->nd_rval; + if (body->nd_rval) ruby_frame->cbase = body->nd_rval; if (body->nd_tbl) { - local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]+1); + local_vars = TMP_ALLOC(body->nd_tbl[0]+1); *local_vars++ = (VALUE)body; - memclear(local_vars, body->nd_tbl[0]); - the_scope->local_tbl = body->nd_tbl; - the_scope->local_vars = local_vars; + rb_mem_clear(local_vars, body->nd_tbl[0]); + ruby_scope->local_tbl = body->nd_tbl; + ruby_scope->local_vars = local_vars; } else { - local_vars = the_scope->local_vars = 0; - the_scope->local_tbl = 0; + local_vars = ruby_scope->local_vars = 0; + ruby_scope->local_tbl = 0; } - b2 = body = body->nd_body; + b2 = body = body->nd_next; - PUSH_TAG(PROT_FUNC); PUSH_VARS(); + PUSH_TAG(PROT_FUNC); if ((state = EXEC_TAG()) == 0) { - if (nd_type(body) == NODE_BLOCK) { - NODE *node = body->nd_head; - int i; + NODE *node = 0; + int i; + if (nd_type(body) == NODE_ARGS) { + node = body; + body = 0; + } + else if (nd_type(body) == NODE_BLOCK) { + node = body->nd_head; + body = body->nd_next; + } + if (node) { if (nd_type(node) != NODE_ARGS) { - Bug("no argument-node"); + rb_bug("no argument-node"); } - body = body->nd_next; i = node->nd_cnt; if (i > argc) { - ArgError("Wrong # of arguments(%d for %d)", argc, i); + rb_raise(rb_eArgError, "Wrong # of arguments(%d for %d)", + argc, i); } if (node->nd_rest == -1) { int opt = argc - i; @@ -3263,14 +3787,15 @@ rb_call(class, recv, mid, argc, argv, scope) optnode = optnode->nd_next; } if (opt > 0) { - ArgError("Wrong # of arguments(%d for %d)", + rb_raise(rb_eArgError, "Wrong # of arguments(%d for %d)", argc, argc-opt); } } if (local_vars) { if (i > 0) { - MEMCPY(local_vars, argv, VALUE, i); + /* +2 for $_ and $~ */ + MEMCPY(local_vars+2, argv, VALUE, i); } argv += i; argc -= i; if (node->nd_opt) { @@ -3285,53 +3810,52 @@ rb_call(class, recv, mid, argc, argv, scope) } if (node->nd_rest >= 0) { if (argc > 0) - local_vars[node->nd_rest]=ary_new4(argc,argv); + local_vars[node->nd_rest]=rb_ary_new4(argc,argv); else - local_vars[node->nd_rest]=ary_new2(0); + local_vars[node->nd_rest]=rb_ary_new2(0); } } } - else if (nd_type(body) == NODE_ARGS) { - body = 0; - } + if (trace_func) { call_trace_func("call", b2->nd_file, nd_line(b2), - recv, the_frame->last_func); + recv, ruby_frame->last_func, 0); } result = rb_eval(recv, body); } else if (state == TAG_RETURN) { - result = prot_tag->tag_retval; + result = prot_tag->retval; state = 0; } - POP_VARS(); POP_TAG(); + POP_VARS(); POP_SCOPE(); if (trace_func) { - char *file = the_frame->prev->file; - int line = the_frame->prev->line; + char *file = ruby_frame->prev->file; + int line = ruby_frame->prev->line; if (!file) { - file = sourcefile; - line = sourceline; + file = ruby_sourcefile; + line = ruby_sourceline; } - call_trace_func("return", file, line, 0, the_frame->last_func); + call_trace_func("return", file, line, recv, + ruby_frame->last_func, klass); } switch (state) { case 0: break; case TAG_NEXT: - Raise(eLocalJumpError, "unexpected next"); + rb_raise(rb_eLocalJumpError, "unexpected next"); break; case TAG_BREAK: - Raise(eLocalJumpError, "unexpected break"); + rb_raise(rb_eLocalJumpError, "unexpected break"); break; case TAG_REDO: - Raise(eLocalJumpError, "unexpected redo"); + rb_raise(rb_eLocalJumpError, "unexpected redo"); break; case TAG_RETRY: - if (!iterator_p()) { - Raise(eLocalJumpError, "retry outside of rescue clause"); + if (!rb_iterator_p()) { + rb_raise(rb_eLocalJumpError, "retry outside of rescue clause"); } default: JUMP_TAG(state); @@ -3343,6 +3867,46 @@ rb_call(class, recv, mid, argc, argv, scope) return result; } +static VALUE +rb_call(klass, recv, mid, argc, argv, scope) + VALUE klass, recv; + ID mid; + int argc; /* OK */ + VALUE *argv; /* OK */ + int scope; +{ + NODE *body; /* OK */ + int noex; + ID id = mid; + struct cache_entry *ent; + + /* is it in the method cache? */ + ent = cache + EXPR1(klass, mid); + if (ent->mid == mid && ent->klass == klass) { + klass = ent->origin; + id = ent->mid0; + noex = ent->noex; + body = ent->method; + } + else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) { + if (scope == 3) { + rb_raise(rb_eNameError, "super: no superclass method `%s'", + rb_id2name(mid)); + } + return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0); + } + + /* receiver specified form for private method */ + if ((noex & NOEX_PRIVATE) && scope == 0) + return rb_undefined(recv, mid, argc, argv, CSTAT_PRIV); + + /* self must be kind of a specified form for private method */ + if ((noex & NOEX_PROTECTED) && !rb_obj_is_kind_of(ruby_frame->self, klass)) + return rb_undefined(recv, mid, argc, argv, CSTAT_PROT); + + return rb_call0(klass, recv, id, argc, argv, body, noex & NOEX_UNDEF); +} + VALUE rb_apply(recv, mid, args) VALUE recv; @@ -3359,38 +3923,42 @@ rb_apply(recv, mid, args) } static VALUE -f_send(argc, argv, recv) +rb_f_send(argc, argv, recv) int argc; VALUE *argv; VALUE recv; { VALUE vid; - ID mid; - if (argc == 0) ArgError("no method name given"); + if (argc == 0) rb_raise(rb_eArgError, "no method name given"); - vid = argv[0]; argc--; argv++; - if (TYPE(vid) == T_STRING) { - mid = rb_intern(RSTRING(vid)->ptr); - } - else { - mid = NUM2INT(vid); - } - PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT); - vid = rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1); + vid = *argv++; argc--; + PUSH_ITER(rb_iterator_p()?ITER_PRE:ITER_NOT); + vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1); POP_ITER(); return vid; } + +#ifdef HAVE_STDARG_PROTOTYPES +#include +#define va_init_list(a,b) va_start(a,b) +#else #include +#define va_init_list(a,b) va_start(a) +#endif VALUE +#ifdef HAVE_STDARG_PROTOTYPES +rb_funcall(VALUE recv, ID mid, int n, ...) +#else rb_funcall(recv, mid, n, va_alist) VALUE recv; ID mid; int n; va_dcl +#endif { va_list ar; VALUE *argv; @@ -3400,7 +3968,7 @@ rb_funcall(recv, mid, n, va_alist) argv = ALLOCA_N(VALUE, n); - va_start(ar); + va_init_list(ar, n); for (i=0;ilast_func) { - sprintf(buf, "%s:%d:in `%s'", sourcefile, sourceline, - rb_id2name(frame->last_func)); + snprintf(buf, BUFSIZ, "%s:%d:in `%s'", + ruby_sourcefile, ruby_sourceline, + rb_id2name(frame->last_func)); } else { - sprintf(buf, "%s:%d", sourcefile, sourceline); + snprintf(buf, BUFSIZ, "%s:%d", ruby_sourcefile, ruby_sourceline); } - ary_push(ary, str_new2(buf)); + rb_ary_push(ary, rb_str_new2(buf)); } else { while (lev-- > 0) { @@ -3452,14 +4021,14 @@ backtrace(lev) } while (frame && frame->file) { if (frame->prev && frame->prev->last_func) { - sprintf(buf, "%s:%d:in `%s'", - frame->file, frame->line, - rb_id2name(frame->prev->last_func)); + snprintf(buf, BUFSIZ, "%s:%d:in `%s'", + frame->file, frame->line, + rb_id2name(frame->prev->last_func)); } else { - sprintf(buf, "%s:%d", frame->file, frame->line); + snprintf(buf, BUFSIZ, "%s:%d", frame->file, frame->line); } - ary_push(ary, str_new2(buf)); + rb_ary_push(ary, rb_str_new2(buf)); frame = frame->prev; } safe_level = slev; @@ -3467,7 +4036,7 @@ backtrace(lev) } static VALUE -f_caller(argc, argv) +rb_f_caller(argc, argv) int argc; VALUE *argv; { @@ -3478,7 +4047,7 @@ f_caller(argc, argv) if (NIL_P(level)) lev = 1; else lev = NUM2INT(level); - if (lev < 0) ArgError("negative level(%d)", lev); + if (lev < 0) rb_raise(rb_eArgError, "negative level(%d)", lev); return backtrace(lev); } @@ -3508,77 +4077,91 @@ make_backtrace() ID rb_frame_last_func() { - return the_frame->last_func; + return ruby_frame->last_func; } static NODE* -compile(src) +compile(src, place) VALUE src; + char *place; { NODE *node; Check_Type(src, T_STRING); + if (place == 0) place = ruby_sourcefile; + node = rb_compile_string(place, src); - node = compile_string(sourcefile, RSTRING(src)->ptr, RSTRING(src)->len); - - if (nerrs == 0) return node; + if (ruby_nerrs == 0) return node; return 0; } static VALUE -eval(self, src, scope) +eval(self, src, scope, file, line) VALUE self, src, scope; + char *file; + int line; { struct BLOCK *data; volatile VALUE result = Qnil; struct SCOPE * volatile old_scope; struct BLOCK * volatile old_block; + struct BLOCK * volatile old_call_block; struct RVarmap * volatile old_d_vars; + int volatile old_vmode; struct FRAME frame; - char *file = sourcefile; - int line = sourceline; - volatile int iter = the_frame->iter; + char *filesave = ruby_sourcefile; + int linesave = ruby_sourceline; + volatile int iter = ruby_frame->iter; int state; + if (file == 0) { + file = ruby_sourcefile; + line = ruby_sourceline; + } if (!NIL_P(scope)) { - if (TYPE(scope) != T_DATA || RDATA(scope)->dfree != blk_free) { - TypeError("wrong argument type %s (expected Proc/Binding)", - rb_class2name(CLASS_OF(scope))); + if (!rb_obj_is_block(scope)) { + rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Binding)", + rb_class2name(CLASS_OF(scope))); } Data_Get_Struct(scope, struct BLOCK, data); /* PUSH BLOCK from data */ frame = data->frame; - frame.prev = the_frame; - the_frame = &(frame); - old_scope = the_scope; - the_scope = data->scope; - old_block = the_block; - the_block = data->prev; - old_d_vars = the_dyna_vars; - the_dyna_vars = data->d_vars; + frame.prev = ruby_frame; + ruby_frame = &(frame); + old_scope = ruby_scope; + ruby_scope = data->scope; + old_call_block = ruby_calling_block; + ruby_calling_block = data; + old_block = ruby_block; + ruby_block = data->prev; + old_d_vars = ruby_dyna_vars; + ruby_dyna_vars = data->d_vars; + old_vmode = scope_vmode; + scope_vmode = data->vmode; self = data->self; - the_frame->iter = data->iter; + ruby_frame->iter = data->iter; } else { - if (the_frame->prev) { - the_frame->iter = the_frame->prev->iter; + if (ruby_frame->prev) { + ruby_frame->iter = ruby_frame->prev->iter; } } PUSH_CLASS(); - the_class = ((NODE*)the_frame->cbase)->nd_clss; + ruby_class = ((NODE*)ruby_frame->cbase)->nd_clss; rb_in_eval++; - if (TYPE(the_class) == T_ICLASS) { - the_class = RBASIC(the_class)->class; + if (TYPE(ruby_class) == T_ICLASS) { + ruby_class = RBASIC(ruby_class)->klass; } PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - eval_tree = 0; - compile(src); - if (nerrs > 0) { + ruby_sourcefile = file; + ruby_sourceline = line; + compile(src, file); + if (ruby_nerrs > 0) { compile_error(0); } result = eval_node(self); @@ -3587,31 +4170,41 @@ eval(self, src, scope) POP_CLASS(); rb_in_eval--; if (!NIL_P(scope)) { - the_frame = the_frame->prev; - the_scope = old_scope; - the_block = old_block; - the_dyna_vars = old_d_vars; + ruby_frame = ruby_frame->prev; + if (FL_TEST(ruby_scope, SCOPE_DONT_RECYCLE)) + FL_SET(old_scope, SCOPE_DONT_RECYCLE); + ruby_scope = old_scope; + ruby_block = old_block; + ruby_calling_block = old_call_block; + data->d_vars = ruby_dyna_vars; + ruby_dyna_vars = old_d_vars; + data->vmode = scope_vmode; /* write back visibility mode */ + scope_vmode = old_vmode; } else { - the_frame->iter = iter; + ruby_frame->iter = iter; } + ruby_sourcefile = filesave; + ruby_sourceline = linesave; if (state) { - VALUE err; - if (state == TAG_RAISE) { - sourcefile = file; - sourceline = line; - if (strcmp(sourcefile, "(eval)") == 0) { - err = str_dup(errinfo); - if (sourceline > 1) { + VALUE err; + VALUE errat; + + errat = get_backtrace(rb_errinfo); + if (strcmp(file, "(eval)") == 0) { + if (ruby_sourceline > 1) { err = RARRAY(errat)->ptr[0]; - str_cat(err, ": ", 2); - str_cat(err, RSTRING(errinfo)->ptr, RSTRING(errinfo)->len); + rb_str_cat(err, ": ", 2); + rb_str_concat(err, rb_errinfo); + } + else { + err = rb_str_dup(rb_errinfo); } errat = Qnil; - rb_raise(exc_new3(CLASS_OF(errinfo), err)); + rb_exc_raise(rb_exc_new3(CLASS_OF(rb_errinfo), err)); } - rb_raise(Qnil); + rb_exc_raise(rb_errinfo); } JUMP_TAG(state); } @@ -3620,40 +4213,55 @@ eval(self, src, scope) } static VALUE -f_eval(argc, argv, self) +rb_f_eval(argc, argv, self) int argc; VALUE *argv; VALUE self; { - VALUE src, scope; + VALUE src, scope, vfile, vline; + char *file = "(eval)"; + int line = 0; - rb_scan_args(argc, argv, "11", &src, &scope); + rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline); + if (argc >= 3) { + Check_Type(vfile, T_STRING); + file = RSTRING(vfile)->ptr; + } + if (argc >= 4) { + line = NUM2INT(vline); + } Check_SafeStr(src); - return eval(self, src, scope); + return eval(self, src, scope, file, line); } static VALUE -eval_under(under, self, src) - VALUE under, self, src; +exec_under(func, under, args) + VALUE (*func)(); + VALUE under; + void *args; { VALUE val; /* OK */ int state; - VALUE cbase = the_frame->cbase; + int mode; + VALUE cbase = ruby_frame->cbase; PUSH_CLASS(); - the_class = under; + ruby_class = under; PUSH_FRAME(); - the_frame->last_func = _frame->last_func; - the_frame->last_class = _frame->last_class; - the_frame->argc = 1; - the_frame->argv = &src; - the_frame->cbase = (VALUE)node_newnode(NODE_CREF,under,0,cbase); + ruby_frame->last_func = _frame.prev->last_func; + ruby_frame->last_class = _frame.prev->last_class; + ruby_frame->argc = _frame.prev->argc; + ruby_frame->argv = _frame.prev->argv; + ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,cbase); + mode = scope_vmode; + SCOPE_SET(SCOPE_PUBLIC); PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - val = eval(self, src, Qnil); + val = (*func)(args); } POP_TAG(); + SCOPE_SET(mode); POP_FRAME(); POP_CLASS(); if (state) JUMP_TAG(state); @@ -3662,36 +4270,145 @@ eval_under(under, self, src) } static VALUE -obj_instance_eval(self, src) - VALUE self, src; +eval_under_i(args) + VALUE *args; { - return eval_under(CLASS_OF(self), self, src); + return eval(args[0], args[1], Qnil, (char*)args[2], (int)args[3]); +} + +static VALUE +eval_under(under, self, src, file, line) + VALUE under, self, src; + char *file; + int line; +{ + VALUE args[4]; + + Check_SafeStr(src); + args[0] = self; + args[1] = src; + args[2] = (VALUE)file; + args[3] = (VALUE)line; + return exec_under(eval_under_i, under, args); +} + +static VALUE +yield_under_i(self) + VALUE self; +{ + return rb_yield_0(self, self, ruby_class); +} + +static VALUE +yield_under(under, self) + VALUE under, self; +{ + rb_secure(4); + return exec_under(yield_under_i, under, self); +} + +VALUE +rb_obj_instance_eval(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + char *file = 0; + int line = 0; + VALUE klass; + + if (argc == 0) { + if (!rb_iterator_p()) { + rb_raise(rb_eArgError, "block not supplied"); + } + } + else if (argc < 4) { + Check_SafeStr(argv[0]); + if (argc > 1) file = STR2CSTR(argv[1]); + if (argc > 2) line = NUM2INT(argv[2]); + } + else { + rb_raise(rb_eArgError, "Wrong # of arguments: %s(src) or %s{..}", + rb_id2name(ruby_frame->last_func), + rb_id2name(ruby_frame->last_func)); + } + + if (rb_special_const_p(self)) { + klass = Qnil; + } + else { + klass = rb_singleton_class(self); + } + if (argc == 0) { + return yield_under(klass, self); + } + else { + return eval_under(klass, self, argv[0], file, line); + } } static VALUE -mod_module_eval(mod, src) - VALUE mod, src; +rb_mod_module_eval(argc, argv, mod) + int argc; + VALUE *argv; + VALUE mod; { - return eval_under(mod, mod, src); + char *file = 0; + int line = 0; + + if (argc == 0) { + if (!rb_iterator_p()) { + rb_raise(rb_eArgError, "block not supplied"); + } + } + else if (argc < 4) { + Check_SafeStr(argv[0]); + if (argc > 1) file = STR2CSTR(argv[1]); + if (argc > 2) line = NUM2INT(argv[2]); + } + else { + rb_raise(rb_eArgError, "Wrong # of arguments: %s(src) or %s{..}", + rb_id2name(ruby_frame->last_func), + rb_id2name(ruby_frame->last_func)); + } + + if (argc == 0) { + return yield_under(mod, mod); + } + else { + return eval_under(mod, mod, argv[0], file, line); + } } VALUE rb_load_path; -char *dln_find_file(); +static int +is_absolute_path(path) + char *path; +{ + if (path[0] == '/') return 1; +# if defined(MSDOS) || defined(NT) || defined(__human68k__) + if (path[0] == '\\') return 1; + if (strlen(path) > 2 && path[1] == ':') return 1; +# endif + return 0; +} static char* find_file(file) char *file; { extern VALUE rb_load_path; - VALUE vpath; + volatile VALUE vpath; char *path; - if (file[0] == '/') return file; -#if defined(MSDOS) || defined(NT) || defined(__human68k__) - if (file[0] == '\\') return file; - if (file[1] == ':') return file; -#endif + if (is_absolute_path(file)) { + FILE *f = fopen(file, "r"); + + if (f == NULL) return 0; + fclose(f); + return file; + } if (rb_load_path) { int i; @@ -3700,13 +4417,11 @@ find_file(file) for (i=0;ilen;i++) { Check_SafeStr(RARRAY(rb_load_path)->ptr[i]); } -#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__) - vpath = ary_join(rb_load_path, str_new2(":")); -#else - vpath = ary_join(rb_load_path, str_new2(";")); -#endif - Check_SafeStr(vpath); - path = RSTRING(vpath)->ptr; + vpath = rb_ary_join(rb_load_path, rb_str_new2(RUBY_PATH_SEP)); + path = STR2CSTR(vpath); + if (safe_level >= 2 && !rb_path_check(path)) { + rb_raise(rb_eSecurityError, "loading from unsefe path %s", path); + } } else { path = 0; @@ -3715,62 +4430,117 @@ find_file(file) return dln_find_file(file, path); } -VALUE -f_load(obj, fname) - VALUE obj, fname; +void +rb_load(fname, wrap) + VALUE fname; + int wrap; { int state; char *file; volatile ID last_func; + VALUE self = ruby_top_self; + TMP_PROTECT; - Check_SafeStr(fname); + if (wrap) { + Check_Type(fname, T_STRING); + } + else { + Check_SafeStr(fname); + } +#ifndef __MACOS__ if (RSTRING(fname)->ptr[0] == '~') { - fname = file_s_expand_path(0, fname); + fname = rb_file_s_expand_path(1, &fname); } +#endif file = find_file(RSTRING(fname)->ptr); - if (!file) LoadError("No such file to load -- %s", RSTRING(fname)->ptr); + if (!file) { + rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr); + } + PUSH_VARS(); PUSH_TAG(PROT_NONE); PUSH_CLASS(); - the_class = cObject; + if (!wrap) { + rb_secure(4); /* should alter global state */ + ruby_class = rb_cObject; + } + else { + /* load in anonymous module as toplevel */ + ruby_class = ruby_wrapper = rb_module_new(); + self = rb_obj_clone(ruby_top_self); + rb_extend_object(self, ruby_class); + } + PUSH_FRAME(); + ruby_frame->last_func = 0; + ruby_frame->self = ruby_top_self; + ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_class,0,0); PUSH_SCOPE(); - if (top_scope->local_tbl) { + if (ruby_class == rb_cObject && top_scope->local_tbl) { int len = top_scope->local_tbl[0]+1; ID *tbl = ALLOC_N(ID, len); - VALUE *vars = ALLOCA_N(VALUE, len); + VALUE *vars = TMP_ALLOC(len); *vars++ = 0; MEMCPY(tbl, top_scope->local_tbl, ID, len); MEMCPY(vars, top_scope->local_vars, ID, len-1); - the_scope->local_tbl = tbl; - the_scope->local_vars = vars; + ruby_scope->local_tbl = tbl; /* copy toplevel scope */ + ruby_scope->local_vars = vars; /* will not alter toplevel variables */ } /* default visibility is private at loading toplevel */ - FL_SET(the_scope, SCOPE_PRIVATE); + SCOPE_SET(SCOPE_PRIVATE); state = EXEC_TAG(); - last_func = the_frame->last_func; - the_frame->last_func = 0; + last_func = ruby_frame->last_func; if (state == 0) { rb_in_eval++; rb_load_file(file); rb_in_eval--; - if (nerrs == 0) { - eval_node(TopSelf); + if (ruby_nerrs == 0) { + eval_node(self); } } - the_frame->last_func = last_func; - if (the_scope->flag == SCOPE_ALLOCA && the_scope->local_tbl) { - free(the_scope->local_tbl); + ruby_frame->last_func = last_func; + if (ruby_scope->flag == SCOPE_ALLOCA && ruby_class == rb_cObject) { + if (ruby_scope->local_tbl) /* toplevel was empty */ + free(ruby_scope->local_tbl); } POP_SCOPE(); + POP_FRAME(); POP_CLASS(); POP_TAG(); - if (nerrs > 0) { - rb_raise(errinfo); + POP_VARS(); + ruby_wrapper = 0; + if (ruby_nerrs > 0) { + rb_exc_raise(rb_errinfo); } if (state) JUMP_TAG(state); +} + +void +rb_load_protect(fname, wrap, state) + VALUE fname; + int wrap; + int *state; +{ + int status; - return TRUE; + PUSH_TAG(PROT_NONE); + if ((status = EXEC_TAG()) == 0) { + rb_load(fname, wrap); + } + POP_TAG(); + if (state) *state = status; +} + +static VALUE +rb_f_load(argc, argv) + int argc; + VALUE *argv; +{ + VALUE fname, wrap; + + rb_scan_args(argc, argv, "11", &fname, &wrap); + rb_load(fname, RTEST(wrap)); + return Qtrue; } static VALUE rb_features; @@ -3779,30 +4549,28 @@ static int rb_provided(feature) char *feature; { - struct RArray *features = RARRAY(rb_features); VALUE *p, *pend; char *f; int len; - p = features->ptr; - pend = p + features->len; + p = RARRAY(rb_features)->ptr; + pend = p + RARRAY(rb_features)->len; while (p < pend) { - Check_Type(*p, T_STRING); - f = RSTRING(*p)->ptr; - if (strcmp(f, feature) == 0) return TRUE; + f = STR2CSTR(*p); + if (strcmp(f, feature) == 0) return Qtrue; len = strlen(feature); if (strncmp(f, feature, len) == 0 - && (strcmp(f+len, ".rb") == 0 ||strcmp(f+len, ".o") == 0)) { - return TRUE; + && (strcmp(f+len, ".rb") == 0 ||strcmp(f+len, ".so") == 0)) { + return Qtrue; } p++; } - return FALSE; + return Qfalse; } -#ifdef THREAD -static int thread_loading(); -static void thread_loading_done(); +#ifdef USE_THREAD +static int rb_thread_loading _((char*)); +static void rb_thread_loading_done _((void)); #endif void @@ -3813,27 +4581,28 @@ rb_provide(feature) if (!rb_provided(feature)) { ext = strrchr(feature, '.'); - if (strcmp(DLEXT, ext) == 0) { - buf = ALLOCA_N(char, strlen(feature)+1); + if (ext && strcmp(DLEXT, ext) == 0) { + buf = ALLOCA_N(char, strlen(feature)+4); strcpy(buf, feature); ext = strrchr(buf, '.'); - strcpy(ext, ".o"); + strcpy(ext, ".so"); feature = buf; } - ary_push(rb_features, str_new2(feature)); + rb_ary_push(rb_features, rb_str_new2(feature)); } } VALUE -f_require(obj, fname) +rb_f_require(obj, fname) VALUE obj, fname; { char *ext, *file, *feature, *buf; /* OK */ - VALUE load; + volatile VALUE load; + rb_secure(4); Check_SafeStr(fname); if (rb_provided(RSTRING(fname)->ptr)) - return FALSE; + return Qfalse; ext = strrchr(RSTRING(fname)->ptr, '.'); if (ext) { @@ -3842,15 +4611,16 @@ f_require(obj, fname) file = find_file(file); if (file) goto rb_load; } - else if (strcmp(".o", ext) == 0) { + else if (strcmp(".so", ext) == 0 || strcmp(".o", ext) == 0) { file = feature = RSTRING(fname)->ptr; - if (strcmp(".o", DLEXT) != 0) { + if (strcmp(ext, DLEXT) != 0) { buf = ALLOCA_N(char, strlen(file)+sizeof(DLEXT)+1); strcpy(buf, feature); ext = strrchr(buf, '.'); strcpy(ext, DLEXT); - file = find_file(buf); + file = feature = buf; } + file = find_file(file); if (file) goto dyna_load; } else if (strcmp(DLEXT, ext) == 0) { @@ -3860,60 +4630,63 @@ f_require(obj, fname) } } buf = ALLOCA_N(char, strlen(RSTRING(fname)->ptr) + 5); - sprintf(buf, "%s.rb", RSTRING(fname)->ptr); + strcpy(buf, RSTRING(fname)->ptr); + strcat(buf, ".rb"); file = find_file(buf); if (file) { - fname = str_new2(file); + fname = rb_str_new2(file); feature = buf; goto rb_load; } - sprintf(buf, "%s%s", RSTRING(fname)->ptr, DLEXT); + strcpy(buf, RSTRING(fname)->ptr); + strcat(buf, DLEXT); file = find_file(buf); if (file) { feature = buf; goto dyna_load; } - LoadError("No such file to load -- %s", RSTRING(fname)->ptr); + rb_raise(rb_eLoadError, "No such file to load -- %s", + RSTRING(fname)->ptr); dyna_load: -#ifdef THREAD - if (thread_loading(feature)) return FALSE; +#ifdef USE_THREAD + if (rb_thread_loading(feature)) return Qfalse; else { int state; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { #endif - load = str_new2(file); + load = rb_str_new2(file); file = RSTRING(load)->ptr; dln_load(file); rb_provide(feature); -#ifdef THREAD +#ifdef USE_THREAD } POP_TAG(); - thread_loading_done(); + rb_thread_loading_done(); if (state) JUMP_TAG(state); } #endif - return TRUE; + return Qtrue; rb_load: -#ifdef THREAD - if (thread_loading(feature)) return FALSE; +#ifdef USE_THREAD + if (rb_thread_loading(feature)) return Qfalse; else { int state; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { #endif - f_load(obj, fname); + rb_load(fname, 0); rb_provide(feature); -#ifdef THREAD +#ifdef USE_THREAD } POP_TAG(); - thread_loading_done(); + rb_thread_loading_done(); if (state) JUMP_TAG(state); } #endif - return TRUE; + return Qtrue; } static void @@ -3921,7 +4694,7 @@ set_method_visibility(self, argc, argv, ex) VALUE self; int argc; VALUE *argv; - int ex; + ID ex; { int i; @@ -3931,13 +4704,13 @@ set_method_visibility(self, argc, argv, ex) } static VALUE -mod_public(argc, argv, module) +rb_mod_public(argc, argv, module) int argc; VALUE *argv; VALUE module; { if (argc == 0) { - FL_UNSET(the_scope, SCOPE_PRIVATE); + SCOPE_SET(SCOPE_PUBLIC); } else { set_method_visibility(module, argc, argv, NOEX_PUBLIC); @@ -3946,13 +4719,28 @@ mod_public(argc, argv, module) } static VALUE -mod_private(argc, argv, module) +rb_mod_protected(argc, argv, module) int argc; VALUE *argv; VALUE module; { if (argc == 0) { - FL_SET(the_scope, SCOPE_PRIVATE); + SCOPE_SET(SCOPE_PROTECTED); + } + else { + set_method_visibility(module, argc, argv, NOEX_PROTECTED); + } + return module; +} + +static VALUE +rb_mod_private(argc, argv, module) + int argc; + VALUE *argv; + VALUE module; +{ + if (argc == 0) { + SCOPE_SET(SCOPE_PRIVATE); } else { set_method_visibility(module, argc, argv, NOEX_PRIVATE); @@ -3961,7 +4749,7 @@ mod_private(argc, argv, module) } static VALUE -mod_public_method(argc, argv, obj) +rb_mod_public_method(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -3971,7 +4759,7 @@ mod_public_method(argc, argv, obj) } static VALUE -mod_private_method(argc, argv, obj) +rb_mod_private_method(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -3985,7 +4773,7 @@ top_public(argc, argv) int argc; VALUE *argv; { - return mod_public(argc, argv, cObject); + return rb_mod_public(argc, argv, rb_cObject); } static VALUE @@ -3993,11 +4781,11 @@ top_private(argc, argv) int argc; VALUE *argv; { - return mod_private(argc, argv, cObject); + return rb_mod_private(argc, argv, rb_cObject); } static VALUE -mod_modfunc(argc, argv, module) +rb_mod_modfunc(argc, argv, module) int argc; VALUE *argv; VALUE module; @@ -4006,22 +4794,27 @@ mod_modfunc(argc, argv, module) ID id; NODE *body; - rb_clear_cache(); + if (argc == 0) { + SCOPE_SET(SCOPE_MODFUNC); + return module; + } + set_method_visibility(module, argc, argv, NOEX_PRIVATE); for (i=0; ind_body == 0) { - NameError("undefined method `%s' for module `%s'", - rb_id2name(id), rb_class2name(module)); + rb_raise(rb_eNameError, "undefined method `%s' for module `%s'", + rb_id2name(id), rb_class2name(module)); } + rb_clear_cache_by_id(id); rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC); } return module; } static VALUE -mod_append_features(module, include) +rb_mod_append_features(module, include) VALUE module, include; { switch (TYPE(include)) { @@ -4038,7 +4831,7 @@ mod_append_features(module, include) } static VALUE -mod_include(argc, argv, module) +rb_mod_include(argc, argv, module) int argc; VALUE *argv; VALUE module; @@ -4052,21 +4845,29 @@ mod_include(argc, argv, module) return module; } +void +rb_obj_call_init(obj) + VALUE obj; +{ + PUSH_ITER(rb_iterator_p()?ITER_PRE:ITER_NOT); + rb_funcall2(obj, init, ruby_frame->argc, ruby_frame->argv); + POP_ITER(); +} + VALUE -class_new_instance(argc, argv, class) +rb_class_new_instance(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { VALUE obj; - if (FL_TEST(class, FL_SINGLETON)) { - TypeError("can't create instance of virtual class"); + if (FL_TEST(klass, FL_SINGLETON)) { + rb_raise(rb_eTypeError, "can't create instance of virtual class"); } - obj = obj_alloc(class); - PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT); - rb_funcall2(obj, init, argc, argv); - POP_ITER(); + obj = rb_obj_alloc(klass); + rb_obj_call_init(obj); + return obj; } @@ -4076,7 +4877,7 @@ top_include(argc, argv) VALUE *argv; { rb_secure(4); - return mod_include(argc, argv, cObject); + return rb_mod_include(argc, argv, rb_cObject); } void @@ -4087,7 +4888,7 @@ rb_extend_object(obj, module) } static VALUE -mod_extend_object(mod, obj) +rb_mod_extend_object(mod, obj) VALUE mod, obj; { rb_extend_object(obj, mod); @@ -4095,7 +4896,7 @@ mod_extend_object(mod, obj) } static VALUE -obj_extend(argc, argv, obj) +rb_obj_extend(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -4109,10 +4910,27 @@ obj_extend(argc, argv, obj) return obj; } -VALUE f_trace_var(); -VALUE f_untrace_var(); +VALUE rb_f_trace_var(); +VALUE rb_f_untrace_var(); -extern void rb_str_setter(); +static void +errinfo_setter(val, id, var) + VALUE val; + ID id; + VALUE *var; +{ + if (!rb_obj_is_kind_of(val, rb_eException)) { + rb_raise(rb_eTypeError, "assigning non-exception to $!"); + } + *var = val; +} + +static VALUE +errat_getter(id) + ID id; +{ + return get_backtrace(rb_errinfo); +} static void errat_setter(val, id, var) @@ -4120,18 +4938,52 @@ errat_setter(val, id, var) ID id; VALUE *var; { - *var = check_errat(val); + if (NIL_P(rb_errinfo)) { + rb_raise(rb_eArgError, "$! not set"); + } + set_backtrace(rb_errinfo, val); } -VALUE f_global_variables(); -static VALUE f_catch(); -static VALUE f_throw(); +VALUE rb_f_global_variables(); +VALUE f_instance_variables(); + +static VALUE +rb_f_local_variables() +{ + ID *tbl; + int n, i; + VALUE ary = rb_ary_new(); + struct RVarmap *vars; + + tbl = ruby_scope->local_tbl; + if (tbl) { + n = *tbl++; + for (i=2; iid) { + rb_ary_push(ary, rb_str_new2(rb_id2name(vars->id))); + } + vars = vars->next; + } + + return ary; +} + +static VALUE rb_f_catch _((VALUE,VALUE)); +static VALUE rb_f_throw _((int,VALUE*)) NORETURN; struct end_proc_data { void (*func)(); VALUE data; struct end_proc_data *next; -} *end_proc_data; +}; +static struct end_proc_data *end_proc_data; void rb_set_end_proc(func, data) @@ -4155,19 +5007,20 @@ call_end_proc(data) } static void -f_END() +rb_f_END() { PUSH_FRAME(); - rb_set_end_proc(call_end_proc, f_lambda()); + ruby_frame->argc = 0; + rb_set_end_proc(call_end_proc, rb_f_lambda()); POP_FRAME(); } static VALUE -f_at_exit() +rb_f_at_exit() { VALUE proc; - proc = f_lambda(); + proc = rb_f_lambda(); rb_set_end_proc(call_end_proc, proc); return proc; @@ -4196,85 +5049,91 @@ Init_eval() match = rb_intern("=~"); rb_global_variable((VALUE*)&top_scope); - rb_global_variable((VALUE*)&eval_tree0); - rb_global_variable((VALUE*)&eval_tree); - rb_global_variable((VALUE*)&the_dyna_vars); + rb_global_variable((VALUE*)&ruby_eval_tree_begin); - rb_define_hooked_variable("$@", &errat, 0, errat_setter); - rb_define_hooked_variable("$!", &errinfo, 0, rb_str_setter); + rb_global_variable((VALUE*)&ruby_eval_tree); + rb_global_variable((VALUE*)&ruby_dyna_vars); - rb_define_global_function("eval", f_eval, -1); - rb_define_global_function("iterator?", f_iterator_p, 0); - rb_define_global_function("method_missing", f_missing, -1); - rb_define_global_function("loop", f_loop, 0); + rb_define_virtual_variable("$@", errat_getter, errat_setter); + rb_define_hooked_variable("$!", &rb_errinfo, 0, errinfo_setter); - rb_define_method(mKernel, "respond_to?", obj_respond_to, -1); + rb_define_global_function("eval", rb_f_eval, -1); + rb_define_global_function("iterator?", rb_f_iterator_p, 0); + rb_define_global_function("method_missing", rb_f_missing, -1); + rb_define_global_function("loop", rb_f_loop, 0); - rb_define_global_function("raise", f_raise, -1); - rb_define_alias(mKernel, "fail", "raise"); + rb_define_method(rb_mKernel, "respond_to?", rb_obj_respond_to, -1); - rb_define_global_function("caller", f_caller, -1); + rb_define_global_function("raise", rb_f_raise, -1); + rb_define_global_function("fail", rb_f_raise, -1); - rb_define_global_function("exit", f_exit, -1); - rb_define_global_function("abort", f_abort, 0); + rb_define_global_function("caller", rb_f_caller, -1); - rb_define_global_function("at_exit", f_at_exit, 0); + rb_define_global_function("exit", rb_f_exit, -1); + rb_define_global_function("abort", rb_f_abort, 0); - rb_define_global_function("catch", f_catch, 1); - rb_define_global_function("throw", f_throw, -1); - rb_define_global_function("global_variables", f_global_variables, 0); + rb_define_global_function("at_exit", rb_f_at_exit, 0); - rb_define_method(mKernel, "send", f_send, -1); - rb_define_method(mKernel, "instance_eval", obj_instance_eval, 1); + rb_define_global_function("catch", rb_f_catch, 1); + rb_define_global_function("throw", rb_f_throw, -1); + rb_define_global_function("global_variables", rb_f_global_variables, 0); + rb_define_global_function("local_variables", rb_f_local_variables, 0); - rb_define_private_method(cModule, "append_features", mod_append_features, 1); - rb_define_private_method(cModule, "extend_object", mod_extend_object, 1); - rb_define_private_method(cModule, "include", mod_include, -1); - rb_define_private_method(cModule, "public", mod_public, -1); - rb_define_private_method(cModule, "private", mod_private, -1); - rb_define_private_method(cModule, "module_function", mod_modfunc, -1); - rb_define_method(cModule, "method_defined?", mod_method_defined, 1); - rb_define_method(cModule, "public_class_method", mod_public_method, -1); - rb_define_method(cModule, "private_class_method", mod_private_method, -1); - rb_define_method(cModule, "module_eval", mod_module_eval, 1); + rb_define_method(rb_mKernel, "send", rb_f_send, -1); + rb_define_method(rb_mKernel, "__send__", rb_f_send, -1); + rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1); - rb_define_method(cModule, "remove_method", mod_remove_method, -1); - rb_define_method(cModule, "undef_method", mod_undef_method, 1); - rb_define_method(cModule, "alias_method", mod_alias_method, 2); + rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1); + rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1); + rb_define_private_method(rb_cModule, "include", rb_mod_include, -1); + rb_define_private_method(rb_cModule, "public", rb_mod_public, -1); + rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1); + rb_define_private_method(rb_cModule, "private", rb_mod_private, -1); + rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1); + rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1); + rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1); + rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1); + rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1); + rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1); - rb_define_singleton_method(cModule, "nesting", mod_nesting, 0); - rb_define_singleton_method(cModule, "constants", mod_s_constants, 0); + rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, 1); + rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, 1); + rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2); - rb_define_singleton_method(TopSelf, "include", top_include, -1); - rb_define_singleton_method(TopSelf, "public", top_public, -1); - rb_define_singleton_method(TopSelf, "private", top_private, -1); + rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0); + rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0); - rb_define_method(mKernel, "extend", obj_extend, -1); + rb_define_singleton_method(ruby_top_self, "include", top_include, -1); + rb_define_singleton_method(ruby_top_self, "public", top_public, -1); + rb_define_singleton_method(ruby_top_self, "private", top_private, -1); - rb_define_global_function("trace_var", f_trace_var, -1); - rb_define_global_function("untrace_var", f_untrace_var, -1); + rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1); + + rb_define_global_function("trace_var", rb_f_trace_var, -1); + rb_define_global_function("untrace_var", rb_f_untrace_var, -1); rb_define_global_function("set_trace_func", set_trace_func, 1); rb_define_virtual_variable("$SAFE", safe_getter, safe_setter); } -VALUE f_autoload(); +VALUE rb_f_autoload(); void Init_load() { - rb_load_path = ary_new(); + rb_load_path = rb_ary_new(); rb_define_readonly_variable("$:", &rb_load_path); rb_define_readonly_variable("$-I", &rb_load_path); rb_define_readonly_variable("$LOAD_PATH", &rb_load_path); - rb_features = ary_new(); + rb_features = rb_ary_new(); rb_define_readonly_variable("$\"", &rb_features); - rb_define_global_function("load", f_load, 1); - rb_define_global_function("require", f_require, 1); - rb_define_global_function("autoload", f_autoload, 2); + rb_define_global_function("load", rb_f_load, -1); + rb_define_global_function("require", rb_f_require, 1); + rb_define_global_function("autoload", rb_f_autoload, 2); + rb_global_variable(&ruby_wrapper); } static void @@ -4303,36 +5162,99 @@ static void blk_mark(data) struct BLOCK *data; { - gc_mark_frame(&data->frame); - gc_mark(data->scope); - gc_mark(data->var); - gc_mark(data->body); - gc_mark(data->self); - gc_mark(data->d_vars); + while (data) { + rb_gc_mark_frame(&data->frame); + rb_gc_mark(data->scope); + rb_gc_mark(data->var); + rb_gc_mark(data->body); + rb_gc_mark(data->self); + rb_gc_mark(data->d_vars); + rb_gc_mark(data->klass); + data = data->prev; + } } static void blk_free(data) struct BLOCK *data; { - free(data->frame.argv); + struct BLOCK *tmp; + + while (data) { + free(data->frame.argv); + tmp = data; + data = data->prev; + free(tmp); + } +} + +static void +blk_copy_prev(block) + struct BLOCK *block; +{ + struct BLOCK *tmp; + + while (block->prev) { + tmp = ALLOC_N(struct BLOCK, 1); + MEMCPY(tmp, block->prev, struct BLOCK, 1); + tmp->frame.argv = ALLOC_N(VALUE, tmp->frame.argc); + MEMCPY(tmp->frame.argv, block->frame.argv, VALUE, tmp->frame.argc); + block->prev = tmp; + block = tmp; + } } + static VALUE -f_binding(self) +bind_clone(self) + VALUE self; +{ + struct BLOCK *orig, *data; + VALUE bind; + + Data_Get_Struct(self, struct BLOCK, orig); + bind = Data_Make_Struct(self,struct BLOCK,blk_mark,blk_free,data); + MEMCPY(data, orig, struct BLOCK, 1); + data->frame.argv = ALLOC_N(VALUE, orig->frame.argc); + MEMCPY(data->frame.argv, orig->frame.argv, VALUE, orig->frame.argc); + + if (data->iter) { + blk_copy_prev(data); + } + else { + data->prev = 0; + } + + return bind; +} + +static VALUE +rb_f_binding(self) VALUE self; { struct BLOCK *data; VALUE bind; PUSH_BLOCK(0,0); - bind = Data_Make_Struct(cData, struct BLOCK, blk_mark, blk_free, data); - MEMCPY(data, the_block, struct BLOCK, 1); + bind = Data_Make_Struct(rb_cBinding,struct BLOCK,blk_mark,blk_free,data); + *data = *ruby_block; - data->iter = f_iterator_p(); - data->frame.last_func = 0; +#ifdef USE_THREAD + data->orig_thread = rb_thread_current(); +#endif + data->iter = rb_f_iterator_p(); + if (ruby_frame->prev) { + data->frame.last_func = ruby_frame->prev->last_func; + } data->frame.argv = ALLOC_N(VALUE, data->frame.argc); - MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc); + MEMCPY(data->frame.argv, ruby_block->frame.argv, VALUE, data->frame.argc); + + if (data->iter) { + blk_copy_prev(data); + } + else { + data->prev = 0; + } scope_dup(data->scope); POP_BLOCK(); @@ -4340,62 +5262,110 @@ f_binding(self) return bind; } -#define PROC_TAINT FL_USER0 #define PROC_T3 FL_USER1 #define PROC_T4 FL_USER2 #define PROC_T5 (FL_USER1|FL_USER2) #define PROC_TMASK (FL_USER1|FL_USER2) +static void +proc_save_safe_level(data) + VALUE data; +{ + if (FL_TEST(data, FL_TAINT)) { + switch (safe_level) { + case 3: + FL_SET(data, PROC_T3); + break; + case 4: + FL_SET(data, PROC_T4); + break; + case 5: + FL_SET(data, PROC_T5); + break; + } + } +} + +static void +proc_set_safe_level(data) + VALUE data; +{ + if (FL_TEST(data, FL_TAINT)) { + switch (RBASIC(data)->flags & PROC_TMASK) { + case PROC_T3: + safe_level = 3; + break; + case PROC_T4: + safe_level = 4; + break; + case PROC_T5: + safe_level = 5; + break; + } + } +} + static VALUE -proc_s_new(class) - VALUE class; +proc_s_new(klass) + VALUE klass; { volatile VALUE proc; struct BLOCK *data; - if (!iterator_p() && !f_iterator_p()) { - ArgError("tryed to create Procedure-Object out of iterator"); + if (!rb_iterator_p() && !rb_f_iterator_p()) { + rb_raise(rb_eArgError, "tried to create Procedure-Object out of iterator"); } - proc = Data_Make_Struct(class, struct BLOCK, blk_mark, blk_free, data); - *data = *the_block; + proc = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data); + *data = *ruby_block; -#ifdef THREAD - data->orig_thread = thread_current(); +#ifdef USE_THREAD + data->orig_thread = rb_thread_current(); #endif - data->iter = f_iterator_p(); + data->iter = data->prev?Qtrue:Qfalse; data->frame.argv = ALLOC_N(VALUE, data->frame.argc); - MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc); + MEMCPY(data->frame.argv, ruby_block->frame.argv, VALUE, data->frame.argc); + if (data->iter) { + blk_copy_prev(data); + } + else { + data->prev = 0; + } scope_dup(data->scope); - if (safe_level >= 3) { - FL_SET(proc, PROC_TAINT); - switch (safe_level) { - case 3: - FL_SET(proc, PROC_T3); - break; - case 4: - FL_SET(proc, PROC_T4); - break; - case 5: - FL_SET(proc, PROC_T5); - break; - } - } + proc_save_safe_level(proc); + rb_obj_call_init(proc); return proc; } VALUE -f_lambda() +rb_f_lambda() { - return proc_s_new(cProc); + return proc_s_new(rb_cProc); +} + +static int +blk_orphan(data) + struct BLOCK *data; +{ + if (data->scope && data->scope != top_scope && + (data->scope->flag & SCOPE_NOSTACK)) { + return 1; + } +#ifdef USE_THREAD + if (data->orig_thread != rb_thread_current()) { + return 1; + } +#endif + return 0; } static VALUE proc_call(proc, args) VALUE proc, args; /* OK */ { + struct BLOCK * volatile old_block; struct BLOCK *data; volatile VALUE result = Qnil; int state; @@ -4414,100 +5384,298 @@ proc_call(proc, args) } Data_Get_Struct(proc, struct BLOCK, data); + orphan = blk_orphan(data); + + /* PUSH BLOCK from data */ + old_block = ruby_block; + ruby_block = data; + PUSH_ITER(ITER_CUR); + ruby_frame->iter = ITER_CUR; - if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) { - orphan = 1; - } - else { -#ifdef THREAD - if (data->orig_thread != thread_current()) { - orphan = 1; - } - else -#endif - orphan = 0; - } if (orphan) {/* orphan procedure */ - if (iterator_p()) { - data->frame.iter = ITER_CUR; + if (rb_iterator_p()) { + ruby_block->frame.iter = ITER_CUR; } else { - data->frame.iter = ITER_NOT; + ruby_block->frame.iter = ITER_NOT; } } + PUSH_TAG(PROT_NONE); + state = EXEC_TAG(); + if (state == 0) { + proc_set_safe_level(proc); + result = rb_yield_0(args, 0, 0); + } + POP_TAG(); + + POP_ITER(); + if (ruby_block->tag->dst == state) { + state &= TAG_MASK; + } + ruby_block = old_block; + safe_level = safe; + + if (state) { + if (orphan) {/* orphan procedure */ + switch (state) { + case TAG_BREAK: + rb_raise(rb_eLocalJumpError, "break from proc-closure"); + break; + case TAG_RETRY: + rb_raise(rb_eLocalJumpError, "retry from proc-closure"); + break; + case TAG_RETURN: + rb_raise(rb_eLocalJumpError, "return from proc-closure"); + break; + } + } + JUMP_TAG(state); + } + return result; +} + +static VALUE +block_pass(self, node) + VALUE self; + NODE *node; +{ + VALUE block = rb_eval(self, node->nd_body); + struct BLOCK * volatile old_block; + struct BLOCK *data; + volatile VALUE result = Qnil; + int state; + volatile int orphan; + volatile int safe = safe_level; + + if (NIL_P(block)) { + return rb_eval(self, node->nd_iter); + } + if (rb_obj_is_kind_of(block, rb_cMethod)) { + block = method_proc(block); + } + else if (!rb_obj_is_proc(block)) { + rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", + rb_class2name(CLASS_OF(block))); + } + + Data_Get_Struct(block, struct BLOCK, data); + orphan = blk_orphan(data); + /* PUSH BLOCK from data */ - PUSH_BLOCK2(data); - PUSH_ITER(ITER_CUR); - the_frame->iter = ITER_CUR; - if (FL_TEST(proc, PROC_TAINT)) { - switch (RBASIC(proc)->flags & PROC_TMASK) { - case PROC_T3: - safe_level = 3; - break; - case PROC_T4: - safe_level = 4; - break; - case PROC_T5: - safe_level = 5; - break; + old_block = ruby_block; + ruby_block = data; + PUSH_ITER(ITER_PRE); + ruby_frame->iter = ITER_PRE; + + PUSH_TAG(PROT_NONE); + state = EXEC_TAG(); + if (state == 0) { + proc_set_safe_level(block); + result = rb_eval(self, node->nd_iter); + } + POP_TAG(); + POP_ITER(); + if (ruby_block->tag->dst == state) { + state &= TAG_MASK; + orphan = 2; + } + ruby_block = old_block; + safe_level = safe; + + if (state) { + if (orphan == 2) {/* escape from orphan procedure */ + switch (state) { + case TAG_BREAK: + rb_raise(rb_eLocalJumpError, "break from proc-closure"); + break; + case TAG_RETRY: + rb_raise(rb_eLocalJumpError, "retry from proc-closure"); + break; + case TAG_RETURN: + rb_raise(rb_eLocalJumpError, "return from proc-closure"); + break; + } } + JUMP_TAG(state); + } + return result; +} + +struct METHOD { + VALUE klass, oklass; + VALUE recv; + ID id, oid; + NODE *body; +}; + +static void +bm_mark(data) + struct METHOD *data; +{ + rb_gc_mark(data->oklass); + rb_gc_mark(data->klass); + rb_gc_mark(data->recv); + rb_gc_mark(data->body); +} + +static VALUE +rb_obj_method(obj, vid) + VALUE obj; + VALUE vid; +{ + VALUE method; + VALUE klass = CLASS_OF(obj); + ID id; + NODE *body; + int noex; + struct METHOD *data; + + id = rb_to_id(vid); + + again: + if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) { + return rb_undefined(obj, rb_to_id(vid), 0, 0, 0); + } + + if (nd_type(body) == NODE_ZSUPER) { + klass = RCLASS(klass)->super; + goto again; } + method = Data_Make_Struct(rb_cMethod, struct METHOD, bm_mark, free, data); + data->klass = klass; + data->recv = obj; + data->id = id; + data->body = body; + data->oklass = CLASS_OF(obj); + data->oid = rb_to_id(vid); + if (FL_TEST(obj, FL_TAINT)) { + FL_SET(method, FL_TAINT); + } + + return method; +} + +static VALUE +method_call(argc, argv, method) + int argc; + VALUE *argv; + VALUE method; +{ + VALUE result; + struct METHOD *data; + int state; + volatile int safe = safe_level; + + Data_Get_Struct(method, struct METHOD, data); + PUSH_ITER(rb_iterator_p()?ITER_PRE:ITER_NOT); PUSH_TAG(PROT_NONE); - state = EXEC_TAG(); - if (state == 0) { - result = rb_yield(args); + if (FL_TEST(data->recv, FL_TAINT) || FL_TEST(method, FL_TAINT)) { + FL_SET(method, FL_TAINT); + if (safe_level < 4) safe_level = 4; + } + if ((state = EXEC_TAG()) == 0) { + result = rb_call0(data->klass, data->recv, data->id, + argc, argv, data->body, 0); } POP_TAG(); - POP_ITER(); - if (the_block->tag->dst == state) { - state &= TAG_MASK; - } - POP_BLOCK(); safe_level = safe; + if (state) JUMP_TAG(state); + return result; +} - if (state) { - if (orphan) {/* orphan procedure */ - switch (state) { - case TAG_BREAK: - Raise(eLocalJumpError, "break from proc-closure"); - break; - case TAG_RETRY: - Raise(eLocalJumpError, "retry from proc-closure"); - break; - case TAG_RETURN: - Raise(eLocalJumpError, "return from proc-closure"); - break; - } - } - JUMP_TAG(state); +static VALUE +method_inspect(method) + VALUE method; +{ + struct METHOD *data; + VALUE str; + char *s; + + Data_Get_Struct(method, struct METHOD, data); + str = rb_str_new2("#<"); + s = rb_class2name(CLASS_OF(method)); + rb_str_cat(str, s, strlen(s)); + rb_str_cat(str, ": ", 2); + s = rb_class2name(data->oklass); + rb_str_cat(str, s, strlen(s)); + rb_str_cat(str, "#", 1); + s = rb_id2name(data->oid); + rb_str_cat(str, s, strlen(s)); + rb_str_cat(str, ">", 1); + + return str; +} + +static VALUE +mproc() +{ + VALUE proc; + + /* emulate ruby's method call */ + PUSH_ITER(ITER_CUR); + PUSH_FRAME(); + proc = rb_f_lambda(); + POP_FRAME(); + POP_ITER(); + + return proc; +} + +static VALUE +mcall(args, method) + VALUE args, method; +{ + if (TYPE(args) == T_ARRAY) { + return method_call(RARRAY(args)->len, RARRAY(args)->ptr, method); } - return result; + return method_call(1, &args, method); +} + +static VALUE +method_proc(method) + VALUE method; +{ + return rb_iterate(mproc, 0, mcall, method); } void Init_Proc() { - eLocalJumpError = rb_define_class("LocalJumpError", eException); + rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError); + rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError); + + rb_cProc = rb_define_class("Proc", rb_cObject); + rb_define_singleton_method(rb_cProc, "new", proc_s_new, 0); - cProc = rb_define_class("Proc", cObject); - rb_define_singleton_method(cProc, "new", proc_s_new, 0); + rb_define_method(rb_cProc, "call", proc_call, -2); + rb_define_method(rb_cProc, "[]", proc_call, -2); + 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); + rb_cBinding = rb_define_class("Binding", rb_cObject); + rb_undef_method(CLASS_OF(rb_cMethod), "new"); + rb_define_method(rb_cBinding, "clone", bind_clone, 0); - rb_define_method(cProc, "call", proc_call, -2); - rb_define_global_function("proc", f_lambda, 0); - rb_define_global_function("lambda", f_lambda, 0); - rb_define_global_function("binding", f_binding, 0); + rb_cMethod = rb_define_class("Method", rb_cObject); + rb_undef_method(CLASS_OF(rb_cMethod), "new"); + rb_define_method(rb_cMethod, "call", method_call, -1); + rb_define_method(rb_cMethod, "[]", method_call, -1); + rb_define_method(rb_cMethod, "inspect", method_inspect, 0); + rb_define_method(rb_cMethod, "to_s", method_inspect, 0); + rb_define_method(rb_cMethod, "to_proc", method_proc, 0); + rb_define_method(rb_mKernel, "method", rb_obj_method, 1); } -#ifdef THREAD +#ifdef USE_THREAD -static VALUE eThreadError; +static VALUE rb_eThreadError; -int thread_pending = 0; +int rb_thread_pending = 0; -static VALUE cThread; +VALUE rb_cThread; #include #ifdef HAVE_SYS_TIME_H @@ -4527,7 +5695,7 @@ struct timeval { #include #endif -extern VALUE last_status; +extern VALUE rb_last_status; enum thread_status { THREAD_RUNNABLE, @@ -4560,23 +5728,26 @@ struct thread { struct SCOPE *scope; struct RVarmap *dyna_vars; struct BLOCK *block; + struct BLOCK *cblock; struct iter *iter; struct tag *tag; - VALUE class; + VALUE klass; + VALUE wrapper; VALUE trace; + int misc; /* misc. states (vmode/rb_trap_immediate) */ char *file; int line; - VALUE errat, errinfo; + VALUE rb_errinfo; VALUE last_status; VALUE last_line; VALUE last_match; int safe; - enum thread_status status; + enum thread_status status; int wait_for; int fd; double delay; @@ -4584,6 +5755,8 @@ struct thread { int abort; + st_table *locals; + VALUE thread; }; @@ -4619,29 +5792,33 @@ thread_mark(th) struct FRAME *frame; struct BLOCK *block; - gc_mark(th->result); + rb_gc_mark(th->result); + rb_gc_mark(th->thread); + if (th->join) rb_gc_mark(th->join->thread); + + rb_gc_mark(th->klass); + rb_gc_mark(th->wrapper); + + rb_gc_mark(th->scope); + rb_gc_mark(th->dyna_vars); + rb_gc_mark(th->rb_errinfo); + rb_gc_mark(th->last_line); + rb_gc_mark(th->last_match); + + /* mark data in copied stack */ + if (th->status == THREAD_KILLED) return; + if (th->stk_len == 0) return; /* stack not active, no need to mark. */ if (th->stk_ptr) { - gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len); + rb_gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len); #if defined(THINK_C) || defined(__human68k__) - gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2); + rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2); #endif } - gc_mark(th->thread); - if (th->join) gc_mark(th->join->thread); - - gc_mark(th->scope); - gc_mark(th->dyna_vars); - gc_mark(th->errat); - gc_mark(th->errinfo); - gc_mark(th->last_line); - gc_mark(th->last_match); - - /* mark data in copied stack */ frame = th->frame; while (frame && frame != top_frame) { frame = ADJ(frame); if (frame->argv && !STACK(frame->argv)) { - gc_mark_frame(frame); + rb_gc_mark_frame(frame); } frame = frame->prev; } @@ -4649,19 +5826,21 @@ thread_mark(th) while (block) { block = ADJ(block); if (block->frame.argv && !STACK(block->frame.argv)) { - gc_mark_frame(&block->frame); + rb_gc_mark_frame(&block->frame); } block = block->prev; } + rb_mark_tbl(th->locals); } void -gc_mark_threads() +rb_gc_mark_threads() { thread_t th; + if (!curr_thread) return; FOREACH_THREAD(th) { - thread_mark(th); + rb_gc_mark(th->thread); } END_FOREACH(th); } @@ -4671,60 +5850,63 @@ thread_free(th) { if (th->stk_ptr) free(th->stk_ptr); th->stk_ptr = 0; + if (th->locals) st_free_table(th->locals); + if (th != main_thread) free(th); } static thread_t -thread_check(data) +rb_thread_check(data) VALUE data; { if (TYPE(data) != T_DATA || RDATA(data)->dfree != thread_free) { - TypeError("wrong argument type %s (expected Thread)", - rb_class2name(CLASS_OF(data))); + rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", + rb_class2name(CLASS_OF(data))); } return (thread_t)RDATA(data)->data; } -VALUE lastline_get(); -void lastline_set(); -VALUE backref_get(); -void backref_set(); - static void -thread_save_context(th) +rb_thread_save_context(th) thread_t th; { VALUE v; - th->stk_len = stack_length(); - th->stk_pos = (gc_stack_start<(VALUE*)&v)?gc_stack_start - :gc_stack_start - th->stk_len; - if (th->stk_len > th->stk_max) { - th->stk_max = th->stk_len; - REALLOC_N(th->stk_ptr, VALUE, th->stk_max); - } - FLUSH_REGISTER_WINDOWS; + int len = stack_length(); + th->stk_len = 0; + th->stk_pos = (rb_gc_stack_start<(VALUE*)&v)?rb_gc_stack_start + :rb_gc_stack_start - len; + if (len > th->stk_max) { + REALLOC_N(th->stk_ptr, VALUE, len); + th->stk_max = len; + } + th->stk_len = len; + FLUSH_REGISTER_WINDOWS; MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len); - th->frame = the_frame; - th->scope = the_scope; - th->class = the_class; - th->dyna_vars = the_dyna_vars; - th->block = the_block; - th->iter = the_iter; + th->frame = ruby_frame; + th->scope = ruby_scope; + th->klass = ruby_class; + th->wrapper = ruby_wrapper; + th->dyna_vars = ruby_dyna_vars; + th->block = ruby_block; + th->cblock = ruby_calling_block; + th->misc = scope_vmode | (rb_trap_immediate<<8); + th->iter = ruby_iter; th->tag = prot_tag; - th->errat = errat; - th->errinfo = errinfo; - th->last_status = last_status; - th->last_line = lastline_get(); - th->last_match = backref_get(); + th->rb_errinfo = rb_errinfo; + th->last_status = rb_last_status; + th->last_line = rb_lastline_get(); + th->last_match = rb_backref_get(); th->safe = safe_level; th->trace = trace_func; - th->file = sourcefile; - th->line = sourceline; + th->file = ruby_sourcefile; + th->line = ruby_sourceline; + + th->locals = 0; } -static void thread_restore_context(); +static void rb_thread_restore_context _((thread_t,int)); static void stack_extend(th, exit) @@ -4734,16 +5916,18 @@ stack_extend(th, exit) VALUE space[1024]; memset(space, 0, 1); /* prevent array from optimization */ - thread_restore_context(th, exit); + rb_thread_restore_context(th, exit); } static int th_raise_argc; static VALUE th_raise_argv[2]; static char *th_raise_file; static int th_raise_line; +static VALUE th_cmd; +static int th_sig; static void -thread_restore_context(th, exit) +rb_thread_restore_context(th, exit) thread_t th; int exit; { @@ -4751,9 +5935,9 @@ thread_restore_context(th, exit) static thread_t tmp; static int ex; - if (!th->stk_ptr) Bug("unsaved context"); + if (!th->stk_ptr) rb_bug("unsaved context"); - if (&v < gc_stack_start) { + if (&v < rb_gc_stack_start) { /* Stack grows downward */ if (&v > th->stk_pos) stack_extend(th, exit); } @@ -4762,30 +5946,32 @@ thread_restore_context(th, exit) if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit); } - the_frame = th->frame; - the_scope = th->scope; - the_class = th->class; - the_dyna_vars = th->dyna_vars; - the_block = th->block; - the_iter = th->iter; + ruby_frame = th->frame; + ruby_scope = th->scope; + ruby_class = th->klass; + ruby_wrapper = th->wrapper; + ruby_dyna_vars = th->dyna_vars; + ruby_block = th->block; + ruby_calling_block = th->cblock; + scope_vmode = th->misc&SCOPE_MASK; + rb_trap_immediate = th->misc>>8; + ruby_iter = th->iter; prot_tag = th->tag; - the_class = th->class; - errat = th->errat; - errinfo = th->errinfo; - last_status = th->last_status; + rb_errinfo = th->rb_errinfo; + rb_last_status = th->last_status; safe_level = th->safe; trace_func = th->trace; - sourcefile = th->file; - sourceline = th->line; + ruby_sourcefile = th->file; + ruby_sourceline = th->line; tmp = th; ex = exit; FLUSH_REGISTER_WINDOWS; MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len); - lastline_set(tmp->last_line); - backref_set(tmp->last_match); + rb_lastline_set(tmp->last_line); + rb_backref_set(tmp->last_match); switch (ex) { case 1: @@ -4797,10 +5983,15 @@ thread_restore_context(th, exit) break; case 3: - the_frame->last_func = 0; - sourcefile = th_raise_file; - sourceline = th_raise_line; - f_raise(th_raise_argc, th_raise_argv); + rb_trap_eval(th_cmd, th_sig); + errno = EINTR; + break; + + case 4: + ruby_frame->last_func = 0; + ruby_sourcefile = th_raise_file; + ruby_sourceline = th_raise_line; + rb_f_raise(th_raise_argc, th_raise_argv); break; default: @@ -4809,7 +6000,7 @@ thread_restore_context(th, exit) } static void -thread_ready(th) +rb_thread_ready(th) thread_t th; { /* The thread is no longer waiting on anything */ @@ -4827,42 +6018,41 @@ thread_ready(th) } static void -thread_remove() +rb_thread_remove() { - thread_ready(curr_thread); + rb_thread_ready(curr_thread); curr_thread->status = THREAD_KILLED; curr_thread->prev->next = curr_thread->next; curr_thread->next->prev = curr_thread->prev; - thread_schedule(); } static int -thread_dead(th) +rb_thread_dead(th) thread_t th; { return th->status == THREAD_KILLED; } static void -thread_deadlock() +rb_thread_deadlock() { curr_thread = main_thread; th_raise_argc = 1; - th_raise_argv[0] = exc_new2(eFatal, "Thread: deadlock"); - th_raise_file = sourcefile; - th_raise_line = sourceline; - f_abort(); + th_raise_argv[0] = rb_exc_new2(rb_eFatal, "Thread: deadlock"); + th_raise_file = ruby_sourcefile; + th_raise_line = ruby_sourceline; + rb_abort(); } void -thread_schedule() +rb_thread_schedule() { thread_t next; /* OK */ thread_t th; thread_t curr; select_err: - thread_pending = 0; + rb_thread_pending = 0; if (curr_thread == curr_thread->next) return; next = 0; @@ -4872,17 +6062,17 @@ thread_schedule() curr = curr->prev; } - FOREACH_THREAD_FROM(curr,th) { + FOREACH_THREAD_FROM(curr, th) { if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) { next = th; break; } } - END_FOREACH_FROM(curr,th); + END_FOREACH_FROM(curr, th); if (num_waiting_on_join) { - FOREACH_THREAD_FROM(curr,th) { - if ((th->wait_for & WAIT_JOIN) && thread_dead(th->join)) { + FOREACH_THREAD_FROM(curr, th) { + if ((th->wait_for&WAIT_JOIN) && rb_thread_dead(th->join)) { th->join = 0; th->wait_for &= ~WAIT_JOIN; th->status = THREAD_RUNNABLE; @@ -4890,7 +6080,7 @@ thread_schedule() if (!next) next = th; } } - END_FOREACH_FROM(curr,th); + END_FOREACH_FROM(curr, th); } if (num_waiting_on_fd > 0 || num_waiting_on_timer > 0) { @@ -4904,19 +6094,19 @@ thread_schedule() max = 0; FD_ZERO(&readfds); if (num_waiting_on_fd > 0) { - FOREACH_THREAD_FROM(curr,th) { + FOREACH_THREAD_FROM(curr, th) { if (th->wait_for & WAIT_FD) { FD_SET(th->fd, &readfds); if (th->fd > max) max = th->fd; } } - END_FOREACH_FROM(curr,th); + END_FOREACH_FROM(curr, th); } delay = DELAY_INFTY; if (num_waiting_on_timer > 0) { now = timeofday(); - FOREACH_THREAD_FROM(curr,th) { + FOREACH_THREAD_FROM(curr, th) { if (th->wait_for & WAIT_TIME) { if (th->delay <= now) { th->delay = 0.0; @@ -4929,7 +6119,7 @@ thread_schedule() } } } - END_FOREACH_FROM(curr,th); + END_FOREACH_FROM(curr, th); } /* Do the select if needed */ if (num_waiting_on_fd > 0 || !next) { @@ -4946,19 +6136,19 @@ thread_schedule() else { delay -= now; delay_tv.tv_sec = (unsigned int)delay; - delay_tv.tv_usec = (delay - (double)delay_tv.tv_sec) * 1e6; + delay_tv.tv_usec = (long)((delay-(double)delay_tv.tv_sec)*1e6); delay_ptr = &delay_tv; } n = select(max+1, &readfds, 0, 0, delay_ptr); if (n < 0) { - if (trap_pending) rb_trap_exec(); + if (rb_trap_pending) rb_trap_exec(); goto select_err; } if (n > 0) { /* Some descriptors are ready. Make the corresponding threads runnable. */ - FOREACH_THREAD_FROM(curr,th) { + FOREACH_THREAD_FROM(curr, th) { if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &readfds)) { /* Wake up only one thread per fd. */ @@ -4970,7 +6160,7 @@ thread_schedule() if (!next) next = th; /* Found one. */ } } - END_FOREACH_FROM(curr,th); + END_FOREACH_FROM(curr, th); } } /* The delays for some of the threads should have expired. @@ -4979,24 +6169,24 @@ thread_schedule() } if (!next) { - curr_thread->file = sourcefile; - curr_thread->line = sourceline; - FOREACH_THREAD_FROM(curr,th) { + curr_thread->file = ruby_sourcefile; + curr_thread->line = ruby_sourceline; + FOREACH_THREAD_FROM(curr, th) { fprintf(stderr, "%s:%d:deadlock 0x%x: %d:%d %s\n", th->file, th->line, th->thread, th->status, th->wait_for, th==main_thread?"(main)":""); } - END_FOREACH_FROM(curr,th); + END_FOREACH_FROM(curr, th); /* raise fatal error to main thread */ - thread_deadlock(); + rb_thread_deadlock(); } - if (next == curr_thread) { + if (next->status == THREAD_RUNNABLE && next == curr_thread) { return; } /* context switch */ if (curr == curr_thread) { - thread_save_context(curr); + rb_thread_save_context(curr); if (setjmp(curr->context)) { return; } @@ -5005,13 +6195,13 @@ thread_schedule() curr_thread = next; if (next->status == THREAD_TO_KILL) { /* execute ensure-clause if any */ - thread_restore_context(next, 1); + rb_thread_restore_context(next, 1); } - thread_restore_context(next, 0); + rb_thread_restore_context(next, 0); } void -thread_wait_fd(fd) +rb_thread_wait_fd(fd) int fd; { if (curr_thread == curr_thread->next) return; @@ -5020,11 +6210,11 @@ thread_wait_fd(fd) curr_thread->fd = fd; num_waiting_on_fd++; curr_thread->wait_for |= WAIT_FD; - thread_schedule(); + rb_thread_schedule(); } void -thread_fd_writable(fd) +rb_thread_fd_writable(fd) int fd; { struct timeval zero; @@ -5037,12 +6227,12 @@ thread_fd_writable(fd) FD_ZERO(&fds); FD_SET(fd, &fds); if (select(fd+1, 0, &fds, 0, &zero) == 1) break; - thread_schedule(); + rb_thread_schedule(); } } void -thread_wait_for(time) +rb_thread_wait_for(time) struct timeval time; { double date; @@ -5065,7 +6255,7 @@ thread_wait_for(time) time.tv_sec = (int)d; time.tv_usec = (int)((d - (int)d)*1e6); if (time.tv_usec < 0) { - time.tv_usec += 1e6; + time.tv_usec += (long)1e6; time.tv_sec -= 1; } if (time.tv_sec < 0) return; @@ -5078,19 +6268,19 @@ thread_wait_for(time) curr_thread->delay = date; num_waiting_on_timer++; curr_thread->wait_for |= WAIT_TIME; - thread_schedule(); + rb_thread_schedule(); } -void thread_sleep_forever(); +void rb_thread_sleep_forever _((void)); int -thread_alone() +rb_thread_alone() { return curr_thread == curr_thread->next; } int -thread_select(max, read, write, except, timeout) +rb_thread_select(max, read, write, except, timeout) int max; fd_set *read, *write, *except; struct timeval *timeout; @@ -5102,10 +6292,10 @@ thread_select(max, read, write, except, timeout) if (!read && !write && !except) { if (!timeout) { - thread_sleep_forever(); + rb_thread_sleep_forever(); return 0; } - thread_wait_for(*timeout); + rb_thread_wait_for(*timeout); return 0; } @@ -5131,7 +6321,7 @@ thread_select(max, read, write, except, timeout) double d = timeofday() - limit; tv.tv_sec = (unsigned int)d; - tv.tv_usec = (d - (double)tv.tv_sec) * 1e6; + tv.tv_usec = (long)((d-(double)tv.tv_sec)*1e6); } continue; } @@ -5172,124 +6362,126 @@ thread_select(max, read, write, except, timeout) if (limit <= timeofday()) return 0; } - thread_schedule(); + rb_thread_schedule(); CHECK_INTS; } } static VALUE -thread_join(dmy, thread) - VALUE dmy; +rb_thread_join(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - if (thread_dead(th)) return thread; + if (rb_thread_dead(th)) return thread; if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread) - Raise(eThreadError, "Thread.join: deadlock"); + rb_raise(rb_eThreadError, "Thread#join: deadlock"); curr_thread->status = THREAD_STOPPED; curr_thread->join = th; num_waiting_on_join++; curr_thread->wait_for |= WAIT_JOIN; - thread_schedule(); + rb_thread_schedule(); return thread; } static VALUE -thread_current() +rb_thread_s_join(dmy, thread) /* will be removed in 1.4 */ + VALUE dmy; + VALUE thread; +{ + rb_warn("Thread::join is obsolete; use Thread#join instead"); + return rb_thread_join(thread); +} + +VALUE +rb_thread_current() { return curr_thread->thread; } -static VALUE -thread_main() +VALUE +rb_thread_main() { return main_thread->thread; } static VALUE -thread_wakeup(thread) +rb_thread_wakeup(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - if (th->status == THREAD_KILLED) Raise(eThreadError, "killed thread"); - thread_ready(th); + if (th->status == THREAD_KILLED) + rb_raise(rb_eThreadError, "killed thread"); + rb_thread_ready(th); return thread; } static VALUE -thread_run(thread) +rb_thread_run(thread) VALUE thread; { - thread_wakeup(thread); - if (!thread_critical) thread_schedule(); + rb_thread_wakeup(thread); + if (!rb_thread_critical) rb_thread_schedule(); return thread; } static VALUE -thread_kill(thread) +rb_thread_kill(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED) return thread; if (th == th->next || th == main_thread) rb_exit(0); - thread_ready(th); + rb_thread_ready(th); th->status = THREAD_TO_KILL; - thread_schedule(); + rb_thread_schedule(); return Qnil; /* not reached */ } static VALUE -thread_s_kill(obj, th) +rb_thread_s_kill(obj, th) VALUE obj, th; { - return thread_kill(th); + return rb_thread_kill(th); } static VALUE -thread_exit() +rb_thread_exit() { - return thread_kill(curr_thread->thread); + return rb_thread_kill(curr_thread->thread); } static VALUE -thread_pass() +rb_thread_pass() { - thread_schedule(); + rb_thread_schedule(); return Qnil; } static VALUE -thread_stop_method(thread) - VALUE thread; +rb_thread_stop() { - thread_t th = thread_check(thread); - - thread_critical = 0; - th->status = THREAD_STOPPED; - thread_schedule(); - - return thread; -} + rb_thread_critical = 0; + curr_thread->status = THREAD_STOPPED; + if (curr_thread == curr_thread->next) { + rb_raise(rb_eThreadError, "stopping only thread"); + } + rb_thread_schedule(); -static VALUE -thread_stop() -{ - thread_stop_method(curr_thread->thread); return Qnil; } -struct timeval time_timeval(); +struct timeval rb_time_timeval(); void -thread_sleep(sec) +rb_thread_sleep(sec) int sec; { if (curr_thread == curr_thread->next) { @@ -5298,15 +6490,15 @@ thread_sleep(sec) TRAP_END; return; } - thread_wait_for(time_timeval(INT2FIX(sec))); + rb_thread_wait_for(rb_time_timeval(INT2FIX(sec))); } void -thread_sleep_forever() +rb_thread_sleep_forever() { if (curr_thread == curr_thread->next) { TRAP_BEG; - sleep((32767<<16)+32767); + sleep((32767L<<16)+32767); TRAP_END; return; } @@ -5315,46 +6507,47 @@ thread_sleep_forever() curr_thread->delay = DELAY_INFTY; curr_thread->wait_for |= WAIT_TIME; curr_thread->status = THREAD_STOPPED; - thread_schedule(); + rb_thread_schedule(); } -static int thread_abort; +static int rb_thread_abort; static VALUE -thread_s_abort_exc() +rb_thread_s_abort_exc() { - return thread_abort?TRUE:FALSE; + return rb_thread_abort?Qtrue:Qfalse; } static VALUE -thread_s_abort_exc_set(self, val) +rb_thread_s_abort_exc_set(self, val) VALUE self, val; { - thread_abort = RTEST(val); + rb_thread_abort = RTEST(val); return val; } static VALUE -thread_abort_exc(thread) +rb_thread_abort_exc(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - return th->abort?TRUE:FALSE; + return th->abort?Qtrue:Qfalse; } static VALUE -thread_abort_exc_set(thread, val) +rb_thread_abort_exc_set(thread, val) VALUE thread, val; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); th->abort = RTEST(val); return val; } static thread_t -thread_alloc() +rb_thread_alloc(klass) + VALUE klass; { thread_t th; @@ -5363,8 +6556,7 @@ thread_alloc() th->status = 0; th->result = 0; - th->errinfo = Qnil; - th->errat = Qnil; + th->rb_errinfo = Qnil; th->stk_ptr = 0; th->stk_len = 0; @@ -5376,19 +6568,19 @@ thread_alloc() th->frame = 0; th->scope = 0; - th->class = 0; + th->klass = 0; + th->wrapper = 0; th->dyna_vars = 0; th->block = 0; th->iter = 0; th->tag = 0; - th->errat = 0; - th->errinfo = 0; + th->rb_errinfo = 0; th->last_status = 0; th->last_line = 0; th->last_match = 0; th->abort = 0; - th->thread = data_object_alloc(cThread, th, 0, thread_free); + th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th); if (curr_thread) { th->prev = curr_thread; @@ -5412,153 +6604,201 @@ catch_timer(sig) #if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL) signal(sig, catch_timer); #endif - if (!thread_critical) { - if (trap_immediate) { - trap_immediate = 0; - thread_schedule(); + if (!rb_thread_critical) { + if (rb_trap_immediate) { + rb_thread_schedule(); } - else thread_pending = 1; + else rb_thread_pending = 1; } } #else -int thread_tick = THREAD_TICK; +int rb_thread_tick = THREAD_TICK; #endif -VALUE -thread_create(fn, arg) +static VALUE rb_thread_raise _((int, VALUE*, VALUE)); + +#define SCOPE_SHARED FL_USER1 + +#if defined(HAVE_SETITIMER) && !defined(__BOW__) +static int thread_init = 0; + +void +rb_thread_start_timer() +{ + struct itimerval tval; + + if (!thread_init) return; + tval.it_interval.tv_sec = 0; + tval.it_interval.tv_usec = 50000; + tval.it_value = tval.it_interval; + setitimer(ITIMER_VIRTUAL, &tval, NULL); +} + +void +rb_thread_stop_timer() +{ + struct itimerval tval; + + if (!thread_init) return; + tval.it_interval.tv_sec = 0; + tval.it_interval.tv_usec = 0; + tval.it_value = tval.it_interval; + setitimer(ITIMER_VIRTUAL, &tval, NULL); +} +#endif + +static VALUE +rb_thread_create_0(fn, arg, klass) VALUE (*fn)(); void *arg; + VALUE klass; { - thread_t th = thread_alloc(); + thread_t th = rb_thread_alloc(klass); + enum thread_status status; int state; #if defined(HAVE_SETITIMER) && !defined(__BOW__) - static init = 0; - - if (!init) { - struct itimerval tval; - + if (!thread_init) { #ifdef POSIX_SIGNAL posix_signal(SIGVTALRM, catch_timer); #else signal(SIGVTALRM, catch_timer); #endif - tval.it_interval.tv_sec = 0; - tval.it_interval.tv_usec = 100000; - tval.it_value = tval.it_interval; - setitimer(ITIMER_VIRTUAL, &tval, NULL); - - init = 1; + thread_init = 1; + rb_thread_start_timer(); } #endif - thread_save_context(curr_thread); + FL_SET(ruby_scope, SCOPE_SHARED); + rb_thread_save_context(curr_thread); if (setjmp(curr_thread->context)) { return th->thread; } PUSH_TAG(PROT_THREAD); if ((state = EXEC_TAG()) == 0) { - thread_save_context(th); + rb_thread_save_context(th); if (setjmp(th->context) == 0) { curr_thread = th; th->result = (*fn)(arg, th); } } POP_TAG(); - if (state && th->status != THREAD_TO_KILL && !NIL_P(errinfo)) { - if (state == TAG_FATAL || obj_is_kind_of(errinfo, eSystemExit)) { - /* fatal error or global exit within this thread */ - /* need to stop whole script */ - main_thread->errat = errat; - main_thread->errinfo = errinfo; - thread_cleanup(); - } - else if (thread_abort || curr_thread->abort || RTEST(debug)) { - f_abort(); + status = th->status; + rb_thread_remove(); + if (state && status != THREAD_TO_KILL && !NIL_P(rb_errinfo)) { + if (state == TAG_FATAL) { + /* fatal error within this thread, need to stop whole script */ + main_thread->rb_errinfo = rb_errinfo; + rb_thread_cleanup(); + } + else if (rb_obj_is_kind_of(rb_errinfo, rb_eSystemExit)) { + /* delegate exception to main_thread */ + rb_thread_raise(1, &rb_errinfo, main_thread->thread); + } + else if (rb_thread_abort || curr_thread->abort || RTEST(rb_debug)) { + VALUE err = rb_exc_new(rb_eSystemExit, 0, 0); + error_print(); + /* exit on main_thread */ + rb_thread_raise(1, &err, main_thread->thread); } else { - curr_thread->errat = errat; - curr_thread->errinfo = errinfo; + curr_thread->rb_errinfo = rb_errinfo; } } - thread_remove(); - return 0; + rb_thread_schedule(); + return 0; /* not reached */ +} + +VALUE +rb_thread_create(fn, arg) + VALUE (*fn)(); + void *arg; +{ + return rb_thread_create_0(fn, arg, rb_cThread); +} + +int +rb_thread_scope_shared_p() +{ + return FL_TEST(ruby_scope, SCOPE_SHARED); } static VALUE -thread_yield(arg, th) +rb_thread_yield(arg, th) int arg; thread_t th; { - scope_dup(the_block->scope); - rb_yield(th->thread); - return th->thread; + scope_dup(ruby_block->scope); + return rb_yield_0(th->thread, 0, 0); } static VALUE -thread_start() +rb_thread_start(klass) + VALUE klass; { - if (!iterator_p()) { - Raise(eThreadError, "must be called as iterator"); + if (!rb_iterator_p()) { + rb_raise(rb_eThreadError, "must be called as iterator"); } - return thread_create(thread_yield, 0); + return rb_thread_create_0(rb_thread_yield, 0, klass); } static VALUE -thread_value(thread) +rb_thread_value(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - thread_join(0, thread); - if (!NIL_P(th->errinfo)) { - errat = make_backtrace(); - ary_unshift(errat, ary_entry(th->errat, 0)); - sourcefile = 0; /* kludge to print errat */ - rb_raise(th->errinfo); + rb_thread_join(thread); + if (!NIL_P(th->rb_errinfo)) { + VALUE oldbt = get_backtrace(th->rb_errinfo); + VALUE errat = make_backtrace(); + + rb_ary_unshift(errat, rb_ary_entry(oldbt, 0)); + set_backtrace(th->rb_errinfo, errat); + rb_exc_raise(th->rb_errinfo); } return th->result; } static VALUE -thread_status(thread) +rb_thread_status(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - if (thread_dead(th)) { - if (NIL_P(th->errinfo)) return FALSE; + if (rb_thread_dead(th)) { + if (NIL_P(th->rb_errinfo)) return Qfalse; return Qnil; } - return TRUE; + return Qtrue; } static VALUE -thread_stopped(thread) +rb_thread_stop_p(thread) VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - if (thread_dead(th)) return TRUE; - if (th->status == THREAD_STOPPED) return TRUE; - return FALSE; + if (rb_thread_dead(th)) return Qtrue; + if (th->status == THREAD_STOPPED) return Qtrue; + return Qfalse; } static void -thread_wait_other_threads() +rb_thread_wait_other_threads() { /* wait other threads to terminate */ while (curr_thread != curr_thread->next) { - thread_schedule(); + rb_thread_schedule(); } } static void -thread_cleanup() +rb_thread_cleanup() { thread_t th; @@ -5575,64 +6815,87 @@ thread_cleanup() END_FOREACH(th); } -int thread_critical; +int rb_thread_critical; static VALUE -thread_get_critical() +rb_thread_get_critical() { - return thread_critical?TRUE:FALSE; + return rb_thread_critical?Qtrue:Qfalse; } static VALUE -thread_set_critical(obj, val) +rb_thread_set_critical(obj, val) VALUE obj, val; { - thread_critical = RTEST(val); + rb_thread_critical = RTEST(val); return val; } void -thread_interrupt() +rb_thread_interrupt() { - thread_critical = 0; - thread_ready(main_thread); + rb_thread_critical = 0; + rb_thread_ready(main_thread); if (curr_thread == main_thread) { rb_interrupt(); } - thread_save_context(curr_thread); + rb_thread_save_context(curr_thread); + if (setjmp(curr_thread->context)) { + return; + } + curr_thread = main_thread; + rb_thread_restore_context(curr_thread, 2); +} + +void +rb_thread_trap_eval(cmd, sig) + VALUE cmd; + int sig; +{ + rb_thread_critical = 0; + if (!rb_thread_dead(curr_thread)) { + rb_thread_ready(curr_thread); + rb_trap_eval(cmd, sig); + return; + } + rb_thread_ready(main_thread); + rb_thread_save_context(curr_thread); if (setjmp(curr_thread->context)) { return; } + th_cmd = cmd; + th_sig = sig; curr_thread = main_thread; - thread_restore_context(curr_thread, 2); + rb_thread_restore_context(curr_thread, 3); } static VALUE -thread_raise(argc, argv, thread) +rb_thread_raise(argc, argv, thread) int argc; VALUE *argv; VALUE thread; { - thread_t th = thread_check(thread); + thread_t th = rb_thread_check(thread); - if (thread_dead(th)) return thread; + if (rb_thread_dead(th)) return thread; if (curr_thread == th) { - f_raise(argc, argv); + rb_f_raise(argc, argv); } - thread_save_context(curr_thread); + if (curr_thread->status != THREAD_KILLED) + rb_thread_save_context(curr_thread); if (setjmp(curr_thread->context)) { return thread; } rb_scan_args(argc, argv, "11", &th_raise_argv[0], &th_raise_argv[1]); - thread_ready(th); + rb_thread_ready(th); curr_thread = th; th_raise_argc = argc; - th_raise_file = sourcefile; - th_raise_line = sourceline; - thread_restore_context(curr_thread, 3); + th_raise_file = ruby_sourcefile; + th_raise_line = ruby_sourceline; + rb_thread_restore_context(curr_thread, 4); return Qnil; /* not reached */ } @@ -5640,75 +6903,223 @@ static thread_t loading_thread; static int loading_nest; static int -thread_loading(feature) +rb_thread_loading(feature) char *feature; { if (curr_thread != curr_thread->next && loading_thread) { while (loading_thread != curr_thread) { - thread_schedule(); + rb_thread_schedule(); CHECK_INTS; } - if (rb_provided(feature)) return TRUE; /* no need to load */ + if (rb_provided(feature)) return Qtrue; /* no need to load */ } loading_thread = curr_thread; loading_nest++; - return FALSE; + return Qfalse; } static void -thread_loading_done() +rb_thread_loading_done() { if (--loading_nest == 0) { loading_thread = 0; } } +VALUE +rb_thread_local_aref(thread, id) + VALUE thread; + ID id; +{ + thread_t th; + VALUE val; + + th = rb_thread_check(thread); + if (!th->locals) return Qnil; + if (st_lookup(th->locals, id, &val)) { + return val; + } + return Qnil; +} + +static VALUE +rb_thread_aref(thread, id) + VALUE thread, id; +{ + return rb_thread_local_aref(thread, rb_to_id(id)); +} + +VALUE +rb_thread_local_aset(thread, id, val) + VALUE thread; + ID id; + VALUE val; +{ + thread_t th; + + + if (safe_level >= 4 && !FL_TEST(thread, FL_TAINT)) + rb_raise(rb_eSecurityError, "Insecure: can't modify thread values"); + + th = rb_thread_check(thread); + if (!th->locals) { + th->locals = st_init_numtable(); + } + if (NIL_P(val)) { + st_delete(th->locals, &id, 0); + return Qnil; + } + st_insert(th->locals, id, val); + + return val; +} + +static VALUE +rb_thread_aset(thread, id, val) + VALUE thread, id, val; +{ + return rb_thread_local_aset(thread, rb_to_id(id), val); +} + +static VALUE +rb_thread_key_p(thread, id) + VALUE thread, id; +{ + thread_t th = rb_thread_check(thread); + + if (!th->locals) return Qfalse; + if (st_lookup(th->locals, rb_to_id(id), 0)) + return Qtrue; + return Qfalse; +} + +static VALUE rb_cContinuation; + +static VALUE +rb_callcc(self) + VALUE self; +{ + volatile VALUE cont; + thread_t th = ALLOC(struct thread); + + th->status = THREAD_RUNNABLE; + + th->status = 0; + th->result = 0; + th->rb_errinfo = Qnil; + + th->stk_ptr = 0; + th->stk_len = 0; + th->stk_max = 0; + th->wait_for = 0; + th->fd = 0; + th->delay = 0.0; + th->join = 0; + + th->frame = 0; + th->scope = 0; + th->klass = 0; + th->dyna_vars = 0; + th->block = 0; + th->iter = 0; + th->tag = 0; + th->rb_errinfo = 0; + th->last_status = 0; + th->last_line = 0; + th->last_match = 0; + th->abort = 0; + + th->thread = cont = Data_Wrap_Struct(rb_cContinuation, thread_mark, + thread_free, th); + + FL_SET(ruby_scope, SCOPE_DONT_RECYCLE); + rb_thread_save_context(th); + if (setjmp(th->context)) { + return th->result; + } + else { + return rb_yield(th->thread); + } +} + +static VALUE +rb_continuation_call(argc, argv, cont) + int argc; + VALUE *argv; + VALUE cont; +{ + thread_t th = rb_thread_check(cont); + + switch (argc) { + case 0: + th->result = Qnil; + break; + case 1: + th->result = *argv; + break; + default: + th->result = rb_ary_new4(argc, argv); + break; + } + rb_thread_restore_context(th, 0); + return Qnil; +} + void Init_Thread() { - eThreadError = rb_define_class("ThreadError", eException); - cThread = rb_define_class("Thread", cObject); + rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError); + rb_cThread = rb_define_class("Thread", rb_cObject); - rb_define_singleton_method(cThread, "new", thread_start, 0); - rb_define_singleton_method(cThread, "start", thread_start, 0); - rb_define_singleton_method(cThread, "fork", thread_start, 0); + rb_define_singleton_method(rb_cThread, "new", rb_thread_start, 0); + rb_define_singleton_method(rb_cThread, "start", rb_thread_start, 0); + rb_define_singleton_method(rb_cThread, "fork", rb_thread_start, 0); - rb_define_singleton_method(cThread, "stop", thread_stop, 0); - rb_define_singleton_method(cThread, "kill", thread_s_kill, 1); - rb_define_singleton_method(cThread, "exit", thread_exit, 0); - rb_define_singleton_method(cThread, "pass", thread_pass, 0); - rb_define_singleton_method(cThread, "join", thread_join, 1); - rb_define_singleton_method(cThread, "current", thread_current, 0); - rb_define_singleton_method(cThread, "main", thread_main, 0); + rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0); + rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1); + rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0); + rb_define_singleton_method(rb_cThread, "pass", rb_thread_pass, 0); + rb_define_singleton_method(rb_cThread, "join", rb_thread_s_join, 1); + rb_define_singleton_method(rb_cThread, "current", rb_thread_current, 0); + rb_define_singleton_method(rb_cThread, "main", rb_thread_main, 0); - rb_define_singleton_method(cThread, "critical", thread_get_critical, 0); - rb_define_singleton_method(cThread, "critical=", thread_set_critical, 1); + rb_define_singleton_method(rb_cThread, "critical", rb_thread_get_critical, 0); + rb_define_singleton_method(rb_cThread, "critical=", rb_thread_set_critical, 1); - rb_define_singleton_method(cThread, "abort_on_exception", thread_s_abort_exc, 0); - rb_define_singleton_method(cThread, "abort_on_exception=", thread_s_abort_exc_set, 1); + rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0); + rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1); - rb_define_method(cThread, "run", thread_run, 0); - rb_define_method(cThread, "wakeup", thread_wakeup, 0); - rb_define_method(cThread, "stop", thread_stop_method, 0); - rb_define_method(cThread, "exit", thread_kill, 0); - rb_define_method(cThread, "value", thread_value, 0); - rb_define_method(cThread, "status", thread_status, 0); - rb_define_method(cThread, "alive?", thread_status, 0); - rb_define_method(cThread, "stop?", thread_stopped, 0); - rb_define_method(cThread, "raise", thread_raise, -1); + rb_define_method(rb_cThread, "run", rb_thread_run, 0); + rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0); + rb_define_method(rb_cThread, "exit", rb_thread_kill, 0); + rb_define_method(rb_cThread, "value", rb_thread_value, 0); + rb_define_method(rb_cThread, "status", rb_thread_status, 0); + rb_define_method(rb_cThread, "join", rb_thread_join, 0); + rb_define_method(rb_cThread, "alive?", rb_thread_status, 0); + rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0); + rb_define_method(rb_cThread, "raise", rb_thread_raise, -1); - rb_define_method(cThread, "abort_on_exception", thread_abort_exc, 0); - rb_define_method(cThread, "abort_on_exception=", thread_abort_exc_set, 1); + rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0); + rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1); + + rb_define_method(rb_cThread, "[]", rb_thread_aref, 1); + rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2); + rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1); /* allocate main thread */ - main_thread = thread_alloc(); + main_thread = rb_thread_alloc(rb_cThread); + + rb_cContinuation = rb_define_class("Continuation", rb_cObject); + rb_undef_method(CLASS_OF(rb_cContinuation), "new"); + rb_define_method(rb_cContinuation, "call", rb_continuation_call, -1); + rb_define_method(rb_mKernel, "callcc", rb_callcc, 0); } #endif static VALUE -f_catch(dmy, tag) +rb_f_catch(dmy, tag) VALUE dmy, tag; { int state; @@ -5718,10 +7129,10 @@ f_catch(dmy, tag) t = rb_to_id(tag); PUSH_TAG(t); if ((state = EXEC_TAG()) == 0) { - val = rb_yield(tag); + val = rb_yield_0(tag, 0, 0); } - else if (state == TAG_THROW && prot_tag->tag == prot_tag->dst) { - val = prot_tag->tag_retval; + else if (state == TAG_THROW && t == prot_tag->dst) { + val = prot_tag->retval; state = 0; } POP_TAG(); @@ -5731,7 +7142,23 @@ f_catch(dmy, tag) } static VALUE -f_throw(argc, argv) +catch_i(tag) + ID tag; +{ + return rb_f_catch(0, FIX2INT(tag)); +} + +VALUE +rb_catch(tag, proc, data) + char *tag; + VALUE (*proc)(); + VALUE data; +{ + return rb_iterate(catch_i, rb_intern(tag), proc, data); +} + +static VALUE +rb_f_throw(argc, argv) int argc; VALUE *argv; { @@ -5745,44 +7172,55 @@ f_throw(argc, argv) while (tt) { if (tt->tag == t) { tt->dst = t; - tt->tag_retval = value; break; } -#ifdef THREAD +#ifdef USE_THREAD if (tt->tag == PROT_THREAD) { - Raise(eThreadError, "uncaught throw `%s' in thread 0x%x\n", - rb_id2name(t), - curr_thread); + rb_raise(rb_eThreadError, "uncaught throw `%s' in thread 0x%x", + rb_id2name(t), + curr_thread); } #endif tt = tt->prev; } - if (!tt) { - NameError("uncaught throw `%s'\n", rb_id2name(t)); + rb_raise(rb_eNameError, "uncaught throw `%s'", rb_id2name(t)); } + return_value(value); + rb_trap_restore_mask(); JUMP_TAG(TAG_THROW); /* not reached */ } -static void -return_value(val) +void +rb_throw(tag, val) + char *tag; VALUE val; { + VALUE argv[2]; + ID t = rb_intern(tag); + + argv[0] = FIX2INT(t); + argv[1] = val; + rb_f_throw(2, argv); +} + +static void +return_check() +{ +#ifdef USE_THREAD struct tag *tt = prot_tag; - + while (tt) { if (tt->tag == PROT_FUNC) { - tt->tag_retval = val; break; } -#ifdef THREAD if (tt->tag == PROT_THREAD) { - Raise(eThreadError, "return from within thread 0x%x\n", - curr_thread); + rb_raise(rb_eThreadError, "return from within thread 0x%x", + curr_thread); } -#endif tt = tt->prev; } +#endif } diff --git a/ext/Setup b/ext/Setup index c92ac53e00..9e3a2474c3 100644 --- a/ext/Setup +++ b/ext/Setup @@ -10,3 +10,4 @@ #socket #tkutil #tcltklib +#gtk diff --git a/ext/aix_ld.rb b/ext/aix_ld.rb index 1058977b88..42b2087a46 100644 --- a/ext/aix_ld.rb +++ b/ext/aix_ld.rb @@ -43,7 +43,7 @@ def extract(nm, out) else next end - }.sort! + }.compact!.sort! uniq(data) exp = open(out, "w") for line in data diff --git a/ext/curses/curses.c b/ext/curses/curses.c index 3ae8db192d..f3d1bc0970 100644 --- a/ext/curses/curses.c +++ b/ext/curses/curses.c @@ -2,7 +2,7 @@ * ext/curses/curses.c * * by MAEDA Shugo (ender@pic-internet.or.jp) - * modified by Yukihiro Matsumoto (matz@ruby.club.or.jp) + * modified by Yukihiro Matsumoto (matz@netlab.co.jp) */ #ifdef HAVE_NCURSES_H @@ -12,12 +12,18 @@ # include # else # include -# if defined(__NetBSD__) && !defined(_maxx) +# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxx) # define _maxx maxx # endif -# if defined(__NetBSD__) && !defined(_maxy) +# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxy) # define _maxy maxy # endif +# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begx) +# define _begx begx +# endif +# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begy) +# define _begy begy +# endif # endif #endif @@ -32,14 +38,10 @@ struct windata { WINDOW *window; }; -#define NUM2CHAR(x) ((TYPE(x) == T_STRING)&&(RSTRING(x)->len>=1))?\ - RSTRING(x)->ptr[0]:(char)NUM2INT(x) -#define CHAR2FIX(x) INT2FIX((int)x) - static void no_window() { - Fail("already closed window"); + rb_raise(rb_eRuntimeError, "already closed window"); } #define GetWINDOW(obj, winp) {\ @@ -55,6 +57,7 @@ free_window(winp) { if (winp->window && winp->window != stdscr) delwin(winp->window); winp->window = 0; + free(winp); } static VALUE @@ -66,7 +69,7 @@ prep_window(class, window) struct windata *winp; if (window == NULL) { - Fail("failed to create window"); + rb_raise(rb_eRuntimeError, "failed to create window"); } obj = Data_Make_Struct(class, struct windata, 0, free_window, winp); @@ -83,7 +86,7 @@ curses_init_screen() { initscr(); if (stdscr == 0) { - Fail("cannot initialize curses"); + rb_raise(rb_eRuntimeError, "cannot initialize curses"); } clear(); rb_stdscr = prep_window(cWindow, stdscr); @@ -102,19 +105,33 @@ curses_stdscr() static VALUE curses_close_screen() { - endwin(); +#ifdef HAVE_ISENDWIN + if (!isendwin()) +#endif + endwin(); return Qnil; } +static void +curses_finalize() +{ + if (stdscr +#ifdef HAVE_ISENDWIN + && !isendwin() +#endif + ) + endwin(); +} + /* def closed? */ static VALUE curses_closed() { -#ifdef HAVE_ENDWIN +#ifdef HAVE_ISENDWIN if (isendwin()) { - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; #else rb_notimplement(); #endif @@ -138,12 +155,16 @@ curses_refresh(obj) return Qnil; } -/* def refresh */ +/* def doupdate */ static VALUE curses_doupdate(obj) VALUE obj; { +#ifdef HAVE_DOUPDATE doupdate(); +#else + refresh(); +#endif return Qnil; } @@ -235,7 +256,9 @@ static VALUE curses_flash(obj) VALUE obj; { +#ifdef HAVE_FLASH flash(); +#endif return Qnil; } @@ -287,7 +310,7 @@ static VALUE curses_inch(obj) VALUE obj; { - return CHAR2FIX(inch()); + return CHR2FIX(inch()); } /* def addch(ch) */ @@ -296,7 +319,7 @@ curses_addch(obj, ch) VALUE obj; VALUE ch; { - addch(NUM2CHAR(ch)); + addch(NUM2CHR(ch)); return Qnil; } @@ -306,7 +329,7 @@ curses_insch(obj, ch) VALUE obj; VALUE ch; { - insch(NUM2CHAR(ch)); + insch(NUM2CHR(ch)); return Qnil; } @@ -316,7 +339,9 @@ curses_addstr(obj, str) VALUE obj; VALUE str; { - addstr(RSTRING(str)->ptr); + if (!NIL_P(str)) { + addstr(STR2CSTR(str)); + } return Qnil; } @@ -325,7 +350,7 @@ static VALUE curses_getch(obj) VALUE obj; { - return CHAR2FIX(getch()); + return CHR2FIX(getch()); } /* def getstr */ @@ -335,7 +360,7 @@ curses_getstr(obj) { char rtn[1024]; /* This should be big enough.. I hope */ getstr(rtn); - return str_taint(str_new2(rtn)); + return rb_tainted_str_new2(rtn); } /* def delch */ @@ -352,7 +377,9 @@ static VALUE curses_deleteln(obj) VALUE obj; { +#ifdef HAVE_DELETELN deleteln(); +#endif return Qnil; } @@ -379,11 +406,15 @@ window_s_new(class, lines, cols, top, left) VALUE top; VALUE left; { + VALUE w; WINDOW *window; window = newwin(NUM2INT(lines), NUM2INT(cols), NUM2INT(top), NUM2INT(left)); wclear(window); - return prep_window(class, window); + w = prep_window(class, window); + rb_obj_call_init(w); + + return w; } /* def subwin(lines, cols, top, left) */ @@ -412,7 +443,8 @@ window_close(obj) struct windata *winp; GetWINDOW(obj, winp); - free_window(winp); + delwin(winp->window); + winp->window = 0; return Qnil; } @@ -453,7 +485,7 @@ window_box(obj, vert, hor) struct windata *winp; GetWINDOW(obj, winp); - box(winp->window, NUM2CHAR(vert), NUM2CHAR(hor)); + box(winp->window, NUM2CHR(vert), NUM2CHR(hor)); return Qnil; } @@ -622,7 +654,7 @@ window_inch(obj) struct windata *winp; GetWINDOW(obj, winp); - return CHAR2FIX(winch(winp->window)); + return CHR2FIX(winch(winp->window)); } /* def addch(ch) */ @@ -634,7 +666,7 @@ window_addch(obj, ch) struct windata *winp; GetWINDOW(obj, winp); - waddch(winp->window, NUM2CHAR(ch)); + waddch(winp->window, NUM2CHR(ch)); return Qnil; } @@ -648,7 +680,7 @@ window_insch(obj, ch) struct windata *winp; GetWINDOW(obj, winp); - winsch(winp->window, NUM2CHAR(ch)); + winsch(winp->window, NUM2CHR(ch)); return Qnil; } @@ -659,11 +691,12 @@ window_addstr(obj, str) VALUE obj; VALUE str; { - struct windata *winp; - - GetWINDOW(obj, winp); - waddstr(winp->window, RSTRING(str)->ptr); - + if (!NIL_P(str)) { + struct windata *winp; + + GetWINDOW(obj, winp); + waddstr(winp->window, STR2CSTR(str)); + } return Qnil; } @@ -685,7 +718,7 @@ window_getch(obj) struct windata *winp; GetWINDOW(obj, winp); - return CHAR2FIX(wgetch(winp->window)); + return CHR2FIX(wgetch(winp->window)); } /* def getstr */ @@ -698,7 +731,7 @@ window_getstr(obj) GetWINDOW(obj, winp); wgetstr(winp->window, rtn); - return str_taint(str_new2(rtn)); + return rb_tainted_str_new2(rtn); } /* def delch */ @@ -718,10 +751,12 @@ static VALUE window_deleteln(obj) VALUE obj; { +#ifdef HAVE_WDELETELN struct windata *winp; GetWINDOW(obj, winp); wdeleteln(winp->window); +#endif return Qnil; } @@ -764,7 +799,7 @@ Init_curses() rb_define_module_function(mCurses, "lines", curses_lines, 0); rb_define_module_function(mCurses, "cols", curses_cols, 0); - cWindow = rb_define_class_under(mCurses, "Window", cObject); + cWindow = rb_define_class_under(mCurses, "Window", rb_cObject); rb_define_singleton_method(cWindow, "new", window_s_new, 4); rb_define_method(cWindow, "subwin", window_subwin, 4); rb_define_method(cWindow, "close", window_close, 0); @@ -790,4 +825,6 @@ Init_curses() rb_define_method(cWindow, "getstr", window_getstr, 0); rb_define_method(cWindow, "delch", window_delch, 0); rb_define_method(cWindow, "deleteln", window_deleteln, 0); + + rb_set_end_proc(curses_finalize, 0); } diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb index 9b28437843..442a9424a2 100644 --- a/ext/curses/extconf.rb +++ b/ext/curses/extconf.rb @@ -1,6 +1,9 @@ +require 'mkmf' $CFLAGS="-I/usr/include/ncurses -I/usr/local/include/ncurses" $LDFLAGS="-L/usr/local/lib" make=FALSE + +have_library("mytinfo", "tgetent") if /bow/ =~ PLATFORM if have_header("ncurses.h") and have_library("ncurses", "initscr") make=TRUE elsif have_header("ncurses/curses.h") and have_library("ncurses", "initscr") @@ -14,7 +17,7 @@ else end if make then - for f in ["isendwin", "ungetch", "beep"] + for f in %w(isendwin ungetch beep doupdate flash deleteln wdeleteln) have_func(f) end create_makefile("curses") diff --git a/ext/curses/hello.rb b/ext/curses/hello.rb index bed7779aac..a1915ce60d 100644 --- a/ext/curses/hello.rb +++ b/ext/curses/hello.rb @@ -10,6 +10,7 @@ def show_message(message) win.box(?|, ?=) win.setpos(2, 3) win.addstr(message) + win.refresh win.getch win.close end @@ -18,8 +19,9 @@ init_screen begin crmode # show_message("Hit any key") - setpos (lines - 5) / 2, (cols - 10) / 2 + setpos((lines - 5) / 2, (cols - 10) / 2) addstr("Hit any key") + refresh getch show_message("Hello, World!") refresh diff --git a/ext/curses/view.rb b/ext/curses/view.rb index e59a74ed44..5ba1a8413c 100644 --- a/ext/curses/view.rb +++ b/ext/curses/view.rb @@ -43,6 +43,7 @@ while TRUE addstr(data_lines[lptr + i]) #if data_lines[lptr + i] i += 1 end + refresh explicit = FALSE n = 0 diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c index b416802241..2764a325e1 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 Yukihiro Matsumoto + Copyright (C) 1995-1998 Yukihiro Matsumoto ************************************************/ @@ -15,11 +15,12 @@ #include #include #include +#ifdef USE_CWGUSI +# include +#endif VALUE cDBM; -extern VALUE mEnumerable; - struct dbmdata { int di_size; DBM *di_dbm; @@ -28,7 +29,7 @@ struct dbmdata { static void closed_dbm() { - Fail("closed DBM file"); + rb_raise(rb_eRuntimeError, "closed DBM file"); } #define GetDBM(obj, dbmp) {\ @@ -41,13 +42,14 @@ free_dbm(dbmp) struct dbmdata *dbmp; { if (dbmp->di_dbm) dbm_close(dbmp->di_dbm); + free(dbmp); } static VALUE -fdbm_s_open(argc, argv, class) +fdbm_s_open(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { VALUE file, vmode; DBM *dbm; @@ -79,9 +81,10 @@ fdbm_s_open(argc, argv, class) rb_sys_fail(RSTRING(file)->ptr); } - obj = Data_Make_Struct(class,struct dbmdata,0,free_dbm,dbmp); + obj = Data_Make_Struct(klass,struct dbmdata,0,free_dbm,dbmp); dbmp->di_dbm = dbm; dbmp->di_size = -1; + rb_obj_call_init(obj); return obj; } @@ -118,23 +121,23 @@ fdbm_fetch(obj, keystr) if (value.dptr == 0) { return Qnil; } - return str_taint(str_new(value.dptr, value.dsize)); + return rb_tainted_str_new(value.dptr, value.dsize); } static VALUE -fdbm_indexes(obj, ag) - VALUE obj, ag; +fdbm_indexes(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; { - VALUE *p, *pend; VALUE new; - int i = 0; - struct RArray *args = RARRAY(rb_Array(ag)); + int i; - new = ary_new2(args->len); - p = args->ptr; pend = p + args->len; - while (p < pend) { - ary_push(new, fdbm_fetch(obj, *p++)); + new = rb_ary_new2(argc); + for (i=0; idi_size = -1; - Fail("dbm_delete failed"); + rb_raise(rb_eRuntimeError, "dbm_delete failed"); } else if (dbmp->di_size >= 0) { dbmp->di_size--; @@ -188,9 +191,9 @@ fdbm_shift(obj) val = dbm_fetch(dbm, key); dbm_delete(dbm, key); - keystr = str_taint(str_new(key.dptr, key.dsize)); - valstr = str_taint(str_new(val.dptr, val.dsize)); - return assoc_new(keystr, valstr); + keystr = rb_tainted_str_new(key.dptr, key.dsize); + valstr = rb_tainted_str_new(val.dptr, val.dsize); + return rb_assoc_new(keystr, valstr); } static VALUE @@ -207,11 +210,11 @@ fdbm_delete_if(obj) dbm = dbmp->di_dbm; for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); - keystr = str_taint(str_new(key.dptr, key.dsize)); - valstr = str_taint(str_new(val.dptr, val.dsize)); - if (RTEST(rb_yield(assoc_new(keystr, valstr)))) { + 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)) { - Fail("dbm_delete failed"); + rb_raise(rb_eRuntimeError, "dbm_delete failed"); } } } @@ -232,12 +235,71 @@ fdbm_clear(obj) dbmp->di_size = -1; for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { if (dbm_delete(dbm, key)) { - Fail("dbm_delete failed"); + rb_raise(rb_eRuntimeError, "dbm_delete failed"); } } return obj; } +static VALUE +fdbm_invert(obj) + VALUE obj; +{ + datum key, val; + struct dbmdata *dbmp; + DBM *dbm; + VALUE keystr, valstr; + VALUE hash = rb_hash_new(); + + GetDBM(obj, dbmp); + dbm = dbmp->di_dbm; + 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); + rb_hash_aset(hash, valstr, keystr); + } + return obj; +} + +static VALUE +each_pair(obj) + VALUE obj; +{ + return rb_funcall(obj, rb_intern("each_pair"), 0, 0); +} + +static VALUE fdbm_store _((VALUE,VALUE,VALUE)); + +static VALUE +update_i(pair, dbm) + VALUE pair, dbm; +{ + Check_Type(pair, T_ARRAY); + if (RARRAY(pair)->len < 2) { + rb_raise(rb_eArgError, "pair must be [key, value]"); + } + fdbm_store(dbm, RARRAY(pair)->ptr[0], RARRAY(pair)->ptr[1]); + return Qnil; +} + +static VALUE +fdbm_update(obj, other) + VALUE obj, other; +{ + rb_iterate(each_pair, other, update_i, obj); + return obj; +} + +static VALUE +fdbm_replace(obj, other) + VALUE obj, other; +{ + fdbm_clear(obj); + rb_iterate(each_pair, other, update_i, obj); + return obj; +} + static VALUE fdbm_store(obj, keystr, valstr) VALUE obj, keystr, valstr; @@ -252,14 +314,14 @@ fdbm_store(obj, keystr, valstr) } rb_secure(4); - keystr = obj_as_string(keystr); + keystr = rb_obj_as_string(keystr); key.dptr = RSTRING(keystr)->ptr; key.dsize = RSTRING(keystr)->len; if (NIL_P(valstr)) return fdbm_delete(obj, keystr); - valstr = obj_as_string(valstr); + valstr = rb_obj_as_string(valstr); val.dptr = RSTRING(valstr)->ptr; val.dsize = RSTRING(valstr)->len; @@ -267,9 +329,11 @@ fdbm_store(obj, keystr, valstr) dbmp->di_size = -1; dbm = dbmp->di_dbm; if (dbm_store(dbm, key, val, DBM_REPLACE)) { +#ifdef HAVE_DBM_CLAERERR dbm_clearerr(dbm); - if (errno == EPERM) rb_sys_fail(Qnil); - Fail("dbm_store failed"); +#endif + if (errno == EPERM) rb_sys_fail(0); + rb_raise(rb_eRuntimeError, "dbm_store failed"); } return valstr; @@ -316,8 +380,8 @@ fdbm_empty_p(obj) else { i = dbmp->di_size; } - if (i == 0) return TRUE; - return FALSE; + if (i == 0) return Qtrue; + return Qfalse; } static VALUE @@ -332,7 +396,7 @@ fdbm_each_value(obj) dbm = dbmp->di_dbm; for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); - rb_yield(str_taint(str_new(val.dptr, val.dsize))); + rb_yield(rb_tainted_str_new(val.dptr, val.dsize)); } return obj; } @@ -348,7 +412,7 @@ fdbm_each_key(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { - rb_yield(str_taint(str_new(key.dptr, key.dsize))); + rb_yield(rb_tainted_str_new(key.dptr, key.dsize)); } return obj; } @@ -367,9 +431,9 @@ fdbm_each_pair(obj) for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); - keystr = str_taint(str_new(key.dptr, key.dsize)); - valstr = str_taint(str_new(val.dptr, val.dsize)); - rb_yield(assoc_new(keystr, valstr)); + 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)); } return obj; @@ -387,9 +451,9 @@ fdbm_keys(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - ary = ary_new(); + ary = rb_ary_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { - ary_push(ary, str_taint(str_new(key.dptr, key.dsize))); + rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize)); } return ary; @@ -407,10 +471,10 @@ fdbm_values(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - ary = ary_new(); + ary = rb_ary_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); - ary_push(ary, str_taint(str_new(val.dptr, val.dsize))); + rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize)); } return ary; @@ -431,8 +495,8 @@ fdbm_has_key(obj, keystr) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; val = dbm_fetch(dbm, key); - if (val.dptr) return TRUE; - return FALSE; + if (val.dptr) return Qtrue; + return Qfalse; } static VALUE @@ -453,9 +517,9 @@ fdbm_has_value(obj, valstr) val = dbm_fetch(dbm, key); if (val.dsize == RSTRING(valstr)->len && memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } static VALUE @@ -470,26 +534,29 @@ fdbm_to_a(obj) GetDBM(obj, dbmp); dbm = dbmp->di_dbm; - ary = ary_new(); + ary = rb_ary_new(); for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { val = dbm_fetch(dbm, key); - ary_push(ary, assoc_new(str_taint(str_new(key.dptr, key.dsize)), - str_taint(str_new(val.dptr, val.dsize)))); + rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize), + rb_tainted_str_new(val.dptr, val.dsize))); } return ary; } +void Init_dbm() { - cDBM = rb_define_class("DBM", cObject); - rb_include_module(cDBM, mEnumerable); + cDBM = rb_define_class("DBM", rb_cObject); + rb_include_module(cDBM, rb_mEnumerable); rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1); + rb_define_singleton_method(cDBM, "new", fdbm_s_open, -1); rb_define_method(cDBM, "close", fdbm_close, 0); rb_define_method(cDBM, "[]", fdbm_fetch, 1); rb_define_method(cDBM, "[]=", fdbm_store, 2); - rb_define_method(cDBM, "indexes", fdbm_indexes, -2); + rb_define_method(cDBM, "indexes", fdbm_indexes, -1); + rb_define_method(cDBM, "indices", fdbm_indexes, -1); rb_define_method(cDBM, "length", fdbm_length, 0); rb_define_alias(cDBM, "size", "length"); rb_define_method(cDBM, "empty?", fdbm_empty_p, 0); @@ -503,6 +570,10 @@ Init_dbm() rb_define_method(cDBM, "delete", fdbm_delete, 1); rb_define_method(cDBM, "delete_if", fdbm_delete_if, 0); rb_define_method(cDBM, "clear", fdbm_clear, 0); + rb_define_method(cDBM,"invert", fdbm_invert, 0); + rb_define_method(cDBM,"update", fdbm_update, 1); + rb_define_method(cDBM,"replace", fdbm_replace, 1); + rb_define_method(cDBM, "include?", fdbm_has_key, 1); rb_define_method(cDBM, "has_key?", fdbm_has_key, 1); rb_define_method(cDBM, "has_value?", fdbm_has_value, 1); diff --git a/ext/dbm/extconf.rb b/ext/dbm/extconf.rb index 4a5d41f275..3a96cee12f 100644 --- a/ext/dbm/extconf.rb +++ b/ext/dbm/extconf.rb @@ -1,5 +1,9 @@ +require 'mkmf' $LDFLAGS = "-L/usr/local/lib" -have_library("gdbm", "dbm_open") or have_library("dbm", "dbm_open") +have_library("gdbm", "dbm_open") or + have_library("db", "dbm_open") or + have_library("dbm", "dbm_open") if have_func("dbm_open") + have_func("dbm_clearerr") create_makefile("dbm") end diff --git a/ext/etc/etc.c b/ext/etc/etc.c index 20cd9295ed..c10680c7d3 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -37,7 +37,7 @@ etc_getlogin(obj) #endif if (login) - return str_new2(login); + return rb_tainted_str_new2(login); return Qnil; } @@ -47,34 +47,36 @@ setup_passwd(pwd) struct passwd *pwd; { if (pwd == 0) rb_sys_fail("/etc/passwd"); - return struct_new(sPasswd, - str_new2(pwd->pw_name), - str_new2(pwd->pw_passwd), - INT2FIX(pwd->pw_uid), - INT2FIX(pwd->pw_gid), - str_new2(pwd->pw_gecos), - str_new2(pwd->pw_dir), - str_new2(pwd->pw_shell), + return rb_struct_new(sPasswd, + rb_tainted_str_new2(pwd->pw_name), + rb_tainted_str_new2(pwd->pw_passwd), + INT2FIX(pwd->pw_uid), + INT2FIX(pwd->pw_gid), +#ifdef PW_GECOS + rb_tainted_str_new2(pwd->pw_gecos), +#endif + rb_tainted_str_new2(pwd->pw_dir), + rb_tainted_str_new2(pwd->pw_shell), #ifdef PW_CHANGE - INT2FIX(pwd->pw_change), + INT2FIX(pwd->pw_change), #endif #ifdef PW_QUOTA - INT2FIX(pwd->pw_quota), + INT2FIX(pwd->pw_quota), #endif #ifdef PW_AGE - INT2FIX(pwd->pw_age), + INT2FIX(pwd->pw_age), #endif #ifdef PW_CLASS - str_new2(pwd->pw_class), + rb_tainted_str_new2(pwd->pw_class), #endif #ifdef PW_COMMENT - str_new2(pwd->pw_comment), + rb_tainted_str_new2(pwd->pw_comment), #endif #ifdef PW_EXPIRE - INT2FIX(pwd->pw_expire), + INT2FIX(pwd->pw_expire), #endif - 0 /*dummy*/ - ); + 0 /*dummy*/ + ); } #endif @@ -96,7 +98,7 @@ etc_getpwuid(argc, argv, obj) uid = getuid(); } pwd = getpwuid(uid); - if (pwd == 0) Fail("can't find user for %d", uid); + if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", uid); return setup_passwd(pwd); #else return Qnil; @@ -112,7 +114,7 @@ etc_getpwnam(obj, nam) Check_Type(nam, T_STRING); pwd = getpwnam(RSTRING(nam)->ptr); - if (pwd == 0) Fail("can't find user for %s", RSTRING(nam)->ptr); + if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING(nam)->ptr); return setup_passwd(pwd); #else return Qnil; @@ -123,10 +125,10 @@ static VALUE etc_passwd(obj) VALUE obj; { -#if defined(HAVE_GETPWENT) && !defined(__CYGWIN32__) +#if defined(HAVE_GETPWENT) struct passwd *pw; - if (iterator_p()) { + if (rb_iterator_p()) { setpwent(); while (pw = getpwent()) { rb_yield(setup_passwd(pw)); @@ -135,7 +137,7 @@ etc_passwd(obj) return obj; } pw = getpwent(); - if (pw == 0) Fail("can't fetch next -- /etc/passwd"); + if (pw == 0) rb_raise(rb_eRuntimeError, "can't fetch next -- /etc/passwd"); return setup_passwd(pw); #else return Qnil; @@ -150,17 +152,17 @@ setup_group(grp) VALUE mem; char **tbl; - mem = ary_new(); + mem = rb_ary_new(); tbl = grp->gr_mem; while (*tbl) { - ary_push(mem, str_new2(*tbl)); + rb_ary_push(mem, rb_tainted_str_new2(*tbl)); tbl++; } - return struct_new(sGroup, - str_new2(grp->gr_name), - str_new2(grp->gr_passwd), - INT2FIX(grp->gr_gid), - mem); + return rb_struct_new(sGroup, + rb_tainted_str_new2(grp->gr_name), + rb_tainted_str_new2(grp->gr_passwd), + INT2FIX(grp->gr_gid), + mem); } #endif @@ -174,7 +176,7 @@ etc_getgrgid(obj, id) gid = NUM2INT(id); grp = getgrgid(gid); - if (grp == 0) Fail("can't find group for %d", gid); + if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", gid); return setup_group(grp); #else return Qnil; @@ -190,7 +192,7 @@ etc_getgrnam(obj, nam) Check_Type(nam, T_STRING); grp = getgrnam(RSTRING(nam)->ptr); - if (grp == 0) Fail("can't find group for %s", RSTRING(nam)->ptr); + if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING(nam)->ptr); return setup_group(grp); #else return Qnil; @@ -204,7 +206,7 @@ etc_group(obj) #ifdef HAVE_GETGRENT struct group *grp; - if (iterator_p()) { + if (rb_iterator_p()) { setgrent(); while (grp = getgrent()) { rb_yield(setup_group(grp)); @@ -235,32 +237,35 @@ Init_etc() rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1); rb_define_module_function(mEtc, "group", etc_group, 0); - sPasswd = struct_define("Passwd", - "name", "passwd", "uid", "gid", - "gecos", "dir", "shell", + sPasswd = rb_struct_define("Passwd", + "name", "passwd", "uid", "gid", +#ifdef PW_GECOS + "gecos", +#endif + "dir", "shell", #ifdef PW_CHANGE - "change", + "change", #endif #ifdef PW_QUOTA - "quota", + "quota", #endif #ifdef PW_AGE - "age", + "age", #endif #ifdef PW_CLASS - "class", + "class", #endif #ifdef PW_COMMENT - "comment", + "comment", #endif #ifdef PW_EXPIRE - "expire", + "expire", #endif - 0); + 0); rb_global_variable(&sPasswd); #ifdef HAVE_GETGRENT - sGroup = struct_define("Group", "name", "passwd", "gid", "mem", 0); + sGroup = rb_struct_define("Group", "name", "passwd", "gid", "mem", 0); rb_global_variable(&sGroup); #endif } diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb index 884de93ec8..4cf04a3ec3 100644 --- a/ext/etc/extconf.rb +++ b/ext/etc/extconf.rb @@ -1,7 +1,31 @@ +require 'mkmf' + +def etc_grep_header(field) + f = open("conftest.c", "w") + f.print < +EOF + f.close + begin + if xsystem("#{CPP} | egrep #{field}") + $defs.push(format("-D%s", field.upcase)) + end + ensure + system "rm -f conftest.c" + end +end + have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4 a = have_func("getlogin") b = have_func("getpwent") c = have_func("getgrent") if a or b or c + etc_grep_header("pw_gecos") + etc_grep_header("pw_change") + etc_grep_header("pw_quota") + etc_grep_header("pw_age") + etc_grep_header("pw_class") + etc_grep_header("pw_comment") + etc_grep_header("pw_expire") create_makefile("etc") end diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in index e1d318d19c..058c144f94 100644 --- a/ext/extmk.rb.in +++ b/ext/extmk.rb.in @@ -1,12 +1,14 @@ #! /usr/local/bin/ruby -$".push 'mkmf.rb' +$".push 'mkmf.rb' #" +load '@top_srcdir@/lib/find.rb' if ARGV[0] == 'static' $force_static = TRUE ARGV.shift elsif ARGV[0] == 'install' $install = TRUE + $destdir = ARGV[1] || '' ARGV.shift elsif ARGV[0] == 'clean' $clean = TRUE @@ -19,8 +21,16 @@ $cache_mod = FALSE; $lib_cache = {} $func_cache = {} $hdr_cache = {} -$topdir = "@top_srcdir@" -if $topdir !~ "^/" +$top_srcdir = "@top_srcdir@" +if $top_srcdir !~ "^/" + # get absolute path + save = Dir.pwd + Dir.chdir $top_srcdir + $top_srcdir = Dir.pwd + Dir.chdir save +end +$topdir = ".." +if $topdir !~ "^/" # get absolute path save = Dir.pwd Dir.chdir $topdir @@ -59,23 +69,59 @@ end if PLATFORM == "m68k-human" CFLAGS = "@CFLAGS@".gsub(/-c..-stack=[0-9]+ */, '') -LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c @LIBS@ %s > nul 2>&1" -CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > nul 2>&1" else CFLAGS = "@CFLAGS@" -LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c %s > /dev/null 2>&1" -CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > /dev/null 2>&1" +end +LINK = "@CC@ -o conftest -I#$topdir -I#$top_srcdir -I@includedir@ #{CFLAGS} %s @LDFLAGS@ %s conftest.c @LIBS@ %s" +CPP = "@CPP@ @CPPFLAGS@ -I#$topdir -I#$top_srcdir -I@includedir@ #{CFLAGS} %s conftest.c" + +if /cygwin|mswin32|djgpp|mingw32|m68k-human/i =~ PLATFORM + $null = open("nul", "w") +else + $null = open("/dev/null", "w") +end + +$orgerr = $stderr.dup +$orgout = $stdout.dup +def xsystem command + if $DEBUG + return system(command) + end + $stderr.reopen($null) + $stdout.reopen($null) + r = system(command) + $stderr.reopen($orgerr) + $stdout.reopen($orgout) + return r end def try_link(libs) - system(format(LINK, $CFLAGS, $LDFLAGS, libs)) + xsystem(format(LINK, $CFLAGS, $LDFLAGS, libs)) end def try_cpp - system(format(CPP, $CFLAGS)) + xsystem(format(CPP, $CFLAGS)) +end + +def install_rb(mfile) + path = [] + dir = [] + Find.find("lib") do |f| + next unless /\.rb$/ =~ f + f = f[4..-1] + path.push f + dir |= File.dirname(f) + end + for f in dir + next if f == "." + mfile.printf "\t@test -d $(DESTDIR)$(pkglibdir)/%s || mkdir $(DESTDIR)$(pkglibdir)/%s\n", f, f + end + for f in path + mfile.printf "\t$(INSTALL_DATA) lib/%s $(DESTDIR)$(pkglibdir)/%s\n", f, f + end end -def have_library(lib, func) +def have_library(lib, func="main") if $lib_cache[lib] if $lib_cache[lib] == "yes" if $libs @@ -89,26 +135,34 @@ def have_library(lib, func) end end - cfile = open("conftest.c", "w") - cfile.printf "\ + if func && func != "" + cfile = open("conftest.c", "w") + cfile.printf "\ int main() { return 0; } int t() { %s(); return 0; } ", func - cfile.close + cfile.close - begin + begin + if $libs + libs = "-l" + lib + " " + $libs + else + libs = "-l" + lib + end + unless try_link(libs) + $lib_cache[lib] = 'no' + $cache_mod = TRUE + return FALSE + end + ensure + system "rm -f conftest*" + end + else if $libs libs = "-l" + lib + " " + $libs else libs = "-l" + lib end - unless try_link(libs) - $lib_cache[lib] = 'no' - $cache_mod = TRUE - return FALSE - end - ensure - system "rm -f conftest*" end $libs = libs @@ -206,9 +260,19 @@ def create_makefile(target) end $defs.push(format("-DEXTLIB='%s'", libs.join(","))) end - $libs = "" unless $libs - $srcdir = $topdir + "/ext/" + target + $DLDFLAGS = '@DLDFLAGS@' + + if PLATFORM =~ /beos/ + if $libs + $libs = $libs + " -lruby" + else + $libs = "-lruby" + end + $DLDFLAGS = $DLDFLAGS + " -L" + $topdir + end + + $srcdir = $top_srcdir + "/ext/" + target mfile = open("Makefile", "w") mfile.printf "\ SHELL = /bin/sh @@ -222,10 +286,11 @@ hdrdir = #{$topdir} CC = @CC@ -CFLAGS = %s -I#{$topdir} %s #$CFLAGS %s -DLDFLAGS = @DLDFLAGS@ #$LDFLAGS +prefix = @prefix@ +CFLAGS = %s -I#{$topdir} -I#{$top_srcdir} -I@includedir@ #{CFLAGS} #$CFLAGS %s +DLDFLAGS = #$DLDFLAGS @LDFLAGS@ #$LDFLAGS LDSHARED = @LDSHARED@ -", if $static then "" else "@CCDLFLAGS@" end, CFLAGS, $defs.join(" ") +", if $static then "" else "@CCDLFLAGS@" end, $defs.join(" ") mfile.printf "\ @@ -234,18 +299,20 @@ RUBY_INSTALL_NAME = `t='$(program_transform_name)'; echo ruby | sed $$t` prefix = @prefix@ exec_prefix = @exec_prefix@ -libdir = @libdir@/$(RUBY_INSTALL_NAME)/@arch@ +libdir = @libdir@ +pkglibdir = $(libdir)/$(RUBY_INSTALL_NAME) +archdir = $(pkglibdir)/@arch@ @SET_MAKE@ #### End of system configuration section. #### " - mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs + mfile.printf "LOCAL_LIBS = %s\n", $local_libs unless $local_libs == "" mfile.printf "LIBS = %s\n", $libs mfile.printf "OBJS = " if !$objs then $objs = [] - for f in Dir["#{$topdir}/ext/#{target}/*.{c,cc}"] + for f in Dir["#{$top_srcdir}/ext/#{$mdir}/*.{c,cc}"] f = File.basename(f) f.sub!(/\.(c|cc)$/, ".o") $objs.push f @@ -254,42 +321,48 @@ libdir = @libdir@/$(RUBY_INSTALL_NAME)/@arch@ mfile.printf $objs.join(" ") mfile.printf "\n" - mfile.printf "\ -TARGET = %s.%s + mfile.printf < /dev/null || true +" + elsif "@DLEXT@" != "o" mfile.printf "\ $(TARGET): $(OBJS) - $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS) + $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) $(LOCAL_LIBS) " elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc") if PLATFORM == "m68k-human" @@ -297,15 +370,10 @@ $(TARGET): $(OBJS) $(TARGET): $(OBJS) ar cru $(TARGET) $(OBJS) " - elsif PLATFORM =~ "-nextstep" + elsif PLATFORM =~ "-nextstep" || PLATFORM =~ "-openstep" || PLATFORM =~ "-rhapsody" mfile.printf "\ $(TARGET): $(OBJS) cc -r $(CFLAGS) -o $(TARGET) $(OBJS) -" - elsif $static - mfile.printf "\ -$(TARGET): $(OBJS) - ld -r -o $(TARGET) $(OBJS) " else mfile.printf "\ @@ -324,6 +392,19 @@ $(TARGET): $(OBJS) dfile.close end mfile.close + + if PLATFORM =~ /beos/ + if PLATFORM =~ /^powerpc/ then + deffilename = "ruby.exp" + else + deffilename = "ruby.def" + end + print "creating ruby.def\n" + open(deffilename, "w") do |file| + file.print("EXPORTS\n") if PLATFORM =~ /^i/ + file.print("Init_#{target}\n") + end + end end def extmake(target) @@ -335,24 +416,25 @@ def extmake(target) return if $nodynamic and not $static - $local_libs = nil - $libs = nil $objs = nil - $CFLAGS = nil - $LDFLAGS = nil + $libs = PLATFORM =~ /cygwin|beos|openstep|nextstep|rhapsody/ ? nil : "-lc" + $local_libs = "" # to be assigned in extconf.rb + $CFLAGS = "" + $LDFLAGS = "" begin - system "mkdir " + target unless File.directory?(target) + system "mkdir", target unless File.directory?(target) Dir.chdir target + $mdir = target if $static_ext.size > 0 || !File.exist?("./Makefile") || - older("./Makefile", "#{$topdir}/ext/@setup@") || + older("./Makefile", "#{$top_srcdir}/ext/@setup@") || older("./Makefile", "../extmk.rb") || - older("./Makefile", "#{$topdir}/ext/#{target}/extconf.rb") + older("./Makefile", "#{$top_srcdir}/ext/#{target}/extconf.rb") then $defs = [] - if File.exist?("#{$topdir}/ext/#{target}/extconf.rb") - load "#{$topdir}/ext/#{target}/extconf.rb" + if File.exist?("#{$top_srcdir}/ext/#{target}/extconf.rb") + load "#{$top_srcdir}/ext/#{target}/extconf.rb" else create_makefile(target); end @@ -362,7 +444,7 @@ def extmake(target) $extlist.push [$static,target] end if $install - system "make install" + system "make install DESTDIR=#{$destdir}" elsif $clean system "make clean" else @@ -370,9 +452,10 @@ def extmake(target) end end if $static - $extlibs += " " + $LDFLAGS if $LDFLAGS - $extlibs += " " + $local_libs if $local_libs + $extlibs ||= "" + $extlibs += " " + $LDFLAGS unless $LDFLAGS == "" $extlibs += " " + $libs if $libs + $extlibs += " " + $local_libs unless $local_libs == "" end ensure Dir.chdir ".." @@ -381,11 +464,11 @@ end # get static-link modules $static_ext = {} -for setup in ["@setup@", "#{$topdir}/ext/@setup@"] +for setup in ["@setup@", "#{$top_srcdir}/ext/@setup@"] if File.file? setup f = open(setup) while f.gets() - $_.chop! + $_.chomp! sub!(/#.*$/, '') next if /^\s*$/ if /^option +nodynamic/ @@ -399,7 +482,7 @@ for setup in ["@setup@", "#{$topdir}/ext/@setup@"] end end -for d in Dir["#{$topdir}/ext/*"] +for d in Dir["#{$top_srcdir}/ext/*"] File.directory?(d) || next File.file?(d + "/MANIFEST") || next @@ -429,15 +512,16 @@ if $cache_mod end exit if $install or $clean -$extinit += "" +$extinit = "" unless $extinit if $extlist.size > 0 for s,t in $extlist - f = format("%s/%s.o", s, t) + f = format("%s/%s.a", s, t) if File.exist?(f) $extinit += format("\ \tInit_%s();\n\ \trb_provide(\"%s.o\");\n\ ", t, t) + $extobjs = "" unless $extobjs $extobjs += "ext/" $extobjs += f $extobjs += " " @@ -446,7 +530,7 @@ if $extlist.size > 0 end end - if older("extinit.c", "#{$topdir}/ext/@setup@") + if older("extinit.c", "#{$top_srcdir}/ext/@setup@") f = open("extinit.c", "w") f.printf "void Init_ext() {\n" f.printf $extinit @@ -461,17 +545,24 @@ if $extlist.size > 0 Dir.chdir ".." - if older("ruby@binsuffix@", "#{$topdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@") + if older("ruby@binsuffix@", "#{$top_srcdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@") `rm -f ruby@binsuffix@` end - $extobjs = "ext/extinit.o " + $extobjs + if $extobjs + $extobjs = "ext/extinit.o " + $extobjs + else + $extobjs = "ext/extinit.o " + end + if PLATFORM =~ /m68k-human|beos/ + $extlibs.gsub!("-L/usr/local/lib", "") if $extlibs + end system format('make ruby@binsuffix@ EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs) else Dir.chdir ".." if older("ruby@binsuffix@", "miniruby@binsuffix@") `rm -f ruby@binsuffix@` - `cp miniruby@binsuffix@ ruby@binsuffix@` + system("make ruby@binsuffix@") end end diff --git a/ext/extmk.rb.nt b/ext/extmk.rb.nt index 6792f2717b..5836e5c681 100644 --- a/ext/extmk.rb.nt +++ b/ext/extmk.rb.nt @@ -1,5 +1,7 @@ #! /usr/local/bin/ruby +$".push 'mkmf.rb' #" + if ARGV[0] == 'static' $force_static = TRUE ARGV.shift @@ -379,7 +381,7 @@ def extmake(target) end end if $static - #$extlibs = " " + $extlibs = " " $extlibs += " " + $LDFLAGS if $LDFLAGS $extlibs += " " + $local_libs if $local_libs $extlibs += " " + $libs if $libs @@ -438,6 +440,8 @@ if $cache_mod end exit if $install or $clean +$extinit = " " unless $extinit +$extobjs = "" if $extlist.size > 0 for s,t in $extlist #for s,t in $static_ext diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c index 17aacb13c3..186f9ac893 100644 --- a/ext/fcntl/fcntl.c +++ b/ext/fcntl/fcntl.c @@ -5,7 +5,7 @@ $Author$ created at: Mon Apr 7 18:53:05 JST 1997 - Copyright (C) 1997 Yukihiro Matsumoto + Copyright (C) 1997-1998 Yukihiro Matsumoto ************************************************/ diff --git a/ext/kconv/kconv.c b/ext/kconv/kconv.c index 6778afcfe6..a3349826f1 100644 --- a/ext/kconv/kconv.c +++ b/ext/kconv/kconv.c @@ -1780,12 +1780,30 @@ kconv_kconv(argc, argv) VALUE src, dst; VALUE in, out; int in_code, out_code; + char *codename = 0; rb_scan_args(argc, argv, "12", &src, &out, &in); Check_Type(src, T_STRING); if (NIL_P(out)) { - out_code = _JIS; + codename = rb_get_kcode(); + goto codeselect; + } + else if (TYPE(out) == T_STRING) { + codename = RSTRING(out)->ptr; + codeselect: + switch (codename[0]) { + case 'E': case 'e': + out_code = _EUC; + break; + case 'S': case 's': + out_code = _SJIS; + break; + case 'J': case 'j': + default: + out_code = _JIS; + break; + } } else { out_code = NUM2INT(out); @@ -1794,12 +1812,28 @@ kconv_kconv(argc, argv) if (NIL_P(in)) { in_code = _AUTO; } + else if (TYPE(in) == T_STRING) { + switch (RSTRING(in)->ptr[0]) { + case 'E': case 'e': + in_code = _EUC; + break; + case 'S': case 's': + in_code = _SJIS; + break; + case 'J': case 'j': + in_code = _JIS; + break; + default: + in_code = _AUTO; + break; + } + } else { in_code = NUM2INT(in); if (in_code == _NOCONV) return (VALUE)src; } - dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */ + dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */ RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, out_code, in_code); return dst; @@ -1813,7 +1847,7 @@ kconv_tojis(obj, src) Check_Type(src, T_STRING); - dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */ + dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */ RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, _JIS, _AUTO); return dst; @@ -1827,7 +1861,7 @@ kconv_toeuc(obj, src) Check_Type(src, T_STRING); - dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */ + dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */ RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, _EUC, _AUTO); return (VALUE)dst; @@ -1841,7 +1875,7 @@ kconv_tosjis(obj, src) Check_Type(src, T_STRING); - dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */ + dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */ RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, _SJIS, _AUTO); return dst; @@ -1857,10 +1891,29 @@ static VALUE kconv_guess(obj, src) VALUE obj, src; { - unsigned char *p = RSTRING(src)->ptr; - unsigned char *pend = p + RSTRING(src)->len; + unsigned char *p; + unsigned char *pend; + int sequence_counter = 0; + + Check_Type(src, T_STRING); + + p = RSTRING(src)->ptr; + pend = p + RSTRING(src)->len; + +#define INCR do {\ + p++;\ + if (p==pend) return INT2FIX(_UNKNOWN);\ + sequence_counter++;\ + if (sequence_counter % 2 == 1 && *p != 0xa4)\ + sequence_counter = 0;\ + if (6 <= sequence_counter) {\ + sequence_counter = 0;\ + return INT2FIX(_EUC);\ + }\ +} while (0) -#define INCR {p++;if (p==pend) return INT2FIX(_UNKNOWN);} + if (*p == 0xa4) + sequence_counter = 1; while (p= 0x40) { + while (p < pend && *p >= 0x40) { if (*p >= 0x81) { - if (0x8d <= *p || (0x8f <= *p && *p <= 0x9f)) { + if (*p <= 0x8d || (0x8f <= *p && *p <= 0x9f)) { return INT2FIX(_SJIS); } else if (0xfd <= *p && *p <= 0xfe) { return INT2FIX(_EUC); } } + INCR; } } - if (*p <= 0x9f) { + else if (*p <= 0x9f) { return INT2FIX(_SJIS); } } - if (0xf0 <= *p && *p <= 0xfe) { + else if (0xf0 <= *p && *p <= 0xfe) { return INT2FIX(_EUC); } - if (0xe0 <= *p && *p <= 0xef) { + else if (0xe0 <= *p && *p <= 0xef) { INCR; if ((0x40 <= *p && *p <= 0x7e) || (0x80 <= *p && *p <= 0xa0)) { @@ -1914,7 +1971,7 @@ kconv_guess(obj, src) return INT2FIX(_EUC); } } - p++; + INCR; } return INT2FIX(_UNKNOWN); } diff --git a/ext/md5/md5init.c b/ext/md5/md5init.c index 47f913792f..a825f96d47 100644 --- a/ext/md5/md5init.c +++ b/ext/md5/md5init.c @@ -5,7 +5,7 @@ $Author$ created at: Fri Aug 2 09:24:12 JST 1996 - Copyright (C) 1995 Yukihiro Matsumoto + Copyright (C) 1995-1998 Yukihiro Matsumoto ************************************************/ /* This module provides an interface to the RSA Data Security, @@ -42,7 +42,7 @@ md5_digest(obj) ctx = *md5; MD5Final(digest, &ctx); - return str_new(digest, 16); + return rb_str_new(digest, 16); } static VALUE @@ -53,7 +53,7 @@ md5_clone(obj) MD5_CTX *md5, *md5_new; Data_Get_Struct(obj, MD5_CTX, md5); - obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new); + obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, free, md5_new); *md5_new = *md5; return obj; @@ -61,6 +61,9 @@ md5_clone(obj) static VALUE md5_new(argc, argv, class) + int argc; + VALUE* argv; + VALUE class; { int i; VALUE arg, obj; @@ -69,18 +72,19 @@ md5_new(argc, argv, class) rb_scan_args(argc, argv, "01", &arg); if (!NIL_P(arg)) Check_Type(arg, T_STRING); - obj = Data_Make_Struct(class, MD5_CTX, 0, 0, md5); + obj = Data_Make_Struct(class, MD5_CTX, 0, free, md5); MD5Init(md5); if (!NIL_P(arg)) { md5_update(obj, arg); } + rb_obj_call_init(obj); return obj; } Init_md5() { - cMD5 = rb_define_class("MD5", cObject); + cMD5 = rb_define_class("MD5", rb_cObject); rb_define_singleton_method(cMD5, "new", md5_new, -1); diff --git a/ext/socket/depend b/ext/socket/depend index 3d54fa073c..6e8c3b7d97 100644 --- a/ext/socket/depend +++ b/ext/socket/depend @@ -1 +1 @@ -socket.o : socket.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h $(hdrdir)/io.h $(hdrdir)/sig.h +socket.o : socket.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h $(hdrdir)/rubyio.h $(hdrdir)/rubysig.h diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb index f719723864..449d5a2785 100644 --- a/ext/socket/extconf.rb +++ b/ext/socket/extconf.rb @@ -1,18 +1,22 @@ -$LDFLAGS = "-L/usr/local/lib" +require 'mkmf' +$LDFLAGS = "-L/usr/local/lib" if File.directory?("/usr/local/lib") case PLATFORM when /mswin32/ test_func = "WSACleanup" have_library("wsock32", "WSACleanup") when /cygwin32/ - test_func = "cygwin32_socket" + test_func = "socket" +when /beos/ + test_func = "socket" + have_library("net", "socket") else test_func = "socket" + have_library("nsl", "t_open") have_library("socket", "socket") - have_library("inet", "gethostbyname") - have_library("nsl", "gethostbyname") end have_header("sys/un.h") if have_func(test_func) + have_func("inet_aton") have_func("hsterror") unless have_func("gethostname") have_func("uname") diff --git a/ext/socket/socket.c b/ext/socket/socket.c index f5d191b056..e9bdbc9e8c 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -9,7 +9,8 @@ ************************************************/ #include "ruby.h" -#include "io.h" +#include "rubyio.h" +#include "rubysig.h" #include #include #ifndef NT @@ -22,7 +23,14 @@ #include #endif -#if defined(THREAD) && defined(HAVE_FCNTL) +#ifdef USE_CWGUSI +extern int fileno(FILE *stream); /* */ +extern int rb_thread_select(int, fd_set*, fd_set*, fd_set*, struct timeval*); /* thread.c */ +# include +# include +#endif + +#if defined(USE_THREAD) && defined(HAVE_FCNTL) #ifdef HAVE_SYS_SELECT_H #include #endif @@ -34,30 +42,25 @@ #define EWOULDBLOCK EAGAIN #endif -extern VALUE cIO; -extern VALUE cInteger; - -VALUE cBasicSocket; -VALUE cIPsocket; -VALUE cTCPsocket; -VALUE cTCPserver; -VALUE cUDPsocket; +VALUE rb_cBasicSocket; +VALUE rb_cIPsocket; +VALUE rb_cTCPsocket; +VALUE rb_cTCPserver; +VALUE rb_cUDPsocket; #ifdef AF_UNIX -VALUE cUNIXsocket; -VALUE cUNIXserver; +VALUE rb_cUNIXsocket; +VALUE rb_cUNIXserver; #endif -VALUE cSocket; +VALUE rb_cSocket; -extern VALUE eException; -static VALUE eSocket; +static VALUE rb_eSocket; #ifdef SOCKS -VALUE cSOCKSsocket; +VALUE rb_cSOCKSsocket; void SOCKSinit(); int Rconnect(); #endif -FILE *rb_fdopen(); char *strdup(); #define INET_CLIENT 0 @@ -69,9 +72,12 @@ static void sock_finalize(fptr) OpenFile *fptr; { - SOCKET s = fileno(fptr->f); + SOCKET s; + + if (!fptr->f) return; + s = fileno(fptr->f); free(fptr->f); - free(fptr->f2); + if (fptr->f2) free(fptr->f2); closesocket(s); } #endif @@ -85,6 +91,7 @@ sock_new(class, fd) NEWOBJ(sock, struct RFile); OBJSETUP(sock, class, T_FILE); + rb_secure(4); MakeOpenFile(sock, fp); fp->f = rb_fdopen(fd, "r"); #ifdef NT @@ -92,7 +99,8 @@ sock_new(class, fd) #endif fp->f2 = rb_fdopen(fd, "w"); fp->mode = FMODE_READWRITE; - io_unbuffered(fp); + rb_io_unbuffered(fp); + rb_obj_call_init((VALUE)sock); return (VALUE)sock; } @@ -107,12 +115,15 @@ bsock_shutdown(argc, argv, sock) int how; OpenFile *fptr; + rb_secure(4); rb_scan_args(argc, argv, "01", &howto); if (howto == Qnil) how = 2; else { how = NUM2INT(howto); - if (how < 0 && how > 2) how = 2; + if (how < 0 || 2 < how) { + rb_raise(rb_eArgError, "`how' should be either 0, 1, 2"); + } } GetOpenFile(sock, fptr); if (shutdown(fileno(fptr->f), how) == -1) @@ -121,10 +132,58 @@ bsock_shutdown(argc, argv, sock) return INT2FIX(0); } +static VALUE +bsock_close_read(sock) + VALUE sock; +{ + OpenFile *fptr; + + rb_secure(4); + GetOpenFile(sock, fptr); + if (fptr->f2 == 0) { + return rb_io_close(sock); + } + if (shutdown(fileno(fptr->f), 0) == -1) + rb_sys_fail(0); + fptr->mode &= ~FMODE_READABLE; +#ifdef NT + free(fptr->f); +#else + fclose(fptr->f); +#endif + fptr->f = fptr->f2; + fptr->f2 = 0; + + return Qnil; +} + +static VALUE +bsock_close_write(sock) + VALUE sock; +{ + OpenFile *fptr; + + rb_secure(4); + GetOpenFile(sock, fptr); + if (fptr->f2 == 0) { + return rb_io_close(sock); + } + if (shutdown(fileno(fptr->f), 1) == -1) + rb_sys_fail(0); + fptr->mode &= ~FMODE_WRITABLE; +#ifdef NT + free(fptr->f2); +#else + fclose(fptr->f2); +#endif + fptr->f2 = 0; + + return Qnil; +} + static VALUE bsock_setsockopt(sock, lev, optname, val) - VALUE sock, lev, optname; - struct RString *val; + VALUE sock, lev, optname, val; { int level, option; OpenFile *fptr; @@ -148,8 +207,7 @@ bsock_setsockopt(sock, lev, optname, val) v = (char*)&i; vlen = sizeof(i); break; default: - Check_Type(val, T_STRING); - v = val->ptr; vlen = val->len; + v = rb_str2cstr(val, &vlen); } GetOpenFile(sock, fptr); @@ -163,6 +221,7 @@ static VALUE bsock_getsockopt(sock, lev, optname) VALUE sock, lev, optname; { +#if !defined(__BEOS__) int level, option, len; char *buf; OpenFile *fptr; @@ -176,7 +235,10 @@ bsock_getsockopt(sock, lev, optname) if (getsockopt(fileno(fptr->f), level, option, buf, &len) < 0) rb_sys_fail(fptr->path); - return str_new(buf, len); + return rb_str_new(buf, len); +#else + rb_notimplement(); +#endif } static VALUE @@ -190,7 +252,7 @@ bsock_getsockname(sock) GetOpenFile(sock, fptr); if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) rb_sys_fail("getsockname(2)"); - return str_new(buf, len); + return rb_str_new(buf, len); } static VALUE @@ -204,7 +266,7 @@ bsock_getpeername(sock) GetOpenFile(sock, fptr); if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) rb_sys_fail("getpeername(2)"); - return str_new(buf, len); + return rb_str_new(buf, len); } static VALUE @@ -213,31 +275,32 @@ bsock_send(argc, argv, sock) VALUE *argv; VALUE sock; { - struct RString *msg, *to; + VALUE msg, to; VALUE flags; OpenFile *fptr; FILE *f; int fd, n; + char *m, *t; + int mlen, tlen; rb_secure(4); rb_scan_args(argc, argv, "21", &msg, &flags, &to); - Check_Type(msg, T_STRING); - GetOpenFile(sock, fptr); - f = fptr->f2?fptr->f2:fptr->f; + f = GetWriteFile(fptr); fd = fileno(f); retry: -#ifdef THREAD - thread_fd_writable(fd); +#ifdef USE_THREAD + rb_thread_fd_writable(fd); #endif + m = rb_str2cstr(msg, &mlen); if (RTEST(to)) { - Check_Type(to, T_STRING); - n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags), - (struct sockaddr*)to->ptr, to->len); + t = rb_str2cstr(to, &tlen); + n = sendto(fd, m, mlen, NUM2INT(flags), + (struct sockaddr*)t, tlen); } else { - n = send(fd, msg->ptr, msg->len, NUM2INT(flags)); + n = send(fd, m, mlen, NUM2INT(flags)); } if (n < 0) { switch (errno) { @@ -246,8 +309,8 @@ bsock_send(argc, argv, sock) #if EAGAIN != EWOULDBLOCK case EAGAIN: #endif -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif goto retry; } @@ -277,7 +340,6 @@ s_recv(sock, argc, argv, from) enum sock_recv_type from; { OpenFile *fptr; - FILE f; VALUE str; char buf[1024]; int fd, alen = sizeof buf; @@ -289,12 +351,12 @@ s_recv(sock, argc, argv, from) if (flg == Qnil) flags = 0; else flags = NUM2INT(flg); - str = str_new(0, NUM2INT(len)); + str = rb_str_new(0, NUM2INT(len)); GetOpenFile(sock, fptr); fd = fileno(fptr->f); -#ifdef THREAD - thread_wait_fd(fd); +#ifdef USE_THREAD + rb_thread_wait_fd(fd); #endif TRAP_BEG; retry: @@ -309,38 +371,35 @@ s_recv(sock, argc, argv, from) #if EAGAIN != EWOULDBLOCK case EAGAIN: #endif -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif goto retry; } rb_sys_fail("recvfrom(2)"); } - str_taint(str); + rb_obj_taint(str); switch (from) { case RECV_RECV: return (VALUE)str; case RECV_TCP: if (alen != sizeof(struct sockaddr_in)) { - TypeError("sockaddr size differs - should not happen"); + rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); } - return assoc_new(str, ipaddr((struct sockaddr_in *)buf)); + return rb_assoc_new(str, ipaddr((struct sockaddr_in *)buf)); case RECV_UDP: { VALUE addr = ipaddr((struct sockaddr_in *)buf); - return assoc_new(str, assoc_new(RARRAY(addr)->ptr[2], - RARRAY(addr)->ptr[1])); + return rb_assoc_new(str, rb_assoc_new(RARRAY(addr)->ptr[2], + RARRAY(addr)->ptr[1])); } #ifdef HAVE_SYS_UN_H case RECV_UNIX: - if (alen != sizeof(struct sockaddr_un)) { - TypeError("sockaddr size differs - should not happen"); - } - return assoc_new(str, unixaddr((struct sockaddr_un *)buf)); + return rb_assoc_new(str, unixaddr((struct sockaddr_un *)buf)); #endif case RECV_SOCKET: - return assoc_new(str, str_new(buf, alen)); + return rb_assoc_new(str, rb_str_new(buf, alen)); } } @@ -353,7 +412,96 @@ bsock_recv(argc, argv, sock) return s_recv(sock, argc, argv, RECV_RECV); } -#if defined(THREAD) && defined(HAVE_FCNTL) +static VALUE +mkipaddr(x) + unsigned long x; +{ + char buf[16]; + + x = ntohl(x); + sprintf(buf, "%d.%d.%d.%d", + (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, + (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff); + return rb_str_new2(buf); +} + +static VALUE +ipaddr(sockaddr) + struct sockaddr_in *sockaddr; +{ + VALUE family, port, addr1, addr2; + VALUE ary; + struct hostent *hostent; + + family = rb_str_new2("AF_INET"); + hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr, + sizeof(sockaddr->sin_addr), + AF_INET); + addr1 = 0; + if (hostent) { + addr1 = rb_str_new2(hostent->h_name); + } + addr2 = mkipaddr(sockaddr->sin_addr.s_addr); + if (!addr1) addr1 = addr2; + + port = INT2FIX(ntohs(sockaddr->sin_port)); + ary = rb_ary_new3(4, family, port, addr1, addr2); + + return ary; +} + +#ifndef HAVE_INET_ATON +static unsigned long +inet_aton(host, inp) + char *host; + struct in_addr *inp; +{ + int d1, d2, d3, d4; + char ch; + + if (sscanf(host, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && + 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && + 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { + inp->s_addr = htonl( + ((long) d1 << 24) | ((long) d2 << 16) | + ((long) d3 << 8) | ((long) d4 << 0)); + return 1; + } + return 0; +} +#endif + +static void +setipaddr(name, addr) + char *name; + struct sockaddr_in *addr; +{ + struct hostent *hp; + + if (name[0] == 0) { + addr->sin_addr.s_addr = INADDR_ANY; + } + else if (name[0] == '<' && strcmp(name, "") == 0) { + addr->sin_addr.s_addr = INADDR_BROADCAST; + } + else if (inet_aton(name, &addr->sin_addr) != 0) { + /* ok to set addr->sin_addr */ + } + else { + hp = gethostbyname(name); + if (!hp) { +#ifdef HAVE_HSTRERROR + extern int h_errno; + rb_raise(rb_eSocket, (char *)hstrerror(h_errno)); +#else + rb_raise(rb_eSocket, "host not found"); +#endif + } + memcpy((char *) &addr->sin_addr, hp->h_addr, hp->h_length); + } +} + +#if defined(USE_THREAD) && defined(HAVE_FCNTL) static int thread_connect(fd, sockaddr, len, type) int fd; @@ -396,7 +544,7 @@ thread_connect(fd, sockaddr, len, type) #endif FD_ZERO(&fds); FD_SET(fd, &fds); - thread_select(fd+1, 0, &fds, 0, 0, 0); + rb_thread_select(fd+1, 0, &fds, 0, 0); continue; #endif @@ -434,26 +582,25 @@ open_inet(class, h, serv, type) int hostaddr, hostaddrPtr[2]; int servport; char *syscall; - VALUE sock; if (h) { Check_SafeStr(h); host = RSTRING(h)->ptr; hostent = gethostbyname(host); if (hostent == NULL) { - hostaddr = inet_addr(host); - if (hostaddr == -1) { + if (!inet_aton(host, &sockaddr.sin_addr)) { if (type == INET_SERVER && !strlen(host)) hostaddr = INADDR_ANY; else { #ifdef HAVE_HSTRERROR extern int h_errno; - Raise(eSocket, (char *)hstrerror(h_errno)); + rb_raise(rb_eSocket, (char *)hstrerror(h_errno)); #else - Raise(eSocket, "host not found"); + rb_raise(rb_eSocket, "host not found"); #endif } } + hostaddr = sockaddr.sin_addr.s_addr; _hostent.h_addr_list = (char **)hostaddrPtr; _hostent.h_addr_list[0] = (char *)&hostaddr; _hostent.h_addr_list[1] = NULL; @@ -467,24 +614,30 @@ open_inet(class, h, serv, type) servport = FIX2UINT(serv); goto setup_servent; } - Check_Type(serv, T_STRING); - servent = getservbyname(RSTRING(serv)->ptr, "tcp"); + servent = getservbyname(STR2CSTR(serv), "tcp"); if (servent == NULL) { - servport = strtoul(RSTRING(serv)->ptr, 0, 0); - if (servport == -1) { - Raise(eSocket, "no such servce %s", RSTRING(serv)->ptr); + char *s = STR2CSTR(serv); + char *end; + + servport = strtoul(s, &end, 0); + if (*end != '\0') { + rb_raise(rb_eSocket, "no such servce %s", s); } setup_servent: _servent.s_port = htons(servport); _servent.s_proto = "tcp"; servent = &_servent; } +#ifdef __BEOS__ + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +#else protoent = getprotobyname(servent->s_proto); if (protoent == NULL) { - Raise(eSocket, "no such proto %s", servent->s_proto); + rb_raise(rb_eSocket, "no such proto %s", servent->s_proto); } fd = socket(AF_INET, SOCK_STREAM, protoent->p_proto); +#endif memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; @@ -505,9 +658,9 @@ open_inet(class, h, serv, type) syscall = "bind(2)"; } else { -#if defined(THREAD) && defined(HAVE_FCNTL) +#if defined(USE_THREAD) && defined(HAVE_FCNTL) status = thread_connect(fd, (struct sockaddr*)&sockaddr, - sizeof(sockaddr), type); + sizeof(sockaddr), type); #else #ifdef SOCKS if (type == INET_SOCKS) { @@ -523,7 +676,7 @@ open_inet(class, h, serv, type) } if (status < 0) { - close (fd); + close(fd); rb_sys_fail(syscall); } if (type == INET_SERVER) listen(fd, 5); @@ -557,6 +710,49 @@ socks_s_open(class, host, serv) } #endif +static VALUE +tcp_s_gethostbyname(obj, host) + VALUE obj, host; +{ + struct sockaddr_in addr; + struct hostent *h; + char **pch; + VALUE ary, names; + + setipaddr(STR2CSTR(host), &addr); + h = gethostbyaddr((char *)&addr.sin_addr, + sizeof(addr.sin_addr), + AF_INET); + + if (h == NULL) { +#ifdef HAVE_HSTRERROR + extern int h_errno; + rb_raise(rb_eSocket, (char *)hstrerror(h_errno)); +#else + rb_raise(rb_eSocket, "host not found"); +#endif + } + ary = rb_ary_new(); + rb_ary_push(ary, rb_str_new2(h->h_name)); + names = rb_ary_new(); + rb_ary_push(ary, names); + for (pch = h->h_aliases; *pch; pch++) { + rb_ary_push(names, rb_str_new2(*pch)); + } + rb_ary_push(ary, NUM2INT(h->h_addrtype)); +#ifdef h_addr + for (pch = h->h_addr_list; *pch; pch++) { + memcpy((char *) &addr.sin_addr, *pch, h->h_length); + rb_ary_push(ary, mkipaddr(addr.sin_addr.s_addr)); + } +#else + memcpy((char *)&addr.sin_addr, h->h_addr, h->h_length); + rb_ary_push(ary, mkipaddr(addr.sin_addr.s_addr)); +#endif + + return ary; +} + static VALUE tcp_svr_s_open(argc, argv, class) int argc; @@ -581,8 +777,8 @@ s_accept(class, fd, sockaddr, len) int fd2; retry: -#ifdef THREAD - thread_wait_fd(fd); +#ifdef USE_THREAD + rb_thread_wait_fd(fd); #endif TRAP_BEG; fd2 = accept(fd, sockaddr, len); @@ -594,8 +790,8 @@ s_accept(class, fd, sockaddr, len) #if EAGAIN != EWOULDBLOCK case EAGAIN: #endif -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif goto retry; } @@ -614,7 +810,7 @@ tcp_accept(sock) GetOpenFile(sock, fptr); fromlen = sizeof(struct sockaddr_in); - return s_accept(cTCPsocket, fileno(fptr->f), + return s_accept(rb_cTCPsocket, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); } @@ -670,81 +866,6 @@ open_unix(class, path, server) } #endif -static void -setipaddr(name, addr) - char *name; - struct sockaddr_in *addr; -{ - int d1, d2, d3, d4; - char ch; - struct hostent *hp; - long x; - - if (name[0] == 0) { - addr->sin_addr.s_addr = INADDR_ANY; - } - else if (name[0] == '<' && strcmp(name, "") == 0) { - addr->sin_addr.s_addr = INADDR_BROADCAST; - } - else if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && - 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && - 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { - addr->sin_addr.s_addr = htonl( - ((long) d1 << 24) | ((long) d2 << 16) | - ((long) d3 << 8) | ((long) d4 << 0)); - } - else { - hp = gethostbyname(name); - if (!hp) { -#ifdef HAVE_HSTRERROR - extern int h_errno; - Raise(eSocket, (char *)hstrerror(h_errno)); -#else - Raise(eSocket, "host not found"); -#endif - } - memcpy((char *) &addr->sin_addr, hp->h_addr, hp->h_length); - } -} - -static VALUE -mkipaddr(x) - unsigned long x; -{ - char buf[16]; - - x = ntohl(x); - sprintf(buf, "%d.%d.%d.%d", - (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, - (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff); - return str_new2(buf); -} - -static VALUE -ipaddr(sockaddr) - struct sockaddr_in *sockaddr; -{ - VALUE family, port, addr1, addr2; - VALUE ary; - struct hostent *hostent; - - family = str_new2("AF_INET"); - hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr, - sizeof(sockaddr->sin_addr), - AF_INET); - addr1 = 0; - if (hostent) { - addr1 = str_new2(hostent->h_name); - } - addr2 = mkipaddr(sockaddr->sin_addr.s_addr); - if (!addr1) addr1 = addr2; - - port = INT2FIX(ntohs(sockaddr->sin_port)); - ary = ary_new3(4, family, port, addr1, addr2); - - return ary; -} - static VALUE ip_addr(sock) VALUE sock; @@ -781,13 +902,12 @@ ip_s_getaddress(obj, host) { struct sockaddr_in addr; - if (obj_is_kind_of(host, cInteger)) { + if (rb_obj_is_kind_of(host, rb_cInteger)) { int i = NUM2INT(host); addr.sin_addr.s_addr = htonl(i); } else { - Check_Type(host, T_STRING); - setipaddr(RSTRING(host)->ptr, &addr); + setipaddr(STR2CSTR(host), &addr); } return mkipaddr(addr.sin_addr.s_addr); @@ -805,37 +925,36 @@ udp_addrsetup(host, port, addr) VALUE host, port; struct sockaddr_in *addr; { - struct hostent *hostent; - memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; if (NIL_P(host)) { addr->sin_addr.s_addr = INADDR_ANY; } - else if (obj_is_kind_of(host, cInteger)) { + else if (rb_obj_is_kind_of(host, rb_cInteger)) { int i = NUM2INT(host); addr->sin_addr.s_addr = htonl(i); } else { - Check_Type(host, T_STRING); - setipaddr(RSTRING(host)->ptr, addr); + setipaddr(STR2CSTR(host), addr); } if (FIXNUM_P(port)) { - addr->sin_port = FIX2INT(port); + addr->sin_port = htons(FIX2INT(port)); } else { struct servent *servent; - Check_Type(port, T_STRING); - servent = getservbyname(RSTRING(port)->ptr, "udp"); + servent = getservbyname(STR2CSTR(port), "udp"); if (servent) { addr->sin_port = servent->s_port; } else { - int port = strtoul(RSTRING(port)->ptr, 0, 0); + char *s = STR2CSTR(port); + char *end; + int portno; - if (port == -1) { - Raise(eSocket, "no such servce %s", RSTRING(port)->ptr); + portno = strtoul(s, &end, 0); + if (*end != '\0') { + rb_raise(rb_eSocket, "no such servce %s", s); } addr->sin_port = htons(port); } @@ -859,8 +978,8 @@ udp_connect(sock, host, port) #if EAGAIN != EWOULDBLOCK case EAGAIN: #endif -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif goto retry; } @@ -896,19 +1015,21 @@ udp_send(argc, argv, sock) OpenFile *fptr; FILE *f; int n; + char *m; + int mlen; if (argc == 2) { return bsock_send(argc, argv, sock); } rb_scan_args(argc, argv, "4", &mesg, &flags, &host, &port); - Check_Type(mesg, T_STRING); udp_addrsetup(host, port, &addr); GetOpenFile(sock, fptr); - f = fptr->f2?fptr->f2:fptr->f; + f = GetWriteFile(fptr); + m = rb_str2cstr(mesg, &mlen); retry: - n = sendto(fileno(f), RSTRING(mesg)->ptr, RSTRING(mesg)->len, - NUM2INT(flags), (struct sockaddr*)&addr, sizeof(addr)); + n = sendto(fileno(f), m, mlen, NUM2INT(flags), + (struct sockaddr*)&addr, sizeof(addr)); if (n < 0) { switch (errno) { case EINTR: @@ -916,8 +1037,8 @@ udp_send(argc, argv, sock) #if EAGAIN != EWOULDBLOCK case EAGAIN: #endif -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif goto retry; } @@ -957,14 +1078,14 @@ unix_path(sock) rb_sys_fail(0); fptr->path = strdup(addr.sun_path); } - return str_new2(fptr->path); + return rb_str_new2(fptr->path); } static VALUE -unix_svr_s_open(class, path) - VALUE class, path; +unix_svr_s_open(sock, path) + VALUE sock, path; { - return open_unix(class, path, 1); + return open_unix(sock, path, 1); } static VALUE @@ -986,7 +1107,7 @@ unix_accept(sock) GetOpenFile(sock, fptr); fromlen = sizeof(struct sockaddr_un); - return s_accept(cUNIXsocket, fileno(fptr->f), + return s_accept(rb_cUNIXsocket, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); } @@ -994,7 +1115,7 @@ static VALUE unixaddr(sockaddr) struct sockaddr_un *sockaddr; { - return assoc_new(str_new2("AF_UNIX"),str_new2(sockaddr->sun_path)); + return rb_assoc_new(rb_str_new2("AF_UNIX"),rb_str_new2(sockaddr->sun_path)); } static VALUE @@ -1055,8 +1176,10 @@ setup_domain_and_type(domain, dv, type, tv) else if (strcmp(ptr, "AF_IMPLINK") == 0) *dv = AF_IMPLINK; #endif +#ifdef PF_INET else if (strcmp(ptr, "PF_INET") == 0) *dv = PF_INET; +#endif #ifdef PF_UNIX else if (strcmp(ptr, "PF_UNIX") == 0) *dv = PF_UNIX; @@ -1076,7 +1199,7 @@ setup_domain_and_type(domain, dv, type, tv) *dv = PF_IPX; #endif else - Raise(eSocket, "Unknown socket domain %s", ptr); + rb_raise(rb_eSocket, "Unknown socket domain %s", ptr); } else { *dv = NUM2INT(domain); @@ -1104,7 +1227,7 @@ setup_domain_and_type(domain, dv, type, tv) *tv = SOCK_PACKET; #endif else - Raise(eSocket, "Unknown socket type %s", ptr); + rb_raise(rb_eSocket, "Unknown socket type %s", ptr); } else { *tv = NUM2INT(type); @@ -1121,6 +1244,7 @@ sock_s_open(class, domain, type, protocol) setup_domain_and_type(domain, &d, type, &t); fd = socket(d, t, NUM2INT(protocol)); if (fd < 0) rb_sys_fail("socket(2)"); + return sock_new(class, fd); } @@ -1135,15 +1259,14 @@ static VALUE sock_s_socketpair(class, domain, type, protocol) VALUE class, domain, type, protocol; { -#if !defined(__CYGWIN32__) && !defined(NT) - int fd; +#if !defined(NT) && !defined(__BEOS__) int d, t, sp[2]; setup_domain_and_type(domain, &d, type, &t); if (socketpair(d, t, NUM2INT(protocol), sp) < 0) rb_sys_fail("socketpair(2)"); - return assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1])); + return rb_assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1])); #else rb_notimplement(); #endif @@ -1156,7 +1279,7 @@ sock_connect(sock, addr) OpenFile *fptr; Check_Type(addr, T_STRING); - str_modify(addr); + rb_str_modify(addr); GetOpenFile(sock, fptr); retry: @@ -1167,8 +1290,8 @@ sock_connect(sock, addr) #if EAGAIN != EWOULDBLOCK case EAGAIN: #endif -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif goto retry; } @@ -1185,7 +1308,7 @@ sock_bind(sock, addr) OpenFile *fptr; Check_Type(addr, T_STRING); - str_modify(addr); + rb_str_modify(addr); GetOpenFile(sock, fptr); if (bind(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len) < 0) @@ -1226,9 +1349,9 @@ sock_accept(sock) int len = sizeof buf; GetOpenFile(sock, fptr); - sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len); + sock2 = s_accept(rb_cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len); - return assoc_new(sock2, str_new(buf, len)); + return rb_assoc_new(sock2, rb_str_new(buf, len)); } #ifdef HAVE_GETHOSTNAME @@ -1242,7 +1365,7 @@ sock_gethostname(obj) rb_sys_fail("gethostname"); buf[sizeof buf - 1] = '\0'; - return str_new2(buf); + return rb_str_new2(buf); } #else #ifdef HAVE_UNAME @@ -1256,7 +1379,7 @@ sock_gethostname(obj) struct utsname un; uname(&un); - return str_new2(un.nodename); + return rb_str_new2(un.nodename); } #else static VALUE @@ -1272,32 +1395,31 @@ static VALUE mkhostent(h) struct hostent *h; { - struct sockaddr_in addr; char **pch; VALUE ary, names; if (h == NULL) { #ifdef HAVE_HSTRERROR extern int h_errno; - Raise(eSocket, (char *)hstrerror(h_errno)); + rb_raise(rb_eSocket, (char *)hstrerror(h_errno)); #else - Raise(eSocket, "host not found"); + rb_raise(rb_eSocket, "host not found"); #endif } - ary = ary_new(); - ary_push(ary, str_new2(h->h_name)); - names = ary_new(); - ary_push(ary, names); + ary = rb_ary_new(); + rb_ary_push(ary, rb_str_new2(h->h_name)); + names = rb_ary_new(); + rb_ary_push(ary, names); for (pch = h->h_aliases; *pch; pch++) { - ary_push(names, str_new2(*pch)); + rb_ary_push(names, rb_str_new2(*pch)); } - ary_push(ary, INT2FIX(h->h_length)); + rb_ary_push(ary, NUM2INT(h->h_addrtype)); #ifdef h_addr for (pch = h->h_addr_list; *pch; pch++) { - ary_push(ary, str_new(*pch, h->h_length)); + rb_ary_push(ary, rb_str_new(*pch, h->h_length)); } #else - ary_push(ary, str_new(h->h_addr, h->h_length)); + rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length)); #endif return ary; @@ -1310,13 +1432,12 @@ sock_s_gethostbyname(obj, host) struct sockaddr_in addr; struct hostent *h; - if (obj_is_kind_of(host, cInteger)) { + if (rb_obj_is_kind_of(host, rb_cInteger)) { int i = NUM2INT(host); addr.sin_addr.s_addr = htonl(i); } else { - Check_Type(host, T_STRING); - setipaddr(RSTRING(host)->ptr, &addr); + setipaddr(STR2CSTR(host), &addr); } h = gethostbyaddr((char *)&addr.sin_addr, sizeof(addr.sin_addr), @@ -1332,20 +1453,20 @@ sock_s_gethostbyaddr(argc, argv) { VALUE vaddr, vtype; int type; - - struct sockaddr_in *addr; + int alen; + char *addr; struct hostent *h; - rb_scan_args(argc, argv, "11", &addr, &type); - Check_Type(addr, T_STRING); - if (!NIL_P(type)) { + rb_scan_args(argc, argv, "11", &vaddr, &vtype); + addr = rb_str2cstr(vaddr, &alen); + if (!NIL_P(vtype)) { type = NUM2INT(vtype); } else { type = AF_INET; } - h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len, type); + h = gethostbyaddr(addr, alen, type); return mkhostent(h); } @@ -1361,15 +1482,22 @@ sock_s_getservbyaname(argc, argv) int port; rb_scan_args(argc, argv, "11", &service, &protocol); - Check_Type(service, T_STRING); if (NIL_P(protocol)) proto = "tcp"; - else proto = RSTRING(protocol)->ptr; + else proto = STR2CSTR(protocol); - sp = getservbyname(RSTRING(service)->ptr, proto); - if (!sp) { - Raise(eSocket, "service/proto not found"); + sp = getservbyname(STR2CSTR(service), proto); + if (sp) { + port = ntohs(sp->s_port); + } + else { + char *s = STR2CSTR(service); + char *end; + + port = strtoul(s, &end, 0); + if (*end != '\0') { + rb_raise(rb_eSocket, "no such servce %s/%s", s, proto); + } } - port = ntohs(sp->s_port); return INT2FIX(port); } @@ -1377,225 +1505,240 @@ sock_s_getservbyaname(argc, argv) static VALUE mConst; static void -sock_define_const(name, value) +sock_rb_define_const(name, value) char *name; - INT value; + int value; { - rb_define_const(cSocket, name, INT2FIX(value)); + rb_define_const(rb_cSocket, name, INT2FIX(value)); rb_define_const(mConst, name, INT2FIX(value)); } Init_socket() { - eSocket = rb_define_class("SocketError", eException); - - cBasicSocket = rb_define_class("BasicSocket", cIO); - rb_undef_method(CLASS_OF(cBasicSocket), "new"); - rb_undef_method(CLASS_OF(cBasicSocket), "open"); - rb_define_method(cBasicSocket, "shutdown", bsock_shutdown, -1); - rb_define_method(cBasicSocket, "setsockopt", bsock_setsockopt, 3); - rb_define_method(cBasicSocket, "getsockopt", bsock_getsockopt, 2); - rb_define_method(cBasicSocket, "getsockname", bsock_getsockname, 0); - rb_define_method(cBasicSocket, "getpeername", bsock_getpeername, 0); - rb_define_method(cBasicSocket, "send", bsock_send, -1); - rb_define_method(cBasicSocket, "recv", bsock_recv, -1); - - cIPsocket = rb_define_class("IPsocket", cBasicSocket); - rb_define_method(cIPsocket, "addr", ip_addr, 0); - rb_define_method(cIPsocket, "peeraddr", ip_peeraddr, 0); - rb_define_singleton_method(cIPsocket, "getaddress", ip_s_getaddress, 1); - - cTCPsocket = rb_define_class("TCPsocket", cIPsocket); - rb_define_singleton_method(cTCPsocket, "open", tcp_s_open, 2); - rb_define_singleton_method(cTCPsocket, "new", tcp_s_open, 2); - rb_define_method(cTCPsocket, "recvfrom", tcp_recvfrom, -1); + rb_eSocket = rb_define_class("SocketError", rb_eStandardError); + + rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO); + rb_undef_method(CLASS_OF(rb_cBasicSocket), "new"); + rb_undef_method(CLASS_OF(rb_cBasicSocket), "open"); + rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0); + rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0); + rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1); + rb_define_method(rb_cBasicSocket, "setsockopt", bsock_setsockopt, 3); + rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2); + rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0); + rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0); + rb_define_method(rb_cBasicSocket, "send", bsock_send, -1); + rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1); + + rb_cIPsocket = rb_define_class("IPsocket", rb_cBasicSocket); + rb_define_method(rb_cIPsocket, "addr", ip_addr, 0); + rb_define_method(rb_cIPsocket, "peeraddr", ip_peeraddr, 0); + rb_define_singleton_method(rb_cIPsocket, "getaddress", ip_s_getaddress, 1); + + rb_cTCPsocket = rb_define_class("TCPsocket", rb_cIPsocket); + rb_define_singleton_method(rb_cTCPsocket, "open", tcp_s_open, 2); + rb_define_singleton_method(rb_cTCPsocket, "new", tcp_s_open, 2); + rb_define_singleton_method(rb_cTCPsocket, "gethostbyname", tcp_s_gethostbyname, 1); + rb_define_method(rb_cTCPsocket, "recvfrom", tcp_recvfrom, -1); #ifdef SOCKS - cSOCKSsocket = rb_define_class("SOCKSsocket", cTCPsocket); - rb_define_singleton_method(cSOCKSsocket, "open", socks_s_open, 2); - rb_define_singleton_method(cSOCKSsocket, "new", socks_s_open, 2); + rb_cSOCKSsocket = rb_define_class("SOCKSsocket", rb_cTCPsocket); + rb_define_singleton_method(rb_cSOCKSsocket, "open", socks_s_open, 2); + rb_define_singleton_method(rb_cSOCKSsocket, "new", socks_s_open, 2); #endif - cTCPserver = rb_define_class("TCPserver", cTCPsocket); - rb_define_singleton_method(cTCPserver, "open", tcp_svr_s_open, -1); - rb_define_singleton_method(cTCPserver, "new", tcp_svr_s_open, -1); - rb_define_method(cTCPserver, "accept", tcp_accept, 0); + rb_cTCPserver = rb_define_class("TCPserver", rb_cTCPsocket); + rb_define_singleton_method(rb_cTCPserver, "open", tcp_svr_s_open, -1); + rb_define_singleton_method(rb_cTCPserver, "new", tcp_svr_s_open, -1); + rb_define_method(rb_cTCPserver, "accept", tcp_accept, 0); - cUDPsocket = rb_define_class("UDPsocket", cIPsocket); - rb_define_singleton_method(cUDPsocket, "open", udp_s_open, 0); - rb_define_singleton_method(cUDPsocket, "new", udp_s_open, 0); - rb_define_method(cUDPsocket, "connect", udp_connect, 2); - rb_define_method(cUDPsocket, "bind", udp_bind, 2); - rb_define_method(cUDPsocket, "send", udp_send, -1); - rb_define_method(cUDPsocket, "recvfrom", udp_recvfrom, -1); + rb_cUDPsocket = rb_define_class("UDPsocket", rb_cIPsocket); + rb_define_singleton_method(rb_cUDPsocket, "open", udp_s_open, 0); + rb_define_singleton_method(rb_cUDPsocket, "new", udp_s_open, 0); + rb_define_method(rb_cUDPsocket, "connect", udp_connect, 2); + rb_define_method(rb_cUDPsocket, "bind", udp_bind, 2); + rb_define_method(rb_cUDPsocket, "send", udp_send, -1); + rb_define_method(rb_cUDPsocket, "recvfrom", udp_recvfrom, -1); #ifdef HAVE_SYS_UN_H - cUNIXsocket = rb_define_class("UNIXsocket", cBasicSocket); - rb_define_singleton_method(cUNIXsocket, "open", unix_s_sock_open, 1); - rb_define_singleton_method(cUNIXsocket, "new", unix_s_sock_open, 1); - rb_define_method(cUNIXsocket, "path", unix_path, 0); - rb_define_method(cUNIXsocket, "addr", unix_addr, 0); - rb_define_method(cUNIXsocket, "peeraddr", unix_peeraddr, 0); - rb_define_method(cUNIXsocket, "recvfrom", unix_recvfrom, -1); - - cUNIXserver = rb_define_class("UNIXserver", cUNIXsocket); - rb_define_singleton_method(cUNIXserver, "open", unix_svr_s_open, 1); - rb_define_singleton_method(cUNIXserver, "new", unix_svr_s_open, 1); - rb_define_method(cUNIXserver, "accept", unix_accept, 0); -#endif - - cSocket = rb_define_class("Socket", cBasicSocket); - rb_define_singleton_method(cSocket, "open", sock_s_open, 3); - rb_define_singleton_method(cSocket, "new", sock_s_open, 3); - rb_define_singleton_method(cSocket, "for_fd", sock_s_for_fd, 1); - - rb_define_method(cSocket, "connect", sock_connect, 1); - rb_define_method(cSocket, "bind", sock_bind, 1); - rb_define_method(cSocket, "listen", sock_listen, 1); - rb_define_method(cSocket, "accept", sock_accept, 0); - - rb_define_method(cSocket, "recvfrom", sock_recvfrom, -1); - - rb_define_singleton_method(cSocket, "socketpair", sock_s_socketpair, 3); - rb_define_singleton_method(cSocket, "pair", sock_s_socketpair, 3); - rb_define_singleton_method(cSocket, "gethostname", sock_gethostname, 0); - rb_define_singleton_method(cSocket, "gethostbyname", sock_s_gethostbyname, 1); - rb_define_singleton_method(cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); - rb_define_singleton_method(cSocket, "getservbyname", sock_s_getservbyaname, -1); + rb_cUNIXsocket = rb_define_class("UNIXsocket", rb_cBasicSocket); + rb_define_singleton_method(rb_cUNIXsocket, "open", unix_s_sock_open, 1); + rb_define_singleton_method(rb_cUNIXsocket, "new", unix_s_sock_open, 1); + rb_define_method(rb_cUNIXsocket, "path", unix_path, 0); + rb_define_method(rb_cUNIXsocket, "addr", unix_addr, 0); + rb_define_method(rb_cUNIXsocket, "peeraddr", unix_peeraddr, 0); + rb_define_method(rb_cUNIXsocket, "recvfrom", unix_recvfrom, -1); + + rb_cUNIXserver = rb_define_class("UNIXserver", rb_cUNIXsocket); + rb_define_singleton_method(rb_cUNIXserver, "open", unix_svr_s_open, 1); + rb_define_singleton_method(rb_cUNIXserver, "new", unix_svr_s_open, 1); + rb_define_method(rb_cUNIXserver, "accept", unix_accept, 0); +#endif + + rb_cSocket = rb_define_class("Socket", rb_cBasicSocket); + rb_define_singleton_method(rb_cSocket, "open", sock_s_open, 3); + rb_define_singleton_method(rb_cSocket, "new", sock_s_open, 3); + rb_define_singleton_method(rb_cSocket, "for_fd", sock_s_for_fd, 1); + + rb_define_method(rb_cSocket, "connect", sock_connect, 1); + rb_define_method(rb_cSocket, "bind", sock_bind, 1); + rb_define_method(rb_cSocket, "listen", sock_listen, 1); + rb_define_method(rb_cSocket, "accept", sock_accept, 0); + + rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1); + + rb_define_singleton_method(rb_cSocket, "socketpair", sock_s_socketpair, 3); + rb_define_singleton_method(rb_cSocket, "pair", sock_s_socketpair, 3); + rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0); + rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1); + rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1); + rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyaname, -1); /* constants */ - mConst = rb_define_module_under(cSocket, "Constants"); - sock_define_const("SOCK_STREAM", SOCK_STREAM); - sock_define_const("SOCK_DGRAM", SOCK_DGRAM); - sock_define_const("SOCK_RAW", SOCK_RAW); + mConst = rb_define_module_under(rb_cSocket, "Constants"); + sock_rb_define_const("SOCK_STREAM", SOCK_STREAM); + sock_rb_define_const("SOCK_DGRAM", SOCK_DGRAM); +#ifdef SOCK_RAW + sock_rb_define_const("SOCK_RAW", SOCK_RAW); +#endif #ifdef SOCK_RDM - sock_define_const("SOCK_RDM", SOCK_RDM); + sock_rb_define_const("SOCK_RDM", SOCK_RDM); #endif #ifdef SOCK_SEQPACKET - sock_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET); + sock_rb_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET); #endif #ifdef SOCK_PACKET - sock_define_const("SOCK_PACKET", SOCK_PACKET); + sock_rb_define_const("SOCK_PACKET", SOCK_PACKET); #endif - sock_define_const("AF_INET", AF_INET); - sock_define_const("PF_INET", PF_INET); + sock_rb_define_const("AF_INET", AF_INET); +#ifdef PF_INET + sock_rb_define_const("PF_INET", PF_INET); +#endif #ifdef AF_UNIX - sock_define_const("AF_UNIX", AF_UNIX); - sock_define_const("PF_UNIX", PF_UNIX); + sock_rb_define_const("AF_UNIX", AF_UNIX); + sock_rb_define_const("PF_UNIX", PF_UNIX); #endif #ifdef AF_AX25 - sock_define_const("AF_AX25", AF_AX25); - sock_define_const("PF_AX25", PF_AX25); + sock_rb_define_const("AF_AX25", AF_AX25); + sock_rb_define_const("PF_AX25", PF_AX25); #endif #ifdef AF_IPX - sock_define_const("AF_IPX", AF_IPX); - sock_define_const("PF_IPX", PF_IPX); + sock_rb_define_const("AF_IPX", AF_IPX); + sock_rb_define_const("PF_IPX", PF_IPX); #endif #ifdef AF_APPLETALK - sock_define_const("AF_APPLETALK", AF_APPLETALK); - sock_define_const("PF_APPLETALK", PF_APPLETALK); + sock_rb_define_const("AF_APPLETALK", AF_APPLETALK); + sock_rb_define_const("PF_APPLETALK", PF_APPLETALK); #endif - sock_define_const("MSG_OOB", MSG_OOB); - sock_define_const("MSG_PEEK", MSG_PEEK); - sock_define_const("MSG_DONTROUTE", MSG_DONTROUTE); + sock_rb_define_const("MSG_OOB", MSG_OOB); +#ifdef MSG_PEEK + sock_rb_define_const("MSG_PEEK", MSG_PEEK); +#endif +#ifdef MSG_DONTROUTE + sock_rb_define_const("MSG_DONTROUTE", MSG_DONTROUTE); +#endif - sock_define_const("SOL_SOCKET", SOL_SOCKET); + sock_rb_define_const("SOL_SOCKET", SOL_SOCKET); #ifdef SOL_IP - sock_define_const("SOL_IP", SOL_IP); + sock_rb_define_const("SOL_IP", SOL_IP); #endif #ifdef SOL_IPX - sock_define_const("SOL_IPX", SOL_IPX); + sock_rb_define_const("SOL_IPX", SOL_IPX); #endif #ifdef SOL_AX25 - sock_define_const("SOL_AX25", SOL_AX25); + sock_rb_define_const("SOL_AX25", SOL_AX25); #endif #ifdef SOL_ATALK - sock_define_const("SOL_ATALK", SOL_ATALK); + sock_rb_define_const("SOL_ATALK", SOL_ATALK); #endif #ifdef SOL_TCP - sock_define_const("SOL_TCP", SOL_TCP); + sock_rb_define_const("SOL_TCP", SOL_TCP); #endif #ifdef SOL_UDP - sock_define_const("SOL_UDP", SOL_UDP); + sock_rb_define_const("SOL_UDP", SOL_UDP); #endif #ifdef SO_DEBUG - sock_define_const("SO_DEBUG", SO_DEBUG); + sock_rb_define_const("SO_DEBUG", SO_DEBUG); #endif - sock_define_const("SO_REUSEADDR", SO_REUSEADDR); + sock_rb_define_const("SO_REUSEADDR", SO_REUSEADDR); #ifdef SO_TYPE - sock_define_const("SO_TYPE", SO_TYPE); + sock_rb_define_const("SO_TYPE", SO_TYPE); #endif #ifdef SO_ERROR - sock_define_const("SO_ERROR", SO_ERROR); + sock_rb_define_const("SO_ERROR", SO_ERROR); #endif #ifdef SO_DONTROUTE - sock_define_const("SO_DONTROUTE", SO_DONTROUTE); + sock_rb_define_const("SO_DONTROUTE", SO_DONTROUTE); #endif #ifdef SO_BROADCAST - sock_define_const("SO_BROADCAST", SO_BROADCAST); + sock_rb_define_const("SO_BROADCAST", SO_BROADCAST); #endif #ifdef SO_SNDBUF - sock_define_const("SO_SNDBUF", SO_SNDBUF); + sock_rb_define_const("SO_SNDBUF", SO_SNDBUF); #endif #ifdef SO_RCVBUF - sock_define_const("SO_RCVBUF", SO_RCVBUF); + sock_rb_define_const("SO_RCVBUF", SO_RCVBUF); +#endif +#ifdef SO_KEEPALIVE + sock_rb_define_const("SO_KEEPALIVE", SO_KEEPALIVE); #endif - sock_define_const("SO_KEEPALIVE", SO_KEEPALIVE); #ifdef SO_OOBINLINE - sock_define_const("SO_OOBINLINE", SO_OOBINLINE); + sock_rb_define_const("SO_OOBINLINE", SO_OOBINLINE); #endif #ifdef SO_NO_CHECK - sock_define_const("SO_NO_CHECK", SO_NO_CHECK); + sock_rb_define_const("SO_NO_CHECK", SO_NO_CHECK); #endif #ifdef SO_PRIORITY - sock_define_const("SO_PRIORITY", SO_PRIORITY); + sock_rb_define_const("SO_PRIORITY", SO_PRIORITY); +#endif +#ifdef SO_LINGER + sock_rb_define_const("SO_LINGER", SO_LINGER); #endif - sock_define_const("SO_LINGER", SO_LINGER); #ifdef SOPRI_INTERACTIVE - sock_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE); + sock_rb_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE); #endif #ifdef SOPRI_NORMAL - sock_define_const("SOPRI_NORMAL", SOPRI_NORMAL); + sock_rb_define_const("SOPRI_NORMAL", SOPRI_NORMAL); #endif #ifdef SOPRI_BACKGROUND - sock_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND); + sock_rb_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND); #endif #ifdef IP_MULTICAST_IF - sock_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF); + sock_rb_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF); #endif #ifdef IP_MULTICAST_TTL - sock_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL); + sock_rb_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL); #endif #ifdef IP_MULTICAST_LOOP - sock_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP); + sock_rb_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP); #endif #ifdef IP_ADD_MEMBERSHIP - sock_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP); + sock_rb_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP); #endif #ifdef IP_DEFAULT_MULTICAST_TTL - sock_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL); + sock_rb_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL); #endif #ifdef IP_DEFAULT_MULTICAST_LOOP - sock_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP); + sock_rb_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP); #endif #ifdef IP_MAX_MEMBERSHIPS - sock_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS); + sock_rb_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS); #endif #ifdef IPX_TYPE - sock_define_const("IPX_TYPE", IPX_TYPE); + sock_rb_define_const("IPX_TYPE", IPX_TYPE); #endif #ifdef TCP_NODELAY - sock_define_const("TCP_NODELAY", TCP_NODELAY); + sock_rb_define_const("TCP_NODELAY", TCP_NODELAY); #endif #ifdef TCP_MAXSEG - sock_define_const("TCP_MAXSEG", TCP_MAXSEG); + sock_rb_define_const("TCP_MAXSEG", TCP_MAXSEG); #endif } diff --git a/ext/tcltklib/extconf.rb b/ext/tcltklib/extconf.rb index 26e7fe7b09..e34e549ca0 100644 --- a/ext/tcltklib/extconf.rb +++ b/ext/tcltklib/extconf.rb @@ -1,19 +1,27 @@ # extconf.rb for tcltklib +require 'mkmf' + +have_library("nsl", "t_open") have_library("socket", "socket") -have_library("nsl", "gethostbyname") +have_library("dl", "dlopen") +have_library("m", "log") -def search_file(var, include, *path) +$includes = [] +def search_header(include, *path) pwd = Dir.getwd begin - for i in path.reverse! + for i in path.sort!.reverse! dir = Dir[i] - for path in dir + for path in dir.sort!.reverse! + next unless File.directory? path Dir.chdir path files = Dir[include] if files.size > 0 - var << path - return files.pop + unless $includes.include? path + $includes << path + end + return end end end @@ -22,58 +30,56 @@ def search_file(var, include, *path) end end -$includes = [] -search_file($includes, - "tcl.h", - "/usr/include/tcl*", - "/usr/include", - "/usr/local/include/tcl*", - "/usr/local/include") -search_file($includes, - "tk.h", - "/usr/include/tk*", - "/usr/include", - "/usr/local/include/tk*", - "/usr/local/include") -search_file($includes, - "X11/Xlib.h", - "/usr/include", - "/usr/X11*/include", - "/usr/include", - "/usr/X11*/include") +search_header("tcl.h", + "/usr/include/tcl{,8*,7*}", + "/usr/include", + "/usr/local/include/tcl{,8*,7*}", + "/usr/local/include") +search_header("tk.h", + "/usr/include/tk{,8*,4*}", + "/usr/include", + "/usr/local/include/tk{,8*,4*}", + "/usr/local/include") +search_header("X11/Xlib.h", + "/usr/include/X11*", + "/usr/include", + "/usr/openwin/include", + "/usr/X11*/include") -$CFLAGS = "-Wall " + $includes.collect{|path| "-I" + path}.join(" ") +$CFLAGS = $includes.collect{|path| "-I" + path}.join(" ") $libraries = [] -tcllibfile = search_file($libraries, - "libtcl{,7*,8*}.{a,so}", - "/usr/lib", - "/usr/local/lib") -if tcllibfile - tcllibfile.sub!(/^lib/, '') - tcllibfile.sub!(/\.(a|so)$/, '') -end -tklibfile = search_file($libraries, - "libtk{,4*,8*}.{a,so}", - "/usr/lib", - "/usr/local/lib") -if tklibfile - tklibfile.sub!(/^lib/, '') - tklibfile.sub!(/\.(a|so)$/, '') +def search_lib(file, func, *path) + for i in path.reverse! + dir = Dir[i] + for path in dir.sort!.reverse! + $LDFLAGS = $libraries.collect{|p| "-L" + p}.join(" ") + " -L" + path + files = Dir[path+"/"+file] + if files.size > 0 + for lib in files.sort!.reverse! + lib = File::basename(lib) + lib.sub!(/^lib/, '') + lib.sub!(/\.(a|so)$/, '') + if have_library(lib, func) + unless $libraries.include? path + $libraries << path + end + return true + end + end + end + end + end + return false; end -search_file($libraries, - "libX11.{a,so}", - "/usr/lib", - "/usr/X11*/lib") -$LDFLAGS = $libraries.collect{|path| "-L" + path}.join(" ") - -have_library("dl", "dlopen") -if have_header("tcl.h") && - have_header("tk.h") && - have_library("X11", "XOpenDisplay") && - have_library("m", "log") && - have_library(tcllibfile, "Tcl_FindExecutable") && - have_library(tklibfile, "Tk_Init") +if have_header("tcl.h") && have_header("tk.h") && + search_lib("libX11.{so,a}", "XOpenDisplay", + "/usr/lib", "/usr/openwin/lib", "/usr/X11*/lib") && + search_lib("libtcl{8*,7*,}.{so,a}", "Tcl_FindExecutable", + "/usr/lib", "/usr/local/lib") && + search_lib("libtk{8*,4*,}.{so,a}", "Tk_Init", + "/usr/lib", "/usr/local/lib") + $LDFLAGS = $libraries.collect{|path| "-L" + path}.join(" ") create_makefile("tcltklib") end diff --git a/ext/tcltklib/lib/tcltk.rb b/ext/tcltklib/lib/tcltk.rb index 81d01f930d..54a00e8f3c 100644 --- a/ext/tcltklib/lib/tcltk.rb +++ b/ext/tcltklib/lib/tcltk.rb @@ -1,48 +1,44 @@ # tof -#### tcltk ĄéĄ¤ĄÖĄéĄę +#### tcltk library, more direct manipulation of tcl/tk #### Sep. 5, 1997 Y. Shigehiro require "tcltklib" ################ -# module TclTk: tcl/tk ¤ÎĄéĄ¤ĄÖĄéĄęÁ´ÂΤÇɬÍפˤʤë¤â¤Î¤ň˝¸¤á¤ż¤â¤Î -# (Ľç¤Ë, ĚľÁ°¶ő´Ö¤ÎĹŔ¤«¤é module ¤Ë¤ą¤ë»Č¤¦.) +# module TclTk: collection of tcl/tk utilities (supplies namespace.) module TclTk - # ñ¤Ë¤ł¤ł¤Ë˝ń¤±¤ĐşÇ˝é¤Ë 1 ĹŮĽÂąÔ¤µ¤ě¤ë¤Î¤«?? - - # Ŕ¸Ŕ®¤·¤ż°ě°Ő¤ĘĚľÁ°¤ňĘÝ»ý¤·¤Ć¤Ş¤ŻĎ˘ÁŰÇŰÎó¤ň˝é´ü˛˝¤ą¤ë. + # initialize Hash to hold unique symbols and such @namecnt = {} - # ĄłˇĽĄëĄĐĄĂĄŻ¤ňĘÝ»ý¤·¤Ć¤Ş¤ŻĎ˘ÁŰÇŰÎó¤ň˝é´ü˛˝¤ą¤ë. + # initialize Hash to hold callbacks @callback = {} end -# TclTk.mainloop(): TclTkLib.mainloop() ¤ň¸Ć¤Ö. +# TclTk.mainloop(): call TclTkLib.mainloop() def TclTk.mainloop() print("mainloop: start\n") if $DEBUG TclTkLib.mainloop() print("mainloop: end\n") if $DEBUG end -# TclTk.deletecallbackkey(ca): ĄłˇĽĄëĄĐĄĂĄŻ¤ň TclTk module ¤«¤éĽč¤ę˝ü¤Ż. -# tcl/tk Ą¤ĄóĄżĄ×ĄęĄż¤Ë¤Ş¤¤¤ĆĄłˇĽĄëĄĐĄĂĄŻ¤¬Ľč¤ęľĂ¤µ¤ě¤ë¤ď¤±¤Ç¤Ď¤Ę¤¤. -# ¤ł¤ě¤ň¤·¤Ę¤¤¤Č, şÇ¸ĺ¤Ë TclTkInterpreter ¤¬ GC ¤Ç¤­¤Ę¤¤. -# (GC ¤·¤ż¤Ż¤Ę¤±¤ě¤Đ, Ę̤Ë, ¤ł¤ě¤ň¤·¤Ę¤Ż¤Ć¤âÎɤ¤.) -# ca: ĄłˇĽĄëĄĐĄĂĄŻ(TclTkCallback) +# TclTk.deletecallbackkey(ca): remove callback from TclTk module +# this does not remove callbacks from tcl/tk interpreter +# without calling this method, TclTkInterpreter will not be GCed +# ca: callback(TclTkCallback) def TclTk.deletecallbackkey(ca) print("deletecallbackkey: ", ca.to_s(), "\n") if $DEBUG @callback.delete(ca.to_s) end -# TclTk.dcb(ca, wid, W): ÇŰÎó¤ËĆţ¤Ă¤Ć¤¤¤ëĘŁżô¤ÎĄłˇĽĄëĄĐĄĂĄŻ¤ËÂФ·¤Ć -# TclTk.deletecallbackkey() ¤ň¸Ć¤Ö. -# ĄČĄĂĄ×ĄěĄŮĄë¤Î Ą¤ĄŮĄóĄČ¤ÎĄłˇĽĄëĄĐĄĂĄŻ¤Č¤·¤Ć¸Ć¤Ö¤ż¤á¤Î¤â¤Î. -# ca: ĄłˇĽĄëĄĐĄĂĄŻ(TclTkCallback) ¤Î Array -# wid: ĄČĄĂĄ×ĄěĄŮĄë¤ÎĄ¦ĄŁĄ¸Ą§ĄĂĄČ(TclTkWidget) -# w: ĄłˇĽĄëĄĐĄĂĄŻ¤Ë %W ¤ÇÍż¤¨¤é¤ě¤ë, Ą¦Ą¤ĄóĄÉĄ¦¤Ë´Ř¤ą¤ëĄŃĄéĄáˇĽĄż(String) +# TclTk.dcb(ca, wid, W): call TclTk.deletecallbackkey() for each callbacks +# in an array. +# this is for callback for top-level +# ca: array of callbacks(TclTkCallback) +# wid: top-level widget(TclTkWidget) +# w: information about window given by %W(String) def TclTk.dcb(ca, wid, w) if wid.to_s() == w ca.each{|i| @@ -51,33 +47,33 @@ def TclTk.dcb(ca, wid, w) end end -# TclTk._addcallback(ca): ĄłˇĽĄëĄĐĄĂĄŻ¤ňĹĐĎż¤ą¤ë. -# ca: ĄłˇĽĄëĄĐĄĂĄŻ(TclTkCallback) +# TclTk._addcallback(ca): register callback +# ca: callback(TclTkCallback) def TclTk._addcallback(ca) print("_addcallback: ", ca.to_s(), "\n") if $DEBUG @callback[ca.to_s()] = ca end -# TclTk._callcallback(key, arg): ĹĐĎż¤·¤żĄłˇĽĄëĄĐĄĂĄŻ¤ň¸Ć¤Ó˝Đ¤ą. -# key: ĄłˇĽĄëĄĐĄĂĄŻ¤ňÁŞÂň¤ą¤ëĄ­ˇĽ (TclTkCallback ¤¬ to_s() ¤ÇĘÖ¤ąĂÍ) -# arg: tcl/tk Ą¤ĄóĄżĄ×ĄęĄż¤«¤é¤ÎĄŃĄéĄáˇĽĄż +# TclTk._callcallback(key, arg): invoke registered callback +# key: key to select callback (to_s value of the TclTkCallback) +# arg: parameter from tcl/tk interpreter def TclTk._callcallback(key, arg) print("_callcallback: ", @callback[key].inspect, "\n") if $DEBUG @callback[key]._call(arg) - # ĄłˇĽĄëĄĐĄĂĄŻ¤«¤é¤ÎĘÖ¤ęĂͤϤɤ¦¤»ĽÎ¤Ć¤é¤ě¤ë. - # String ¤ňĘÖ¤µ¤Ę¤¤¤Č, rb_eval_string() ¤¬Ą¨ĄéˇĽ¤Ë¤Ę¤ë. + # throw out callback value + # should return String to satisfy rb_eval_string() return "" end -# TclTk._newname(prefix): °ě°Ő¤ĘĚľÁ°(String)¤ňŔ¸Ŕ®¤·¤ĆĘÖ¤ą. -# prefix: ĚľÁ°¤ÎŔÜƬ¸ě +# TclTk._newname(prefix): generate unique name(String) +# prefix: prefix of the unique name def TclTk._newname(prefix) - # Ŕ¸Ŕ®¤·¤żĚľÁ°¤ÎĄ«Ą¦ĄóĄż¤Ď @namecnt ¤ËĆţ¤Ă¤Ć¤¤¤ë¤Î¤Ç, Ä´¤Ů¤ë. + # generated name counter is stored in @namecnt if !@namecnt.key?(prefix) - # ˝é¤á¤Ć»Č¤¦ŔÜƬ¸ě¤Ę¤Î¤Ç˝é´ü˛˝¤ą¤ë. + # first appearing prefix, initialize @namecnt[prefix] = 1 else - # »Č¤Ă¤ż¤ł¤Č¤Î¤˘¤ëŔÜƬ¸ě¤Ę¤Î¤Ç, Ľˇ¤ÎĚľÁ°¤Ë¤ą¤ë. + # already appeared prefix, generate next name @namecnt[prefix] += 1 end return "#{prefix}#{@namecnt[prefix]}" @@ -85,51 +81,48 @@ end ################ -# class TclTkInterpreter: tcl/tk ¤ÎĄ¤ĄóĄżĄ×ĄęĄż +# class TclTkInterpreter: tcl/tk interpreter class TclTkInterpreter - # initialize(): ˝é´ü˛˝. + # initialize(): def initialize() - # Ą¤ĄóĄżĄ×ĄęĄż¤ňŔ¸Ŕ®¤ą¤ë. + # generate interpreter object @ip = TclTkIp.new() - # Ą¤ĄóĄżĄ×ĄęĄż¤Ë ruby_fmt ĄłĄŢĄóĄÉ¤ňÄɲ乤ë. - # ruby_fmt ĄłĄŢĄóĄÉ¤Č¤Ď, ¸ĺ¤í¤Î°úżô¤ň format ĄłĄŢĄóĄÉ¤Ç˝čÍý¤·¤Ć - # ruby ĄłĄŢĄóĄÉ¤ËĹϤą¤â¤Î¤Ç¤˘¤ë. - # (¤Ę¤Ş, ruby ĄłĄŢĄóĄÉ¤Ď, °úżô¤ň 1 ¤Ä¤·¤«¤Č¤ě¤Ę¤¤.) + # add ruby_fmt command to tcl interpreter + # ruby_fmt command format arguments by `format' and call `ruby' command + # (notice ruby command receives only one argument) if $DEBUG @ip._eval("proc ruby_fmt {fmt args} { puts \"ruby_fmt: $fmt $args\" ; ruby [format $fmt $args] }") else @ip._eval("proc ruby_fmt {fmt args} { ruby [format $fmt $args] }") end - # @ip._get_eval_string(*args): tcl/tk Ą¤ĄóĄżĄ×ĄęĄż¤ÇÉľ˛Á¤ą¤ë - # ʸ»úÎó(String)¤ňŔ¸Ŕ®¤·¤ĆĘÖ¤ą. - # *args: tcl/tk ¤ÇÉľ˛Á¤ą¤ëĄąĄŻĄęĄ×ĄČ(¤ËÂбţ¤ą¤ëĄŞĄÖĄ¸Ą§ĄŻĄČÎó) + # @ip._get_eval_string(*args): generate string to evaluate in tcl interpreter + # *args: script which is going to be evaluated under tcl/tk def @ip._get_eval_string(*args) argstr = "" args.each{|arg| argstr += " " if argstr != "" - # ¤â¤· to_eval() ĄáĄ˝ĄĂĄÉ¤¬ + # call to_eval if it is defined if (arg.respond_to?(:to_eval)) - # ÄęµÁ¤µ¤ě¤Ć¤¤¤ě¤Đ¤˝¤ě¤ň¸Ć¤Ö. argstr += arg.to_eval() else - # ÄęµÁ¤µ¤ě¤Ć¤¤¤Ę¤±¤ě¤Đ to_s() ¤ň¸Ć¤Ö. + # call to_s unless defined argstr += arg.to_s() end } return argstr end - # @ip._eval_args(*args): tcl/tk Ą¤ĄóĄżĄ×ĄęĄż¤ÇÉľ˛Á¤·, - # ¤˝¤Î·ë˛Ě(String)¤ňĘÖ¤ą. - # *args: tcl/tk ¤ÇÉľ˛Á¤ą¤ëĄąĄŻĄęĄ×ĄČ(¤ËÂбţ¤ą¤ëĄŞĄÖĄ¸Ą§ĄŻĄČÎó) + # @ip._eval_args(*args): evaluate string under tcl/tk interpreter + # returns result string. + # *args: script which is going to be evaluated under tcl/tk def @ip._eval_args(*args) - # Ą¤ĄóĄżĄ×ĄęĄż¤ÇÉľ˛Á¤ą¤ëʸ»úÎó¤ňµá¤á¤ë. + # calculate the string to eval in the interpreter argstr = _get_eval_string(*args) - # Ą¤ĄóĄżĄ×ĄęĄż¤ÇÉľ˛Á¤ą¤ë. + # evaluate under the interpreter print("_eval: \"", argstr, "\"") if $DEBUG res = _eval(argstr) if $DEBUG @@ -137,219 +130,205 @@ class TclTkInterpreter elsif _return_value() != 0 print(res, "\n") end - fail(%Q/can't eval "#{argstr}"/) if _return_value() != 0 + fail(%Q/can't eval "#{argstr}"/) if _return_value() != 0 #' return res end - # tcl/tk ¤ÎĄłĄŢĄóĄÉ¤ËÂбţ¤ą¤ëĄŞĄÖĄ¸Ą§ĄŻĄČ¤ňŔ¸Ŕ®¤·, ϢÁŰÇŰÎó¤ËĆţ¤ě¤Ć¤Ş¤Ż. + # generate tcl/tk command object and register in the hash @commands = {} - # tcl/tk Ą¤ĄóĄżĄ×ĄęĄż¤ËĹĐĎż¤µ¤ě¤Ć¤¤¤ë¤ą¤Ů¤Ć¤ÎĄłĄŢĄóĄÉ¤ËÂФ·¤Ć, + # for all commands registered in tcl/tk interpreter: @ip._eval("info command").split(/ /).each{|comname| if comname =~ /^[.]/ - # ĄłĄŢĄóĄÉ¤¬Ą¦ĄŁĄ¸Ą§ĄĂĄČ(¤ÎĄŃĄąĚľ)¤Îľěąç¤Ď - # TclTkWidget ¤ÎĄ¤ĄóĄąĄżĄóĄą¤ňşî¤Ă¤ĆϢÁŰÇŰÎó¤ËĆţ¤ě¤ë. + # if command is a widget (path), generate TclTkWidget, + # and register it in the hash @commands[comname] = TclTkWidget.new(@ip, comname) else - # ¤˝¤¦¤Ç¤Ę¤¤ľěąç¤Ď - # TclTkCommand ¤ÎĄ¤ĄóĄąĄżĄóĄą¤ňşî¤Ă¤ĆϢÁŰÇŰÎó¤ËĆţ¤ě¤ë. + # otherwise, generate TclTkCommand @commands[comname] = TclTkCommand.new(@ip, comname) end } end - # commands(): tcl/tk ¤ÎĄłĄŢĄóĄÉ¤ËÂбţ¤ą¤ëĄŞĄÖĄ¸Ą§ĄŻĄČ¤ň Hash ¤Ë - # Ćţ¤ě¤ż¤â¤Î¤ňĘÖ¤ą. + # commands(): returns hash of the tcl/tk commands def commands() return @commands end - # rootwidget(): ĄëˇĽĄČĄ¦ĄŁĄ¸Ą§ĄĂĄČ(TclTkWidget)¤ňĘÖ¤ą. + # rootwidget(): returns root widget(TclTkWidget) def rootwidget() return @commands["."] end - # _tcltkip(): @ip(TclTkIp) ¤ňĘÖ¤ą. + # _tcltkip(): returns @ip(TclTkIp) def _tcltkip() return @ip end - # method_missing(id, *args): ̤ÄęµÁ¤ÎĄáĄ˝ĄĂĄÉ¤Ď tcl/tk ¤ÎĄłĄŢĄóĄÉ¤Č¤ß¤Ę¤·¤Ć - # ĽÂąÔ¤·, ¤˝¤Î·ë˛Ě(String)¤ňĘÖ¤ą. - # id: ĄáĄ˝ĄĂĄÉ¤ÎĄ·ĄóĄÜĄë - # *args: ĄłĄŢĄóĄÉ¤Î°úżô + # method_missing(id, *args): execute undefined method as tcl/tk command + # id: method symbol + # *args: method arguments def method_missing(id, *args) - # ¤â¤·, ĄáĄ˝ĄĂĄÉ¤Î tcl/tk ĄłĄŢĄóĄÉ¤¬ + # if command named by id registered, then execute it if @commands.key?(id.id2name) - # ¤˘¤ě¤Đ, ĽÂąÔ¤·¤Ć·ë˛Ě¤ňĘÖ¤ą. return @commands[id.id2name].e(*args) else - # ̵¤±¤ě¤Đ¤â¤Č¤â¤Č¤Î˝čÍý. + # otherwise, exception super end end end -# class TclTkObject: tcl/tk ¤ÎĄŞĄÖĄ¸Ą§ĄŻĄČ -# (´đÄ쥯ĄéĄą¤Č¤·¤Ć»Č¤¦. -# tcltk ĄéĄ¤ĄÖĄéĄę¤ň»Č¤¦żÍ¤¬ TclTkObject.new() ¤ą¤ë¤ł¤Č¤Ď¤Ę¤¤¤Ď¤ş.) +# class TclTkObject: base class of the tcl/tk objects class TclTkObject - # initialize(ip, exp): ˝é´ü˛˝. - # ip: Ą¤ĄóĄżĄ×ĄęĄż(TclTkIp) - # exp: tcl/tk ¤Ç¤ÎÉ˝¸˝·Á + # initialize(ip, exp): + # ip: interpreter(TclTkIp) + # exp: tcl/tk representation def initialize(ip, exp) fail("type is not TclTkIp") if !ip.kind_of?(TclTkIp) @ip = ip @exp = exp end - # to_s(): tcl/tk ¤Ç¤ÎÉ˝¸˝·Á(String)¤ňĘÖ¤ą. + # to_s(): returns tcl/tk representation def to_s() return @exp end end -# class TclTkCommand: tcl/tk ¤ÎĄłĄŢĄóĄÉ -# (tcltk ĄéĄ¤ĄÖĄéĄę¤ň»Č¤¦żÍ¤¬ TclTkCommand.new() ¤ą¤ë¤ł¤Č¤Ď¤Ę¤¤¤Ď¤ş. -# TclTkInterpreter:initialize() ¤«¤é new() ¤µ¤ě¤ë.) +# class TclTkCommand: tcl/tk commands +# you should not call TclTkCommand.new() +# commands are created by TclTkInterpreter:initialize() class TclTkCommand < TclTkObject - # e(*args): ĄłĄŢĄóĄÉ¤ňĽÂąÔ¤·, ¤˝¤Î·ë˛Ě(String)¤ňĘÖ¤ą. - # (e ¤Ď exec ¤Ţ¤ż¤Ď eval ¤Î e.) - # *args: ĄłĄŢĄóĄÉ¤Î°úżô + # e(*args): execute command. returns String (e is for exec or eval) + # *args: command arguments def e(*args) return @ip._eval_args(to_s(), *args) end end -# class TclTkLibCommand: tcl/tk ¤ÎĄłĄŢĄóĄÉ -# (ĄéĄ¤ĄÖĄéĄę¤Ë¤č¤ęĽÂ¸˝¤µ¤ě¤ëĄłĄŢĄóĄÉ¤Ç, tcl/tk Ą¤ĄóĄżĄ×ĄęĄż¤ËşÇ˝é¤«¤é -# ¸şß¤·¤Ę¤¤¤â¤Î¤Ď, Ą¤ĄóĄżĄ×ĄęĄż¤Î commands() ¤Ç¤ĎŔ¸Ŕ®¤Ç¤­¤Ę¤¤. -# ¤˝¤Î¤č¤¦¤Ę¤â¤Î¤ËÂФ·, ĄłĄŢĄóĄÉ¤ÎĚľÁ°¤«¤é TclTkCommand ĄŞĄÖĄ¸Ą§ĄŻĄČ¤ň -# Ŕ¸Ŕ®¤ą¤ë. +# class TclTkLibCommand: tcl/tk commands in the library class TclTkLibCommand < TclTkCommand - # initialize(ip, name): ˝é´ü˛˝ - # ip: Ą¤ĄóĄżĄ×ĄęĄż(TclTkInterpreter) - # name: ĄłĄŢĄóĄÉĚľ (String) + # initialize(ip, name): + # ip: interpreter(TclTkInterpreter) + # name: command name (String) def initialize(ip, name) super(ip._tcltkip, name) end end -# class TclTkVariable: tcl/tk ¤ÎĘŃżô +# class TclTkVariable: tcl/tk variable class TclTkVariable < TclTkObject - # initialize(interp, dat): ˝é´ü˛˝. - # interp: Ą¤ĄóĄżĄ×ĄęĄż(TclTkInterpreter) - # dat: ŔßÄꤹ¤ëĂÍ(String) - # nil ¤Ę¤é, ŔßÄꤷ¤Ę¤¤. + # initialize(interp, dat): + # interp: interpreter(TclTkInterpreter) + # dat: the value to set(String) + # if nil, not initialize variable def initialize(interp, dat) - # tcl/tk ¤Ç¤ÎÉ˝¸˝·Á(ĘŃżôĚľ)¤ňĽ«Ć°Ŕ¸Ŕ®¤ą¤ë. + # auto-generate tcl/tk representation (variable name) exp = TclTk._newname("v_") - # TclTkObject ¤ň˝é´ü˛˝¤ą¤ë. + # initialize TclTkObject super(interp._tcltkip(), exp) - # set ĄłĄŢĄóĄÉ¤ň»Č¤¦¤Î¤Ç¤Č¤Ă¤Ć¤Ş¤Ż. + # safe this for `set' command @set = interp.commands()["set"] - # ĂͤňŔßÄꤹ¤ë. + # set value set(dat) if dat end - # tcl/tk ¤Î set ¤ň»Č¤¨¤Đ, ĂͤÎŔßÄę/»˛ľČ¤Ď¤Ç¤­¤ë¤¬, - # ¤˝¤ě¤Ŕ¤±¤Ç¤Ď¤Ę¤ó¤Ę¤Î¤Ç, °ě±ţ, ĄáĄ˝ĄĂĄÉ¤ň¤«¤Ö¤»¤ż¤â¤Î¤âÍŃ°Ő¤·¤Ć¤Ş¤Ż. + # although you can set/refer variable by using set in tcl/tk, + # we provide the method for accessing variables - # set(data): tcl/tk ¤ÎĘŃżô¤Ë set ¤ňÍѤ¤¤ĆĂͤňŔßÄꤹ¤ë. - # data: ŔßÄꤹ¤ëĂÍ + # set(data): set tcl/tk variable using `set' + # data: new value def set(data) @set.e(to_s(), data.to_s()) end - # get(): tcl/tk ¤ÎĘŃżô¤ÎĂÍ(String)¤ň set ¤ňÍѤ¤¤ĆĆɤߤŔ¤·ĘÖ¤ą. + # get(): read tcl/tk variable(String) using `set' def get() return @set.e(to_s()) end end -# class TclTkWidget: tcl/tk ¤ÎĄ¦ĄŁĄ¸Ą§ĄĂĄČ +# class TclTkWidget: tcl/tk widget class TclTkWidget < TclTkCommand - # initialize(*args): ˝é´ü˛˝. - # *args: ĄŃĄéĄáˇĽĄż + # initialize(*args): + # *args: parameters def initialize(*args) if args[0].kind_of?(TclTkIp) - # şÇ˝é¤Î°úżô¤¬ TclTkIp ¤Îľěąç: + # in case the 1st argument is TclTkIp: - # ´ű¤Ë tcl/tk ¤ËÄęµÁ¤µ¤ě¤Ć¤¤¤ëĄ¦ĄŁĄ¸Ą§ĄĂĄČ¤Ë TclTkWidget ¤Îą˝Â¤¤ň - # ¤«¤Ö¤»¤ë. (TclTkInterpreter:initialize() ¤«¤é»Č¤ď¤ě¤ë.) + # Wrap tcl/tk widget by TclTkWidget + # (used in TclTkInterpreter#initialize()) - # ĄŃĄéĄáˇĽĄżżô¤¬ 2 ¤Ç¤Ę¤±¤ě¤ĐĄ¨ĄéˇĽ. + # need two arguments fail("illegal # of parameter") if args.size != 2 - # ip: Ą¤ĄóĄżĄ×ĄęĄż(TclTkIp) - # exp: tcl/tk ¤Ç¤ÎÉ˝¸˝·Á + # ip: interpreter(TclTkIp) + # exp: tcl/tk representation ip, exp = args - # TclTkObject ¤ň˝é´ü˛˝¤ą¤ë. + # initialize TclTkObject super(ip, exp) elsif args[0].kind_of?(TclTkInterpreter) - # şÇ˝é¤Î°úżô¤¬ TclTkInterpreter ¤Îľěąç: + # in case 1st parameter is TclTkInterpreter: - # żĆĄ¦ĄŁĄ¸Ą§ĄĂĄČ¤«¤éż·¤ż¤ĘĄ¦ĄŁĄ¸Ą§ĄČ¤ňŔ¸Ŕ®¤ą¤ë. + # generate new widget from parent widget - # interp: Ą¤ĄóĄżĄ×ĄęĄż(TclTkInterpreter) - # parent: żĆĄ¦ĄŁĄ¸Ą§ĄĂĄČ - # command: Ą¦ĄŁĄ¸Ą§ĄĂĄČ¤ňŔ¸Ŕ®¤ą¤ëĄłĄŢĄóĄÉ(label Ĺů) - # *args: command ¤ËĹϤą°úżô + # interp: interpreter(TclTkInterpreter) + # parent: parent widget + # command: widget generating tk command(label Ĺů) + # *args: argument to the command interp, parent, command, *args = args - # Ą¦ĄŁĄ¸Ą§ĄĂĄČ¤ÎĚľÁ°¤ňşî¤ë. + # generate widget name exp = parent.to_s() exp += "." if exp !~ /[.]$/ exp += TclTk._newname("w_") - # TclTkObject ¤ň˝é´ü˛˝¤ą¤ë. + # initialize TclTkObject super(interp._tcltkip(), exp) - # Ą¦ĄŁĄ¸Ą§ĄĂĄČ¤ňŔ¸Ŕ®¤ą¤ë. + # generate widget res = @ip._eval_args(command, exp, *args) # fail("can't create Widget") if res != exp - # tk_optionMenu ¤Ç¤Ď, ĄÜĄżĄóĚľ¤ň exp ¤Ç»ŘÄꤹ¤ë¤Č - # res ¤ËĄáĄËĄĺˇĽĚľ¤ňĘÖ¤ą¤Î¤Ç res != exp ¤Č¤Ę¤ë. + # for tk_optionMenu, it is legal res != exp else fail("first parameter is not TclTkInterpreter") end end end -# class TclTkCallback: tcl/tk ¤ÎĄłˇĽĄëĄĐĄĂĄŻ +# class TclTkCallback: tcl/tk callbacks class TclTkCallback < TclTkObject - # initialize(interp, pr, arg): ˝é´ü˛˝. - # interp: Ą¤ĄóĄżĄ×ĄęĄż(TclTkInterpreter) - # pr: ĄłˇĽĄëĄĐĄĂĄŻĽęÂł¤­(Proc) - # arg: pr ¤ÎĄ¤ĄĆĄěˇĽĄżĘŃżô¤ËĹϤąĘ¸»úÎó - # tcl/tk ¤Î bind ĄłĄŢĄóĄÉ¤Ç¤ĎĄŃĄéĄáˇĽĄż¤ňĽő¤±Ľč¤ë¤ż¤á¤Ë % ĂÖ´ą¤ň - # ÍѤ¤¤ë¤¬, pr ¤ÎĆâÉô¤Ç % ¤ň˝ń¤¤¤Ć¤â¤¦¤Ţ¤Ż¤¤¤«¤Ę¤¤. - # arg ¤Ëʸ»úÎó¤ň˝ń¤¤¤Ć¤Ş¤Ż¤Č, ¤˝¤ÎĂÖ´ą·ë˛Ě¤ň, pr ¤Ç - # Ą¤ĄĆĄěˇĽĄżĘŃżô¤ňÄ̤·¤ĆĽő¤±Ľč¤ë¤ł¤Č¤¬¤Ç¤­¤ë. - # scrollbar ĄłĄŢĄóĄÉ¤Î -command ĄŞĄ×Ą·ĄçĄó¤Î¤č¤¦¤Ë - # ˛ż¤â»ŘÄꤷ¤Ę¤Ż¤Ć¤âĄŃĄéĄáˇĽĄż¤¬ÉŐ¤ŻĄłĄŢĄóĄÉ¤ËÂФ·¤Ć¤Ď, - # arg ¤ň»ŘÄꤷ¤Ć¤Ď¤Ę¤é¤Ę¤¤. + # initialize(interp, pr, arg): + # interp: interpreter(TclTkInterpreter) + # pr: callback procedure(Proc) + # arg: string to pass as block parameters of pr + # bind command of tcl/tk uses % replacement for parameters + # pr can receive replaced data using block parameter + # its format is specified by arg string + # You should not specify arg for the command like + # scrollbar with -command option, which receives parameters + # without specifying any replacement def initialize(interp, pr, arg = nil) - # tcl/tk ¤Ç¤ÎÉ˝¸˝·Á(ĘŃżôĚľ)¤ňĽ«Ć°Ŕ¸Ŕ®¤ą¤ë. + # auto-generate tcl/tk representation (variable name) exp = TclTk._newname("c_") - # TclTkObject ¤ň˝é´ü˛˝¤ą¤ë. + # initialize TclTkObject super(interp._tcltkip(), exp) - # ĄŃĄéĄáˇĽĄż¤ň¤Č¤Ă¤Ć¤Ş¤Ż. + # save parameters @pr = pr @arg = arg - # ĄâĄ¸ĄĺˇĽĄë¤ËĹĐĎż¤·¤Ć¤Ş¤Ż. + # register in the module TclTk._addcallback(self) end - # to_eval(): @ip._eval_args ¤ÇÉľ˛Á¤ą¤ë¤Č¤­¤ÎÉ˝¸˝·Á(String)¤ňĘÖ¤ą. + # to_eval(): retuens string representation for @ip._eval_args def to_eval() if @arg - # %s ¤Ď ruby_fmt ¤č¤ęÁ°¤Ë bind ¤Ë¤č¤ęĂÖ´ą¤µ¤ě¤Ć¤·¤Ţ¤¦¤Î¤Ç - # %%s ¤Č¤·¤Ć¤˘¤ë. ¤·¤ż¤¬¤Ă¤Ć, ¤ł¤ě¤Ď bind ŔěÍŃ. + # bind replaces %s before calling ruby_fmt, so %%s is used s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%%s")} #{@arg}}/ else s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%s")}}/ @@ -358,28 +337,28 @@ class TclTkCallback < TclTkObject return s end - # _call(arg): ĄłˇĽĄëĄĐĄĂĄŻ¤ň¸Ć¤Ó˝Đ¤ą. - # arg: ĄłˇĽĄëĄĐĄĂĄŻ¤ËĹϤµ¤ě¤ëĄŃĄéĄáˇĽĄż + # _call(arg): invoke callback + # arg: callback parameter def _call(arg) @pr.call(arg) end end -# class TclTkImage: tcl/tk ¤ÎĄ¤ĄáˇĽĄ¸ +# class TclTkImage: tcl/tk images class TclTkImage < TclTkCommand - # initialize(interp, t, *args): ˝é´ü˛˝. - # Ą¤ĄáˇĽĄ¸¤ÎŔ¸Ŕ®¤Ď TclTkImage.new() ¤ÇąÔ¤¦¤¬, - # Ç˲ő¤Ď image delete ¤ÇąÔ¤¦. (¤¤¤Ţ¤¤¤Á¤Ŕ¤±¤É»ĹĘý¤¬Ěµ¤¤.) - # interp: Ą¤ĄóĄżĄ×ĄęĄż(TclTkInterpreter) - # t: Ą¤ĄáˇĽĄ¸¤ÎĄżĄ¤Ą× (photo, bitmap, etc.) - # *args: ĄłĄŢĄóĄÉ¤Î°úżô + # initialize(interp, t, *args): + # generating image is done by TclTkImage.new() + # destrying is done by image delete (inconsistent, sigh) + # interp: interpreter(TclTkInterpreter) + # t: image type (photo, bitmap, etc.) + # *args: command argument def initialize(interp, t, *args) - # tcl/tk ¤Ç¤ÎÉ˝¸˝·Á(ĘŃżôĚľ)¤ňĽ«Ć°Ŕ¸Ŕ®¤ą¤ë. + # auto-generate tcl/tk representation exp = TclTk._newname("i_") - # TclTkObject ¤ň˝é´ü˛˝¤ą¤ë. + # initialize TclTkObject super(interp._tcltkip(), exp) - # Ą¤ĄáˇĽĄ¸¤ňŔ¸Ŕ®¤ą¤ë. + # generate image res = @ip._eval_args("image create", t, exp, *args) fail("can't create Image") if res != exp end diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c index e7fe77d2b7..625fe61ccc 100644 --- a/ext/tcltklib/tcltklib.c +++ b/ext/tcltklib/tcltklib.c @@ -5,22 +5,31 @@ */ #include "ruby.h" -#include "sig.h" +#include "rubysig.h" #include #include #include #include -/* for debug */ +#ifdef __MACOS__ +# include +# include +#endif -#define DUMP1(ARG1) if (debug) { fprintf(stderr, "tcltklib: %s\n", ARG1);} -#define DUMP2(ARG1, ARG2) if (debug) { fprintf(stderr, "tcltklib: ");\ +/* for rb_debug */ + +#define DUMP1(ARG1) if (rb_debug) { fprintf(stderr, "tcltklib: %s\n", ARG1);} +#define DUMP2(ARG1, ARG2) if (rb_debug) { fprintf(stderr, "tcltklib: ");\ fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); } /* #define DUMP1(ARG1) #define DUMP2(ARG1, ARG2) */ +/* for callback break & continue */ +VALUE eTkCallbackBreak; +VALUE eTkCallbackContinue; + /* from tkAppInit.c */ /* @@ -33,26 +42,52 @@ int *tclDummyMathPtr = (int *) matherr; /*---- module TclTkLib ----*/ -static VALUE thread_safe = Qnil; +/* Tk_ThreadTimer */ +typedef struct { + Tcl_TimerToken token; + int flag; +} Tk_TimerData; + +/* timer callback */ +void _timer_for_tcl (ClientData clientData) +{ + Tk_TimerData *timer = (Tk_TimerData*)clientData; + + timer->flag = 0; + CHECK_INTS; +#ifdef USE_THREAD + if (!rb_thread_critical) rb_thread_schedule(); +#endif + + timer->token = Tk_CreateTimerHandler(200, _timer_for_tcl, + (ClientData)timer); + timer->flag = 1; +} /* execute Tk_MainLoop */ static VALUE lib_mainloop(VALUE self) { - int old_trapflg; - int flags = RTEST(thread_safe)?TCL_DONT_WAIT:0; + Tk_TimerData *timer; + + timer = (Tk_TimerData *) ckalloc(sizeof(Tk_TimerData)); + timer->flag = 0; + timer->token = Tk_CreateTimerHandler(200, _timer_for_tcl, + (ClientData)timer); + timer->flag = 1; DUMP1("start Tk_Mainloop"); while (Tk_GetNumMainWindows() > 0) { - old_trapflg = trap_immediate; - trap_immediate = 1; - Tcl_DoOneEvent(flags); - trap_immediate = old_trapflg; - CHECK_INTS; - flags = (thread_safe == 0 || thread_safe == Qnil)?0:TCL_DONT_WAIT; + Tcl_DoOneEvent(0); } DUMP1("stop Tk_Mainloop"); +#ifdef USE_THREAD + if (timer->flag) { + Tk_DeleteTimerHandler(timer->token); + } +#endif + return Qnil; } @@ -71,27 +106,49 @@ ip_eval_rescue(VALUE *failed, VALUE einfo) } static int +#if TCL_MAJOR_VERSION >= 8 +ip_ruby(ClientData clientData, Tcl_Interp *interp, + int argc, Tcl_Obj *CONST argv[]) +#else ip_ruby(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) +#endif { VALUE res; int old_trapflg; VALUE failed = 0; + char *arg; + int dummy; /* ruby command has 1 arg. */ if (argc != 2) { - ArgError("wrong # of arguments (%d for 1)", argc); + rb_raise(rb_eArgError, "wrong # of arguments (%d for 1)", argc); } + /* get C string from Tcl object */ +#if TCL_MAJOR_VERSION >= 8 + arg = Tcl_GetStringFromObj(argv[1], &dummy); +#else + arg = argv[1]; +#endif + /* evaluate the argument string by ruby */ - DUMP2("rb_eval_string(%s)", argv[1]); - old_trapflg = trap_immediate; - trap_immediate = 0; - res = rb_rescue(rb_eval_string, argv[1], ip_eval_rescue, &failed); - trap_immediate = old_trapflg; + DUMP2("rb_eval_string(%s)", arg); + old_trapflg = rb_trap_immediate; + rb_trap_immediate = 0; + res = rb_rescue(rb_eval_string, (VALUE)arg, ip_eval_rescue, (VALUE)&failed); + rb_trap_immediate = old_trapflg; + Tcl_ResetResult(interp); if (failed) { - Tcl_AppendResult(interp, RSTRING(failed)->ptr, (char*)NULL); - return TCL_ERROR; + VALUE eclass = CLASS_OF(failed); + Tcl_AppendResult(interp, STR2CSTR(failed), (char*)NULL); + if (eclass == eTkCallbackBreak) { + return TCL_BREAK; + } else if (eclass == eTkCallbackContinue) { + return TCL_CONTINUE; + } else { + return TCL_ERROR; + } } /* result must be string or nil */ @@ -99,12 +156,11 @@ ip_ruby(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) DUMP1("(rb_eval_string result) nil"); return TCL_OK; } - Check_Type(res, T_STRING); /* copy result to the tcl interpreter */ - DUMP2("(rb_eval_string result) %s", RSTRING(res)->ptr); + DUMP2("(rb_eval_string result) %s", STR2CSTR(res)); DUMP1("Tcl_AppendResult"); - Tcl_AppendResult(interp, RSTRING(res)->ptr, (char *)NULL); + Tcl_AppendResult(interp, STR2CSTR(res), (char *)NULL); return TCL_OK; } @@ -115,6 +171,7 @@ ip_free(struct tcltkip *ptr) { DUMP1("Tcl_DeleteInterp"); Tcl_DeleteInterp(ptr->ip); + free(ptr); } /* create and initialize interpreter */ @@ -135,20 +192,26 @@ ip_new(VALUE self) /* from Tcl_AppInit() */ DUMP1("Tcl_Init"); if (Tcl_Init(ptr->ip) == TCL_ERROR) { - Fail("Tcl_Init"); + rb_raise(rb_eRuntimeError, "Tcl_Init"); } DUMP1("Tk_Init"); if (Tk_Init(ptr->ip) == TCL_ERROR) { - Fail("Tk_Init"); + rb_raise(rb_eRuntimeError, "Tk_Init"); } DUMP1("Tcl_StaticPackage(\"Tk\")"); Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL); /* add ruby command to the interpreter */ +#if TCL_MAJOR_VERSION >= 8 + DUMP1("Tcl_CreateObjCommand(\"ruby\")"); + Tcl_CreateObjCommand(ptr->ip, "ruby", ip_ruby, (ClientData *)NULL, + (Tcl_CmdDeleteProc *)NULL); +#else DUMP1("Tcl_CreateCommand(\"ruby\")"); Tcl_CreateCommand(ptr->ip, "ruby", ip_ruby, (ClientData *)NULL, (Tcl_CmdDeleteProc *)NULL); +#endif return obj; } @@ -157,6 +220,7 @@ ip_new(VALUE self) static VALUE ip_eval(VALUE self, VALUE str) { + char *s; char *buf; /* Tcl_Eval requires re-writable string region */ struct tcltkip *ptr; /* tcltkip data struct */ @@ -164,18 +228,162 @@ ip_eval(VALUE self, VALUE str) Data_Get_Struct(self, struct tcltkip, ptr); /* call Tcl_Eval() */ - Check_Type(str, T_STRING); - buf = ALLOCA_N(char,RSTRING(str)->len+1); - strcpy(buf, RSTRING(str)->ptr); + s = STR2CSTR(str); + buf = ALLOCA_N(char, strlen(s)+1); + strcpy(buf, s); DUMP2("Tcl_Eval(%s)", buf); ptr->return_value = Tcl_Eval(ptr->ip, buf); if (ptr->return_value == TCL_ERROR) { - Fail(ptr->ip->result); + rb_raise(rb_eRuntimeError, ptr->ip->result); } DUMP2("(TCL_Eval result) %d", ptr->return_value); /* pass back the result (as string) */ - return(str_new2(ptr->ip->result)); + return(rb_str_new2(ptr->ip->result)); +} + + +static VALUE +ip_toUTF8(VALUE self, VALUE str, VALUE encodename) +{ +#ifndef TCL_UTF_MAX + return str; +#else + Tcl_Interp *interp; + Tcl_Encoding encoding; + Tcl_DString dstr; + struct tcltkip *ptr; + char *buff1,*buff2; + + Data_Get_Struct(self,struct tcltkip, ptr); + interp = ptr->ip; + + encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename)); + buff1 = ALLOCA_N(char,strlen(STR2CSTR(str))+1); + strcpy(buff1,STR2CSTR(str)); + + Tcl_DStringInit(&dstr); + Tcl_DStringFree(&dstr); + Tcl_ExternalToUtfDString(encoding,buff1,strlen(buff1),&dstr); + buff2 = ALLOCA_N(char,Tcl_DStringLength(&dstr)+1); + strcpy(buff2,Tcl_DStringValue(&dstr)); + + Tcl_FreeEncoding(encoding); + Tcl_DStringFree(&dstr); + + return rb_str_new2(buff2); +#endif +} + +static VALUE +ip_fromUTF8(VALUE self, VALUE str, VALUE encodename) +{ +#ifndef TCL_UTF_MAX + return str; +#else + Tcl_Interp *interp; + Tcl_Encoding encoding; + Tcl_DString dstr; + struct tcltkip *ptr; + char *buff1,*buff2; + + Data_Get_Struct(self,struct tcltkip, ptr); + interp = ptr->ip; + + encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename)); + buff1 = ALLOCA_N(char,strlen(STR2CSTR(str))+1); + strcpy(buff1,STR2CSTR(str)); + + Tcl_DStringInit(&dstr); + Tcl_DStringFree(&dstr); + Tcl_UtfToExternalDString(encoding,buff1,strlen(buff1),&dstr); + buff2 = ALLOCA_N(char,Tcl_DStringLength(&dstr)+1); + strcpy(buff2,Tcl_DStringValue(&dstr)); + + Tcl_FreeEncoding(encoding); + Tcl_DStringFree(&dstr); + + return rb_str_new2(buff2); +#endif +} + + +static VALUE +ip_invoke(int argc, VALUE *argv, VALUE obj) +{ + struct tcltkip *ptr; /* tcltkip data struct */ + int i; + int object = 0; + Tcl_CmdInfo info; + char *cmd; + char **av = (char **)NULL; +#if TCL_MAJOR_VERSION >= 8 + Tcl_Obj **ov = (Tcl_Obj **)NULL; + Tcl_Obj *resultPtr; +#endif + + /* get the data struct */ + Data_Get_Struct(obj, struct tcltkip, ptr); + + /* get the command name string */ + cmd = STR2CSTR(argv[0]); + + /* map from the command name to a C procedure */ + if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) { + rb_raise(rb_eNameError, "invalid command name `%s'", cmd); + } +#if TCL_MAJOR_VERSION >= 8 + object = info.isNativeObjectProc; +#endif + + /* memory allocation for arguments of this command */ + if (object) { +#if TCL_MAJOR_VERSION >= 8 + /* object interface */ + ov = (Tcl_Obj **)ALLOCA_N(Tcl_Obj *, argc+1); + for (i = 0; i < argc; ++i) { + char *s = STR2CSTR(argv[i]); + ov[i] = Tcl_NewStringObj(s, strlen(s)); + } + ov[argc] = (Tcl_Obj *)NULL; +#endif + } else { + /* string interface */ + av = (char **)ALLOCA_N(char *, argc+1); + for (i = 0; i < argc; ++i) { + char *s = STR2CSTR(argv[i]); + + av[i] = ALLOCA_N(char, strlen(s)+1); + strcpy(av[i], s); + } + av[argc] = (char *)NULL; + } + + Tcl_ResetResult(ptr->ip); + + /* Invoke the C procedure */ + if (object) { +#if TCL_MAJOR_VERSION >= 8 + int dummy; + ptr->return_value = (*info.objProc)(info.objClientData, + ptr->ip, argc, ov); + + /* get the string value from the result object */ + resultPtr = Tcl_GetObjResult(ptr->ip); + Tcl_SetResult(ptr->ip, Tcl_GetStringFromObj(resultPtr, &dummy), + TCL_VOLATILE); +#endif + } else { + ptr->return_value = (*info.proc)(info.clientData, + ptr->ip, argc, av); + } + + if (ptr->return_value == TCL_ERROR) { + rb_raise(rb_eRuntimeError, ptr->ip->result); + } + + /* pass back the result (as string) */ + return(rb_str_new2(ptr->ip->result)); } /* get return code from Tcl_Eval() */ @@ -190,27 +398,44 @@ ip_retval(VALUE self) return (INT2FIX(ptr->return_value)); } +#ifdef __MACOS__ +static void +_macinit() +{ + tcl_macQdPtr = &qd; /* setup QuickDraw globals */ + Tcl_MacSetEventProc(TkMacConvertEvent); /* setup event handler */ +} +#endif + /*---- initialization ----*/ void Init_tcltklib() { extern VALUE rb_argv0; /* the argv[0] */ VALUE lib = rb_define_module("TclTkLib"); - VALUE ip = rb_define_class("TclTkIp", cObject); + VALUE ip = rb_define_class("TclTkIp", rb_cObject); + + eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); + eTkCallbackContinue = rb_define_class("TkCallbackContinue",rb_eStandardError); rb_define_module_function(lib, "mainloop", lib_mainloop, 0); rb_define_singleton_method(ip, "new", ip_new, 0); rb_define_method(ip, "_eval", ip_eval, 1); + rb_define_method(ip, "_toUTF8",ip_toUTF8,2); + rb_define_method(ip, "_fromUTF8",ip_fromUTF8,2); + rb_define_method(ip, "_invoke", ip_invoke, -1); rb_define_method(ip, "_return_value", ip_retval, 0); rb_define_method(ip, "mainloop", lib_mainloop, 0); +#ifdef __MACOS__ + _macinit(); +#endif + /*---- initialize tcl/tk libraries ----*/ /* from Tk_Main() */ DUMP1("Tcl_FindExecutable"); Tcl_FindExecutable(RSTRING(rb_argv0)->ptr); - - rb_define_variable("$tk_thread_safe", &thread_safe); } /* eof */ diff --git a/file.c b/file.c index b60ec65d55..11a8dedf14 100644 --- a/file.c +++ b/file.c @@ -6,12 +6,17 @@ $Date$ created at: Mon Nov 15 12:24:34 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ +#ifdef NT +#include "missing/file.h" +#endif + #include "ruby.h" -#include "io.h" +#include "rubyio.h" +#include "rubysig.h" #ifdef HAVE_UNISTD_H #include @@ -43,44 +48,44 @@ struct timeval { #endif #ifndef HAVE_STRING_H -char *strrchr(); +char *strrchr _((char*,char)); #endif +#include #include -#ifndef NT -char *strdup(); -char *getenv(); +#ifdef USE_CWGUSI + #include "macruby_missing.h" + extern int fileno(FILE *stream); + extern int utimes(); #endif -extern VALUE cIO; -VALUE cFile; -VALUE mFileTest; +VALUE rb_cFile; +VALUE rb_mFileTest; static VALUE sStat; -VALUE time_new(); - VALUE -file_open(fname, mode) +rb_file_open(fname, mode) char *fname, *mode; { OpenFile *fptr; NEWOBJ(port, struct RFile); - OBJSETUP(port, cFile, T_FILE); + OBJSETUP(port, rb_cFile, T_FILE); MakeOpenFile(port, fptr); - fptr->mode = io_mode_flags(mode); + fptr->mode = rb_io_mode_flags(mode); fptr->f = rb_fopen(fname, mode); fptr->path = strdup(fname); + rb_obj_call_init((VALUE)port); return (VALUE)port; } static VALUE -file_s_open(argc, argv, class) +rb_file_s_open(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { VALUE fname, vmode, file; char *mode; @@ -88,24 +93,24 @@ file_s_open(argc, argv, class) rb_scan_args(argc, argv, "11", &fname, &vmode); Check_SafeStr(fname); if (!NIL_P(vmode)) { - Check_Type(vmode, T_STRING); - mode = RSTRING(vmode)->ptr; + mode = STR2CSTR(vmode); } else { mode = "r"; } - file = file_open(RSTRING(fname)->ptr, mode); + file = rb_file_open(RSTRING(fname)->ptr, mode); - RBASIC(file)->class = class; - if (iterator_p()) { - rb_ensure(rb_yield, file, io_close, file); + RBASIC(file)->klass = klass; + rb_obj_call_init(file); + if (rb_iterator_p()) { + return rb_ensure(rb_yield, file, rb_io_close, file); } return file; } static VALUE -file_reopen(argc, argv, file) +rb_file_reopen(argc, argv, file) int argc; VALUE *argv; VALUE file; @@ -114,16 +119,16 @@ file_reopen(argc, argv, file) char *mode; OpenFile *fptr; + rb_secure(4); if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) { if (TYPE(fname) == T_FILE) { /* fname must be IO */ - return io_reopen(file, fname); + return rb_io_reopen(file, fname); } } Check_SafeStr(fname); if (!NIL_P(nmode)) { - Check_Type(nmode, T_STRING); - mode = RSTRING(nmode)->ptr; + mode = STR2CSTR(nmode); } else { mode = "r"; @@ -132,12 +137,11 @@ file_reopen(argc, argv, file) GetOpenFile(file, fptr); if (fptr->path) free(fptr->path); fptr->path = strdup(RSTRING(fname)->ptr); - fptr->mode = io_mode_flags(mode); + fptr->mode = rb_io_mode_flags(mode); if (!fptr->f) { fptr->f = rb_fopen(RSTRING(fname)->ptr, mode); if (fptr->f2) { - if (fileno(fptr->f2) < 3) /* need to keep stdio */ - fclose(fptr->f2); + fclose(fptr->f2); fptr->f2 = NULL; } return file; @@ -179,95 +183,20 @@ apply2files(func, vargs, arg) } static VALUE -file_tell(obj) - VALUE obj; -{ - OpenFile *fptr; - long pos; - - GetOpenFile(obj, fptr); - - pos = ftell(fptr->f); - if (ferror(fptr->f) != 0) rb_sys_fail(0); - - return int2inum(pos); -} - -static VALUE -file_seek(obj, offset, ptrname) - VALUE obj, offset, ptrname; -{ - OpenFile *fptr; - long pos; - - GetOpenFile(obj, fptr); - - pos = fseek(fptr->f, NUM2INT(offset), NUM2INT(ptrname)); - if (pos != 0) rb_sys_fail(0); - clearerr(fptr->f); - - return obj; -} - -static VALUE -file_set_pos(obj, offset) - VALUE obj, offset; -{ - OpenFile *fptr; - long pos; - - GetOpenFile(obj, fptr); - pos = fseek(fptr->f, NUM2INT(offset), 0); - if (pos != 0) rb_sys_fail(0); - clearerr(fptr->f); - - return obj; -} - -static VALUE -file_rewind(obj) - VALUE obj; -{ - OpenFile *fptr; - - GetOpenFile(obj, fptr); - if (fseek(fptr->f, 0L, 0) != 0) rb_sys_fail(0); - clearerr(fptr->f); - - return obj; -} - -static VALUE -file_eof(obj) +rb_file_path(obj) VALUE obj; { OpenFile *fptr; GetOpenFile(obj, fptr); - if (feof(fptr->f) == 0) return FALSE; - return TRUE; + if (fptr->path == NULL) return Qnil; + return rb_str_new2(fptr->path); } -static VALUE -file_path(obj) - VALUE obj; -{ - OpenFile *fptr; - - GetOpenFile(obj, fptr); - return str_new2(fptr->path); -} - -static VALUE -file_isatty(obj) - VALUE obj; -{ - return FALSE; -} - -#include #ifndef NT -#include +# ifndef USE_CWGUSI +# include +# endif #else #include "missing/file.h" #endif @@ -276,37 +205,53 @@ static VALUE stat_new(st) struct stat *st; { - if (!st) Bug("stat_new() called with bad value"); - return struct_new(sStat, - INT2FIX((int)st->st_dev), - INT2FIX((int)st->st_ino), - INT2FIX((int)st->st_mode), - INT2FIX((int)st->st_nlink), - INT2FIX((int)st->st_uid), - INT2FIX((int)st->st_gid), + if (!st) rb_bug("stat_new() called with bad value"); + return rb_struct_new(sStat, + INT2FIX((int)st->st_dev), + INT2FIX((int)st->st_ino), + INT2FIX((int)st->st_mode), + INT2FIX((int)st->st_nlink), + INT2FIX((int)st->st_uid), + INT2FIX((int)st->st_gid), #ifdef HAVE_ST_RDEV - INT2FIX((int)st->st_rdev), + INT2FIX((int)st->st_rdev), #else - INT2FIX(0), + INT2FIX(0), #endif - INT2FIX((int)st->st_size), + INT2FIX((int)st->st_size), #ifdef HAVE_ST_BLKSIZE - INT2FIX((int)st->st_blksize), + INT2FIX((int)st->st_blksize), #else - INT2FIX(0), + INT2FIX(0), #endif #ifdef HAVE_ST_BLOCKS - INT2FIX((int)st->st_blocks), + INT2FIX((int)st->st_blocks), #else - INT2FIX(0), + INT2FIX(0), #endif - time_new(st->st_atime, 0), - time_new(st->st_mtime, 0), - time_new(st->st_ctime, 0)); + rb_time_new(st->st_atime, 0), + rb_time_new(st->st_mtime, 0), + rb_time_new(st->st_ctime, 0)); +} + +static int +rb_stat(file, st) + VALUE file; + struct stat *st; +{ + if (TYPE(file) == T_FILE) { + OpenFile *fptr; + + rb_secure(4); + GetOpenFile(file, fptr); + return fstat(fileno(fptr->f), st); + } + Check_SafeStr(file); + return stat(RSTRING(file)->ptr, st); } static VALUE -file_s_stat(obj, fname) +rb_file_s_stat(obj, fname) VALUE obj, fname; { struct stat st; @@ -319,7 +264,7 @@ file_s_stat(obj, fname) } static VALUE -file_stat(obj) +rb_io_stat(obj) VALUE obj; { OpenFile *fptr; @@ -333,7 +278,7 @@ file_stat(obj) } static VALUE -file_s_lstat(obj, fname) +rb_file_s_lstat(obj, fname) VALUE obj, fname; { #if !defined(MSDOS) && !defined(NT) @@ -345,25 +290,28 @@ file_s_lstat(obj, fname) } return stat_new(&st); #else - rb_notimplement(); + rb_notimplement(); + return Qnil; /* not reached */ #endif } static VALUE -file_lstat(obj) +rb_file_lstat(obj) VALUE obj; { #if !defined(MSDOS) && !defined(NT) OpenFile *fptr; struct stat st; + rb_secure(4); GetOpenFile(obj, fptr); if (lstat(fptr->path, &st) == -1) { rb_sys_fail(fptr->path); } return stat_new(&st); #else - rb_notimplement(); + rb_notimplement(); + return Qnil; /* not reached */ #endif } @@ -371,9 +319,9 @@ static int group_member(gid) GETGROUPS_T gid; { -#ifndef NT +#if !defined(NT) && !defined(USE_CWGUSI) if (getgid() == gid || getegid() == gid) - return TRUE; + return Qtrue; # ifdef HAVE_GETGROUPS # ifndef NGROUPS @@ -386,11 +334,11 @@ group_member(gid) anum = getgroups(NGROUPS, gary); while (--anum >= 0) if (gary[anum] == gid) - return TRUE; + return Qtrue; } # endif #endif - return FALSE; + return Qfalse; } #ifndef S_IXUGO @@ -446,10 +394,9 @@ test_d(obj, fname) struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISDIR(st.st_mode)) return TRUE; - return FALSE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (S_ISDIR(st.st_mode)) return Qtrue; + return Qfalse; } static VALUE @@ -463,12 +410,11 @@ test_p(obj, fname) struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISFIFO(st.st_mode)) return TRUE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (S_ISFIFO(st.st_mode)) return Qtrue; #endif - return FALSE; + return Qfalse; } static VALUE @@ -493,11 +439,11 @@ test_l(obj, fname) struct stat st; Check_SafeStr(fname); - if (lstat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISLNK(st.st_mode)) return TRUE; + if (lstat(RSTRING(fname)->ptr, &st) < 0) return Qfalse; + if (S_ISLNK(st.st_mode)) return Qtrue; #endif - return FALSE; + return Qfalse; } static VALUE @@ -521,12 +467,11 @@ test_S(obj, fname) #ifdef S_ISSOCK struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISSOCK(st.st_mode)) return TRUE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (S_ISSOCK(st.st_mode)) return Qtrue; #endif - return FALSE; + return Qfalse; } static VALUE @@ -544,12 +489,11 @@ test_b(obj, fname) #ifdef S_ISBLK struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISBLK(st.st_mode)) return TRUE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (S_ISBLK(st.st_mode)) return Qtrue; #endif - return FALSE; + return Qfalse; } static VALUE @@ -562,11 +506,10 @@ test_c(obj, fname) struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISBLK(st.st_mode)) return TRUE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (S_ISBLK(st.st_mode)) return Qtrue; - return FALSE; + return Qfalse; } static VALUE @@ -575,9 +518,8 @@ test_e(obj, fname) { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - return TRUE; + if (rb_stat(fname, &st) < 0) return Qfalse; + return Qtrue; } static VALUE @@ -585,8 +527,8 @@ test_r(obj, fname) VALUE obj, fname; { Check_SafeStr(fname); - if (eaccess(RSTRING(fname)->ptr, R_OK) < 0) return FALSE; - return TRUE; + if (eaccess(RSTRING(fname)->ptr, R_OK) < 0) return Qfalse; + return Qtrue; } static VALUE @@ -594,8 +536,8 @@ test_R(obj, fname) VALUE obj, fname; { Check_SafeStr(fname); - if (access(RSTRING(fname)->ptr, R_OK) < 0) return FALSE; - return TRUE; + if (access(RSTRING(fname)->ptr, R_OK) < 0) return Qfalse; + return Qtrue; } static VALUE @@ -603,8 +545,8 @@ test_w(obj, fname) VALUE obj, fname; { Check_SafeStr(fname); - if (eaccess(RSTRING(fname)->ptr, W_OK) < 0) return FALSE; - return TRUE; + if (eaccess(RSTRING(fname)->ptr, W_OK) < 0) return Qfalse; + return Qtrue; } static VALUE @@ -612,8 +554,8 @@ test_W(obj, fname) VALUE obj, fname; { Check_SafeStr(fname); - if (access(RSTRING(fname)->ptr, W_OK) < 0) return FALSE; - return TRUE; + if (access(RSTRING(fname)->ptr, W_OK) < 0) return Qfalse; + return Qtrue; } static VALUE @@ -621,8 +563,8 @@ test_x(obj, fname) VALUE obj, fname; { Check_SafeStr(fname); - if (eaccess(RSTRING(fname)->ptr, X_OK) < 0) return FALSE; - return TRUE; + if (eaccess(RSTRING(fname)->ptr, X_OK) < 0) return Qfalse; + return Qtrue; } static VALUE @@ -630,8 +572,8 @@ test_X(obj, fname) VALUE obj, fname; { Check_SafeStr(fname); - if (access(RSTRING(fname)->ptr, X_OK) < 0) return FALSE; - return TRUE; + if (access(RSTRING(fname)->ptr, X_OK) < 0) return Qfalse; + return Qtrue; } #ifndef S_ISREG @@ -644,10 +586,9 @@ test_f(obj, fname) { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (S_ISREG(st.st_mode)) return TRUE; - return FALSE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (S_ISREG(st.st_mode)) return Qtrue; + return Qfalse; } static VALUE @@ -656,10 +597,9 @@ test_z(obj, fname) { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (st.st_size == 0) return TRUE; - return FALSE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (st.st_size == 0) return Qtrue; + return Qfalse; } static VALUE @@ -668,10 +608,9 @@ test_s(obj, fname) { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (st.st_size == 0) return FALSE; - return int2inum(st.st_size); + if (rb_stat(fname, &st) < 0) return Qfalse; + if (st.st_size == 0) return Qfalse; + return rb_int2inum(st.st_size); } static VALUE @@ -680,10 +619,9 @@ test_owned(obj, fname) { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (st.st_uid == geteuid()) return TRUE; - return FALSE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (st.st_uid == geteuid()) return Qtrue; + return Qfalse; } static VALUE @@ -692,10 +630,9 @@ test_rowned(obj, fname) { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (st.st_uid == getuid()) return TRUE; - return FALSE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (st.st_uid == getuid()) return Qtrue; + return Qfalse; } static VALUE @@ -705,11 +642,10 @@ test_grpowned(obj, fname) #ifndef NT struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) return FALSE; - if (st.st_gid == getegid()) return TRUE; + if (rb_stat(fname, &st) < 0) return Qfalse; + if (st.st_gid == getegid()) return Qtrue; #endif - return FALSE; + return Qfalse; } #if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX) @@ -720,9 +656,9 @@ check3rdbyte(file, mode) { struct stat st; - if (stat(file, &st) < 0) return FALSE; - if (st.st_mode & mode) return TRUE; - return FALSE; + if (stat(file, &st) < 0) return Qfalse; + if (st.st_mode & mode) return Qtrue; + return Qfalse; } #endif @@ -734,7 +670,7 @@ test_suid(obj, fname) Check_SafeStr(fname); return check3rdbyte(RSTRING(fname)->ptr, S_ISUID); #else - return FALSE; + return Qfalse; #endif } @@ -746,7 +682,7 @@ test_sgid(obj, fname) Check_SafeStr(fname); return check3rdbyte(RSTRING(fname)->ptr, S_ISGID); #else - return FALSE; + return Qfalse; #endif } @@ -754,36 +690,40 @@ static VALUE test_sticky(obj, fname) VALUE obj, fname; { - Check_Type(fname, T_STRING); #ifdef S_ISVTX - return check3rdbyte(RSTRING(fname)->ptr, S_ISVTX); + return check3rdbyte(STR2CSTR(fname), S_ISVTX); #else - return FALSE; + return Qfalse; #endif } static VALUE -file_s_size(obj, fname) +rb_file_s_size(obj, fname) VALUE obj, fname; { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) + if (rb_stat(fname, &st) < 0) rb_sys_fail(RSTRING(fname)->ptr); - return int2inum(st.st_size); + return rb_int2inum(st.st_size); } static VALUE -file_s_ftype(obj, fname) +rb_file_s_ftype(obj, fname) VALUE obj, fname; { struct stat st; char *t; +#if defined(MSDOS) || defined(NT) + if (rb_stat(fname, &st) < 0) + rb_sys_fail(RSTRING(fname)->ptr); +#else Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) + if (lstat(RSTRING(fname)->ptr, &st) == -1) { rb_sys_fail(RSTRING(fname)->ptr); + } +#endif if (S_ISREG(st.st_mode)) { t = "file"; @@ -816,23 +756,22 @@ file_s_ftype(obj, fname) t = "unknown"; } - return str_new2(t); + return rb_str_new2(t); } static VALUE -file_s_atime(obj, fname) +rb_file_s_atime(obj, fname) VALUE obj, fname; { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) + if (rb_stat(fname, &st) < 0) rb_sys_fail(RSTRING(fname)->ptr); - return time_new(st.st_atime, 0); + return rb_time_new(st.st_atime, 0); } static VALUE -file_atime(obj) +rb_file_atime(obj) VALUE obj; { OpenFile *fptr; @@ -842,23 +781,22 @@ file_atime(obj) if (fstat(fileno(fptr->f), &st) == -1) { rb_sys_fail(fptr->path); } - return time_new(st.st_atime, 0); + return rb_time_new(st.st_atime, 0); } static VALUE -file_s_mtime(obj, fname) +rb_file_s_mtime(obj, fname) VALUE obj, fname; { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) + if (rb_stat(fname, &st) < 0) rb_sys_fail(RSTRING(fname)->ptr); - return time_new(st.st_mtime, 0); + return rb_time_new(st.st_mtime, 0); } static VALUE -file_mtime(obj) +rb_file_mtime(obj) VALUE obj; { OpenFile *fptr; @@ -868,23 +806,22 @@ file_mtime(obj) if (fstat(fileno(fptr->f), &st) == -1) { rb_sys_fail(fptr->path); } - return time_new(st.st_mtime, 0); + return rb_time_new(st.st_mtime, 0); } static VALUE -file_s_ctime(obj, fname) +rb_file_s_ctime(obj, fname) VALUE obj, fname; { struct stat st; - Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) < 0) + if (rb_stat(fname, &st) < 0) rb_sys_fail(RSTRING(fname)->ptr); - return time_new(st.st_ctime, 0); + return rb_time_new(st.st_ctime, 0); } static VALUE -file_ctime(obj) +rb_file_ctime(obj) VALUE obj; { OpenFile *fptr; @@ -894,7 +831,7 @@ file_ctime(obj) if (fstat(fileno(fptr->f), &st) == -1) { rb_sys_fail(fptr->path); } - return time_new(st.st_ctime, 0); + return rb_time_new(st.st_ctime, 0); } static void @@ -907,7 +844,7 @@ chmod_internal(path, mode) } static VALUE -file_s_chmod(argc, argv) +rb_file_s_chmod(argc, argv) int argc; VALUE *argv; { @@ -923,17 +860,17 @@ file_s_chmod(argc, argv) } static VALUE -file_chmod(obj, vmode) +rb_file_chmod(obj, vmode) VALUE obj, vmode; { OpenFile *fptr; int mode; - rb_secure(2); + rb_secure(4); mode = NUM2INT(vmode); GetOpenFile(obj, fptr); -#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) +#if defined(DJGPP) || defined(NT) || defined(USE_CWGUSI) || defined(__BEOS__) if (chmod(fptr->path, mode) == -1) rb_sys_fail(fptr->path); #else @@ -958,7 +895,7 @@ chown_internal(path, args) } static VALUE -file_s_chown(argc, argv) +rb_file_s_chown(argc, argv) int argc; VALUE *argv; { @@ -985,14 +922,14 @@ file_s_chown(argc, argv) } static VALUE -file_chown(obj, owner, group) +rb_file_chown(obj, owner, group) VALUE obj, owner, group; { OpenFile *fptr; - rb_secure(2); + rb_secure(4); GetOpenFile(obj, fptr); -#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) +#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(USE_CWGUSI) if (chown(fptr->path, NUM2INT(owner), NUM2INT(group)) == -1) rb_sys_fail(fptr->path); #else @@ -1003,7 +940,7 @@ file_chown(obj, owner, group) return INT2FIX(0); } -struct timeval time_timeval(); +struct timeval rb_time_timeval(); #ifdef HAVE_UTIMES @@ -1017,7 +954,7 @@ utime_internal(path, tvp) } static VALUE -file_s_utime(argc, argv) +rb_file_s_utime(argc, argv) int argc; VALUE *argv; { @@ -1027,8 +964,8 @@ file_s_utime(argc, argv) rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest); - tvp[0] = time_timeval(atime); - tvp[1] = time_timeval(mtime); + tvp[0] = rb_time_timeval(atime); + tvp[1] = rb_time_timeval(mtime); n = apply2files(utime_internal, rest, tvp); return INT2FIX(n); @@ -1038,8 +975,14 @@ file_s_utime(argc, argv) #ifndef HAVE_UTIME_H # ifdef NT +# if defined(__BORLANDC__) +# include +# else # include +# endif +# if defined(_MSC_VER) # define utimbuf _utimbuf +# endif # else struct utimbuf { long actime; @@ -1058,7 +1001,7 @@ utime_internal(path, utp) } static VALUE -file_s_utime(argc, argv) +rb_file_s_utime(argc, argv) int argc; VALUE *argv; { @@ -1069,9 +1012,9 @@ file_s_utime(argc, argv) rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest); - tv = time_timeval(atime); + tv = rb_time_timeval(atime); utbuf.actime = tv.tv_sec; - tv = time_timeval(mtime); + tv = rb_time_timeval(mtime); utbuf.modtime = tv.tv_sec; n = apply2files(utime_internal, rest, &utbuf); @@ -1081,19 +1024,23 @@ file_s_utime(argc, argv) #endif static VALUE -file_s_link(obj, from, to) +rb_file_s_link(obj, from, to) VALUE obj, from, to; { +#if defined(USE_CWGUSI) + rb_notimplement(); +#else Check_SafeStr(from); Check_SafeStr(to); if (link(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0) rb_sys_fail(RSTRING(from)->ptr); return INT2FIX(0); +#endif /* USE_CWGUSI */ } static VALUE -file_s_symlink(obj, from, to) +rb_file_s_symlink(obj, from, to) VALUE obj, from, to; { #if !defined(MSDOS) && !defined(NT) @@ -1102,14 +1049,15 @@ file_s_symlink(obj, from, to) if (symlink(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0) rb_sys_fail(RSTRING(from)->ptr); - return TRUE; + return INT2FIX(0); #else - rb_notimplement(); + rb_notimplement(); + return Qnil; /* not reached */ #endif } static VALUE -file_s_readlink(obj, path) +rb_file_s_readlink(obj, path) VALUE obj, path; { #if !defined(MSDOS) && !defined(NT) @@ -1121,9 +1069,10 @@ file_s_readlink(obj, path) if ((cc = readlink(RSTRING(path)->ptr, buf, MAXPATHLEN)) < 0) rb_sys_fail(RSTRING(path)->ptr); - return str_new(buf, cc); + return rb_tainted_str_new(buf, cc); #else rb_notimplement(); + return Qnil; /* not reached */ #endif } @@ -1136,7 +1085,7 @@ unlink_internal(path) } static VALUE -file_s_unlink(obj, args) +rb_file_s_unlink(obj, args) VALUE obj, args; { int n; @@ -1146,7 +1095,7 @@ file_s_unlink(obj, args) } static VALUE -file_s_rename(obj, from, to) +rb_file_s_rename(obj, from, to) VALUE obj, from, to; { Check_SafeStr(from); @@ -1159,42 +1108,53 @@ file_s_rename(obj, from, to) } static VALUE -file_s_umask(argc, argv) +rb_file_s_umask(argc, argv) int argc; VALUE *argv; { +#ifdef USE_CWGUSI + rb_notimplement(); +#else int omask = 0; + rb_secure(4); if (argc == 0) { - int omask = umask(0); + omask = umask(0); umask(omask); } else if (argc == 1) { omask = umask(NUM2INT(argv[0])); } else { - ArgError("wrong # of argument"); + rb_raise(rb_eArgError, "wrong # of argument"); } return INT2FIX(omask); +#endif /* USE_CWGUSI */ } VALUE -file_s_expand_path(obj, fname) - VALUE obj, fname; +rb_file_s_expand_path(argc, argv) + int argc; + VALUE *argv; { + VALUE fname, dname; char *s, *p; - char buf[MAXPATHLEN]; + char buf[MAXPATHLEN+2]; - Check_Type(fname, T_STRING); - s = RSTRING(fname)->ptr; + rb_scan_args(argc, argv, "11", &fname, &dname); + s = STR2CSTR(fname); p = buf; if (s[0] == '~') { - if (s[1] == '/' || s[1] == '\0') { + if (s[1] == '/' || +#if defined(MSDOS) || defined(NT) || defined(__human68k__) + s[1] == '\\' || +#endif + s[1] == '\0') { char *dir = getenv("HOME"); if (!dir) { - Fail("couldn't find HOME environment -- expanding `%s'", s); + rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `%s'", s); } strcpy(buf, dir); p = &buf[strlen(buf)]; @@ -1205,7 +1165,6 @@ file_s_expand_path(obj, fname) struct passwd *pwPtr; s++; #endif - while (*s && *s != '/') { *p++ = *s++; } @@ -1214,7 +1173,7 @@ file_s_expand_path(obj, fname) pwPtr = getpwnam(buf); if (!pwPtr) { endpwent(); - Fail("user %s doesn't exist", buf); + rb_raise(rb_eArgError, "user %s doesn't exist", buf); } strcpy(buf, pwPtr->pw_dir); p = &buf[strlen(buf)]; @@ -1223,12 +1182,19 @@ file_s_expand_path(obj, fname) } } else if (s[0] != '/') { + if (argc == 2) { + dname = rb_file_s_expand_path(1, &dname); + strcpy(buf, RSTRING(dname)->ptr); + } + else { #ifdef HAVE_GETCWD - getcwd(buf, MAXPATHLEN); + getcwd(buf, MAXPATHLEN); #else - getwd(buf); + getwd(buf); #endif + } p = &buf[strlen(buf)]; + while (p > buf && *(p - 1) == '/') p--; } *p = '/'; @@ -1267,7 +1233,7 @@ file_s_expand_path(obj, fname) if (p == buf || *p != '/') p++; *p = '\0'; - return str_taint(str_new2(buf)); + return rb_tainted_str_new2(buf); } static int @@ -1294,67 +1260,68 @@ rmext(p, e) } static VALUE -file_s_basename(argc, argv) +rb_file_s_basename(argc, argv) int argc; VALUE *argv; { - VALUE fname, ext; - char *p; + VALUE fname, fext; + char *name, *p, *ext; int f; - rb_scan_args(argc, argv, "11", &fname, &ext); - Check_Type(fname, T_STRING); - if (!NIL_P(ext)) Check_Type(ext, T_STRING); - p = strrchr(RSTRING(fname)->ptr, '/'); + if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { + ext = STR2CSTR(fext); + } + name = STR2CSTR(fname); + p = strrchr(name, '/'); if (!p) { - if (!NIL_P(ext)) { - f = rmext(RSTRING(fname)->ptr, RSTRING(ext)->ptr); - if (f) return str_new(RSTRING(fname)->ptr, f); + if (!NIL_P(fext)) { + f = rmext(name, ext); + if (f) return rb_str_new(name, f); } - return (VALUE)fname; + return fname; } p++; /* skip last `/' */ - if (!NIL_P(ext)) { - f = rmext(p, RSTRING(ext)->ptr); - if (f) return str_new(p, f); + if (!NIL_P(fext)) { + f = rmext(p, ext); + if (f) return rb_str_new(p, f); } - return str_taint(str_new2(p)); + return rb_tainted_str_new2(p); } static VALUE -file_s_dirname(obj, fname) +rb_file_s_dirname(obj, fname) VALUE obj, fname; { - UCHAR *p; + char *name, *p; - Check_Type(fname, T_STRING); - p = strrchr(RSTRING(fname)->ptr, '/'); + name = STR2CSTR(fname); + p = strrchr(name, '/'); if (!p) { - return str_new2("."); + return rb_str_new2("."); } - if (p == RSTRING(fname)->ptr) + if (p == name) p++; - return str_taint(str_new(RSTRING(fname)->ptr, p - RSTRING(fname)->ptr)); + return rb_tainted_str_new(name, p - name); } static VALUE -file_s_split(obj, path) +rb_file_s_split(obj, path) VALUE obj, path; { - return assoc_new(file_s_dirname(Qnil, path), file_s_basename(1,&path)); + return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path)); } static VALUE separator; static VALUE -file_s_join(obj, args) +rb_file_s_join(obj, args) VALUE obj, args; { - return ary_join(args, separator); + return rb_ary_join(args, separator); } static VALUE -file_s_truncate(obj, path, len) +rb_file_s_truncate(obj, path, len) VALUE obj, path, len; { Check_SafeStr(path); @@ -1386,20 +1353,19 @@ file_s_truncate(obj, path, len) rb_notimplement(); # endif #endif - return TRUE; + return INT2FIX(0); } static VALUE -file_truncate(obj, len) +rb_file_truncate(obj, len) VALUE obj, len; { OpenFile *fptr; + rb_secure(4); GetOpenFile(obj, fptr); - - rb_secure(2); if (!(fptr->mode & FMODE_WRITABLE)) { - Fail("not opened for writing"); + rb_raise(rb_eIOError, "not opened for writing"); } #ifdef HAVE_TRUNCATE if (ftruncate(fileno(fptr->f), NUM2INT(len)) < 0) @@ -1412,29 +1378,71 @@ file_truncate(obj, len) rb_notimplement(); # endif #endif - return TRUE; + return INT2FIX(0); +} + +# 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 + +#if defined(USE_THREAD) && defined(EWOULDBLOCK) +static int +rb_thread_flock(fd, op) + int fd, op; +{ + if (rb_thread_alone() || (op & LOCK_NB)) { + return flock(fd, op); + } + op |= LOCK_NB; + while (flock(fd, op) < 0) { + switch (errno) { + case EINTR: /* can be happen? */ + case EWOULDBLOCK: + rb_thread_schedule(); /* busy wait */ + break; + default: + return -1; + } + } + return 0; } +#define flock rb_thread_flock +#endif static VALUE -file_flock(obj, operation) +rb_file_flock(obj, operation) VALUE obj; VALUE operation; { +#ifdef USE_CWGUSI + rb_notimplement(); +#else OpenFile *fptr; + rb_secure(4); GetOpenFile(obj, fptr); - rb_secure(2); if (flock(fileno(fptr->f), NUM2INT(operation)) < 0) { #ifdef EWOULDBLOCK if (errno == EWOULDBLOCK) { - return FALSE; + return Qfalse; } #endif rb_sys_fail(fptr->path); } - return obj; + return INT2FIX(0); +#endif /* USE_CWGUSI */ } +#undef flock static void test_check(n, argc, argv) @@ -1444,29 +1452,33 @@ test_check(n, argc, argv) int i; n+=1; - if (n < argc) ArgError("Wrong # of arguments(%d for %d)", argc, n); + if (n < argc) rb_raise(rb_eArgError, "Wrong # of arguments(%d for %d)", argc, n); for (i=1; ilen == 1) { - cmd = RSTRING(argv[0])->ptr[0]; - } - else { - cmd = NUM2INT(argv[0]); - } - if (cmd == 0) return FALSE; + if (argc == 0) rb_raise(rb_eArgError, "Wrong # of arguments"); + cmd = NUM2CHR(argv[0]); + if (cmd == 0) return Qfalse; if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) { CHECK(1); switch (cmd) { @@ -1543,17 +1555,17 @@ f_test(argc, argv) struct stat st; CHECK(1); - if (stat(RSTRING(argv[1])->ptr, &st) == -1) { + if (rb_stat(argv[1], &st) == -1) { rb_sys_fail(RSTRING(argv[1])->ptr); } switch (cmd) { case 'A': - return time_new(st.st_atime, 0); + return rb_time_new(st.st_atime, 0); case 'M': - return time_new(st.st_mtime, 0); + return rb_time_new(st.st_mtime, 0); case 'C': - return time_new(st.st_ctime, 0); + return rb_time_new(st.st_ctime, 0); } } @@ -1561,161 +1573,136 @@ f_test(argc, argv) struct stat st1, st2; CHECK(2); - if (stat(RSTRING(argv[1])->ptr, &st1) < 0) return FALSE; - if (stat(RSTRING(argv[2])->ptr, &st2) < 0) return FALSE; + if (rb_stat(argv[1], &st1) < 0) return Qfalse; + if (rb_stat(argv[2], &st2) < 0) return Qfalse; switch (cmd) { case '-': if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) - return TRUE; + return Qtrue; break; case '=': - if (st1.st_mtime == st2.st_mtime) return TRUE; + if (st1.st_mtime == st2.st_mtime) return Qtrue; break; case '>': - if (st1.st_mtime > st2.st_mtime) return TRUE; + if (st1.st_mtime > st2.st_mtime) return Qtrue; break; case '<': - if (st1.st_mtime < st2.st_mtime) return TRUE; + if (st1.st_mtime < st2.st_mtime) return Qtrue; break; } } - return FALSE; + /* unknown command */ + rb_raise(rb_eArgError, "unknow command ?%c", cmd); + return Qnil; /* not reached */ } -extern VALUE mKernel; - void Init_File() { - VALUE mConst; - - mFileTest = rb_define_module("FileTest"); - - rb_define_module_function(mFileTest, "directory?", test_d, 1); - rb_define_module_function(mFileTest, "exist?", test_e, 1); - rb_define_module_function(mFileTest, "exists?", test_e, 1); /* temporary */ - rb_define_module_function(mFileTest, "readable?", test_r, 1); - rb_define_module_function(mFileTest, "readable_real?", test_R, 1); - rb_define_module_function(mFileTest, "writable?", test_w, 1); - rb_define_module_function(mFileTest, "writable_real?", test_W, 1); - rb_define_module_function(mFileTest, "executable?", test_x, 1); - rb_define_module_function(mFileTest, "executable_real?", test_X, 1); - rb_define_module_function(mFileTest, "file?", test_f, 1); - rb_define_module_function(mFileTest, "zero?", test_z, 1); - rb_define_module_function(mFileTest, "size?", test_s, 1); - rb_define_module_function(mFileTest, "size", test_s, 1); - rb_define_module_function(mFileTest, "owned?", test_owned, 1); - rb_define_module_function(mFileTest, "grpowned?", test_grpowned, 1); - - rb_define_module_function(mFileTest, "pipe?", test_p, 1); - rb_define_module_function(mFileTest, "symlink?", test_l, 1); - rb_define_module_function(mFileTest, "socket?", test_S, 1); - - rb_define_module_function(mFileTest, "blockdev?", test_b, 1); - rb_define_module_function(mFileTest, "chardev?", test_c, 1); - - rb_define_module_function(mFileTest, "setuid?", test_suid, 1); - rb_define_module_function(mFileTest, "setgid?", test_sgid, 1); - rb_define_module_function(mFileTest, "sticky?", test_sticky, 1); - - cFile = rb_define_class("File", cIO); - rb_extend_object(cFile, CLASS_OF(mFileTest)); - - rb_define_singleton_method(cFile, "new", file_s_open, -1); - rb_define_singleton_method(cFile, "open", file_s_open, -1); - - rb_define_singleton_method(cFile, "stat", file_s_stat, 1); - rb_define_singleton_method(cFile, "lstat", file_s_lstat, 1); - rb_define_singleton_method(cFile, "ftype", file_s_ftype, 1); - - rb_define_singleton_method(cFile, "atime", file_s_atime, 1); - rb_define_singleton_method(cFile, "mtime", file_s_mtime, 1); - rb_define_singleton_method(cFile, "ctime", file_s_ctime, 1); - rb_define_singleton_method(cFile, "size", file_s_size, 1); - - rb_define_singleton_method(cFile, "utime", file_s_utime, -1); - rb_define_singleton_method(cFile, "chmod", file_s_chmod, -1); - rb_define_singleton_method(cFile, "chown", file_s_chown, -1); - - rb_define_singleton_method(cFile, "link", file_s_link, 2); - rb_define_singleton_method(cFile, "symlink", file_s_symlink, 2); - rb_define_singleton_method(cFile, "readlink", file_s_readlink, 1); - - rb_define_singleton_method(cFile, "unlink", file_s_unlink, -2); - rb_define_singleton_method(cFile, "delete", file_s_unlink, -2); - rb_define_singleton_method(cFile, "rename", file_s_rename, 2); - rb_define_singleton_method(cFile, "umask", file_s_umask, -1); - rb_define_singleton_method(cFile, "truncate", file_s_truncate, 2); - rb_define_singleton_method(cFile, "expand_path", file_s_expand_path, 1); - rb_define_singleton_method(cFile, "basename", file_s_basename, -1); - rb_define_singleton_method(cFile, "dirname", file_s_dirname, 1); - - separator = str_new2("/"); - rb_define_const(cFile, "Separator", separator); - rb_define_singleton_method(cFile, "split", file_s_split, 1); - rb_define_singleton_method(cFile, "join", file_s_join, -2); - - rb_define_method(cFile, "reopen", file_reopen, -1); - - rb_define_method(cFile, "stat", file_stat, 0); - rb_define_method(cFile, "lstat", file_lstat, 0); - - rb_define_method(cFile, "atime", file_atime, 0); - rb_define_method(cFile, "mtime", file_mtime, 0); - rb_define_method(cFile, "ctime", file_ctime, 0); - - rb_define_method(cFile, "chmod", file_chmod, 1); - rb_define_method(cFile, "chown", file_chown, 2); - rb_define_method(cFile, "truncate", file_truncate, 1); - - rb_define_method(cFile, "tell", file_tell, 0); - rb_define_method(cFile, "seek", file_seek, 2); - - rb_define_method(cFile, "pos", file_tell, 0); - rb_define_method(cFile, "pos=", file_set_pos, 1); - - rb_define_method(cFile, "rewind", file_rewind, 0); - rb_define_method(cFile, "isatty", file_isatty, 0); - rb_define_method(cFile, "tty?", file_isatty, 0); - rb_define_method(cFile, "eof", file_eof, 0); - rb_define_method(cFile, "eof?", file_eof, 0); - - rb_define_method(cFile, "flock", file_flock, 1); - -# 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 - - mConst = rb_define_module_under(cFile, "Constants"); - rb_define_const(cFile, "LOCK_SH", INT2FIX(LOCK_SH)); - rb_define_const(cFile, "LOCK_EX", INT2FIX(LOCK_EX)); - rb_define_const(cFile, "LOCK_UN", INT2FIX(LOCK_UN)); - rb_define_const(cFile, "LOCK_NB", INT2FIX(LOCK_NB)); - - rb_define_const(mConst, "LOCK_SH", INT2FIX(LOCK_SH)); - rb_define_const(mConst, "LOCK_EX", INT2FIX(LOCK_EX)); - rb_define_const(mConst, "LOCK_UN", INT2FIX(LOCK_UN)); - rb_define_const(mConst, "LOCK_NB", INT2FIX(LOCK_NB)); - - rb_define_method(cFile, "path", file_path, 0); - - rb_define_global_function("test", f_test, -1); - - sStat = struct_define("Stat", "dev", "ino", "mode", - "nlink", "uid", "gid", "rdev", - "size", "blksize", "blocks", - "atime", "mtime", "ctime", 0); + VALUE rb_mConst; + + rb_mFileTest = rb_define_module("FileTest"); + + rb_define_module_function(rb_mFileTest, "directory?", test_d, 1); + rb_define_module_function(rb_mFileTest, "exist?", test_e, 1); + rb_define_module_function(rb_mFileTest, "exists?", test_e, 1); /* temporary */ + rb_define_module_function(rb_mFileTest, "readable?", test_r, 1); + rb_define_module_function(rb_mFileTest, "readable_real?", test_R, 1); + rb_define_module_function(rb_mFileTest, "writable?", test_w, 1); + rb_define_module_function(rb_mFileTest, "writable_real?", test_W, 1); + rb_define_module_function(rb_mFileTest, "executable?", test_x, 1); + rb_define_module_function(rb_mFileTest, "executable_real?", test_X, 1); + rb_define_module_function(rb_mFileTest, "file?", test_f, 1); + rb_define_module_function(rb_mFileTest, "zero?", test_z, 1); + rb_define_module_function(rb_mFileTest, "size?", test_s, 1); + rb_define_module_function(rb_mFileTest, "size", test_s, 1); + rb_define_module_function(rb_mFileTest, "owned?", test_owned, 1); + rb_define_module_function(rb_mFileTest, "grpowned?", test_grpowned, 1); + + rb_define_module_function(rb_mFileTest, "pipe?", test_p, 1); + rb_define_module_function(rb_mFileTest, "symlink?", test_l, 1); + rb_define_module_function(rb_mFileTest, "socket?", test_S, 1); + + rb_define_module_function(rb_mFileTest, "blockdev?", test_b, 1); + rb_define_module_function(rb_mFileTest, "chardev?", test_c, 1); + + rb_define_module_function(rb_mFileTest, "setuid?", test_suid, 1); + rb_define_module_function(rb_mFileTest, "setgid?", test_sgid, 1); + rb_define_module_function(rb_mFileTest, "sticky?", test_sticky, 1); + + rb_cFile = rb_define_class("File", rb_cIO); + rb_extend_object(rb_cFile, CLASS_OF(rb_mFileTest)); + + rb_define_singleton_method(rb_cFile, "new", rb_file_s_open, -1); + rb_define_singleton_method(rb_cFile, "open", rb_file_s_open, -1); + + rb_define_singleton_method(rb_cFile, "stat", rb_file_s_stat, 1); + rb_define_singleton_method(rb_cFile, "lstat", rb_file_s_lstat, 1); + rb_define_singleton_method(rb_cFile, "ftype", rb_file_s_ftype, 1); + + rb_define_singleton_method(rb_cFile, "atime", rb_file_s_atime, 1); + rb_define_singleton_method(rb_cFile, "mtime", rb_file_s_mtime, 1); + rb_define_singleton_method(rb_cFile, "ctime", rb_file_s_ctime, 1); + rb_define_singleton_method(rb_cFile, "size", rb_file_s_size, 1); + + rb_define_singleton_method(rb_cFile, "utime", rb_file_s_utime, -1); + rb_define_singleton_method(rb_cFile, "chmod", rb_file_s_chmod, -1); + rb_define_singleton_method(rb_cFile, "chown", rb_file_s_chown, -1); + + rb_define_singleton_method(rb_cFile, "link", rb_file_s_link, 2); + rb_define_singleton_method(rb_cFile, "symlink", rb_file_s_symlink, 2); + rb_define_singleton_method(rb_cFile, "readlink", rb_file_s_readlink, 1); + + rb_define_singleton_method(rb_cFile, "unlink", rb_file_s_unlink, -2); + rb_define_singleton_method(rb_cFile, "delete", rb_file_s_unlink, -2); + rb_define_singleton_method(rb_cFile, "rename", rb_file_s_rename, 2); + rb_define_singleton_method(rb_cFile, "umask", rb_file_s_umask, -1); + rb_define_singleton_method(rb_cFile, "truncate", rb_file_s_truncate, 2); + rb_define_singleton_method(rb_cFile, "expand_path", rb_file_s_expand_path, -1); + rb_define_singleton_method(rb_cFile, "basename", rb_file_s_basename, -1); + rb_define_singleton_method(rb_cFile, "dirname", rb_file_s_dirname, 1); + + separator = rb_str_new2("/"); + rb_define_const(rb_cFile, "Separator", separator); + rb_define_singleton_method(rb_cFile, "split", rb_file_s_split, 1); + rb_define_singleton_method(rb_cFile, "join", rb_file_s_join, -2); + + rb_define_method(rb_cFile, "reopen", rb_file_reopen, -1); + + rb_define_method(rb_cIO, "stat", rb_io_stat, 0); /* this is IO's method */ + rb_define_method(rb_cFile, "lstat", rb_file_lstat, 0); + + rb_define_method(rb_cFile, "atime", rb_file_atime, 0); + rb_define_method(rb_cFile, "mtime", rb_file_mtime, 0); + rb_define_method(rb_cFile, "ctime", rb_file_ctime, 0); + + rb_define_method(rb_cFile, "chmod", rb_file_chmod, 1); + rb_define_method(rb_cFile, "chown", rb_file_chown, 2); + rb_define_method(rb_cFile, "truncate", rb_file_truncate, 1); + + rb_define_method(rb_cFile, "flock", rb_file_flock, 1); + + rb_mConst = rb_define_module_under(rb_cFile, "Constants"); + rb_define_const(rb_cFile, "LOCK_SH", INT2FIX(LOCK_SH)); + rb_define_const(rb_cFile, "LOCK_EX", INT2FIX(LOCK_EX)); + rb_define_const(rb_cFile, "LOCK_UN", INT2FIX(LOCK_UN)); + rb_define_const(rb_cFile, "LOCK_NB", INT2FIX(LOCK_NB)); + + rb_define_const(rb_mConst, "LOCK_SH", INT2FIX(LOCK_SH)); + rb_define_const(rb_mConst, "LOCK_EX", INT2FIX(LOCK_EX)); + rb_define_const(rb_mConst, "LOCK_UN", INT2FIX(LOCK_UN)); + rb_define_const(rb_mConst, "LOCK_NB", INT2FIX(LOCK_NB)); + + rb_define_method(rb_cFile, "path", rb_file_path, 0); + + rb_define_global_function("test", rb_f_test, -1); + + sStat = rb_struct_define("Stat", "dev", "ino", "mode", + "nlink", "uid", "gid", "rdev", + "size", "blksize", "blocks", + "atime", "mtime", "ctime", 0); } diff --git a/fnmatch.c b/fnmatch.c index 0847f5cafb..f031749c3d 100644 --- a/fnmatch.c +++ b/fnmatch.c @@ -20,6 +20,10 @@ Cambridge, MA 02139, USA. */ #include #include "fnmatch.h" +#ifdef USE_CWGUSI +#include +#endif + #if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS) # if !defined (errno) extern int errno; @@ -51,15 +55,23 @@ fnmatch (pattern, string, flags) if (*n == '\0') return (FNM_NOMATCH); else if ((flags & FNM_PATHNAME) && *n == '/') + /* If we are matching a pathname, `?' can never match a `/'. */ return (FNM_NOMATCH); else if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + /* `?' cannot match a `.' if it is the first character of the + string or if it is the first character following a slash and + we are matching a pathname. */ return (FNM_NOMATCH); break; case '\\': if (!(flags & FNM_NOESCAPE)) - c = *p++; + { + c = *p++; + if (c == '\0') + return (FNM_NOMATCH); + } if (*n != c) return (FNM_NOMATCH); break; @@ -67,19 +79,38 @@ fnmatch (pattern, string, flags) case '*': if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) + /* `*' cannot match a `.' if it is the first character of the + string or if it is the first character following a slash and + we are matching a pathname. */ return (FNM_NOMATCH); - for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) - if (((flags & FNM_PATHNAME) && *n == '/') || - (c == '?' && *n == '\0')) - return (FNM_NOMATCH); + /* Collapse multiple consecutive, `*' and `?', but make sure that + one character of the string is consumed for each `?'. */ + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if ((flags & FNM_PATHNAME) && *n == '/') + /* A slash does not match a wildcard under FNM_PATHNAME. */ + return (FNM_NOMATCH); + else if (c == '?') + { + if (*n == '\0') + return (FNM_NOMATCH); + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + fewer than three characters. */ + n++; + } + } if (c == '\0') return (0); + /* General case, use recursion. */ { char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; for (--p; *n != '\0'; ++n) + /* Only call fnmatch if the first character indicates a + possible match. */ if ((c == '[' || *n == c1) && fnmatch (p, n, flags & ~FNM_PERIOD) == 0) return (0); @@ -94,22 +125,30 @@ fnmatch (pattern, string, flags) if (*n == '\0') return (FNM_NOMATCH); + /* A character class cannot match a `.' if it is the first + character of the string or if it is the first character + following a slash and we are matching a pathname. */ if ((flags & FNM_PERIOD) && *n == '.' && (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/'))) return (FNM_NOMATCH); - /* Make sure there is a closing `]'. If there isn't, the `[' - is just a character to be matched. */ + /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that + is not preceded by a backslash and is not part of a bracket + expression produces undefined results.' This implementation + treats the `[' as just a character to be matched if there is + not a closing `]'. This code will have to be changed when + POSIX.2 character classes are implemented. */ { register char *np; - for (np = p; np && *np && *np != ']'; np++); + for (np = p; np && *np && *np != ']'; np++) + ; if (np && !*np) { if (*n != '[') return (FNM_NOMATCH); - goto next_char; + break; } } @@ -120,10 +159,18 @@ fnmatch (pattern, string, flags) c = *p++; for (;;) { - register char cstart = c, cend = c; + register char cstart, cend; + + /* Initialize cstart and cend in case `-' is the last + character of the pattern. */ + cstart = cend = c; if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; + { + if (*p == '\0') + return FNM_NOMATCH; + cstart = cend = *p++; + } if (c == '\0') /* [ (unterminated) loses. */ @@ -135,6 +182,9 @@ fnmatch (pattern, string, flags) /* [/] can never match. */ return (FNM_NOMATCH); + /* This introduces a range, unless the `-' is the last + character of the class. Find the end of the range + and move past it. */ if (c == '-' && *p != ']') { cend = *p++; @@ -142,6 +192,7 @@ fnmatch (pattern, string, flags) cend = *p++; if (cend == '\0') return (FNM_NOMATCH); + c = *p++; } @@ -153,8 +204,6 @@ fnmatch (pattern, string, flags) } if (!not) return (FNM_NOMATCH); - - next_char: break; matched: @@ -167,8 +216,12 @@ fnmatch (pattern, string, flags) c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') - /* 1003.2d11 is unclear if this is right. %%% */ - ++p; + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } } if (not) return (FNM_NOMATCH); diff --git a/gc.c b/gc.c index 27065af1cb..31ed11196a 100644 --- a/gc.c +++ b/gc.c @@ -6,12 +6,13 @@ $Date$ created at: Tue Oct 5 09:44:46 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ +#define RUBY_NO_INLINE #include "ruby.h" -#include "sig.h" +#include "rubysig.h" #include "st.h" #include "node.h" #include "env.h" @@ -19,6 +20,9 @@ #include #include +void re_free_registers _((struct re_registers*)); +void rb_io_fptr_finalize _((struct OpenFile*)); + #ifndef setjmp #ifdef HAVE__SETJMP #define setjmp(env) _setjmp(env) @@ -26,43 +30,46 @@ #endif #endif -#ifdef _AIX -#pragma alloca -#endif - #ifdef C_ALLOCA +#ifndef alloca void *alloca(); #endif +#endif static void run_final(); #ifndef GC_MALLOC_LIMIT #if defined(MSDOS) || defined(__human68k__) -#define GC_MALLOC_LIMIT 200000 +#define GC_MALLOC_LIMIT 100000 #else -#define GC_MALLOC_LIMIT 400000 +#define GC_MALLOC_LIMIT 200000 #endif #endif +#define GC_NEWOBJ_LIMIT 1000 static unsigned long malloc_memories = 0; +static unsigned long alloc_objects = 0; void * xmalloc(size) - unsigned long size; + size_t size; { void *mem; + if (size < 0) { + rb_raise(rb_eArgError, "negative allocation size (or too big)"); + } if (size == 0) size = 1; malloc_memories += size; - if (malloc_memories > GC_MALLOC_LIMIT) { - gc_gc(); + if (malloc_memories > GC_MALLOC_LIMIT && alloc_objects > GC_NEWOBJ_LIMIT) { + rb_gc(); } mem = malloc(size); if (!mem) { - gc_gc(); + rb_gc(); mem = malloc(size); if (!mem) - Fatal("failed to allocate memory"); + rb_fatal("failed to allocate memory"); } return mem; @@ -70,7 +77,7 @@ xmalloc(size) void * xcalloc(n, size) - unsigned long n, size; + size_t n, size; { void *mem; @@ -83,17 +90,22 @@ xcalloc(n, size) void * xrealloc(ptr, size) void *ptr; - unsigned long size; + size_t size; { void *mem; + if (size < 0) { + rb_raise(rb_eArgError, "negative re-allocation size"); + } if (!ptr) return xmalloc(size); + if (size == 0) size = 1; + malloc_memories += size; mem = realloc(ptr, size); if (!mem) { - gc_gc(); + rb_gc(); mem = realloc(ptr, size); if (!mem) - Fatal("failed to allocate memory(realloc)"); + rb_fatal("failed to allocate memory(realloc)"); } return mem; @@ -129,28 +141,30 @@ Paradigm Associates Inc Phone: 617-492-6079 Cambridge, MA 02138 */ -extern int rb_in_compile; +extern int ruby_in_compile; static int dont_gc; +static int during_gc; +static int need_call_final = 0; -VALUE -gc_s_enable() +static VALUE +gc_enable() { int old = dont_gc; - dont_gc = FALSE; + dont_gc = Qfalse; return old; } -VALUE -gc_s_disable() +static VALUE +gc_disable() { int old = dont_gc; - dont_gc = TRUE; + dont_gc = Qtrue; return old; } -VALUE mGC; +VALUE rb_mGC; static struct gc_list { VALUE *varptr; @@ -172,12 +186,12 @@ rb_global_variable(var) typedef struct RVALUE { union { struct { - UINT flag; /* always 0 for freed obj */ + unsigned long flag; /* always 0 for freed obj */ struct RVALUE *next; } free; struct RBasic basic; struct RObject object; - struct RClass class; + struct RClass klass; struct RFloat flonum; struct RString string; struct RArray array; @@ -194,7 +208,7 @@ typedef struct RVALUE { } as; } RVALUE; -RVALUE *freelist = 0; +static RVALUE *freelist = 0; #define HEAPS_INCREMENT 10 static RVALUE **heaps; @@ -217,11 +231,11 @@ add_heap() heaps = (heaps_used>0)? (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE)): (RVALUE**)malloc(heaps_length*sizeof(RVALUE)); - if (heaps == 0) Fatal("can't alloc memory"); + if (heaps == 0) rb_fatal("can't alloc memory"); } p = heaps[heaps_used++] = (RVALUE*)malloc(sizeof(RVALUE)*HEAP_SLOTS); - if (p == 0) Fatal("can't alloc memory"); + if (p == 0) rb_fatal("add_heap: can't alloc memory"); pend = p + HEAP_SLOTS; if (lomem == 0 || lomem > p) lomem = p; if (himem < pend) himem = pend; @@ -244,23 +258,24 @@ rb_newobj() retry: obj = (VALUE)freelist; freelist = freelist->as.free.next; + alloc_objects++; return obj; } - if (dont_gc) add_heap(); - else gc_gc(); + if (dont_gc || during_gc || rb_prohibit_interrupt) add_heap(); + else rb_gc(); goto retry; } VALUE -data_object_alloc(class, datap, dmark, dfree) - VALUE class; +rb_data_object_alloc(klass, datap, dmark, dfree) + VALUE klass; void *datap; void (*dfree)(); void (*dmark)(); { NEWOBJ(data, struct RData); - OBJSETUP(data, class, T_DATA); + OBJSETUP(data, klass, T_DATA); data->data = datap; data->dfree = dfree; data->dmark = dmark; @@ -269,8 +284,11 @@ data_object_alloc(class, datap, dmark, dfree) } extern st_table *rb_class_tbl; -VALUE *gc_stack_start; +VALUE *rb_gc_stack_start; +#if defined(__GNUC__) && __GNUC__ >= 2 +__inline__ +#endif static int looks_pointerp(ptr) void *ptr; @@ -279,33 +297,33 @@ looks_pointerp(ptr) register RVALUE *heap_org; register long i; - if (p < lomem || p > himem) return FALSE; + if (p < lomem || p > himem) return Qfalse; /* check if p looks like a pointer */ for (i=0; i < heaps_used; i++) { heap_org = heaps[i]; if (heap_org <= p && p < heap_org + HEAP_SLOTS && ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0) - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } static void mark_locations_array(x, n) - VALUE *x; - long n; + register VALUE *x; + register long n; { while (n--) { if (looks_pointerp(*x)) { - gc_mark(*x); + rb_gc_mark(*x); } x++; } } void -gc_mark_locations(start, end) +rb_gc_mark_locations(start, end) VALUE *start, *end; { VALUE *tmp; @@ -325,12 +343,12 @@ mark_entry(key, value) ID key; VALUE value; { - gc_mark(value); + rb_gc_mark(value); return ST_CONTINUE; } -static void -mark_tbl(tbl) +void +rb_mark_tbl(tbl) st_table *tbl; { if (!tbl) return; @@ -342,13 +360,13 @@ mark_hashentry(key, value) ID key; VALUE value; { - gc_mark(key); - gc_mark(value); + rb_gc_mark(key); + rb_gc_mark(value); return ST_CONTINUE; } -static void -mark_hash(tbl) +void +rb_mark_hash(tbl) st_table *tbl; { if (!tbl) return; @@ -356,16 +374,16 @@ mark_hash(tbl) } void -gc_mark_maybe(obj) +rb_gc_mark_maybe(obj) void *obj; { if (looks_pointerp(obj)) { - gc_mark(obj); + rb_gc_mark(obj); } } void -gc_mark(ptr) +rb_gc_mark(ptr) void *ptr; { register RVALUE *obj = RANY(ptr); @@ -374,14 +392,18 @@ gc_mark(ptr) if (FIXNUM_P(obj)) return; /* fixnum not marked */ if (rb_special_const_p((VALUE)obj)) return; /* special const not marked */ if (obj->as.basic.flags == 0) return; /* free cell */ - if (obj->as.basic.flags & FL_MARK) return; /* marked */ + if (obj->as.basic.flags & FL_MARK) return; /* already marked */ obj->as.basic.flags |= FL_MARK; + if (FL_TEST(obj, FL_EXIVAR)) { + rb_mark_generic_ivar((VALUE)obj); + } + switch (obj->as.basic.flags & T_MASK) { case T_NIL: case T_FIXNUM: - Bug("gc_mark() called for broken object"); + rb_bug("rb_gc_mark() called for broken object"); break; case T_NODE: @@ -389,7 +411,12 @@ gc_mark(ptr) case NODE_IF: /* 1,2,3 */ case NODE_FOR: case NODE_ITER: - gc_mark(obj->as.node.u2.node); + case NODE_CREF: + case NODE_WHEN: + case NODE_MASGN: + case NODE_RESCUE: + case NODE_RESBODY: + rb_gc_mark(obj->as.node.u2.node); /* fall through */ case NODE_BLOCK: /* 1,3 */ case NODE_ARRAY: @@ -399,23 +426,47 @@ gc_mark(ptr) case NODE_DREGX: case NODE_DREGX_ONCE: case NODE_FBODY: + case NODE_ENSURE: case NODE_CALL: - gc_mark(obj->as.node.u1.node); + case NODE_DEFS: + case NODE_OP_ASGN1: + rb_gc_mark(obj->as.node.u1.node); /* fall through */ case NODE_SUPER: /* 3 */ case NODE_FCALL: + case NODE_DEFN: case NODE_NEWLINE: obj = RANY(obj->as.node.u3.node); goto Top; case NODE_WHILE: /* 1,2 */ case NODE_UNTIL: + case NODE_AND: + case NODE_OR: + case NODE_CASE: + case NODE_SCLASS: + case NODE_ARGS: + case NODE_DOT2: + case NODE_DOT3: + case NODE_FLIP2: + case NODE_FLIP3: case NODE_MATCH2: case NODE_MATCH3: - gc_mark(obj->as.node.u1.node); + case NODE_OP_ASGN_OR: + case NODE_OP_ASGN_AND: + rb_gc_mark(obj->as.node.u1.node); /* fall through */ case NODE_METHOD: /* 2 */ case NODE_NOT: + case NODE_GASGN: + case NODE_LASGN: + case NODE_DASGN: + case NODE_DASGN_PUSH: + case NODE_IASGN: + case NODE_CASGN: + case NODE_MODULE: + case NODE_COLON3: + case NODE_OPT_N: obj = RANY(obj->as.node.u2.node); goto Top; @@ -425,15 +476,21 @@ gc_mark(ptr) case NODE_XSTR: case NODE_DEFINED: case NODE_MATCH: + case NODE_RETURN: + case NODE_YIELD: + case NODE_COLON2: obj = RANY(obj->as.node.u1.node); goto Top; case NODE_SCOPE: /* 2,3 */ - gc_mark(obj->as.node.u3.node); + case NODE_CLASS: + case NODE_BLOCK_PASS: + rb_gc_mark(obj->as.node.u3.node); obj = RANY(obj->as.node.u2.node); goto Top; case NODE_ZARRAY: /* - */ + case NODE_ZSUPER: case NODE_CFUNC: case NODE_VCALL: case NODE_GVAR: @@ -445,18 +502,33 @@ gc_mark(ptr) case NODE_BACK_REF: case NODE_ALIAS: case NODE_VALIAS: + case NODE_BREAK: + case NODE_NEXT: + case NODE_REDO: + case NODE_RETRY: case NODE_UNDEF: case NODE_SELF: case NODE_NIL: + case NODE_TRUE: + case NODE_FALSE: + case NODE_ATTRSET: + case NODE_BLOCK_ARG: case NODE_POSTEXE: break; +#ifdef C_ALLOCA + case NODE_ALLOCA: + mark_locations_array((VALUE*)obj->as.node.u1.value, + obj->as.node.u3.cnt); + obj = RANY(obj->as.node.u2.node); + goto Top; +#endif default: if (looks_pointerp(obj->as.node.u1.node)) { - gc_mark(obj->as.node.u1.node); + rb_gc_mark(obj->as.node.u1.node); } if (looks_pointerp(obj->as.node.u2.node)) { - gc_mark(obj->as.node.u2.node); + rb_gc_mark(obj->as.node.u2.node); } if (looks_pointerp(obj->as.node.u3.node)) { obj = RANY(obj->as.node.u3.node); @@ -466,19 +538,14 @@ gc_mark(ptr) return; /* no need to mark class. */ } - gc_mark(obj->as.basic.class); + rb_gc_mark(obj->as.basic.klass); switch (obj->as.basic.flags & T_MASK) { case T_ICLASS: - gc_mark(obj->as.class.super); - mark_tbl(obj->as.class.iv_tbl); - mark_tbl(obj->as.class.m_tbl); - break; - case T_CLASS: case T_MODULE: - gc_mark(obj->as.class.super); - mark_tbl(obj->as.class.m_tbl); - mark_tbl(obj->as.class.iv_tbl); + rb_gc_mark(obj->as.klass.super); + rb_mark_tbl(obj->as.klass.m_tbl); + rb_mark_tbl(obj->as.klass.iv_tbl); break; case T_ARRAY: @@ -487,12 +554,13 @@ gc_mark(ptr) VALUE *ptr = obj->as.array.ptr; for (i=0; i < len; i++) - gc_mark(*ptr++); + rb_gc_mark(*ptr++); } break; case T_HASH: - mark_hash(obj->as.hash.tbl); + rb_mark_hash(obj->as.hash.tbl); + rb_gc_mark(obj->as.hash.ifnone); break; case T_STRING: @@ -507,7 +575,7 @@ gc_mark(ptr) break; case T_OBJECT: - mark_tbl(obj->as.object.iv_tbl); + rb_mark_tbl(obj->as.object.iv_tbl); break; case T_FILE: @@ -524,7 +592,7 @@ gc_mark(ptr) break; case T_VARMAP: - gc_mark(obj->as.varmap.val); + rb_gc_mark(obj->as.varmap.val); obj = RANY(obj->as.varmap.next); goto Top; break; @@ -535,7 +603,7 @@ gc_mark(ptr) VALUE *vars = &obj->as.scope.local_vars[-1]; while (n--) { - gc_mark_maybe(*vars); + rb_gc_mark(*vars); vars++; } } @@ -547,69 +615,95 @@ gc_mark(ptr) VALUE *ptr = obj->as.rstruct.ptr; for (i=0; i < len; i++) - gc_mark(*ptr++); + rb_gc_mark(*ptr++); } break; default: - Bug("gc_mark(): unknown data type 0x%x(0x%x) %s", - obj->as.basic.flags & T_MASK, obj, - looks_pointerp(obj)?"corrupted object":"non object"); + rb_bug("rb_gc_mark(): unknown data type 0x%x(0x%x) %s", + obj->as.basic.flags & T_MASK, obj, + looks_pointerp(obj)?"corrupted object":"non object"); } } #define MIN_FREE_OBJ 512 -static void obj_free(); +static void obj_free _((VALUE)); static void gc_sweep() { - RVALUE *p, *pend; + RVALUE *p, *pend, *final_list; int freed = 0; - int i; + int i, used = heaps_used; - if (rb_in_compile) { - for (i = 0; i < heaps_used; i++) { + if (ruby_in_compile) { + /* sould not reclaim nodes during compilation */ + for (i = 0; i < used; i++) { p = heaps[i]; pend = p + HEAP_SLOTS; while (p < pend) { if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) - gc_mark(p); + rb_gc_mark(p); p++; } } } freelist = 0; - for (i = 0; i < heaps_used; i++) { - RVALUE *nfreelist; + final_list = 0; + for (i = 0; i < used; i++) { int n = 0; - nfreelist = freelist; p = heaps[i]; pend = p + HEAP_SLOTS; - while (p < pend) { if (!(p->as.basic.flags & FL_MARK)) { - if (p->as.basic.flags) obj_free(p); - p->as.free.flag = 0; - p->as.free.next = nfreelist; - nfreelist = p; + if (p->as.basic.flags) { + obj_free((VALUE)p); + } + if (need_call_final && FL_TEST(p, FL_FINALIZE)) { + p->as.free.flag = FL_MARK; /* remain marked */ + p->as.free.next = final_list; + final_list = p; + } + else { + p->as.free.flag = 0; + p->as.free.next = freelist; + freelist = p; + } n++; } - else + else if (RBASIC(p)->flags == FL_MARK) { + /* objects to be finalized */ + /* do notning remain marked */ + } + else { RBASIC(p)->flags &= ~FL_MARK; + } p++; } freed += n; - freelist = nfreelist; } if (freed < FREE_MIN) { add_heap(); } + during_gc = 0; + + /* clear finalization list */ + if (need_call_final) { + RVALUE *tmp; + + for (p = final_list; p; p = tmp) { + tmp = p->as.free.next; + run_final((VALUE)p); + p->as.free.flag = 0; + p->as.free.next = freelist; + freelist = p; + } + } } void -gc_force_recycle(p) +rb_gc_force_recycle(p) VALUE p; { RANY(p)->as.free.flag = 0; @@ -617,8 +711,6 @@ gc_force_recycle(p) freelist = RANY(p); } -static int need_call_final = 0; - static void obj_free(obj) VALUE obj; @@ -628,13 +720,14 @@ obj_free(obj) case T_FIXNUM: case T_TRUE: case T_FALSE: - Bug("obj_free() called for broken object"); + rb_bug("obj_free() called for broken object"); break; } - if (need_call_final) { - run_final(obj); + if (FL_TEST(obj, FL_EXIVAR)) { + rb_free_generic_ivar((VALUE)obj); } + switch (RANY(obj)->as.basic.flags & T_MASK) { case T_OBJECT: if (RANY(obj)->as.object.iv_tbl) { @@ -644,35 +737,48 @@ obj_free(obj) case T_MODULE: case T_CLASS: rb_clear_cache(); - st_free_table(RANY(obj)->as.class.m_tbl); + st_free_table(RANY(obj)->as.klass.m_tbl); if (RANY(obj)->as.object.iv_tbl) { st_free_table(RANY(obj)->as.object.iv_tbl); } break; case T_STRING: - if (!RANY(obj)->as.string.orig) free(RANY(obj)->as.string.ptr); +#define STR_NO_ORIG FL_USER3 /* copied from string.c */ + if (!RANY(obj)->as.string.orig || FL_TEST(obj, STR_NO_ORIG)) + free(RANY(obj)->as.string.ptr); break; case T_ARRAY: if (RANY(obj)->as.array.ptr) free(RANY(obj)->as.array.ptr); break; case T_HASH: - st_free_table(RANY(obj)->as.hash.tbl); + if (RANY(obj)->as.hash.tbl) + st_free_table(RANY(obj)->as.hash.tbl); break; case T_REGEXP: - reg_free(RANY(obj)->as.regexp.ptr); - free(RANY(obj)->as.regexp.str); + if (RANY(obj)->as.regexp.ptr) re_free_pattern(RANY(obj)->as.regexp.ptr); + if (RANY(obj)->as.regexp.str) free(RANY(obj)->as.regexp.str); break; case T_DATA: - if (RANY(obj)->as.data.dfree && DATA_PTR(obj)) - (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + if (DATA_PTR(obj)) { + if ((long)RANY(obj)->as.data.dfree == -1) { + free(DATA_PTR(obj)); + } + else if (RANY(obj)->as.data.dfree) { + (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + } + } break; case T_MATCH: - re_free_registers(RANY(obj)->as.match.regs); - free(RANY(obj)->as.match.regs); + if (RANY(obj)->as.match.regs) + re_free_registers(RANY(obj)->as.match.regs); + if (RANY(obj)->as.match.regs) + free(RANY(obj)->as.match.regs); break; case T_FILE: - io_fptr_finalize(RANY(obj)->as.file.fptr); - free(RANY(obj)->as.file.fptr); + if (RANY(obj)->as.file.fptr) { + rb_io_fptr_finalize(RANY(obj)->as.file.fptr); + free(RANY(obj)->as.file.fptr); + } break; case T_ICLASS: /* iClass shares table with the module */ @@ -686,8 +792,17 @@ obj_free(obj) if (RANY(obj)->as.bignum.digits) free(RANY(obj)->as.bignum.digits); break; case T_NODE: - if (nd_type(obj) == NODE_SCOPE && RANY(obj)->as.node.u1.tbl) { - free(RANY(obj)->as.node.u1.tbl); + switch (nd_type(obj)) { + case NODE_SCOPE: + if (RANY(obj)->as.node.u1.tbl) { + free(RANY(obj)->as.node.u1.tbl); + } + break; +#ifdef C_ALLOCA + case NODE_ALLOCA: + free(RANY(obj)->as.node.u1.value); + break; +#endif } return; /* no need to free iv_tbl */ @@ -702,26 +817,22 @@ obj_free(obj) break; case T_STRUCT: - free(RANY(obj)->as.rstruct.ptr); + if (RANY(obj)->as.rstruct.ptr) + free(RANY(obj)->as.rstruct.ptr); break; default: - Bug("gc_sweep(): unknown data type %d", RANY(obj)->as.basic.flags & T_MASK); + rb_bug("gc_sweep(): unknown data type %d", + RANY(obj)->as.basic.flags & T_MASK); } } void -gc_mark_frame(frame) +rb_gc_mark_frame(frame) struct FRAME *frame; { - int n = frame->argc; - VALUE *tbl = frame->argv; - - while (n--) { - gc_mark_maybe(*tbl); - tbl++; - } - gc_mark(frame->cbase); + mark_locations_array(frame->argv, frame->argc); + rb_gc_mark(frame->cbase); } #ifdef __GNUC__ @@ -760,68 +871,73 @@ int rb_setjmp (rb_jmp_buf); #endif /* __GNUC__ */ void -gc_gc() +rb_gc() { struct gc_list *list; struct FRAME *frame; jmp_buf save_regs_gc_mark; VALUE stack_end; - if (dont_gc) return; - dont_gc++; - + alloc_objects = 0; malloc_memories = 0; + + if (during_gc) return; + during_gc++; + #ifdef C_ALLOCA alloca(0); #endif /* mark frame stack */ - for (frame = the_frame; frame; frame = frame->prev) { - gc_mark_frame(frame); + for (frame = ruby_frame; frame; frame = frame->prev) { + rb_gc_mark_frame(frame); } - gc_mark(the_scope); - gc_mark(the_dyna_vars); + rb_gc_mark(ruby_class); + rb_gc_mark(ruby_scope); + rb_gc_mark(ruby_dyna_vars); FLUSH_REGISTER_WINDOWS; /* This assumes that all registers are saved into the jmp_buf */ setjmp(save_regs_gc_mark); mark_locations_array((VALUE*)&save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); - gc_mark_locations(gc_stack_start, (VALUE*)&stack_end); + rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)&stack_end); #if defined(THINK_C) || defined(__human68k__) #ifndef __human68k__ mark_locations_array((VALUE*)((char*)save_regs_gc_mark+2), sizeof(save_regs_gc_mark) / sizeof(VALUE *)); #endif - gc_mark_locations((VALUE*)((char*)gc_stack_start + 2), + rb_gc_mark_locations((VALUE*)((char*)rb_gc_stack_start + 2), (VALUE*)((char*)&stack_end + 2)); #endif -#ifdef THREAD - gc_mark_threads(); +#ifdef USE_THREAD + rb_gc_mark_threads(); #endif /* mark protected global variables */ for (list = Global_List; list; list = list->next) { - gc_mark(*list->varptr); + rb_gc_mark(*list->varptr); } + rb_gc_mark_global_tbl(); - gc_mark_global_tbl(); - mark_tbl(rb_class_tbl); - gc_mark_trap_list(); + rb_mark_tbl(rb_class_tbl); + rb_gc_mark_trap_list(); + + /* mark generic instance variables for special constants */ + rb_mark_generic_ivar_tbl(); gc_sweep(); - dont_gc--; } static VALUE -gc_method() +gc_start() { - gc_gc(); + rb_gc(); return Qnil; } void -init_stack() +Init_stack() { #ifdef __human68k__ extern void *_SEND; @@ -829,14 +945,14 @@ init_stack() #else VALUE start; - gc_stack_start = &start; + rb_gc_stack_start = &start; #endif } void -init_heap() +Init_heap() { - init_stack(); + Init_stack(); add_heap(); } @@ -893,7 +1009,7 @@ os_obj_of(of) case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; default: - if (obj_is_kind_of((VALUE)p, of)) { + if (rb_obj_is_kind_of((VALUE)p, of)) { rb_yield((VALUE)p); n++; } @@ -926,13 +1042,11 @@ static VALUE add_final(os, proc) VALUE os, proc; { - extern VALUE cProc; - - if (!obj_is_kind_of(proc, cProc)) { - ArgError("wrong type argument %s (Proc required)", - rb_class2name(CLASS_OF(proc))); + if (!rb_obj_is_kind_of(proc, rb_cProc)) { + rb_raise(rb_eArgError, "wrong type argument %s (Proc required)", + rb_class2name(CLASS_OF(proc))); } - ary_push(finalizers, proc); + rb_ary_push(finalizers, proc); return proc; } @@ -940,7 +1054,7 @@ static VALUE rm_final(os, proc) VALUE os, proc; { - ary_delete(finalizers, proc); + rb_ary_delete(finalizers, proc); return proc; } @@ -965,24 +1079,31 @@ run_final(obj) { int i; - if (!FL_TEST(obj, FL_FINALIZE)) return; - - obj = INT2NUM((int)obj); /* make obj into id */ + obj = rb_obj_id(obj); /* make obj into id */ for (i=0; ilen; i++) { - rb_eval_cmd(RARRAY(finalizers)->ptr[i], ary_new3(1,obj)); + rb_eval_cmd(RARRAY(finalizers)->ptr[i], rb_ary_new3(1, obj)); } } void -gc_call_finalizer_at_exit() +rb_gc_call_finalizer_at_exit() { RVALUE *p, *pend; 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)) + run_final((VALUE)p); + p++; + } + } + /* run data object's finaliers */ for (i = 0; i < heaps_used; i++) { p = heaps[i]; pend = p + HEAP_SLOTS; while (p < pend) { - run_final(p); if (BUILTIN_TYPE(p) == T_DATA && DATA_PTR(p) && RANY(p)->as.data.dfree) @@ -996,40 +1117,45 @@ static VALUE id2ref(obj, id) VALUE obj, id; { - INT ptr = NUM2INT(id); + unsigned long ptr; + rb_secure(4); + ptr = NUM2UINT(id); if (FIXNUM_P(ptr)) return (VALUE)ptr; + if (ptr == Qtrue) return Qtrue; + if (ptr == Qfalse) return Qfalse; + if (ptr == Qnil) return Qnil; + + ptr = id ^ FIXNUM_FLAG; if (!looks_pointerp(ptr)) { - IndexError("0x%x is not the id value", ptr); + rb_raise(rb_eIndexError, "0x%x is not id value", ptr); } - if (RANY(ptr)->as.free.flag == 0) { - IndexError("0x%x is recycled object", ptr); + if (BUILTIN_TYPE(ptr) == 0) { + rb_raise(rb_eIndexError, "0x%x is recycled object", ptr); } return (VALUE)ptr; } -extern VALUE cModule; - void Init_GC() { - VALUE mObSpace; - - mGC = rb_define_module("GC"); - rb_define_singleton_method(mGC, "start", gc_method, 0); - rb_define_singleton_method(mGC, "enable", gc_s_enable, 0); - rb_define_singleton_method(mGC, "disable", gc_s_disable, 0); - rb_define_method(mGC, "garbage_collect", gc_method, 0); - - mObSpace = rb_define_module("ObjectSpace"); - rb_define_module_function(mObSpace, "each_object", os_each_obj, -1); - rb_define_module_function(mObSpace, "garbage_collect", gc_method, 0); - rb_define_module_function(mObSpace, "add_finalizer", add_final, 1); - rb_define_module_function(mObSpace, "remove_finalizer", rm_final, 1); - rb_define_module_function(mObSpace, "finalizers", finals, 0); - rb_define_module_function(mObSpace, "call_finalizer", call_final, 1); - rb_define_module_function(mObSpace, "id2ref", id2ref, 1); + VALUE rb_mObSpace; + + rb_mGC = rb_define_module("GC"); + rb_define_singleton_method(rb_mGC, "start", gc_start, 0); + rb_define_singleton_method(rb_mGC, "enable", gc_enable, 0); + rb_define_singleton_method(rb_mGC, "disable", gc_disable, 0); + rb_define_method(rb_mGC, "garbage_collect", gc_start, 0); + + rb_mObSpace = rb_define_module("ObjectSpace"); + rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1); + rb_define_module_function(rb_mObSpace, "garbage_collect", gc_start, 0); + rb_define_module_function(rb_mObSpace, "add_finalizer", add_final, 1); + rb_define_module_function(rb_mObSpace, "remove_finalizer", rm_final, 1); + rb_define_module_function(rb_mObSpace, "finalizers", finals, 0); + rb_define_module_function(rb_mObSpace, "call_finalizer", call_final, 1); + rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1); rb_global_variable(&finalizers); - finalizers = ary_new(); + finalizers = rb_ary_new(); } diff --git a/glob.c b/glob.c index 6c355ad260..09a47e0aa4 100644 --- a/glob.c +++ b/glob.c @@ -14,83 +14,79 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + /* To whomever it may concern: I have never seen the code which most Unix programs use to perform this function. I wrote this from scratch based on specifications for the pattern matching. --RMS. */ #include "config.h" -#include +#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX) + #pragma alloca +#endif /* _AIX && RISC6000 && !__GNUC__ */ + +#if defined (HAVE_ALLOCA_H) +# include +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_STDLIB_H) +# include +#else +# if defined (SHELL) +# include "ansi_stdlib.h" +# endif /* SHELL */ +#endif -#if !defined (SHELL) && (defined (_POSIX_VERSION) || defined (USGr3)) -# if !defined (HAVE_DIRENT_H) -# define HAVE_DIRENT_H -# endif /* !HAVE_DIRENT_H */ -#endif /* !SHELL && (_POSIX_VERSION || USGr3) */ +#include #if defined (HAVE_DIRENT_H) # include -# if !defined (direct) -# define direct dirent -# endif /* !direct */ +# define D_NAMLEN(d) strlen ((d)->d_name) +#elif HAVE_DIRECT_H +# include # define D_NAMLEN(d) strlen ((d)->d_name) #else /* !HAVE_DIRENT_H */ # define D_NAMLEN(d) ((d)->d_namlen) -# if defined (USG) -# if defined (Xenix) -# include -# else /* !Xenix (but USG...) */ -# include "ndir.h" -# endif /* !Xenix */ -# else /* !USG */ -# if defined(NT) -# include "missing/dir.h" -# else +# if defined (HAVE_SYS_NDIR_H) +# include +# endif +# if defined (HAVE_SYS_DIR_H) # include -# endif /* !NT */ -# endif /* !USG */ +# endif /* HAVE_SYS_DIR_H */ +# if defined (HAVE_NDIR_H) +# include +# endif +# if !defined (dirent) +# define dirent direct +# endif #endif /* !HAVE_DIRENT_H */ -#if defined (_POSIX_SOURCE) || defined(DJGPP) +#if defined (_POSIX_SOURCE) || defined(DJGPP) || defined(USE_CWGUSI) /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ # define REAL_DIR_ENTRY(dp) 1 +#elif defined (__BORLANDC__) +# define REAL_DIR_ENTRY(dp) 1 #else # define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) #endif /* _POSIX_SOURCE */ -#if defined (USG) || defined (NeXT) -# if !defined (HAVE_STRING_H) -# define HAVE_STRING_H -# endif /* !HAVE_STRING_H */ -#endif /* USG || NeXT */ - #if defined (HAVE_STRING_H) # include #else /* !HAVE_STRING_H */ # include #endif /* !HAVE_STRING_H */ -#ifndef bcopy -# define bcopy(s, d, n) (memcpy ((d), (s), (n))) -#endif - -#ifdef _AIX -#pragma alloca -#else -#if defined(HAVE_ALLOCA_H) && !defined(__GNUC__) -#include -#else -char *alloca (); -#endif -#endif - -#include "fnmatch.h" +#if !defined (HAVE_BCOPY) && !defined (bcopy) +# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n))) +#endif /* !HAVE_BCOPY */ /* If the opendir () on your system lets you open non-directory files, - then we consider that not robust. Define OPENDIR_NOT_ROBUST in the - SYSDEP_CFLAGS for your machines entry in machines.h. */ + then we consider that not robust. */ #if defined (OPENDIR_NOT_ROBUST) # if defined (SHELL) # include "posixstat.h" @@ -99,6 +95,8 @@ char *alloca (); # endif /* !SHELL */ #endif /* OPENDIR_NOT_ROBUST */ +#include "fnmatch.h" + extern void *xmalloc (), *xrealloc (); #if !defined (HAVE_STDLIB_H) extern void free (); @@ -113,9 +111,15 @@ extern void free (); #endif /* !NULL */ #if defined (SHELL) +extern void throw_to_top_level (); + extern int interrupt_state; #endif /* SHELL */ +#if defined(NT) && defined(_MSC_VER) +#include "missing/dir.h" +#endif + /* Global variable which controls whether or not * matches .*. Non-zero means don't match .*. */ int noglob_dot_filenames = 1; @@ -123,7 +127,6 @@ int noglob_dot_filenames = 1; /* Global variable to return to signify an error in globbing. */ char *glob_error_return; - /* Return nonzero if PATTERN has any special globbing chars in it. */ int glob_pattern_p (pattern) @@ -205,7 +208,7 @@ glob_vector (pat, dir) }; DIR *d; - register struct direct *dp; + register struct dirent *dp; struct globval *lastlink; register struct globval *nextlink; register char *nextname; @@ -276,7 +279,8 @@ glob_vector (pat, dir) continue; /* If a dot must be explicity matched, check to see if they do. */ - if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.') + if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' && + (pat[0] != '\\' || pat[1] != '.')) continue; flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME; @@ -306,7 +310,9 @@ glob_vector (pat, dir) } /* Have we run out of memory? */ +#if defined (SHELL) lost: +#endif if (lose) { /* Here free the strings we have got. */ @@ -365,7 +371,14 @@ glob_dir_to_array (dir, array) + strlen (array[i]) + 1); if (result[i] == NULL) return (NULL); - sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); +#if 1 + strcpy (result[i], dir); + if (add_slash) + result[i][l] = '/'; + strcpy (result[i] + l + add_slash, array[i]); +#else + (void)sprintf (result[i], "%s%s%s", dir, add_slash ? "/" : "", array[i]); +#endif } result[i] = NULL; @@ -435,10 +448,14 @@ glob_filename (pathname) if (directories == NULL) goto memory_error; else if (directories == (char **)&glob_error_return) - return ((char **) &glob_error_return); + { + free ((char *) result); + return ((char **) &glob_error_return); + } else if (*directories == NULL) { free ((char *) directories); + free ((char *) result); return ((char **) &glob_error_return); } diff --git a/hash.c b/hash.c index 49be7de6aa..9141406410 100644 --- a/hash.c +++ b/hash.c @@ -6,37 +6,36 @@ $Date$ created at: Mon Nov 22 18:51:18 JST 1993 - Copyright (C) 1993-1997 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "st.h" -#include "sig.h" +#include "rubysig.h" +#include #include #ifndef HAVE_STRING_H -char *strchr(); +char *strchr _((char*,char)); #endif -#define HASH_DELETED 0x1 -#define HASH_REHASHED 0x2 - #define HASH_FREEZE FL_USER1 +#define HASH_DELETED FL_USER2 static void -hash_modify(hash) +rb_hash_modify(hash) VALUE hash; { - rb_secure(5); - if (FL_TEST(hash, HASH_FREEZE)) { - TypeError("can't modify frozen hash"); - } + if (FL_TEST(hash, HASH_FREEZE)) + rb_raise(rb_eTypeError, "can't modify frozen hash"); + if (rb_safe_level() >= 4 && !FL_TEST(hash, FL_TAINT)) + rb_raise(rb_eSecurityError, "Insecure: can't modify hash"); } VALUE -hash_freeze(hash) +rb_hash_freeze(hash) VALUE hash; { FL_SET(hash, HASH_FREEZE); @@ -44,19 +43,15 @@ hash_freeze(hash) } static VALUE -hash_frozen_p(hash) +rb_hash_frozen_p(hash) VALUE hash; { if (FL_TEST(hash, HASH_FREEZE)) - return TRUE; - return FALSE; + return Qtrue; + return Qfalse; } -#ifndef NT -char *getenv(); -#endif - -VALUE cHash; +VALUE rb_cHash; static VALUE envtbl; static ID hash; @@ -69,14 +64,14 @@ rb_hash(obj) } static int -any_cmp(a, b) +rb_any_cmp(a, b) VALUE a, b; { if (FIXNUM_P(a)) { if (FIXNUM_P(b)) return a != b; } else if (TYPE(a) == T_STRING) { - if (TYPE(b) == T_STRING) return str_cmp(a, b); + if (TYPE(b) == T_STRING) return rb_str_cmp(a, b); } DEFER_INTS; @@ -86,9 +81,8 @@ any_cmp(a, b) } static int -any_hash(a, mod) +rb_any_hash(a) VALUE a; - int mod; { unsigned int hval; @@ -98,7 +92,7 @@ any_hash(a, mod) break; case T_STRING: - hval = str_hash(a); + hval = rb_str_hash(a); break; default: @@ -108,161 +102,181 @@ any_hash(a, mod) hval = rb_funcall(hval, '%', 1, INT2FIX(65439)); } ENABLE_INTS; - hval = FIX2INT(hval); + hval = FIX2LONG(hval); } - return hval % mod; + return hval; } static struct st_hash_type objhash = { - any_cmp, - any_hash, + rb_any_cmp, + rb_any_hash, }; -struct hash_foreach_arg { +struct rb_hash_foreach_arg { VALUE hash; enum st_retval (*func)(); char *arg; }; static int -hash_foreach_iter(key, value, arg) +rb_hash_foreach_iter(key, value, arg) VALUE key, value; - struct hash_foreach_arg *arg; + struct rb_hash_foreach_arg *arg; { int status; + st_table *tbl = RHASH(arg->hash)->tbl; + struct st_table_entry **bins = tbl->bins; if (key == Qnil) return ST_CONTINUE; status = (*arg->func)(key, value, arg->arg); - if (RHASH(arg->hash)->status & HASH_REHASHED) return ST_STOP; + if (RHASH(arg->hash)->tbl != tbl || RHASH(arg->hash)->tbl->bins != bins){ + rb_raise(rb_eIndexError, "rehash occurred during iteration"); + } return status; } static VALUE -hash_foreach_call(arg) - struct hash_foreach_arg *arg; +rb_hash_foreach_call(arg) + struct rb_hash_foreach_arg *arg; { - st_foreach(RHASH(arg->hash)->tbl, hash_foreach_iter, arg); + st_foreach(RHASH(arg->hash)->tbl, rb_hash_foreach_iter, arg); return Qnil; } static int -hash_delete_nil(key, value) +rb_hash_delete_nil(key, value) VALUE key, value; { - if (key == Qnil) return ST_DELETE; + if (value == Qnil) return ST_DELETE; return ST_CONTINUE; } -static void -hash_foreach_ensure(hash) +static VALUE +rb_hash_foreach_ensure(hash) VALUE hash; { RHASH(hash)->iter_lev--; if (RHASH(hash)->iter_lev == 0) { - if (RHASH(hash)->status & HASH_DELETED) { - st_foreach(RHASH(hash)->tbl, hash_delete_nil, 0); + if (FL_TEST(hash, HASH_DELETED)) { + st_foreach(RHASH(hash)->tbl, rb_hash_delete_nil, 0); + FL_UNSET(hash, HASH_DELETED); } - RHASH(hash)->status = 0; } + return 0; } static int -hash_foreach(hash, func, farg) +rb_hash_foreach(hash, func, farg) VALUE hash; enum st_retval (*func)(); char *farg; { - struct hash_foreach_arg arg; + struct rb_hash_foreach_arg arg; RHASH(hash)->iter_lev++; arg.hash = hash; arg.func = func; arg.arg = farg; - return rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, (VALUE)hash); + return rb_ensure(rb_hash_foreach_call, (VALUE)&arg, rb_hash_foreach_ensure, hash); } static VALUE -hash_s_new(argc, argv, class) +rb_hash_s_new(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { - VALUE sz; + VALUE sz, ifnone; int size; NEWOBJ(hash, struct RHash); - OBJSETUP(hash, class, T_HASH); - - rb_scan_args(argc, argv, "01", &sz); - if (NIL_P(sz)) size = 0; - else size = NUM2INT(sz); + OBJSETUP(hash, klass, T_HASH); hash->iter_lev = 0; - hash->status = 0; + hash->ifnone = Qnil; hash->tbl = 0; /* avoid GC crashing */ + + rb_scan_args(argc, argv, "02", &ifnone, &sz); + if (NIL_P(sz)) { + size = 0; + } + else size = NUM2INT(sz); + + hash->ifnone = ifnone; hash->tbl = st_init_table_with_size(&objhash, size); + rb_obj_call_init((VALUE)hash); return (VALUE)hash; } static VALUE -hash_new2(class) - VALUE class; +rb_hash_new2(klass) + VALUE klass; { - return hash_s_new(0, 0, class); + NEWOBJ(hash, struct RHash); + OBJSETUP(hash, klass, T_HASH); + + hash->iter_lev = 0; + hash->ifnone = Qnil; + hash->tbl = 0; /* avoid GC crashing */ + hash->tbl = st_init_table(&objhash); + + return (VALUE)hash; } VALUE -hash_new() +rb_hash_new() { - return hash_new2(cHash); + return rb_hash_new2(rb_cHash); } static VALUE -hash_s_create(argc, argv, class) +rb_hash_s_create(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { VALUE hash; int i; if (argc == 1 && TYPE(argv[0]) == T_HASH) { - if (class == CLASS_OF(argv[0])) return argv[0]; + if (klass == CLASS_OF(argv[0])) return argv[0]; else { NEWOBJ(hash, struct RHash); - OBJSETUP(hash, class, T_HASH); + OBJSETUP(hash, klass, T_HASH); hash->iter_lev = 0; - hash->status = 0; + hash->ifnone = Qnil; hash->tbl = 0; /* avoid GC crashing */ hash->tbl = (st_table*)st_copy(RHASH(argv[0])->tbl); + rb_obj_call_init((VALUE)hash); return (VALUE)hash; } } if (argc % 2 != 0) { - ArgError("odd number args for Hash"); + rb_raise(rb_eArgError, "odd number args for Hash"); } - hash = hash_new2(class); + hash = rb_hash_new2(klass); for (i=0; itbl, argv[i], argv[i+1]); } + rb_obj_call_init(hash); return hash; } static VALUE -hash_clone(hash) +rb_hash_clone(hash) VALUE hash; { NEWOBJ(hash2, struct RHash); CLONESETUP(hash2, hash); hash2->iter_lev = 0; - hash2->status = 0; + hash2->ifnone = RHASH(hash)->ifnone; hash2->tbl = 0; /* avoid GC crashing */ hash2->tbl = (st_table*)st_copy(RHASH(hash)->tbl); @@ -270,22 +284,29 @@ hash_clone(hash) } static VALUE -hash_dup(hash) +rb_hash_dup(hash) VALUE hash; { NEWOBJ(hash2, struct RHash); OBJSETUP(hash2, CLASS_OF(hash), T_HASH); hash2->iter_lev = 0; - hash2->status = 0; + hash2->ifnone = RHASH(hash)->ifnone; hash2->tbl = 0; /* avoid GC crashing */ hash2->tbl = (st_table*)st_copy(RHASH(hash)->tbl); return (VALUE)hash2; } +static VALUE +to_hash(hash) + VALUE hash; +{ + return rb_convert_type(hash, T_HASH, "Hash", "to_hash"); +} + static int -hash_rehash_i(key, value, tbl) +rb_hash_rehash_i(key, value, tbl) VALUE key, value; st_table *tbl; { @@ -296,34 +317,71 @@ hash_rehash_i(key, value, tbl) } static VALUE -hash_rehash(hash) +rb_hash_rehash(hash) VALUE hash; { st_table *tbl; tbl = st_init_table_with_size(&objhash, RHASH(hash)->tbl->num_entries); - st_foreach(RHASH(hash)->tbl, hash_rehash_i, tbl); + st_foreach(RHASH(hash)->tbl, rb_hash_rehash_i, tbl); st_free_table(RHASH(hash)->tbl); RHASH(hash)->tbl = tbl; - if (RHASH(hash)->iter_lev > 0) RHASH(hash)->status |= HASH_REHASHED; - return (VALUE)hash; + return hash; } VALUE -hash_aref(hash, key) +rb_hash_aref(hash, key) VALUE hash, key; { VALUE val; if (!st_lookup(RHASH(hash)->tbl, key, &val)) { - return Qnil; + return RHASH(hash)->ifnone; } return val; } static VALUE -hash_indexes(argc, argv, hash) +rb_hash_fetch(argc, argv, hash) + int argc; + VALUE *argv; + VALUE hash; +{ + VALUE key, if_none; + VALUE val; + + rb_scan_args(argc, argv, "11", &key, &if_none); + + if (!st_lookup(RHASH(hash)->tbl, key, &val)) { + if (rb_iterator_p()) { + if (argc > 1) { + rb_raise(rb_eArgError, "wrong # of arguments", argc); + } + return rb_yield(argv[0]); + } + return if_none; + } + return val; +} + +static VALUE +rb_hash_default(hash) + VALUE hash; +{ + return RHASH(hash)->ifnone; +} + +static VALUE +rb_hash_set_default(hash, ifnone) + VALUE hash, ifnone; +{ + RHASH(hash)->ifnone = ifnone; + return hash; +} + +static VALUE +rb_hash_indexes(argc, argv, hash) int argc; VALUE *argv; VALUE hash; @@ -331,27 +389,31 @@ hash_indexes(argc, argv, hash) VALUE indexes; int i; - indexes = ary_new2(argc); + indexes = rb_ary_new2(argc); for (i=0; iptr[i] = hash_aref(hash, argv[i]); + RARRAY(indexes)->ptr[i] = rb_hash_aref(hash, argv[i]); } RARRAY(indexes)->len = i; return indexes; } static VALUE -hash_delete(hash, key) +rb_hash_delete(hash, key) VALUE hash, key; { VALUE val; - hash_modify(hash); - if (RHASH(hash)->iter_lev > 0 - && st_delete_safe(RHASH(hash)->tbl, &key, &val, Qnil)) + rb_hash_modify(hash); + if (RHASH(hash)->iter_lev > 0 && + st_delete_safe(RHASH(hash)->tbl, &key, &val, Qnil)) { + FL_SET(hash, HASH_DELETED); return val; + } else if (st_delete(RHASH(hash)->tbl, &key, &val)) return val; - if (iterator_p()) rb_yield(key); + if (rb_iterator_p()) { + return rb_yield(key); + } return Qnil; } @@ -375,17 +437,17 @@ shift_i(key, value, var) } static VALUE -hash_shift(hash) +rb_hash_shift(hash) VALUE hash; { struct shift_var var; - hash_modify(hash); + rb_hash_modify(hash); var.stop = 0; st_foreach(RHASH(hash)->tbl, shift_i, &var); if (var.stop == 0) return Qnil; - return assoc_new(var.key, var.val); + return rb_assoc_new(var.key, var.val); } static int @@ -393,19 +455,19 @@ delete_if_i(key, value) VALUE key, value; { if (key == Qnil) return ST_CONTINUE; - if (rb_yield(assoc_new(key, value))) + if (rb_yield(rb_assoc_new(key, value))) return ST_DELETE; return ST_CONTINUE; } static VALUE -hash_delete_if(hash) +rb_hash_delete_if(hash) VALUE hash; { - hash_modify(hash); - hash_foreach(hash, delete_if_i, 0); + rb_hash_modify(hash); + rb_hash_foreach(hash, delete_if_i, 0); - return (VALUE)hash; + return hash; } static int @@ -416,45 +478,66 @@ clear_i(key, value) } static VALUE -hash_clear(hash) +rb_hash_clear(hash) VALUE hash; { - hash_modify(hash); + rb_hash_modify(hash); st_foreach(RHASH(hash)->tbl, clear_i); - return (VALUE)hash; + return hash; } VALUE -hash_aset(hash, key, val) +rb_hash_aset(hash, key, val) VALUE hash, key, val; { - hash_modify(hash); + rb_hash_modify(hash); if (NIL_P(val)) { - hash_delete(hash, key); + rb_hash_delete(hash, key); return Qnil; } - if (TYPE(key) == T_STRING) { - key = str_dup_freezed(key); + if (TYPE(key) != T_STRING || st_lookup(RHASH(hash)->tbl, key, 0)) { + st_insert(RHASH(hash)->tbl, key, val); + } + else { + st_add_direct(RHASH(hash)->tbl, rb_str_dup_frozen(key), val); } - st_insert(RHASH(hash)->tbl, key, val); return val; } +static int +replace_i(key, val, hash) + VALUE key, val, hash; +{ + rb_hash_aset(hash, key, val); + return ST_CONTINUE; +} + static VALUE -hash_length(hash) +rb_hash_replace(hash, hash2) + VALUE hash, hash2; +{ + hash2 = to_hash(hash2); + rb_hash_clear(hash); + st_foreach(RHASH(hash2)->tbl, replace_i, hash); + + return hash; +} + +static VALUE +rb_hash_length(hash) VALUE hash; { return INT2FIX(RHASH(hash)->tbl->num_entries); } static VALUE -hash_empty_p(hash) +rb_hash_empty_p(hash) VALUE hash; { if (RHASH(hash)->tbl->num_entries == 0) - return TRUE; - return FALSE; + return Qtrue; + return Qfalse; } static int @@ -467,11 +550,11 @@ each_value_i(key, value) } static VALUE -hash_each_value(hash) +rb_hash_each_value(hash) VALUE hash; { - hash_foreach(hash, each_value_i); - return (VALUE)hash; + rb_hash_foreach(hash, each_value_i, 0); + return hash; } static int @@ -484,11 +567,11 @@ each_key_i(key, value) } static VALUE -hash_each_key(hash) +rb_hash_each_key(hash) VALUE hash; { - hash_foreach(hash, each_key_i); - return (VALUE)hash; + rb_hash_foreach(hash, each_key_i, 0); + return hash; } static int @@ -496,16 +579,16 @@ each_pair_i(key, value) VALUE key, value; { if (key == Qnil) return ST_CONTINUE; - rb_yield(assoc_new(key, value)); + rb_yield(rb_assoc_new(key, value)); return ST_CONTINUE; } static VALUE -hash_each_pair(hash) +rb_hash_each_pair(hash) VALUE hash; { - hash_foreach(hash, each_pair_i); - return (VALUE)hash; + rb_hash_foreach(hash, each_pair_i, 0); + return hash; } static int @@ -513,22 +596,29 @@ to_a_i(key, value, ary) VALUE key, value, ary; { if (key == Qnil) return ST_CONTINUE; - ary_push(ary, assoc_new(key, value)); + rb_ary_push(ary, rb_assoc_new(key, value)); return ST_CONTINUE; } static VALUE -hash_to_a(hash) +rb_hash_to_a(hash) VALUE hash; { VALUE ary; - ary = ary_new(); + ary = rb_ary_new(); st_foreach(RHASH(hash)->tbl, to_a_i, ary); return ary; } +static VALUE +rb_hash_sort(hash) + VALUE hash; +{ + return rb_ary_sort_bang(rb_hash_to_a(hash)); +} + static int inspect_i(key, value, str) VALUE key, value, str; @@ -537,35 +627,60 @@ inspect_i(key, value, str) if (key == Qnil) return ST_CONTINUE; if (RSTRING(str)->len > 1) { - str_cat(str, ", ", 2); + rb_str_cat(str, ", ", 2); } str2 = rb_inspect(key); - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); - str_cat(str, "=>", 2); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + rb_str_cat(str, "=>", 2); str2 = rb_inspect(value); - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); return ST_CONTINUE; } static VALUE -hash_inspect(hash) +inspect_hash(hash) VALUE hash; { VALUE str; - str = str_new2("{"); + str = rb_str_new2("{"); st_foreach(RHASH(hash)->tbl, inspect_i, str); - str_cat(str, "}", 1); + rb_str_cat(str, "}", 1); return str; } +static VALUE +rb_hash_inspect(hash) + VALUE hash; +{ + if (RHASH(hash)->tbl->num_entries == 0) return rb_str_new2("{}"); + if (rb_inspecting_p(hash)) return rb_str_new2("{...}"); + return rb_protect_inspect(inspect_hash, hash, 0); +} + static VALUE hash_to_s(hash) VALUE hash; { - return ary_to_s(hash_to_a(hash)); + if (rb_inspecting_p(hash)) return rb_str_new2("{...}"); + return rb_ary_to_s(rb_hash_to_a(hash)); +} + +static VALUE +rb_hash_to_s(hash) + VALUE hash; +{ + if (rb_inspecting_p(hash)) return rb_str_new2("{...}"); + return rb_protect_inspect(hash_to_s, hash, 0); +} + +static VALUE +rb_hash_to_hash(hash) + VALUE hash; +{ + return hash; } static int @@ -573,17 +688,17 @@ keys_i(key, value, ary) VALUE key, value, ary; { if (key == Qnil) return ST_CONTINUE; - ary_push(ary, key); + rb_ary_push(ary, key); return ST_CONTINUE; } static VALUE -hash_keys(hash) +rb_hash_keys(hash) VALUE hash; { VALUE ary; - ary = ary_new(); + ary = rb_ary_new(); st_foreach(RHASH(hash)->tbl, keys_i, ary); return ary; @@ -594,55 +709,55 @@ values_i(key, value, ary) VALUE key, value, ary; { if (key == Qnil) return ST_CONTINUE; - ary_push(ary, value); + rb_ary_push(ary, value); return ST_CONTINUE; } static VALUE -hash_values(hash) +rb_hash_values(hash) VALUE hash; { VALUE ary; - ary = ary_new(); + ary = rb_ary_new(); st_foreach(RHASH(hash)->tbl, values_i, ary); return ary; } static VALUE -hash_has_key(hash, key) +rb_hash_has_key(hash, key) VALUE hash; VALUE key; { if (st_lookup(RHASH(hash)->tbl, key, 0)) { - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } static int -hash_search_value(key, value, data) +rb_hash_search_value(key, value, data) VALUE key, value, *data; { if (key == Qnil) return ST_CONTINUE; if (rb_equal(value, data[1])) { - data[0] = TRUE; + data[0] = Qtrue; return ST_STOP; } return ST_CONTINUE; } static VALUE -hash_has_value(hash, val) +rb_hash_has_value(hash, val) VALUE hash; VALUE val; { VALUE data[2]; - data[0] = FALSE; + data[0] = Qfalse; data[1] = val; - st_foreach(RHASH(hash)->tbl, hash_search_value, data); + st_foreach(RHASH(hash)->tbl, rb_hash_search_value, data); return data[0]; } @@ -660,79 +775,79 @@ equal_i(key, val1, data) if (key == Qnil) return ST_CONTINUE; if (!st_lookup(data->tbl, key, &val2)) { - data->result = FALSE; + data->result = Qfalse; return ST_STOP; } if (!rb_equal(val1, val2)) { - data->result = FALSE; + data->result = Qfalse; return ST_STOP; } return ST_CONTINUE; } static VALUE -hash_equal(hash1, hash2) +rb_hash_equal(hash1, hash2) VALUE hash1, hash2; { struct equal_data data; - if (TYPE(hash2) != T_HASH) return FALSE; + if (TYPE(hash2) != T_HASH) return Qfalse; if (RHASH(hash1)->tbl->num_entries != RHASH(hash2)->tbl->num_entries) - return FALSE; + return Qfalse; data.tbl = RHASH(hash2)->tbl; - data.result = TRUE; + data.result = Qtrue; st_foreach(RHASH(hash1)->tbl, equal_i, &data); return data.result; } static int -hash_invert_i(key, value, hash) +rb_hash_invert_i(key, value, hash) VALUE key, value; VALUE hash; { if (key == Qnil) return ST_CONTINUE; - hash_aset(hash, value, key); + rb_hash_aset(hash, value, key); return ST_CONTINUE; } static VALUE -hash_invert(hash) +rb_hash_invert(hash) VALUE hash; { - VALUE h = hash_new(); + VALUE h = rb_hash_new(); - st_foreach(RHASH(hash)->tbl, hash_invert_i, h); + st_foreach(RHASH(hash)->tbl, rb_hash_invert_i, h); return h; } static int -hash_update_i(key, value, hash) +rb_hash_update_i(key, value, hash) VALUE key, value; VALUE hash; { if (key == Qnil) return ST_CONTINUE; - hash_aset(hash, key, value); + rb_hash_aset(hash, key, value); return ST_CONTINUE; } static VALUE -hash_update(hash1, hash2) +rb_hash_update(hash1, hash2) VALUE hash1, hash2; { - Check_Type(hash2, T_HASH); - - st_foreach(RHASH(hash2)->tbl, hash_update_i, hash1); + hash2 = to_hash(hash2); + st_foreach(RHASH(hash2)->tbl, rb_hash_update_i, hash1); return hash1; } -int env_path_tainted(); +#ifndef __MACOS__ /* no environment variables on MacOS. */ static int path_tainted = -1; #ifndef NT extern char **environ; #endif +static char **origenviron; static VALUE env_delete(obj, name) @@ -742,10 +857,9 @@ env_delete(obj, name) char *nam, *val = 0; rb_secure(4); - Check_Type(name, T_STRING); - nam = RSTRING(name)->ptr; - len = strlen(nam); + nam = STR2CSTR(name); if (strcmp(nam, "PATH") == 0) path_tainted = 0; + len = strlen(nam); for(i=0; environ[i]; i++) { if (strncmp(environ[i], nam, len) == 0 && environ[i][len] == '=') { val = environ[i]+len+1; @@ -757,7 +871,7 @@ env_delete(obj, name) i++; } if (val) { - return str_new2(val); + return rb_str_new2(val); } return Qnil; } @@ -767,26 +881,26 @@ env_delete_method(obj, name) VALUE obj, name; { VALUE val = env_delete(obj, name); - if (iterator_p()) rb_yield(name); + if (rb_iterator_p()) rb_yield(name); return val; } static VALUE -f_getenv(obj, name) +rb_f_getenv(obj, name) VALUE obj, name; { - char *env; + char *nam, *env; + int len; - Check_Type(name, T_STRING); - - if (strlen(RSTRING(name)->ptr) != RSTRING(name)->len) - ArgError("Bad environment name"); - - env = getenv(RSTRING(name)->ptr); + nam = str2cstr(name, &len); + if (strlen(nam) != len) { + rb_raise(rb_eArgError, "Bad environment variable name"); + } + env = getenv(nam); if (env) { - if (strcmp(RSTRING(name)->ptr, "PATH") == 0 && !env_path_tainted()) - return str_new2(env); - return str_taint(str_new2(env)); + if (strcmp(nam, "PATH") == 0 && !rb_env_path_tainted()) + return rb_str_new2(env); + return rb_tainted_str_new2(env); } return Qnil; } @@ -800,7 +914,7 @@ path_check_1(path) char *s; for (;;) { - if (stat(path, &st) == 0 && (st.st_mode & 2)) { + if (stat(path, &st) == 0 && (st.st_mode & 002)) { return 0; } s = strrchr(path, '/'); @@ -811,19 +925,17 @@ path_check_1(path) } } -static void -path_check(path) +int +rb_path_check(path) char *path; { - char *p = path; - char *pend = strchr(path, ':'); + char *p, *pend; + const char sep = RUBY_PATH_SEP[0]; - if (!path) { - path_tainted = 0; - } + if (!path) return 1; p = path; - pend = strchr(path, ':'); + pend = strchr(path, sep); for (;;) { int safe; @@ -831,72 +943,207 @@ path_check(path) if (pend) *pend = '\0'; safe = path_check_1(p); if (!pend) break; - *pend = ':'; + *pend = sep; if (!safe) { - path_tainted = 1; - return; + return 0; } p = pend + 1; - pend = strchr(p, ':'); + pend = strchr(p, sep); } - path_tainted = 0; + return 1; +} + +static void +path_tainted_p(path) + char *path; +{ + path_tainted = rb_path_check(path)?0:1; } int -env_path_tainted() +rb_env_path_tainted() { if (path_tainted < 0) { - path_check(getenv("PATH")); + path_tainted_p(getenv("PATH")); } return path_tainted; } +static int +envix(nam) +char *nam; +{ + register int i, len = strlen(nam); + + for (i = 0; environ[i]; i++) { + if ( +#ifdef WIN32 + strnicmp(environ[i],nam,len) == 0 +#else + memcmp(environ[i],nam,len) == 0 +#endif + && environ[i][len] == '=') + break; /* memcmp must come first to avoid */ + } /* potential SEGV's */ + return i; +} + +static void +my_setenv(name, value) + char *name; + char *value; +{ +#ifdef WIN32 +#ifdef USE_WIN32_RTL_ENV + register char *envstr; + STRLEN namlen = strlen(name); + STRLEN vallen; + char *oldstr = environ[envix(name)]; + + /* putenv() has totally broken semantics in both the Borland + * and Microsoft CRTLs. They either store the passed pointer in + * the environment without making a copy, or make a copy and don't + * free it. And on top of that, they dont free() old entries that + * are being replaced/deleted. This means the caller must + * free any old entries somehow, or we end up with a memory + * leak every time setenv() is called. One might think + * one could directly manipulate environ[], like the UNIX code + * above, but direct changes to environ are not allowed when + * calling putenv(), since the RTLs maintain an internal + * *copy* of environ[]. Bad, bad, *bad* stink. + * GSAR 97-06-07 + */ + + if (!value) { + if (!oldstr) + return; + value = ""; + vallen = 0; + } + else + vallen = strlen(val); + envstr = ALLOC_N(char, namelen + vallen + 3); + sprintf(envstr,"%s=%s",name,value); + putenv(envstr); + if (oldstr) free(oldstr); +#ifdef _MSC_VER + free(envstr); /* MSVCRT leaks without this */ +#endif + +#else /* !USE_WIN32_RTL_ENV */ + + /* The sane way to deal with the environment. + * Has these advantages over putenv() & co.: + * * enables us to store a truly empty value in the + * environment (like in UNIX). + * * we don't have to deal with RTL globals, bugs and leaks. + * * Much faster. + * Why you may want to enable USE_WIN32_RTL_ENV: + * * environ[] and RTL functions will not reflect changes, + * which might be an issue if extensions want to access + * the env. via RTL. This cuts both ways, since RTL will + * not see changes made by extensions that call the Win32 + * functions directly, either. + * GSAR 97-06-07 + */ + SetEnvironmentVariable(name,value); +#endif + +#else /* WIN32 */ + + register int i=envix(name); /* where does it go? */ + + if (environ == origenviron) { /* need we copy environment? */ + int j; + int max; + char **tmpenv; + + for (max = i; environ[max]; max++) ; + tmpenv = ALLOC_N(char*, max+2); + for (j=0; j= 4) { - extern VALUE eSecurityError; - Raise(eSecurityError, "cannot change environment variable"); + rb_raise(rb_eSecurityError, "cannot change environment variable"); } - Check_SafeStr(name); - if (NIL_P(value)) { - env_delete(obj, name); + if (NIL_P(val)) { + env_delete(obj, nm); return Qnil; } - Check_SafeStr(value); - if (strlen(RSTRING(name)->ptr) != RSTRING(name)->len) - ArgError("Bad environment name"); - if (strlen(RSTRING(value)->ptr) != RSTRING(value)->len) - ArgError("Bad environment value"); + name = str2cstr(nm, &nlen); + value = STR2CSTR(val &vlen); + if (strlen(name) != nlen) + rb_raise(rb_eArgError, "Bad environment name"); + if (strlen(value) != vlen) + rb_raise(rb_eArgError, "Bad environment value"); - setenv(RSTRING(name)->ptr, RSTRING(value)->ptr, 1); - if (strcmp(RSTRING(name)->ptr, "PATH") == 0) { - char *p, pend; - - if (str_tainted(value)) { + my_setenv(name, value); + if (strcmp(name, "PATH") == 0) { + if (OBJ_TAINTED(val)) { /* already tainted, no check */ path_tainted = 1; - return TRUE; + return Qtrue; + } + else { + path_tainted_p(value); } - - path_check(RSTRING(name)->ptr); } - return TRUE; + return Qtrue; } static VALUE env_keys() { char **env; - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); env = environ; while (*env) { char *s = strchr(*env, '='); - ary_push(ary, str_taint(str_new(*env, s-*env))); + if (s) { + rb_ary_push(ary, rb_tainted_str_new(*env, s-*env)); + } env++; } return ary; @@ -906,19 +1153,31 @@ static VALUE env_each_key(hash) VALUE hash; { - return ary_each(env_keys()); + char **env; + + env = environ; + while (*env) { + char *s = strchr(*env, '='); + if (s) { + rb_yield(rb_tainted_str_new(*env, s-*env)); + } + env++; + } + return Qnil; } static VALUE env_values() { char **env; - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); env = environ; while (*env) { char *s = strchr(*env, '='); - ary_push(ary, str_taint(str_new2(s+1))); + if (s) { + rb_ary_push(ary, rb_tainted_str_new2(s+1)); + } env++; } return ary; @@ -928,38 +1187,53 @@ static VALUE env_each_value(hash) VALUE hash; { - return ary_each(env_values()); + char **env; + + env = environ; + while (*env) { + char *s = strchr(*env, '='); + if (s) { + rb_yield(rb_tainted_str_new2(s+1)); + } + env++; + } + return Qnil; } static VALUE env_each(hash) VALUE hash; { - VALUE ary = env_keys(); - VALUE *ptr = RARRAY(ary)->ptr; - int len = RARRAY(ary)->len; + char **env; - while (len--) { - VALUE val = f_getenv(Qnil, *ptr); - if (!NIL_P(val)) { - rb_yield(assoc_new(*ptr, val)); + env = environ; + while (*env) { + char *s = strchr(*env, '='); + if (s) { + rb_yield(rb_assoc_new(rb_tainted_str_new(*env, s-*env), + rb_tainted_str_new2(s+1))); } - ptr++; + env++; } - return hash; + return Qnil; } static VALUE env_delete_if() { - VALUE ary = env_keys(); - VALUE *ptr = RARRAY(ary)->ptr; - int len = RARRAY(ary)->len; + volatile VALUE keys; + VALUE *ptr; + int len; + + rb_secure(4); + keys = env_keys(); + ptr = RARRAY(keys)->ptr; + len = RARRAY(keys)->len; while (len--) { - VALUE val = f_getenv(Qnil, *ptr); + VALUE val = rb_f_getenv(Qnil, *ptr); if (!NIL_P(val)) { - if (RTEST(rb_yield(assoc_new(*ptr, val)))) { + if (RTEST(rb_yield(rb_assoc_new(*ptr, val)))) { env_delete(Qnil, *ptr); } } @@ -971,20 +1245,22 @@ env_delete_if() static VALUE env_to_s() { - return str_new2("ENV"); + return rb_str_new2("ENV"); } static VALUE env_to_a() { char **env; - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); env = environ; while (*env) { char *s = strchr(*env, '='); - ary_push(ary, assoc_new(str_taint(str_new(*env, s-*env)), - str_taint(str_new2(s+1)))); + if (s) { + rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(*env, s-*env), + rb_tainted_str_new2(s+1))); + } env++; } return ary; @@ -1009,17 +1285,17 @@ env_size() static VALUE env_empty_p() { - if (environ[0] == 0) return TRUE; - return FALSE; + if (environ[0] == 0) return Qtrue; + return Qfalse; } static VALUE env_has_key(env, key) VALUE env, key; { - if (TYPE(key) != T_STRING) return FALSE; - if (getenv(RSTRING(key)->ptr)) return TRUE; - return FALSE; + if (TYPE(key) != T_STRING) return Qfalse; + if (getenv(STR2CSTR(key))) return Qtrue; + return Qfalse; } static VALUE @@ -1027,18 +1303,20 @@ env_has_value(dmy, value) VALUE dmy, value; { char **env; - VALUE ary; + volatile VALUE ary; - if (TYPE(value) != T_STRING) return FALSE; - ary = ary_new(); + if (TYPE(value) != T_STRING) return Qfalse; + ary = rb_ary_new(); env = environ; while (*env) { char *s = strchr(*env, '=')+1; - int len = strlen(s); - if (strncmp(s, RSTRING(value)->ptr, len) == 0) return TRUE; + if (s) { + if (strncmp(s, RSTRING(value)->ptr, strlen(s)) == 0) + return Qtrue; + } env++; } - return FALSE; + return Qfalse; } static VALUE @@ -1047,7 +1325,7 @@ env_indexes(argc, argv) VALUE *argv; { int i; - VALUE indexes = ary_new2(argc); + VALUE indexes = rb_ary_new2(argc); for (i=0;iptr); } if (v) { - RARRAY(indexes)->ptr[i] = str_new2(v); + RARRAY(indexes)->ptr[i] = rb_tainted_str_new2(v); } else { RARRAY(indexes)->ptr[i] = Qnil; @@ -1066,65 +1344,94 @@ env_indexes(argc, argv) return indexes; } -void -Init_Hash() +static VALUE +env_to_hash(obj) + VALUE obj; { - extern VALUE mEnumerable; - - hash = rb_intern("hash"); - - cHash = rb_define_class("Hash", cObject); - - rb_include_module(cHash, mEnumerable); - - rb_define_singleton_method(cHash, "new", hash_s_new, -1); - rb_define_singleton_method(cHash, "[]", hash_s_create, -1); - - rb_define_method(cHash,"clone", hash_clone, 0); - rb_define_method(cHash,"dup", hash_dup, 0); - rb_define_method(cHash,"rehash", hash_rehash, 0); - - rb_define_method(cHash,"freeze", hash_freeze, 0); - rb_define_method(cHash,"frozen?",hash_frozen_p, 0); - - rb_define_method(cHash,"to_a", hash_to_a, 0); - rb_define_method(cHash,"to_s", hash_to_s, 0); - rb_define_method(cHash,"inspect", hash_inspect, 0); - - rb_define_method(cHash,"==", hash_equal, 1); - rb_define_method(cHash,"[]", hash_aref, 1); - rb_define_method(cHash,"[]=", hash_aset, 2); - rb_define_method(cHash,"indexes", hash_indexes, -1); - rb_define_method(cHash,"length", hash_length, 0); - rb_define_alias(cHash, "size", "length"); - rb_define_method(cHash,"empty?", hash_empty_p, 0); - - rb_define_method(cHash,"each", hash_each_pair, 0); - rb_define_method(cHash,"each_value", hash_each_value, 0); - rb_define_method(cHash,"each_key", hash_each_key, 0); - rb_define_method(cHash,"each_pair", hash_each_pair, 0); - - rb_define_method(cHash,"keys", hash_keys, 0); - rb_define_method(cHash,"values", hash_values, 0); + char **env; + VALUE hash = rb_hash_new(); - rb_define_method(cHash,"shift", hash_shift, 0); - rb_define_method(cHash,"delete", hash_delete, 1); - rb_define_method(cHash,"delete_if", hash_delete_if, 0); - rb_define_method(cHash,"clear", hash_clear, 0); - rb_define_method(cHash,"invert", hash_invert, 0); - rb_define_method(cHash,"update", hash_update, 1); + env = environ; + while (*env) { + char *s = strchr(*env, '='); + if (s) { + rb_hash_aset(hash, rb_tainted_str_new(*env, s-*env), + rb_tainted_str_new2(s+1)); + } + env++; + } + return hash; +} - rb_define_method(cHash,"include?", hash_has_key, 1); - rb_define_method(cHash,"has_key?", hash_has_key, 1); - rb_define_method(cHash,"has_value?", hash_has_value, 1); - rb_define_method(cHash,"key?", hash_has_key, 1); - rb_define_method(cHash,"value?", hash_has_value, 1); +#endif /* ifndef __MACOS__ no environment variables on MacOS. */ - envtbl = obj_alloc(cObject); - rb_extend_object(envtbl, mEnumerable); +void +Init_Hash() +{ + hash = rb_intern("hash"); - rb_define_singleton_method(envtbl,"[]", f_getenv, 1); - rb_define_singleton_method(envtbl,"[]=", f_setenv, 2); + rb_cHash = rb_define_class("Hash", rb_cObject); + + rb_include_module(rb_cHash, rb_mEnumerable); + + rb_define_singleton_method(rb_cHash, "new", rb_hash_s_new, -1); + rb_define_singleton_method(rb_cHash, "[]", rb_hash_s_create, -1); + + rb_define_method(rb_cHash,"clone", rb_hash_clone, 0); + rb_define_method(rb_cHash,"dup", rb_hash_dup, 0); + rb_define_method(rb_cHash,"rehash", rb_hash_rehash, 0); + + rb_define_method(rb_cHash,"freeze", rb_hash_freeze, 0); + rb_define_method(rb_cHash,"frozen?",rb_hash_frozen_p, 0); + + rb_define_method(rb_cHash,"to_hash", rb_hash_to_hash, 0); + rb_define_method(rb_cHash,"to_a", rb_hash_to_a, 0); + rb_define_method(rb_cHash,"to_s", rb_hash_to_s, 0); + rb_define_method(rb_cHash,"inspect", rb_hash_inspect, 0); + + rb_define_method(rb_cHash,"==", rb_hash_equal, 1); + rb_define_method(rb_cHash,"[]", rb_hash_aref, 1); + rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1); + rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2); + rb_define_method(rb_cHash,"store", rb_hash_aset, 2); + rb_define_method(rb_cHash,"default", rb_hash_default, 0); + rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1); + rb_define_method(rb_cHash,"indexes", rb_hash_indexes, -1); + rb_define_method(rb_cHash,"indices", rb_hash_indexes, -1); + rb_define_method(rb_cHash,"length", rb_hash_length, 0); + rb_define_alias(rb_cHash, "size", "length"); + rb_define_method(rb_cHash,"empty?", rb_hash_empty_p, 0); + + rb_define_method(rb_cHash,"each", rb_hash_each_pair, 0); + rb_define_method(rb_cHash,"each_value", rb_hash_each_value, 0); + rb_define_method(rb_cHash,"each_key", rb_hash_each_key, 0); + rb_define_method(rb_cHash,"each_pair", rb_hash_each_pair, 0); + rb_define_method(rb_cHash,"sort", rb_hash_sort, 0); + + rb_define_method(rb_cHash,"keys", rb_hash_keys, 0); + rb_define_method(rb_cHash,"values", rb_hash_values, 0); + + rb_define_method(rb_cHash,"shift", rb_hash_shift, 0); + rb_define_method(rb_cHash,"delete", rb_hash_delete, 1); + rb_define_method(rb_cHash,"delete_if", rb_hash_delete_if, 0); + rb_define_method(rb_cHash,"clear", rb_hash_clear, 0); + rb_define_method(rb_cHash,"invert", rb_hash_invert, 0); + rb_define_method(rb_cHash,"update", rb_hash_update, 1); + rb_define_method(rb_cHash,"replace", rb_hash_replace, 1); + + rb_define_method(rb_cHash,"include?", rb_hash_has_key, 1); + rb_define_method(rb_cHash,"has_key?", rb_hash_has_key, 1); + rb_define_method(rb_cHash,"has_value?", rb_hash_has_value, 1); + rb_define_method(rb_cHash,"key?", rb_hash_has_key, 1); + rb_define_method(rb_cHash,"value?", rb_hash_has_value, 1); + +#ifndef __MACOS__ /* environment variables nothing on MacOS. */ + origenviron = environ; + envtbl = rb_obj_alloc(rb_cObject); + rb_extend_object(envtbl, rb_mEnumerable); + + rb_define_singleton_method(envtbl,"[]", rb_f_getenv, 1); + rb_define_singleton_method(envtbl,"[]=", rb_f_setenv, 2); rb_define_singleton_method(envtbl,"each", env_each, 0); rb_define_singleton_method(envtbl,"each_pair", env_each, 0); rb_define_singleton_method(envtbl,"each_key", env_each_key, 0); @@ -1135,6 +1442,7 @@ Init_Hash() rb_define_singleton_method(envtbl,"rehash", env_none, 0); rb_define_singleton_method(envtbl,"to_a", env_to_a, 0); rb_define_singleton_method(envtbl,"indexes", env_indexes, -1); + rb_define_singleton_method(envtbl,"indices", env_indexes, -1); rb_define_singleton_method(envtbl,"length", env_size, 0); rb_define_singleton_method(envtbl,"empty?", env_empty_p, 0); rb_define_singleton_method(envtbl,"keys", env_keys, 0); @@ -1144,6 +1452,11 @@ Init_Hash() rb_define_singleton_method(envtbl,"has_value?", env_has_value, 1); rb_define_singleton_method(envtbl,"key?", env_has_key, 1); rb_define_singleton_method(envtbl,"value?", env_has_value, 1); + rb_define_singleton_method(envtbl,"to_hash", env_to_hash, 0); rb_define_global_const("ENV", envtbl); +#else /* __MACOS__ */ + envtbl = rb_hash_s_new(0, NULL, rb_cHash); + rb_define_global_const("ENV", envtbl); +#endif /* ifndef __MACOS__ environment variables nothing on MacOS. */ } diff --git a/inits.c b/inits.c index 123b32c989..3708edc03a 100644 --- a/inits.c +++ b/inits.c @@ -6,7 +6,7 @@ $Date$ created at: Tue Dec 28 16:01:58 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -49,14 +49,14 @@ rb_call_inits() Init_sym(); Init_var_tables(); Init_Object(); - Init_Exception(); -#ifdef THREAD - Init_Thread(); -#endif Init_Comparable(); Init_Enumerable(); Init_eval(); Init_String(); + Init_Exception(); +#ifdef USE_THREAD + Init_Thread(); +#endif Init_Numeric(); Init_Bignum(); Init_Array(); diff --git a/instruby.rb b/instruby.rb index 8fd77055f2..d489e0f838 100644 --- a/instruby.rb +++ b/instruby.rb @@ -1,7 +1,10 @@ -#!./miniruby +#!./miniruby -I. + require "rbconfig.rb" include Config +destdir = ARGV[0] || '' + $:.unshift CONFIG["srcdir"]+"/lib" require "ftools" @@ -12,26 +15,43 @@ else prefix = CONFIG["prefix"] end ruby_install_name = CONFIG["ruby_install_name"] -bindir = prefix + "/bin" -libdir = prefix + "/lib/" + ruby_install_name -archdir = libdir+"/"+CONFIG["arch"] +bindir = CONFIG["bindir"] +libdir = CONFIG["libdir"] +pkglibdir = libdir + "/" + ruby_install_name +archdir = pkglibdir + "/" + CONFIG["arch"] mandir = CONFIG["mandir"] + "/man1" +wdir = Dir.getwd +File.makedirs "#{destdir}#{bindir}", true File.install "ruby#{binsuffix}", - "#{bindir}/#{ruby_install_name}#{binsuffix}", 0755, TRUE -File.makedirs libdir, TRUE + "#{destdir}#{bindir}/#{ruby_install_name}#{binsuffix}", 0755, true +for dll in Dir['*.dll'] + File.install dll, "#{destdir}#{bindir}/#{dll}", 0755, true +end +File.makedirs "#{destdir}#{libdir}", true +for lib in ["libruby.so", "libruby.so.LIB"] + if File.exist? lib + File.install lib, "#{destdir}#{libdir}", 0644, true + end +end +File.makedirs "#{destdir}#{pkglibdir}", true +File.makedirs "#{destdir}#{archdir}", true Dir.chdir "ext" -system "../miniruby#{binsuffix} extmk.rb install" +system "../miniruby#{binsuffix} extmk.rb install #{destdir}" Dir.chdir CONFIG["srcdir"] -IO.foreach 'MANIFEST' do |$_| - $_.chop! - if /^lib/ - File.install $_, libdir, 0644, TRUE - elsif /^[a-z]+\.h$/ - File.install $_, archdir, 0644, TRUE - end - File.install "config.h", archdir, 0644, TRUE +for f in Dir["lib/*.rb"] + File.install f, "#{destdir}#{pkglibdir}", 0644, true +end + +File.makedirs(archdir,true) +for f in Dir["*.h"] + File.install f, "#{destdir}#{archdir}", 0644, true end -File.install "rbconfig.rb", archdir, 0644, TRUE -File.install "ruby.1", mandir, 0644, TRUE +File.install "libruby.a", "#{destdir}#{archdir}", 0644, true + +File.makedirs "#{destdir}#{mandir}", true +File.install "ruby.1", "#{destdir}#{mandir}", 0644, true +Dir.chdir wdir +File.install "config.h", "#{destdir}#{archdir}", 0644, true +File.install "rbconfig.rb", "#{destdir}#{archdir}", 0644, true # vi:set sw=2: diff --git a/intern.h b/intern.h index 192da014d5..8b88751469 100644 --- a/intern.h +++ b/intern.h @@ -3,289 +3,321 @@ */ /* array.c */ -void memclear _((register VALUE *, register int)); -VALUE assoc_new _((VALUE, VALUE)); -VALUE ary_new _((void)); -VALUE ary_new2 _((int)); -VALUE ary_new3(); -VALUE ary_new4 _((int, VALUE *)); -VALUE ary_freeze _((VALUE)); -void ary_store _((VALUE, int, VALUE)); -VALUE ary_push _((VALUE, VALUE)); -VALUE ary_pop _((VALUE)); -VALUE ary_shift _((VALUE)); -VALUE ary_unshift _((VALUE, VALUE)); -VALUE ary_entry _((VALUE, int)); -VALUE ary_each _((VALUE)); -VALUE ary_join _((VALUE, VALUE)); -VALUE ary_to_s _((VALUE)); -VALUE ary_print_on _((VALUE, VALUE)); -VALUE ary_reverse _((VALUE)); -VALUE ary_sort_bang _((VALUE)); -VALUE ary_sort _((VALUE)); -VALUE ary_delete _((VALUE, VALUE)); -VALUE ary_delete_at _((VALUE, VALUE)); -VALUE ary_plus _((VALUE, VALUE)); -VALUE ary_concat _((VALUE, VALUE)); -VALUE ary_assoc _((VALUE, VALUE)); -VALUE ary_rassoc _((VALUE, VALUE)); -VALUE ary_includes _((VALUE, VALUE)); +void rb_mem_clear _((register VALUE*, register size_t)); +VALUE rb_assoc_new _((VALUE, VALUE)); +VALUE rb_ary_new _((void)); +VALUE rb_ary_new2 _((size_t)); +VALUE rb_ary_new3 __((size_t,...)); +VALUE rb_ary_new4 _((size_t, VALUE *)); +VALUE rb_ary_freeze _((VALUE)); +VALUE rb_ary_aref _((int, VALUE*, VALUE)); +void rb_ary_store _((VALUE, size_t, VALUE)); +VALUE rb_ary_to_s _((VALUE)); +VALUE rb_ary_push _((VALUE, VALUE)); +VALUE rb_ary_pop _((VALUE)); +VALUE rb_ary_shift _((VALUE)); +VALUE rb_ary_unshift _((VALUE, VALUE)); +VALUE rb_ary_entry _((VALUE, size_t)); +VALUE rb_ary_each _((VALUE)); +VALUE rb_ary_join _((VALUE, VALUE)); +VALUE rb_ary_print_on _((VALUE, VALUE)); +VALUE rb_ary_reverse _((VALUE)); +VALUE rb_ary_sort _((VALUE)); +VALUE rb_ary_sort_bang _((VALUE)); +VALUE rb_ary_delete _((VALUE, VALUE)); +VALUE rb_ary_delete_at _((VALUE, VALUE)); +VALUE rb_ary_plus _((VALUE, VALUE)); +VALUE rb_ary_concat _((VALUE, VALUE)); +VALUE rb_ary_assoc _((VALUE, VALUE)); +VALUE rb_ary_rassoc _((VALUE, VALUE)); +VALUE rb_ary_includes _((VALUE, VALUE)); +VALUE rb_protect_inspect _((VALUE(*)(),VALUE,VALUE)); +VALUE rb_inspecting_p _((VALUE)); /* bignum.c */ -VALUE big_clone _((VALUE)); -void big_2comp _((VALUE)); -VALUE big_norm _((VALUE)); -VALUE uint2big _((UINT)); -VALUE int2big _((INT)); -VALUE uint2inum _((UINT)); -VALUE int2inum _((INT)); -VALUE str2inum _((UCHAR *, int)); -VALUE big2str _((VALUE, int)); -INT big2int _((VALUE)); -VALUE big_to_i _((VALUE)); -VALUE dbl2big _((double)); -double big2dbl _((VALUE)); -VALUE big_to_f _((VALUE)); -VALUE big_plus _((VALUE, VALUE)); -VALUE big_minus _((VALUE, VALUE)); -VALUE big_mul _((VALUE, VALUE)); -VALUE big_pow _((VALUE, VALUE)); -VALUE big_and _((VALUE, VALUE)); -VALUE big_or _((VALUE, VALUE)); -VALUE big_xor _((VALUE, VALUE)); -VALUE big_lshift _((VALUE, VALUE)); -VALUE big_rand _((VALUE)); +VALUE rb_big_clone _((VALUE)); +void rb_big_2comp _((VALUE)); +VALUE rb_big_norm _((VALUE)); +VALUE rb_uint2big _((unsigned long)); +VALUE rb_int2big _((long)); +VALUE rb_uint2inum _((unsigned long)); +VALUE rb_int2inum _((long)); +VALUE rb_str2inum _((char*, int)); +VALUE rb_big2str _((VALUE, int)); +long rb_big2long _((VALUE)); +#define rb_big2int(x) rb_big2long(x) +unsigned long rb_big2ulong _((VALUE)); +#define rb_big2uint(x) rb_big2ulong(x) +VALUE rb_dbl2big _((double)); +double rb_big2dbl _((VALUE)); +VALUE rb_big_plus _((VALUE, VALUE)); +VALUE rb_big_minus _((VALUE, VALUE)); +VALUE rb_big_mul _((VALUE, VALUE)); +VALUE rb_big_pow _((VALUE, VALUE)); +VALUE rb_big_and _((VALUE, VALUE)); +VALUE rb_big_or _((VALUE, VALUE)); +VALUE rb_big_xor _((VALUE, VALUE)); +VALUE rb_big_lshift _((VALUE, VALUE)); +VALUE rb_big_rand _((VALUE)); /* class.c */ -VALUE class_new _((VALUE)); -VALUE singleton_class_new _((VALUE)); -VALUE singleton_class_clone _((VALUE)); -void singleton_class_attached _((VALUE,VALUE)); +VALUE rb_class_new _((VALUE)); +VALUE rb_singleton_class_new _((VALUE)); +VALUE rb_singleton_class_clone _((VALUE)); +void rb_singleton_class_attached _((VALUE,VALUE)); VALUE rb_define_class_id _((ID, VALUE)); -VALUE module_new _((void)); +VALUE rb_module_new _((void)); VALUE rb_define_module_id _((ID)); -VALUE mod_included_modules _((VALUE)); -VALUE mod_ancestors _((VALUE)); -VALUE class_instance_methods _((int, VALUE *, VALUE)); -VALUE class_private_instance_methods _((int, VALUE *, VALUE)); -VALUE obj_singleton_methods _((VALUE)); +VALUE rb_mod_included_modules _((VALUE)); +VALUE rb_mod_ancestors _((VALUE)); +VALUE rb_class_instance_methods _((int, VALUE*, VALUE)); +VALUE rb_class_protected_instance_methods _((int, VALUE*, VALUE)); +VALUE rb_class_private_instance_methods _((int, VALUE*, VALUE)); +VALUE rb_obj_singleton_methods _((VALUE)); void rb_define_method_id _((VALUE, ID, VALUE (*)(), int)); -void rb_undef_method _((VALUE, char *)); -void rb_define_private_method _((VALUE, char *, VALUE (*)(), int)); +void rb_undef_method _((VALUE, char*)); +void rb_define_protected_method _((VALUE, char*, VALUE (*)(), int)); +void rb_define_private_method _((VALUE, char*, VALUE (*)(), int)); void rb_define_singleton_method _((VALUE,char*,VALUE(*)(),int)); void rb_define_private_method _((VALUE,char*,VALUE(*)(),int)); VALUE rb_singleton_class _((VALUE)); /* enum.c */ -VALUE enum_length _((VALUE)); +VALUE rb_enum_length _((VALUE)); /* error.c */ -VALUE exc_new _((VALUE, char *, UINT)); -VALUE exc_new2 _((VALUE, char *)); -VALUE exc_new3 _((VALUE, VALUE)); -#ifdef __GNUC__ -volatile voidfn TypeError; -volatile voidfn ArgError; -volatile voidfn NameError; -volatile voidfn IndexError; -volatile voidfn LoadError; -#else -void TypeError(); -void ArgError(); -void NameError(); -void IndexError(); -void LoadError(); -#endif +extern int ruby_nerrs; +VALUE rb_exc_new _((VALUE, char*, int)); +VALUE rb_exc_new2 _((VALUE, char*)); +VALUE rb_exc_new3 _((VALUE, VALUE)); +void rb_loaderror __((char*, ...)) NORETURN; +void rb_compile_error __((char*, ...)); +void rb_compile_error_append __((char*, ...)); /* eval.c */ +void rb_exc_raise _((VALUE)) NORETURN; +void rb_exc_fatal _((VALUE)) NORETURN; +void rb_remove_method _((VALUE, char*)); +void rb_disable_super _((VALUE, char*)); +void rb_enable_super _((VALUE, char*)); void rb_clear_cache _((void)); void rb_alias _((VALUE, ID, ID)); +void rb_attr _((VALUE,ID,int,int,int)); int rb_method_boundp _((VALUE, ID, int)); -VALUE dyna_var_defined _((ID)); -VALUE dyna_var_ref _((ID)); -VALUE dyna_var_asgn _((ID, VALUE)); -void ruby_init _((void)); -void ruby_options _((int, char **)); -void ruby_run _((void)); -void rb_eval_cmd _((VALUE, VALUE)); -void rb_trap_eval _((VALUE, int)); +VALUE rb_dvar_defined _((ID)); +VALUE rb_dvar_ref _((ID)); +void rb_dvar_asgn _((ID, VALUE)); +void rb_dvar_push _((ID, VALUE)); +VALUE rb_eval_cmd _((VALUE, VALUE)); +VALUE rb_trap_eval _((VALUE, int)); int rb_respond_to _((VALUE, ID)); -void rb_raise _((VALUE)); -void rb_fatal _((VALUE)); void rb_interrupt _((void)); -int iterator_p _((void)); -VALUE rb_yield_0 _((VALUE, volatile VALUE)); VALUE rb_apply _((VALUE, ID, VALUE)); -VALUE rb_funcall2 _((VALUE, ID, int, VALUE *)); +VALUE rb_funcall2 _((VALUE, ID, int, VALUE*)); void rb_backtrace _((void)); ID rb_frame_last_func _((void)); -VALUE f_load _((VALUE, VALUE)); -void rb_provide _((char *)); -VALUE f_require _((VALUE, VALUE)); -VALUE class_new_instance _((int, VALUE *, VALUE)); -VALUE f_lambda _((void)); -void rb_set_end_proc _((void (*)(),VALUE)); -void gc_mark_threads _((void)); -void thread_schedule _((void)); -void thread_wait_fd _((int)); -void thread_fd_writable _((int)); -int thread_alone _((void)); -void thread_sleep _((int)); -void thread_sleep_forever _((void)); -VALUE thread_create _((VALUE (*)(), void *)); -void thread_interrupt _((void)); +VALUE rb_obj_instance_eval _((int, VALUE*, VALUE)); +void rb_load _((VALUE, int)); +void rb_load_protect _((VALUE, int, int*)); +void rb_jump_tag _((int)) NORETURN; +void rb_provide _((char*)); +VALUE rb_f_require _((VALUE, VALUE)); +void rb_obj_call_init _((VALUE)); +VALUE rb_class_new_instance _((int, VALUE*, VALUE)); +VALUE rb_f_lambda _((void)); +VALUE rb_protect _((VALUE (*)(), VALUE, int*)); +void rb_set_end_proc _((void (*)(), VALUE)); +void rb_gc_mark_threads _((void)); +void rb_thread_start_timer _((void)); +void rb_thread_stop_timer _((void)); +void rb_thread_schedule _((void)); +void rb_thread_wait_fd _((int)); +void rb_thread_fd_writable _((int)); +int rb_thread_alone _((void)); +void rb_thread_sleep _((int)); +void rb_thread_sleep_forever _((void)); +VALUE rb_thread_create _((VALUE (*)(), void*)); +int rb_thread_scope_shared_p _((void)); +void rb_thread_interrupt _((void)); +void rb_thread_trap_eval _((VALUE, int)); +int rb_thread_select(); +void rb_thread_wait_for(); +VALUE rb_thread_current _((void)); +VALUE rb_thread_main _((void)); +VALUE rb_thread_local_aref _((VALUE, ID)); +VALUE rb_thread_local_aset _((VALUE, ID, VALUE)); /* file.c */ -VALUE file_open _((char *, char *)); -int eaccess _((char *, int)); -VALUE file_s_expand_path _((VALUE, VALUE)); +VALUE rb_file_open _((char*, char*)); +int eaccess _((char*, int)); +VALUE rb_file_s_expand_path _((int, VALUE *)); /* gc.c */ -void rb_global_variable _((VALUE *)); -void gc_mark_locations _((VALUE *, VALUE *)); -void gc_mark_maybe(); -void gc_mark(); -void gc_force_recycle(); -void gc_gc _((void)); -void init_stack _((void)); -void init_heap _((void)); +void rb_global_variable _((VALUE*)); +void rb_gc_mark_locations _((VALUE*, VALUE*)); +void rb_mark_tbl _((struct st_table*)); +void rb_mark_hash _((struct st_table*)); +void rb_gc_mark_maybe(); +void rb_gc_mark(); +void rb_gc_force_recycle _((VALUE)); +void rb_gc _((void)); +void rb_gc_call_finalizer_at_exit _((void)); /* hash.c */ -VALUE hash_freeze _((VALUE)); VALUE rb_hash _((VALUE)); -VALUE hash_new _((void)); -VALUE hash_aref _((VALUE, VALUE)); -VALUE hash_aset _((VALUE, VALUE, VALUE)); +VALUE rb_hash_new _((void)); +VALUE rb_hash_freeze _((VALUE)); +VALUE rb_hash_aref _((VALUE, VALUE)); +VALUE rb_hash_aset _((VALUE, VALUE, VALUE)); +int rb_path_check _((char *)); +int rb_env_path_tainted _((void)); /* io.c */ -void eof_error _((void)); -VALUE io_write _((VALUE, VALUE)); -VALUE io_gets_method _((int, VALUE*, VALUE)); -VALUE io_gets _((VALUE)); -VALUE io_getc _((VALUE)); -VALUE io_ungetc _((VALUE, VALUE)); -VALUE io_close _((VALUE)); -VALUE io_binmode _((VALUE)); -int io_mode_flags _((char *)); -VALUE io_reopen _((VALUE, VALUE)); -VALUE f_gets _((void)); -void rb_str_setter _((VALUE, ID, VALUE *)); +extern VALUE rb_fs; +extern VALUE rb_output_fs; +extern VALUE rb_rs; +extern VALUE rb_default_rs; +extern VALUE rb_output_rs; +VALUE rb_io_write _((VALUE, VALUE)); +VALUE rb_io_gets _((VALUE)); +VALUE rb_io_getc _((VALUE)); +VALUE rb_io_ungetc _((VALUE, VALUE)); +VALUE rb_io_close _((VALUE)); +VALUE rb_io_eof _((VALUE)); +VALUE rb_io_binmode _((VALUE)); +int rb_io_mode_flags _((char*)); +VALUE rb_io_reopen _((VALUE, VALUE)); +VALUE rb_gets _((void)); +void rb_str_setter _((VALUE, ID, VALUE*)); /* numeric.c */ -void num_zerodiv _((void)); -VALUE num_coerce_bin _((VALUE, VALUE)); -VALUE float_new _((double)); -VALUE flo_pow _((VALUE, VALUE)); -VALUE num2fix _((VALUE)); -VALUE fix2str _((VALUE, int)); -VALUE fix_to_s _((VALUE)); -VALUE num_upto _((VALUE, VALUE)); -VALUE fix_upto _((VALUE, VALUE)); +void rb_num_zerodiv _((void)); +VALUE rb_num_coerce_bin _((VALUE, VALUE)); +VALUE rb_float_new _((double)); +VALUE rb_num2fix _((VALUE)); +VALUE rb_fix2str _((VALUE, int)); +VALUE rb_fix_upto _((VALUE, VALUE)); /* object.c */ -VALUE rb_equal _((VALUE, VALUE)); int rb_eql _((VALUE, VALUE)); -VALUE obj_equal _((VALUE, VALUE)); -VALUE any_to_s _((VALUE)); +VALUE rb_any_to_s _((VALUE)); VALUE rb_inspect _((VALUE)); -VALUE obj_is_instance_of _((VALUE, VALUE)); -VALUE obj_is_kind_of _((VALUE, VALUE)); -VALUE obj_alloc _((VALUE)); +VALUE rb_obj_is_instance_of _((VALUE, VALUE)); +VALUE rb_obj_is_kind_of _((VALUE, VALUE)); +VALUE rb_obj_alloc _((VALUE)); +VALUE rb_obj_clone _((VALUE)); +VALUE rb_obj_taint _((VALUE)); +VALUE rb_obj_tainted _((VALUE)); +VALUE rb_obj_untaint _((VALUE)); +VALUE rb_obj_id _((VALUE)); +VALUE rb_convert_type _((VALUE,int,char*,char*)); VALUE rb_Integer _((VALUE)); VALUE rb_Float _((VALUE)); VALUE rb_String _((VALUE)); VALUE rb_Array _((VALUE)); -double num2dbl _((VALUE)); /* parse.y */ +extern int ruby_sourceline; +extern char *ruby_sourcefile; int yyparse _((void)); -void pushback _((int)); -ID id_attrset _((ID)); -void yyappend_print _((void)); -void yywhile_loop _((int, int)); +ID rb_id_attrset _((ID)); +void rb_parser_append_print _((void)); +void rb_parser_while_loop _((int, int)); int rb_is_const_id _((ID)); int rb_is_instance_id _((ID)); -void local_var_append _((ID)); -VALUE backref_get _((void)); -void backref_set _((VALUE)); -VALUE lastline_get _((void)); -void lastline_set _((VALUE)); +VALUE rb_backref_get _((void)); +void rb_backref_set _((VALUE)); +VALUE rb_lastline_get _((void)); +void rb_lastline_set _((VALUE)); /* process.c */ -int rb_proc_exec _((char *)); +int rb_proc_exec _((char*)); void rb_syswait _((int)); /* range.c */ -VALUE range_new _((VALUE, VALUE)); -VALUE range_beg_end _((VALUE, int *, int *)); +VALUE rb_range_new _((VALUE, VALUE)); +VALUE rb_range_beg_end _((VALUE, int*, int*)); /* re.c */ -VALUE reg_nth_defined _((int, VALUE)); -VALUE reg_nth_match _((int, VALUE)); -VALUE reg_last_match _((VALUE)); -VALUE reg_match_pre _((VALUE)); -VALUE reg_match_post _((VALUE)); -VALUE reg_match_last _((VALUE)); -VALUE reg_new _((char *, int, int)); -VALUE reg_match _((VALUE, VALUE)); -VALUE reg_match2 _((VALUE)); -void rb_set_kcode _((char *)); +VALUE rb_reg_nth_defined _((int, VALUE)); +VALUE rb_reg_nth_match _((int, VALUE)); +VALUE rb_reg_last_match _((VALUE)); +VALUE rb_reg_match_pre _((VALUE)); +VALUE rb_reg_match_post _((VALUE)); +VALUE rb_reg_match_last _((VALUE)); +VALUE rb_reg_new _((char*, size_t, int)); +VALUE rb_reg_match _((VALUE, VALUE)); +VALUE rb_reg_match2 _((VALUE)); +int rb_reg_options _((VALUE)); +char*rb_get_kcode _((void)); +void rb_set_kcode _((char*)); +int rb_ignorecase_p _((void)); /* ruby.c */ -void rb_require_modules _((void)); -void rb_load_file _((char *)); -void ruby_script _((char *)); +void rb_load_file _((char*)); +void ruby_script _((char*)); void ruby_prog_init _((void)); -void ruby_set_argv _((int, char **)); -void ruby_process_options _((int, char **)); +void ruby_set_argv _((int, char**)); +void ruby_process_options _((int, char**)); +void ruby_require_modules _((void)); +void ruby_load_script _((void)); /* signal.c */ -VALUE f_kill _((int, VALUE *)); -void gc_mark_trap_list _((void)); +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 (*)())); +#endif void rb_trap_exit _((void)); void rb_trap_exec _((void)); /* sprintf.c */ -VALUE f_sprintf _((int, VALUE *)); +VALUE rb_f_sprintf _((int, VALUE*)); /* string.c */ -VALUE str_new _((UCHAR *, UINT)); -VALUE str_new2 _((UCHAR *)); -VALUE str_new3 _((VALUE)); -VALUE str_new4 _((VALUE)); -VALUE obj_as_string _((VALUE)); -VALUE str_dup _((VALUE)); -VALUE str_plus _((VALUE, VALUE)); -VALUE str_times _((VALUE, VALUE)); -VALUE str_substr _((VALUE, int, int)); -void str_modify _((VALUE)); -VALUE str_freeze _((VALUE)); -VALUE str_dup_freezed _((VALUE)); -VALUE str_taint _((VALUE)); -VALUE str_tainted _((VALUE)); -VALUE str_resize _((VALUE, int)); -VALUE str_cat _((VALUE, UCHAR *, UINT)); -int str_hash _((VALUE)); -int str_cmp _((VALUE, VALUE)); -VALUE str_upto _((VALUE, VALUE)); -VALUE str_inspect _((VALUE)); -VALUE str_split _((VALUE, char *)); +VALUE rb_str_new _((char*, size_t)); +VALUE rb_str_new2 _((char*)); +VALUE rb_str_new3 _((VALUE)); +VALUE rb_str_new4 _((VALUE)); +VALUE rb_tainted_str_new _((char*, size_t)); +VALUE rb_tainted_str_new2 _((char*)); +VALUE rb_obj_as_string _((VALUE)); +VALUE rb_str_to_str _((VALUE)); +VALUE rb_str_dup _((VALUE)); +VALUE rb_str_plus _((VALUE, VALUE)); +VALUE rb_str_times _((VALUE, VALUE)); +VALUE rb_str_substr _((VALUE, size_t, size_t)); +void rb_str_modify _((VALUE)); +VALUE rb_str_freeze _((VALUE)); +VALUE rb_str_dup_frozen _((VALUE)); +VALUE rb_str_resize _((VALUE, size_t)); +VALUE rb_str_cat _((VALUE, char*, size_t)); +VALUE rb_str_concat _((VALUE, VALUE)); +int rb_str_hash _((VALUE)); +int rb_str_cmp _((VALUE, VALUE)); +VALUE rb_str_upto _((VALUE, VALUE)); +VALUE rb_str_inspect _((VALUE)); +VALUE rb_str_split _((VALUE, char*)); /* struct.c */ -VALUE struct_new(); -VALUE struct_define(); -VALUE struct_alloc _((VALUE, VALUE)); -VALUE struct_aref _((VALUE, VALUE)); -VALUE struct_aset _((VALUE, VALUE, VALUE)); -VALUE struct_getmember _((VALUE, ID)); +VALUE rb_struct_new __((VALUE, ...)); +VALUE rb_struct_define __((char*, ...)); +VALUE rb_struct_alloc _((VALUE, VALUE)); +VALUE rb_struct_aref _((VALUE, VALUE)); +VALUE rb_struct_aset _((VALUE, VALUE, VALUE)); +VALUE rb_struct_getmember _((VALUE, ID)); /* time.c */ -VALUE time_new _((int, int)); -/* util.c */ -void add_suffix _((VALUE, char *)); -unsigned long scan_oct _((char *, int, int *)); -unsigned long scan_hex _((char *, int, int *)); +VALUE rb_time_new _((int, int)); /* variable.c */ -VALUE mod_name _((VALUE)); +VALUE rb_mod_name _((VALUE)); VALUE rb_class_path _((VALUE)); -void rb_set_class_path _((VALUE, VALUE, char *)); -VALUE rb_path2class _((char *)); +void rb_set_class_path _((VALUE, VALUE, char*)); +VALUE rb_path2class _((char*)); void rb_name_class _((VALUE, ID)); -void rb_autoload _((char *, char *)); -VALUE f_autoload _((VALUE, VALUE, VALUE)); -void gc_mark_global_tbl _((void)); -VALUE f_trace_var _((int, VALUE *)); -VALUE f_untrace_var _((int, VALUE *)); -VALUE rb_gvar_set2 _((char *, VALUE)); -VALUE f_global_variables _((void)); +void rb_autoload _((char*, char*)); +VALUE rb_f_autoload _((VALUE, VALUE, VALUE)); +void rb_gc_mark_global_tbl _((void)); +VALUE rb_f_trace_var _((int, VALUE*)); +VALUE rb_f_untrace_var _((int, VALUE*)); +VALUE rb_gvar_set2 _((char*, VALUE)); +VALUE rb_f_global_variables _((void)); void rb_alias_variable _((ID, ID)); +void rb_mark_generic_ivar _((VALUE)); +void rb_mark_generic_ivar_tbl _((void)); +void rb_free_generic_ivar _((VALUE)); VALUE rb_ivar_get _((VALUE, ID)); VALUE rb_ivar_set _((VALUE, ID, VALUE)); VALUE rb_ivar_defined _((VALUE, ID)); -VALUE obj_instance_variables _((VALUE)); -VALUE mod_const_at _((VALUE, VALUE)); -VALUE mod_constants _((VALUE)); -VALUE mod_const_of _((VALUE, VALUE)); +VALUE rb_obj_instance_variables _((VALUE)); +VALUE rb_obj_remove_instance_variable _((VALUE, VALUE)); +VALUE rb_mod_const_at _((VALUE, VALUE)); +VALUE rb_mod_constants _((VALUE)); +VALUE rb_mod_const_of _((VALUE, VALUE)); +VALUE rb_mod_remove_const _((VALUE, VALUE)); int rb_const_defined_at _((VALUE, ID)); int rb_autoload_defined _((ID)); int rb_const_defined _((VALUE, ID)); +/* version.c */ +void ruby_show_version _((void)); +void ruby_show_copyright _((void)); diff --git a/io.c b/io.c index f84e15e447..5573e76a64 100644 --- a/io.c +++ b/io.c @@ -6,12 +6,13 @@ $Date$ created at: Fri Oct 15 18:08:59 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" -#include "io.h" +#include "rubyio.h" +#include "rubysig.h" #include #include @@ -39,10 +40,6 @@ struct timeval { #include -#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__) -#include -#endif - #ifdef HAVE_SYS_PARAM_H # include #else @@ -53,29 +50,43 @@ struct timeval { #include #endif -VALUE rb_ad_string(); +#ifdef USE_CWGUSI + #include + #include + #include +#endif +extern void Init_File _((void)); + +#ifdef __BEOS__ +#include +#endif + +#include "util.h" -VALUE cIO; -extern VALUE cFile; -VALUE eEOFError; -VALUE eIOError; +VALUE rb_cIO; +VALUE rb_eEOFError; +VALUE rb_eIOError; VALUE rb_stdin, rb_stdout, rb_stderr, rb_defout; -VALUE FS, OFS; -VALUE RS, ORS; -VALUE RS_default; +VALUE rb_fs; +VALUE rb_output_fs; +VALUE rb_rs; +VALUE rb_output_rs; +VALUE rb_default_rs; static VALUE argf; -ID id_write; +static ID id_write; -VALUE lastline_get(); -void lastline_set(); +extern char *ruby_inplace_mode; -extern char *inplace; +struct timeval rb_time_timeval _((VALUE)); -struct timeval time_timeval(); +static VALUE filename, file; +static int gets_lineno; +static int init_p = 0, next_p = 0; +static VALUE lineno; #ifdef _STDIO_USES_IOSTREAM /* GNU libc */ # ifdef _IO_fpos_t @@ -83,86 +94,89 @@ struct timeval time_timeval(); # else # define READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr) # endif +#elif defined(FILE_COUNT) +# define READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0) +#elif defined(__BEOS__) +# define ReadDataPending(fp) (fp->_state._eof == 0) +#elif defined(USE_CWGUSI) +# define ReadDataPending(fp) (fp->state.eof == 0) #else -# ifdef FILE_COUNT -# define READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0) -# else /* requires systems own version of the ReadDataPending() */ extern int ReadDataPending(); -# define READ_DATA_PENDING(fp) ReadDataPending(fp) -# endif +# define READ_DATA_PENDING(fp) ReadDataPending(fp) #endif -#ifndef THREAD +#ifndef USE_THREAD # define READ_CHECK(fp) 0 #else # define READ_CHECK(fp) do {\ - if (!READ_DATA_PENDING(fp)) thread_wait_fd(fileno(fp));\ + if (!READ_DATA_PENDING(fp)) rb_thread_wait_fd(fileno(fp));\ } while(0) #endif void -eof_error() +rb_eof_error() { - Raise(eEOFError, "End of file reached"); + rb_raise(rb_eEOFError, "End of file reached"); } void -io_writable(fptr) +rb_io_check_closed(fptr) OpenFile *fptr; { - if (!(fptr->mode & FMODE_WRITABLE)) { - Raise(eIOError, "not opened for writing"); - } + if (fptr->f == NULL && fptr->f2 == NULL) + rb_raise(rb_eIOError, "closed stream"); } void -io_readable(fptr) +rb_io_check_readable(fptr) OpenFile *fptr; { if (!(fptr->mode & FMODE_READABLE)) { - Raise(eIOError, "not opened for reading"); + rb_raise(rb_eIOError, "not opened for reading"); } } -static void -closed() +void +rb_io_check_writable(fptr) + OpenFile *fptr; { - Raise(eIOError, "closed stream"); + if (!(fptr->mode & FMODE_WRITABLE)) { + rb_raise(rb_eIOError, "not opened for writing"); + } } /* writing functions */ VALUE -io_write(io, str) +rb_io_write(io, str) VALUE io, str; { OpenFile *fptr; FILE *f; int n; + rb_secure(4); if (TYPE(str) != T_STRING) - str = obj_as_string(str); + str = rb_obj_as_string(str); if (RSTRING(str)->len == 0) return INT2FIX(0); if (BUILTIN_TYPE(io) != T_FILE) { + /* port is not IO, call write method for it. */ return rb_funcall(io, id_write, 1, str); } - rb_secure(4); GetOpenFile(io, fptr); - io_writable(fptr); - + rb_io_check_writable(fptr); f = GetWriteFile(fptr); - if (f == NULL) closed(); #ifdef __human68k__ { - register UCHAR *ptr = str->ptr; - n = (int) str->len; + register char *ptr = RSTRING(str)->ptr; + n = (int)RSTRING(str)->len; while (--n >= 0) if (fputc(*ptr++, f) == EOF) rb_sys_fail(fptr->path); - n = ptr - str->ptr; + n = ptr - RSTRING(str)->ptr; } if (ferror(f)) rb_sys_fail(fptr->path); @@ -180,24 +194,23 @@ io_write(io, str) } static VALUE -io_addstr(io, str) +rb_io_addstr(io, str) VALUE io, str; { - io_write(io, str); + rb_io_write(io, str); return io; } static VALUE -io_flush(io) +rb_io_flush(io) VALUE io; { OpenFile *fptr; FILE *f; GetOpenFile(io, fptr); - io_writable(fptr); + rb_io_check_writable(fptr); f = GetWriteFile(fptr); - if (f == NULL) closed(); if (fflush(f) == EOF) rb_sys_fail(0); @@ -205,42 +218,108 @@ io_flush(io) } static VALUE -io_eof(io) +rb_io_tell(io) + VALUE io; +{ + OpenFile *fptr; + long pos; + + GetOpenFile(io, fptr); + pos = ftell(fptr->f); + if (ferror(fptr->f) != 0) rb_sys_fail(fptr->path); + + return rb_int2inum(pos); +} + +static VALUE +rb_io_seek(io, offset, ptrname) + VALUE io, offset, ptrname; +{ + OpenFile *fptr; + long pos; + + GetOpenFile(io, fptr); + pos = fseek(fptr->f, NUM2INT(offset), NUM2INT(ptrname)); + if (pos != 0) rb_sys_fail(fptr->path); + clearerr(fptr->f); + + return INT2FIX(0); +} + +#ifndef SEEK_CUR +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif + +static VALUE +rb_io_set_pos(io, offset) + VALUE io, offset; +{ + OpenFile *fptr; + long pos; + + GetOpenFile(io, fptr); + pos = fseek(fptr->f, NUM2INT(offset), SEEK_SET); + if (pos != 0) rb_sys_fail(fptr->path); + clearerr(fptr->f); + + return INT2NUM(pos); +} + +static VALUE +rb_io_rewind(io) + VALUE io; +{ + OpenFile *fptr; + + GetOpenFile(io, fptr); + if (fseek(fptr->f, 0L, 0) != 0) rb_sys_fail(fptr->path); + clearerr(fptr->f); + + return INT2FIX(0); +} + +VALUE +rb_io_eof(io) VALUE io; { OpenFile *fptr; int ch; GetOpenFile(io, fptr); - io_readable(fptr); - if (fptr->f == NULL) closed(); - - if (READ_DATA_PENDING(fptr->f)) return FALSE; - if (feof(fptr->f)) return TRUE; + rb_io_check_readable(fptr); + if (READ_DATA_PENDING(fptr->f)) return Qfalse; +#if 0 + if (feof(fptr->f)) return Qtrue; + return Qfalse; +#else + READ_CHECK(fptr->f); TRAP_BEG; ch = getc(fptr->f); TRAP_END; if (ch != EOF) { - (void)ungetc(ch, fptr->f); - return FALSE; + ungetc(ch, fptr->f); + return Qfalse; } - return TRUE; + return Qtrue; +#endif } static VALUE -io_sync(io) +rb_io_sync(io) VALUE io; { OpenFile *fptr; GetOpenFile(io, fptr); - return (fptr->mode & FMODE_SYNC) ? TRUE : FALSE; + return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse; } static VALUE -io_set_sync(io, mode) +rb_io_set_sync(io, mode) VALUE io, mode; { OpenFile *fptr; @@ -256,7 +335,7 @@ io_set_sync(io, mode) } static VALUE -io_fileno(io) +rb_io_fileno(io) VALUE io; { OpenFile *fptr; @@ -267,6 +346,13 @@ io_fileno(io) return INT2FIX(fd); } +static VALUE +rb_io_to_io(io) + VALUE io; +{ + return io; +} + /* reading functions */ #ifndef S_ISREG @@ -281,45 +367,52 @@ read_all(port) { OpenFile *fptr; VALUE str = Qnil; - char *buf; struct stat st; - int siz = BUFSIZ; - int bytes = 0; + long siz = BUFSIZ; + long bytes = 0; int n; GetOpenFile(port, fptr); - io_readable(fptr); - if (fptr->f == NULL) closed(); + rb_io_check_readable(fptr); - if (fstat(fileno(fptr->f), &st) == 0 && S_ISREG(st.st_mode)) { - if (st.st_size == 0) return Qnil; + if (fstat(fileno(fptr->f), &st) == 0 && S_ISREG(st.st_mode) +#ifdef __BEOS__ + && (st.st_dev > 3) +#endif + ) + { + if (st.st_size == 0) return rb_str_new(0, 0); else { - int pos = ftell(fptr->f); + long pos = ftell(fptr->f); if (st.st_size > pos && pos >= 0) { siz = st.st_size - pos + 1; } } } - str = str_new(0, siz); + str = rb_str_new(0, siz); for (;;) { READ_CHECK(fptr->f); TRAP_BEG; n = fread(RSTRING(str)->ptr+bytes, 1, siz-bytes, fptr->f); TRAP_END; - if (n == 0) break; - if (n < 0) rb_sys_fail(fptr->path); + if (n <= 0) { + if (ferror(fptr->f)) rb_sys_fail(fptr->path); + return rb_str_new(0,0); + } bytes += n; - if (bytes < siz) break; + if (bytes < siz) break; siz += BUFSIZ; - str_resize(str, siz); + rb_str_resize(str, siz); } - if (bytes == 0) return Qnil; - if (bytes != siz) str_resize(str, bytes); - return str_taint(str); + if (bytes == 0) return rb_str_new(0,0); + if (bytes != siz) rb_str_resize(str, bytes); + OBJ_TAINT(str); + + return str; } static VALUE -io_read(argc, argv, io) +rb_io_read(argc, argv, io) int argc; VALUE *argv; VALUE io; @@ -328,36 +421,34 @@ io_read(argc, argv, io) int n, len; VALUE length, str; - if (rb_scan_args(argc, argv, "01", &length) == 0) { + rb_scan_args(argc, argv, "01", &length); + if (NIL_P(length)) { return read_all(io); } len = NUM2INT(length); GetOpenFile(io, fptr); - io_readable(fptr); - if (fptr->f == NULL) closed(); + rb_io_check_readable(fptr); - str = str_new(0, len); + str = rb_str_new(0, len); READ_CHECK(fptr->f); TRAP_BEG; n = fread(RSTRING(str)->ptr, 1, len, fptr->f); TRAP_END; - if (n == 0) return Qnil; - if (n < 0) { - rb_sys_fail(fptr->path); + if (n <= 0) { + if (ferror(fptr->f)) rb_sys_fail(fptr->path); + return Qnil; } - RSTRING(str)->len = n; RSTRING(str)->ptr[n] = '\0'; + OBJ_TAINT(str); - return str_taint(str); + return str; } -static VALUE lineno; - -VALUE -io_gets_method(argc, argv, io) +static VALUE +rb_io_gets_internal(argc, argv, io) int argc; VALUE *argv; VALUE io; @@ -370,33 +461,36 @@ io_gets_method(argc, argv, io) int rslen, rspara = 0; VALUE rs; - if (argc == 0) rs = RS; + if (argc == 0) { + rs = rb_rs; + } else { rb_scan_args(argc, argv, "1", &rs); if (!NIL_P(rs)) Check_Type(rs, T_STRING); } - GetOpenFile(io, fptr); - io_readable(fptr); - f = fptr->f; - if (f == NULL) closed(); - - if (!NIL_P(rs)) { + if (NIL_P(rs)) { + rsptr = 0; + rslen = 0; + } + else { rslen = RSTRING(rs)->len; if (rslen == 0) { rsptr = "\n\n"; rslen = 2; rspara = 1; } + else if (rslen == 1 && RSTRING(rs)->ptr[0] == '\n') { + return rb_io_gets(io); + } else { rsptr = RSTRING(rs)->ptr; } } - else { - rsptr = 0; - rslen = 0; - } - newline = rslen ? rsptr[rslen - 1] : 0777; + + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + f = fptr->f; if (rspara) { do { @@ -411,6 +505,7 @@ io_gets_method(argc, argv, io) } while (c != EOF); } + newline = rslen ? rsptr[rslen - 1] : 0777; { char buf[8192]; char *bp, *bpe = buf + sizeof buf - 3; @@ -426,7 +521,10 @@ io_gets_method(argc, argv, io) TRAP_BEG; c = getc(f); TRAP_END; - if (c == EOF) break; + if (c == EOF) { + if (errno == EINTR) continue; + break; + } if ((*bp++ = c) == newline) break; if (bp == bpe) break; } @@ -437,25 +535,29 @@ io_gets_method(argc, argv, io) TRAP_BEG; cnt = fread(buf, 1, sizeof(buf), f); TRAP_END; - c = cnt ? 0 : EOF; + if (cnt == 0) { + if (ferror(f)) rb_sys_fail(fptr->path); + c = EOF; + } + else { + c = 0; + } } - if (c == EOF) { - if (!append && cnt == 0) { - str = Qnil; - goto return_gets; - } + if (c == EOF && !append && cnt == 0) { + str = Qnil; + goto return_gets; } if (append) - str_cat(str, buf, cnt); + rb_str_cat(str, buf, cnt); else - str = str_new(buf, cnt); + str = rb_str_new(buf, cnt); if (c != EOF && (!rslen || RSTRING(str)->len < rslen || - memcmp(RSTRING(str)->ptr+RSTRING(str)->len-rslen, rsptr, rslen))) { + memcmp(RSTRING(str)->ptr+RSTRING(str)->len-rslen,rsptr,rslen))) { append = 1; goto again; } @@ -478,65 +580,161 @@ io_gets_method(argc, argv, io) if (!NIL_P(str)) { fptr->lineno++; lineno = INT2FIX(fptr->lineno); - str_taint(str); + OBJ_TAINT(str); } - lastline_set(str); return str; } VALUE -io_gets(io) +rb_io_gets(io) VALUE io; { - return io_gets_method(0, 0, io); + OpenFile *fptr; + FILE *f; + VALUE str = Qnil; + int c; + char buf[8192]; + char *bp, *bpe = buf + sizeof buf - 3; + int cnt; + int append = 0; + + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + f = fptr->f; + + again: + bp = buf; + for (;;) { + READ_CHECK(f); + TRAP_BEG; + c = getc(f); + TRAP_END; + if (c == EOF) { + if (errno == EINTR) continue; + break; + } + if ((*bp++ = c) == '\n') break; + if (bp == bpe) break; + } + cnt = bp - buf; + + if (c == EOF && !append && cnt == 0) { + str = Qnil; + goto return_gets; + } + + if (append) + rb_str_cat(str, buf, cnt); + else + str = rb_str_new(buf, cnt); + + if (c != EOF && RSTRING(str)->ptr[RSTRING(str)->len-1] != '\n') { + append = 1; + goto again; + } + + return_gets: + if (!NIL_P(str)) { + fptr->lineno++; + lineno = INT2FIX(fptr->lineno); + OBJ_TAINT(str); + } + + return str; } static VALUE -io_readline(argc, argv, io) +rb_io_gets_method(argc, argv, io) int argc; VALUE *argv; VALUE io; { - VALUE line = io_gets_method(argc, argv, io); + VALUE str = rb_io_gets_internal(argc, argv, io); + + if (!NIL_P(str)) { + rb_lastline_set(str); + } + return str; +} + +static VALUE +rb_io_lineno(io) + VALUE io; +{ + OpenFile *fptr; + + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + return INT2NUM(fptr->lineno); +} + +static VALUE +rb_io_set_lineno(io, lineno) + VALUE io, lineno; +{ + OpenFile *fptr; + + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + return fptr->lineno = NUM2INT(lineno); +} + +static void +lineno_setter(val, id, var) + VALUE val; + ID id; + VALUE *var; +{ + gets_lineno = NUM2INT(val); + *var = INT2FIX(gets_lineno); +} + +static VALUE +rb_io_readline(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ + VALUE line = rb_io_gets_method(argc, argv, io); if (NIL_P(line)) { - eof_error(); + rb_eof_error(); } return line; } static VALUE -io_readlines(argc, argv, io) +rb_io_readlines(argc, argv, io) int argc; VALUE *argv; VALUE io; { VALUE line, ary; - ary = ary_new(); - while (!NIL_P(line = io_gets_method(argc, argv, io))) { - ary_push(ary, line); + ary = rb_ary_new(); + while (!NIL_P(line = rb_io_gets_internal(argc, argv, io))) { + rb_ary_push(ary, line); } return ary; } static VALUE -io_each_line(argc, argv, io) +rb_io_each_line(argc, argv, io) int argc; VALUE *argv; VALUE io; { VALUE str; - while (!NIL_P(str = io_gets_method(argc, argv, io))) { + while (!NIL_P(str = rb_io_gets_internal(argc, argv, io))) { rb_yield(str); } return Qnil; } static VALUE -io_each_byte(io) +rb_io_each_byte(io) VALUE io; { OpenFile *fptr; @@ -544,9 +742,8 @@ io_each_byte(io) int c; GetOpenFile(io, fptr); - io_readable(fptr); + rb_io_check_readable(fptr); f = fptr->f; - if (f == NULL) closed(); for (;;) { READ_CHECK(f); @@ -561,7 +758,7 @@ io_each_byte(io) } VALUE -io_getc(io) +rb_io_getc(io) VALUE io; { OpenFile *fptr; @@ -569,9 +766,8 @@ io_getc(io) int c; GetOpenFile(io, fptr); - io_readable(fptr); + rb_io_check_readable(fptr); f = fptr->f; - if (f == NULL) closed(); READ_CHECK(f); TRAP_BEG; @@ -586,27 +782,26 @@ io_getc(io) } static VALUE -io_readchar(io) +rb_io_readchar(io) VALUE io; { - VALUE c = io_getc(io); + VALUE c = rb_io_getc(io); if (NIL_P(c)) { - eof_error(); + rb_eof_error(); } return c; } VALUE -io_ungetc(io, c) +rb_io_ungetc(io, c) VALUE io, c; { OpenFile *fptr; Check_Type(c, T_FIXNUM); GetOpenFile(io, fptr); - io_readable(fptr); - if (fptr->f == NULL) closed(); + rb_io_check_readable(fptr); if (ungetc(FIX2INT(c), fptr->f) == EOF) rb_sys_fail(fptr->path); @@ -614,16 +809,15 @@ io_ungetc(io, c) } static VALUE -io_isatty(io) +rb_io_isatty(io) VALUE io; { OpenFile *fptr; GetOpenFile(io, fptr); - if (fptr->f == NULL) closed(); if (isatty(fileno(fptr->f)) == 0) - return FALSE; - return TRUE; + return Qfalse; + return Qtrue; } static void @@ -636,23 +830,20 @@ fptr_finalize(fptr) if (fptr->f2 != NULL) { fclose(fptr->f2); } - if (fptr->path) { - free(fptr->path); - fptr->path = NULL; - } if (fptr->pid) { rb_syswait(fptr->pid); fptr->pid = 0; } } -void -io_fptr_finalize(fptr) +static void +rb_io_fptr_close(fptr) OpenFile *fptr; { + if (fptr->f == NULL && fptr->f2 == NULL) return; + if (fptr->finalize) { (*fptr->finalize)(fptr); - fptr->finalize = 0; } else { fptr_finalize(fptr); @@ -660,30 +851,93 @@ io_fptr_finalize(fptr) fptr->f = fptr->f2 = NULL; } +void +rb_io_fptr_finalize(fptr) + OpenFile *fptr; +{ + rb_io_fptr_close(fptr); + if (fptr->path) { + free(fptr->path); + fptr->path = NULL; + } +} + +VALUE +rb_io_close(io) + VALUE io; +{ + OpenFile *fptr; + + GetOpenFile(io, fptr); + rb_io_fptr_close(fptr); + + return Qnil; +} + +static VALUE +rb_io_close_method(io) + VALUE io; +{ + rb_secure(4); + rb_io_close(io); + return Qnil; +} + +static VALUE +rb_io_closed(io) + VALUE io; +{ + OpenFile *fptr; + + fptr = RFILE(io)->fptr; + return (fptr->f || fptr->f2)?Qfalse:Qtrue; +} + VALUE -io_close(io) +rb_io_close_read(io) VALUE io; { OpenFile *fptr; + rb_secure(4); GetOpenFile(io, fptr); - io_fptr_finalize(fptr); + if (fptr->f2 == 0 && (fptr->mode & FMODE_WRITABLE)) { + rb_raise(rb_eIOError, "closing non-duplex IO for reading"); + } + if (fptr->f2 == 0) { + return rb_io_close(io); + } + fclose(fptr->f); + fptr->mode &= ~FMODE_READABLE; + fptr->f = fptr->f2; + fptr->f2 = 0; return Qnil; } static VALUE -io_closed(io) +rb_io_close_write(io) VALUE io; { OpenFile *fptr; + rb_secure(4); GetOpenFile(io, fptr); - return fptr->f?FALSE:TRUE; + if (fptr->f2 == 0 && (fptr->mode & FMODE_READABLE)) { + rb_raise(rb_eIOError, "closing non-duplex IO for writing"); + } + if (fptr->f2 == 0) { + return rb_io_close(io); + } + fclose(fptr->f2); + fptr->f2 = 0; + fptr->mode &= ~FMODE_WRITABLE; + + return Qnil; } static VALUE -io_syswrite(io, str) +rb_io_syswrite(io, str) VALUE io, str; { OpenFile *fptr; @@ -692,15 +946,14 @@ io_syswrite(io, str) rb_secure(4); if (TYPE(str) != T_STRING) - str = obj_as_string(str); + str = rb_obj_as_string(str); GetOpenFile(io, fptr); - io_writable(fptr); + rb_io_check_writable(fptr); f = GetWriteFile(fptr); - if (f == NULL) closed(); -#ifdef THREAD - thread_fd_writable(fileno(f)); +#ifdef USE_THREAD + rb_thread_fd_writable(fileno(f)); #endif n = write(fileno(f), RSTRING(str)->ptr, RSTRING(str)->len); @@ -710,7 +963,7 @@ io_syswrite(io, str) } static VALUE -io_sysread(io, len) +rb_io_sysread(io, len) VALUE io, len; { OpenFile *fptr; @@ -719,44 +972,52 @@ io_sysread(io, len) ilen = NUM2INT(len); GetOpenFile(io, fptr); - io_readable(fptr); - if (fptr->f == NULL) closed(); + rb_io_check_readable(fptr); - str = str_new(0, ilen); + str = rb_str_new(0, ilen); -#ifdef THREAD - thread_wait_fd(fileno(fptr->f)); +#ifdef USE_THREAD + rb_thread_wait_fd(fileno(fptr->f)); #endif TRAP_BEG; n = read(fileno(fptr->f), RSTRING(str)->ptr, RSTRING(str)->len); TRAP_END; if (n == -1) rb_sys_fail(fptr->path); - if (n == 0) eof_error(); + if (n == 0) rb_eof_error(); RSTRING(str)->len = n; RSTRING(str)->ptr[n] = '\0'; - return str_taint(str); + OBJ_TAINT(str); + + return str; } VALUE -io_binmode(io) +rb_io_binmode(io) VALUE io; { -#if defined(NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__) +#if defined(NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__) || defined(USE_CWGUSI) OpenFile *fptr; GetOpenFile(io, fptr); #ifdef __human68k__ if (fptr->f) fmode(fptr->f, _IOBIN); - if (fptr->f2); + if (fptr->f2) fmode(fptr->f2, _IOBIN); #else +# ifndef USE_CWGUSI if (fptr->f && setmode(fileno(fptr->f), O_BINARY) == -1) rb_sys_fail(fptr->path); if (fptr->f2 && setmode(fileno(fptr->f2), O_BINARY) == -1) rb_sys_fail(fptr->path); +# else /* USE_CWGUSI */ + if (fptr->f) + fptr->f->mode.binrb_ary_io = 1; + if (fptr->f2) + fptr->f2->mode.binrb_ary_io = 1; +# endif /* USE_CWGUSI */ #endif fptr->mode |= FMODE_BINMODE; @@ -765,7 +1026,7 @@ io_binmode(io) } int -io_mode_flags(mode) +rb_io_mode_flags(mode) char *mode; { int flags = 0; @@ -781,7 +1042,7 @@ io_mode_flags(mode) flags |= FMODE_WRITABLE; break; default: - ArgError("illegal access mode"); + rb_raise(rb_eArgError, "illegal access mode"); } if (mode[1] == 'b') { @@ -806,7 +1067,7 @@ rb_fopen(fname, mode) f = fopen(fname, mode); if (f == NULL) { if (errno == EMFILE || errno == ENFILE) { - gc_gc(); + rb_gc(); f = fopen(fname, mode); } if (f == NULL) { @@ -862,6 +1123,7 @@ pipe_del_fptr(fptr) if (list->fptr == fptr) { pipe_list = list->next; + free(list); return; } @@ -880,18 +1142,20 @@ static void pipe_atexit() { struct pipe_list *list = pipe_list; + struct pipe_list *tmp; while (list) { - io_fptr_finalize(list->fptr); - list = list->next; + tmp = list->next; + rb_io_fptr_finalize(list->fptr); + list = tmp; } } -#if !defined (__CYGWIN32__) static void pipe_finalize(fptr) OpenFile *fptr; { +#if !defined (__CYGWIN32__) if (fptr->f != NULL) { pclose(fptr->f); } @@ -899,16 +1163,18 @@ pipe_finalize(fptr) pclose(fptr->f2); } fptr->f = fptr->f2 = NULL; +#else + fptr_finalize(fptr); +#endif pipe_del_fptr(fptr); } #endif -#endif void -io_unbuffered(fptr) +rb_io_unbuffered(fptr) OpenFile *fptr; { - if (fptr->f2 == 0) TypeError("non-writable fptr"); + if (fptr->f2 == 0) rb_raise(rb_eTypeError, "non-writable fptr"); if (fptr->f != 0) setbuf(fptr->f, NULL); setbuf(fptr->f2, NULL); fptr->mode |= FMODE_SYNC; @@ -918,7 +1184,8 @@ static VALUE pipe_open(pname, mode) char *pname, *mode; { - int modef = io_mode_flags(mode); +#ifndef USE_CWGUSI + int modef = rb_io_mode_flags(mode); OpenFile *fptr; #if defined(NT) || defined(DJGPP) || defined(__human68k__) @@ -927,7 +1194,7 @@ pipe_open(pname, mode) if (f == NULL) rb_sys_fail(pname); else { NEWOBJ(port, struct RFile); - OBJSETUP(port, cIO, T_FILE); + OBJSETUP(port, rb_cIO, T_FILE); MakeOpenFile(port, fptr); fptr->finalize = pipe_finalize; fptr->mode = modef; @@ -936,8 +1203,9 @@ pipe_open(pname, mode) if (modef & FMODE_READABLE) fptr->f = f; if (modef & FMODE_WRITABLE) { fptr->f2 = f; - io_unbuffered(fptr); + rb_io_unbuffered(fptr); } + rb_obj_call_init((VALUE)port); return (VALUE)port; } #else @@ -974,23 +1242,23 @@ pipe_open(pname, mode) } if (doexec) { - extern char *sourcefile; - extern int sourceline; + extern char *ruby_sourcefile; + extern int ruby_sourceline; int fd; for (fd = 3; fd < NOFILE; fd++) close(fd); rb_proc_exec(pname); fprintf(stderr, "%s:%d: command not found: %s\n", - sourcefile, sourceline, pname); + ruby_sourcefile, ruby_sourceline, pname); _exit(127); } return Qnil; case -1: /* fork failed */ if (errno == EAGAIN) { -#ifdef THREAD - thread_sleep(1); +#ifdef USE_THREAD + rb_thread_sleep(1); #else sleep(1); #endif @@ -1001,9 +1269,10 @@ pipe_open(pname, mode) break; default: /* parent */ - { + if (pid < 0) rb_sys_fail(pname); + else { NEWOBJ(port, struct RFile); - OBJSETUP(port, cIO, T_FILE); + OBJSETUP(port, rb_cIO, T_FILE); MakeOpenFile(port, fptr); fptr->mode = modef; fptr->mode |= FMODE_SYNC; @@ -1021,16 +1290,22 @@ pipe_open(pname, mode) else fptr->f = f; } #if defined (__CYGWIN32__) + fptr->finalize = pipe_finalize; pipe_add_fptr(fptr); #endif + rb_obj_call_init((VALUE)port); return (VALUE)port; } } #endif +#else /* USE_CWGUSI */ + rb_notimplement(); + return Qnil; /* not reached */ +#endif } static VALUE -io_s_popen(argc, argv, self) +rb_io_s_popen(argc, argv, self) int argc; VALUE *argv; VALUE self; @@ -1038,34 +1313,35 @@ io_s_popen(argc, argv, self) char *mode; VALUE pname, pmode; - rb_scan_args(argc, argv, "11", &pname, &pmode); - Check_SafeStr(pname); - if (NIL_P(pmode)) { + if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) { mode = "r"; } else { - Check_Type(pmode, T_STRING); - if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 3) - ArgError("illegal access mode"); - mode = RSTRING(pmode)->ptr; - } + int len; + + mode = STR2CSTR(pmode); + len = strlen(mode); + if (len == 0 || len > 3) + rb_raise(rb_eArgError, "illegal access mode"); + } + Check_SafeStr(pname); return pipe_open(RSTRING(pname)->ptr, mode); } static VALUE -io_open(fname, mode) +rb_io_open(fname, mode) char *fname, *mode; { if (fname[0] == '|') { return pipe_open(fname+1, mode); } else { - return file_open(fname, mode); + return rb_file_open(fname, mode); } } static VALUE -f_open(argc, argv) +rb_f_open(argc, argv) int argc; VALUE *argv; { @@ -1079,26 +1355,31 @@ f_open(argc, argv) mode = "r"; } else { - Check_Type(pmode, T_STRING); - if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 3) - ArgError("illegal access mode"); - mode = RSTRING(pmode)->ptr; + int len; + + mode = STR2CSTR(pmode); + len = strlen(mode); + if (len == 0 || len > 3) + rb_raise(rb_eArgError, "illegal access mode"); } - port = io_open(RSTRING(pname)->ptr, mode); - if (iterator_p()) { - rb_ensure(rb_yield, port, io_close, port); + port = rb_io_open(RSTRING(pname)->ptr, mode); + if (rb_iterator_p()) { + return rb_ensure(rb_yield, port, rb_io_close, port); } return port; } -#ifndef NT -extern char *strdup(); -#endif +static VALUE +rb_io_get_io(io) + VALUE io; +{ + return rb_convert_type(io, T_FILE, "IO", "to_io"); +} static char* -io_mode_string(fptr) +rb_io_mode_string(fptr) OpenFile *fptr; { switch (fptr->mode & FMODE_READWRITE) { @@ -1110,19 +1391,19 @@ io_mode_string(fptr) case FMODE_READWRITE: return "r+"; } - return "r"; } VALUE -io_reopen(io, nfile) +rb_io_reopen(io, nfile) VALUE io, nfile; { OpenFile *fptr, *orig; char *mode; int fd; + rb_secure(4); GetOpenFile(io, fptr); - Check_Type(nfile, T_FILE); + nfile = rb_io_get_io(nfile); GetOpenFile(nfile, orig); if (orig->f2) { @@ -1141,20 +1422,27 @@ io_reopen(io, nfile) else fptr->path = 0; fptr->finalize = orig->finalize; - mode = io_mode_string(fptr); + mode = rb_io_mode_string(fptr); fd = fileno(fptr->f); - if (fileno(fptr->f) < 3) /* need to keep stdio */ + if (fd < 3) { + /* need to keep stdio */ + if (dup2(fileno(orig->f), fd) < 0) + rb_sys_fail(orig->path); + } + else { fclose(fptr->f); - dup2(fileno(orig->f), fd); - fptr->f = rb_fdopen(fd, mode); + if (dup2(fileno(orig->f), fd) < 0) + rb_sys_fail(orig->path); + fptr->f = rb_fdopen(fd, mode); + } if (fptr->f2) { fd = fileno(fptr->f2); - if (fileno(fptr->f2) < 3) - fclose(fptr->f2); + fclose(fptr->f2); if (orig->f2) { - dup2(fileno(orig->f2), fd); - fptr->f = rb_fdopen(fd, "w"); + if (dup2(fileno(orig->f2), fd) < 0) + rb_sys_fail(orig->path); + fptr->f2 = rb_fdopen(fd, "w"); } else { fptr->f2 = 0; @@ -1162,15 +1450,15 @@ io_reopen(io, nfile) } if (fptr->mode & FMODE_BINMODE) { - io_binmode(io); + rb_io_binmode(io); } - RBASIC(io)->class = RBASIC(nfile)->class; + RBASIC(io)->klass = RBASIC(nfile)->klass; return io; } static VALUE -io_clone(io) +rb_io_clone(io) VALUE io; { OpenFile *fptr, *orig; @@ -1215,25 +1503,25 @@ io_clone(io) fptr->f = rb_fdopen(fd, "w"); } if (fptr->mode & FMODE_BINMODE) { - io_binmode((VALUE)obj); + rb_io_binmode((VALUE)obj); } return (VALUE)obj; } static VALUE -io_printf(argc, argv, out) +rb_io_printf(argc, argv, out) int argc; VALUE argv[]; VALUE out; { - rb_funcall(out, id_write, 1, f_sprintf(argc, argv)); + rb_funcall(out, id_write, 1, rb_f_sprintf(argc, argv)); return Qnil; } static VALUE -f_printf(argc, argv) +rb_rb_f_printf(argc, argv) int argc; VALUE argv[]; { @@ -1249,97 +1537,134 @@ f_printf(argc, argv) argc--; } else { - NameError("output must responds to `write'"); + rb_raise(rb_eNameError, "output must responds to `write'"); } - rb_funcall(out, id_write, 1, f_sprintf(argc, argv)); + rb_funcall(out, id_write, 1, rb_f_sprintf(argc, argv)); return Qnil; } static VALUE -io_print(argc, argv, out) +rb_io_print(argc, argv, out) int argc; VALUE *argv; VALUE out; { - int i, j; + int i; VALUE line; /* if no argument given, print `$_' */ if (argc == 0) { argc = 1; - line = lastline_get(); + line = rb_lastline_get(); argv = &line; } for (i=0; i0) { - io_write(out, OFS); + if (!NIL_P(rb_output_fs) && i>0) { + rb_io_write(out, rb_output_fs); } switch (TYPE(argv[i])) { case T_NIL: - io_write(out, str_new2("nil")); - break; - case T_ARRAY: - for (j=0; jlen; j++) { - if (!NIL_P(OFS) && j>0) { - io_write(out, OFS); - } - io_write(out, RARRAY(argv[i])->ptr[j]); - } + rb_io_write(out, rb_str_new2("nil")); break; default: - io_write(out, argv[i]); + rb_io_write(out, argv[i]); break; } } - if (!NIL_P(ORS)) { - io_write(out, ORS); + if (!NIL_P(rb_output_rs)) { + rb_io_write(out, rb_output_rs); } return Qnil; } static VALUE -f_print(argc, argv) +rb_f_print(argc, argv) int argc; VALUE *argv; { - io_print(argc, argv, rb_defout); + rb_io_print(argc, argv, rb_defout); + return Qnil; +} + +static VALUE +rb_io_putc(io, ch) + VALUE io, ch; +{ + OpenFile *fptr; + FILE *f; + int c = NUM2CHR(ch); + + rb_secure(4); + GetOpenFile(io, fptr); + rb_io_check_writable(fptr); + f = GetWriteFile(fptr); + + if (fputc(c, f) == EOF || ferror(f)) + rb_sys_fail(fptr->path); + if (fptr->mode & FMODE_SYNC) + fflush(f); + + return ch; +} + +static VALUE +rb_f_putc(recv, ch) + VALUE recv, ch; +{ + return rb_io_putc(rb_defout, ch); +} + +static VALUE rb_io_puts _((int, VALUE*, VALUE)); + +static VALUE +io_puts_ary(ary, out) + VALUE ary, out; +{ + VALUE tmp; + int i; + + for (i=0; ilen; i++) { + tmp = RARRAY(ary)->ptr[i]; + if (rb_inspecting_p(tmp)) { + tmp = rb_str_new2("[...]"); + } + rb_io_puts(1, &tmp, out); + } return Qnil; } static VALUE -io_puts(argc, argv, out) +rb_io_puts(argc, argv, out) int argc; VALUE *argv; VALUE out; { - int i, j; + int i; VALUE line; /* if no argument given, print newline. */ if (argc == 0) { - io_write(out, str_new2("\n")); + rb_io_write(out, rb_default_rs); return Qnil; } for (i=0; ilen; j++) { - io_puts(1, &RARRAY(argv[i])->ptr[j], out); - } + rb_protect_inspect(io_puts_ary, argv[i], out); continue; default: line = argv[i]; break; } - line = obj_as_string(line); - io_write(out, line); + line = rb_obj_as_string(line); + rb_io_write(out, line); if (RSTRING(line)->ptr[RSTRING(line)->len-1] != '\n') { - io_write(out, str_new2("\n")); + rb_io_write(out, rb_default_rs); } } @@ -1347,122 +1672,127 @@ io_puts(argc, argv, out) } static VALUE -f_puts(argc, argv) +rb_f_puts(argc, argv) int argc; VALUE *argv; { - io_puts(argc, argv, rb_defout); + rb_io_puts(argc, argv, rb_defout); return Qnil; } +void +rb_p(obj) /* for debug print within C code */ + VALUE obj; +{ + obj = rb_obj_as_string(rb_inspect(obj)); + fwrite(RSTRING(obj)->ptr, 1, RSTRING(obj)->len, stdout); + obj = rb_default_rs; + fwrite(RSTRING(obj)->ptr, 1, RSTRING(obj)->len, stdout); +} + static VALUE -f_p(obj, val) - VALUE obj, val; +rb_f_p(argc, argv) + int argc; + VALUE *argv; { - VALUE str = rb_inspect(val); + int i; - Check_Type(str, T_STRING); - io_write(rb_defout, str); - io_write(rb_defout, str_new2("\n")); + for (i=0; iptr, "w"); + val = rb_io_open(RSTRING(val)->ptr, "w"); } if (!rb_respond_to(val, id_write)) { - TypeError("$< must have write method, %s given", - rb_class2name(CLASS_OF(val))); + rb_raise(rb_eTypeError, "$< must have write method, %s given", + rb_class2name(CLASS_OF(val))); } rb_defout = val; } static void -io_errset(val, id) +rb_io_stdio_set(val, id, var) VALUE val; ID id; + VALUE *var; { OpenFile *fptr; int fd; if (TYPE(val) != T_FILE) { - TypeError("$stderr must be IO Object"); + rb_raise(rb_eTypeError, "%s must be IO object", rb_id2name(id)); } + GetOpenFile(*var, fptr); + fd = fileno(fptr->f); GetOpenFile(val, fptr); - io_writable(fptr); - rb_stderr = val; - - fd = fileno(fptr->f2?fptr->f2:fptr->f); - if (fd != 2) { - FILE *f; - - fflush(stderr); - dup2(fd, 2); - f = rb_fdopen(2, io_mode_string(fptr)); - if (fptr->f2) { - if (fileno(fptr->f2) < 3) /* need to keep stdio */ - fclose(fptr->f2); - fptr->f2 = f; - } - else { - if (fileno(fptr->f) < 3) - fclose(fptr->f); - fptr->f = f; - } + if (fd == 0) { + rb_io_check_readable(fptr); } + else { + rb_io_check_writable(fptr); + } + rb_io_reopen(*var, val); } static VALUE -prep_stdio(f, mode) +prep_stdio(f, mode, klass) FILE *f; int mode; + VALUE klass; { OpenFile *fp; - NEWOBJ(obj, struct RFile); - OBJSETUP(obj, cIO, T_FILE); + NEWOBJ(io, struct RFile); + OBJSETUP(io, klass, T_FILE); - MakeOpenFile(obj, fp); + MakeOpenFile(io, fp); fp->f = f; fp->mode = mode; + rb_obj_call_init((VALUE)io); - return (VALUE)obj; + return (VALUE)io; } static VALUE -io_s_new(argc, argv) +rb_io_s_new(argc, argv, klass) int argc; VALUE *argv; + VALUE klass; { VALUE fnum, mode; - FILE *f; char *m = "r"; - rb_scan_args(argc, argv, "11", &fnum, &mode); - - if (!NIL_P(mode)) { + if (rb_scan_args(argc, argv, "11", &fnum, &mode) == 2) { Check_SafeStr(mode); m = RSTRING(mode)->ptr; } - f = rb_fdopen(NUM2INT(fnum), m); - return prep_stdio(f, io_mode_flags(m)); + return prep_stdio(rb_fdopen(NUM2INT(fnum), m), rb_io_mode_flags(m), klass); } -static VALUE filename, file; -static int gets_lineno; -static int init_p = 0, next_p = 0; - static int next_argv() { @@ -1485,32 +1815,33 @@ next_argv() if (next_p == 1) { next_p = 0; if (RARRAY(rb_argv)->len > 0) { - filename = ary_shift(rb_argv); + filename = rb_ary_shift(rb_argv); fn = RSTRING(filename)->ptr; if (RSTRING(filename)->len == 1 && fn[0] == '-') { file = rb_stdin; - if (inplace) { + if (ruby_inplace_mode) { rb_defout = rb_stdout; } } else { FILE *fr = rb_fopen(fn, "r"); - if (inplace) { + if (ruby_inplace_mode) { struct stat st, st2; VALUE str; FILE *fw; if (TYPE(rb_defout) == T_FILE && rb_defout != rb_stdout) { - io_close(rb_defout); + rb_io_close(rb_defout); } fstat(fileno(fr), &st); - if (*inplace) { - str = str_new2(fn); + if (*ruby_inplace_mode) { + str = rb_str_new2(fn); #if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT) - add_suffix(str, inplace); + ruby_add_suffix(str, ruby_inplace_mode); #else - str_cat(str, inplace, strlen(inplace)); + rb_str_cat(str, ruby_inplace_mode, + strlen(ruby_inplace_mode)); #endif #if defined(MSDOS) || defined(__BOW__) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__) (void)fclose(fr); @@ -1519,7 +1850,7 @@ next_argv() fr = rb_fopen(RSTRING(str)->ptr, "r"); #else if (rename(fn, RSTRING(str)->ptr) < 0) { - Warning("Can't rename %s to %s: %s, skipping file", + rb_warn("Can't rename %s to %s: %s, skipping file", fn, RSTRING(str)->ptr, strerror(errno)); fclose(fr); goto retry; @@ -1529,38 +1860,39 @@ next_argv() else { #if !defined(MSDOS) && !defined(__BOW__) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__) if (unlink(fn) < 0) { - Warning("Can't remove %s: %s, skipping file", - fn, strerror(errno)); + rb_warn("Can't remove %s: %s, skipping file", + fn, strerror(errno)); fclose(fr); goto retry; } #else - Fatal("Can't do inplace edit without backup"); + rb_fatal("Can't do inplace edit without backup"); #endif } fw = rb_fopen(fn, "w"); -#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__) +#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__)\ + && !defined(USE_CWGUSI) && !defined(__BEOS__) fstat(fileno(fw), &st2); fchmod(fileno(fw), st.st_mode); if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) { fchown(fileno(fw), st.st_uid, st.st_gid); } #endif - rb_defout = prep_stdio(fw, FMODE_WRITABLE); + rb_defout = prep_stdio(fw, FMODE_WRITABLE, rb_cFile); } - file = prep_stdio(fr, FMODE_READABLE); + file = prep_stdio(fr, FMODE_READABLE, rb_cFile); } } else { init_p = 0; - return FALSE; + return Qfalse; } } - return TRUE; + return Qtrue; } static VALUE -f_gets_method(argc, argv) +rb_f_gets_internal(argc, argv) int argc; VALUE *argv; { @@ -1568,9 +1900,9 @@ f_gets_method(argc, argv) retry: if (!next_argv()) return Qnil; - line = io_gets_method(argc, argv, file); + line = rb_io_gets_internal(argc, argv, file); if (NIL_P(line) && next_p != -1) { - io_close(file); + rb_io_close(file); next_p = 1; goto retry; } @@ -1580,76 +1912,133 @@ f_gets_method(argc, argv) return line; } +static VALUE +rb_f_gets(argc, argv) + int argc; + VALUE *argv; +{ + VALUE line = rb_f_gets_internal(argc, argv); + + if (!NIL_P(line)) rb_lastline_set(line); + return line; +} + VALUE -f_gets() +rb_gets() { - return f_gets_method(0,0); + VALUE line; + + retry: + if (!next_argv()) return Qnil; + line = rb_io_gets(file); + if (NIL_P(line) && next_p != -1) { + rb_io_close(file); + next_p = 1; + goto retry; + } + if (!NIL_P(line)) { + rb_lastline_set(line); + gets_lineno++; + lineno = INT2FIX(gets_lineno); + } + + return line; } static VALUE -f_readline(argc, argv) +rb_f_readline(argc, argv) int argc; - VALUE argv; + VALUE *argv; { - VALUE line = f_gets_method(argc, argv); + VALUE line = rb_f_gets(argc, argv); if (NIL_P(line)) { - eof_error(); + rb_eof_error(); } return line; } static VALUE -f_eof() +rb_f_tell() +{ + return rb_io_tell(file); +} + +static VALUE +rb_f_seek(self, offset, ptrname) + VALUE self, offset, ptrname; +{ + if (!next_argv()) { + rb_raise(rb_eArgError, "no stream to seek"); + } + + return rb_io_seek(file, offset, ptrname); +} + +static VALUE +rb_f_set_pos(self, offset) + VALUE self, offset; +{ + if (!next_argv()) { + rb_raise(rb_eArgError, "no stream to pos"); + } + + return rb_io_set_pos(file, offset); +} + +static VALUE +rb_f_rewind() +{ + return rb_io_rewind(file); +} + +static VALUE +rb_f_eof() { if (init_p == 0 && !next_argv()) - return TRUE; - if (io_eof(file)) { + return Qtrue; + if (rb_io_eof(file)) { next_p = 1; - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } static VALUE -f_getc() +rb_f_getc() { - return io_getc(rb_stdin); + return rb_io_getc(rb_stdin); } static VALUE -f_ungetc(obj, c) - VALUE obj, c; +rb_f_ungetc(self, c) + VALUE self, c; { - if (!next_argv()) { - ArgError("no stream to ungetc"); - } - - return io_ungetc(file, c); + return rb_io_ungetc(rb_stdin, c); } static VALUE -f_readchar() +rb_f_readchar() { - VALUE c = f_getc(); + VALUE c = rb_f_getc(); if (NIL_P(c)) { - eof_error(); + rb_eof_error(); } return c; } static VALUE -f_readlines(argc, argv) +rb_f_readlines(argc, argv) int argc; - VALUE argv; + VALUE *argv; { VALUE line, ary; - ary = ary_new(); - while (!NIL_P(line = f_gets_method(argc, argv))) { - ary_push(ary, line); + ary = rb_ary_new(); + while (!NIL_P(line = rb_f_gets_internal(argc, argv))) { + rb_ary_push(ary, line); } return ary; @@ -1662,13 +2051,13 @@ rb_str_setter(val, id, var) VALUE *var; { if (!NIL_P(val) && TYPE(val) != T_STRING) { - TypeError("value of %s must be String", rb_id2name(id)); + rb_raise(rb_eTypeError, "value of %s must be String", rb_id2name(id)); } *var = val; } static VALUE -f_backquote(obj, str) +rb_f_backquote(obj, str) VALUE obj, str; { VALUE port, result; @@ -1677,9 +2066,9 @@ f_backquote(obj, str) port = pipe_open(RSTRING(str)->ptr, "r"); result = read_all(port); - io_close(port); + rb_io_close(port); - if (NIL_P(result)) return str_new(0,0); + if (NIL_P(result)) return rb_str_new(0,0); return result; } @@ -1691,7 +2080,7 @@ f_backquote(obj, str) #endif static VALUE -f_select(argc, argv, obj) +rb_f_select(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -1702,7 +2091,7 @@ f_select(argc, argv, obj) struct timeval *tp, timerec; OpenFile *fptr; int i, max = 0, n; - int interrupt = 0; + int interrupt_flag = 0; int pending = 0; rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout); @@ -1710,20 +2099,19 @@ f_select(argc, argv, obj) tp = NULL; } else { - timerec = time_timeval(timeout); + timerec = rb_time_timeval(timeout); tp = &timerec; } FD_ZERO(&pset); if (!NIL_P(read)) { - Check_Type(read, T_ARRAY); rp = &rset; FD_ZERO(rp); for (i=0; ilen; i++) { - Check_Type(RARRAY(read)->ptr[i], T_FILE); - GetOpenFile(RARRAY(read)->ptr[i], fptr); - if (fptr->f == NULL) closed(); + VALUE io = rb_io_get_io(RARRAY(read)->ptr[i]); + + GetOpenFile(io, fptr); FD_SET(fileno(fptr->f), rp); if (READ_DATA_PENDING(fptr->f)) { /* check for buffered data */ pending++; @@ -1744,14 +2132,14 @@ f_select(argc, argv, obj) wp = &wset; FD_ZERO(wp); for (i=0; ilen; i++) { - Check_Type(RARRAY(write)->ptr[i], T_FILE); - GetOpenFile(RARRAY(write)->ptr[i], fptr); - if (fptr->f == NULL) closed(); + VALUE io = rb_io_get_io(RARRAY(write)->ptr[i]); + + GetOpenFile(io, fptr); FD_SET(fileno(fptr->f), wp); - if (max > fileno(fptr->f)) max = fileno(fptr->f); + if (max < fileno(fptr->f)) max = fileno(fptr->f); if (fptr->f2) { FD_SET(fileno(fptr->f2), wp); - if (max < (int)fileno(fptr->f2)) max = fileno(fptr->f2); + if (max < fileno(fptr->f2)) max = fileno(fptr->f2); } } } @@ -1763,14 +2151,14 @@ f_select(argc, argv, obj) ep = &eset; FD_ZERO(ep); for (i=0; ilen; i++) { - Check_Type(RARRAY(except)->ptr[i], T_FILE); - GetOpenFile(RARRAY(except)->ptr[i], fptr); - if (fptr->f == NULL) closed(); + VALUE io = rb_io_get_io(RARRAY(except)->ptr[i]); + + GetOpenFile(io, fptr); FD_SET(fileno(fptr->f), ep); if (max < fileno(fptr->f)) max = fileno(fptr->f); if (fptr->f2) { FD_SET(fileno(fptr->f2), ep); - if (max > (int)fileno(fptr->f2)) max = fileno(fptr->f2); + if (max < fileno(fptr->f2)) max = fileno(fptr->f2); } } } @@ -1779,8 +2167,8 @@ f_select(argc, argv, obj) max++; -#ifdef THREAD - n = thread_select(max, rp, wp, ep, tp); +#ifdef USE_THREAD + n = rb_thread_select(max, rp, wp, ep, tp); if (n < 0) { rb_sys_fail(0); } @@ -1794,24 +2182,24 @@ f_select(argc, argv, obj) rb_sys_fail(0); } if (tp == NULL) goto retry; - interrupt = 1; + interrupt_flag = 1; } #endif if (!pending && n == 0) return Qnil; /* returns nil on timeout */ - res = ary_new2(3); - ary_push(res, rp?ary_new():ary_new2(0)); - ary_push(res, wp?ary_new():ary_new2(0)); - ary_push(res, ep?ary_new():ary_new2(0)); + res = rb_ary_new2(3); + rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0)); + rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0)); + rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0)); - if (interrupt == 0) { + if (interrupt_flag == 0) { if (rp) { list = RARRAY(res)->ptr[0]; for (i=0; i< RARRAY(read)->len; i++) { GetOpenFile(RARRAY(read)->ptr[i], fptr); if (FD_ISSET(fileno(fptr->f), rp) || FD_ISSET(fileno(fptr->f), &pset)) { - ary_push(list, RARRAY(read)->ptr[i]); + rb_ary_push(list, RARRAY(read)->ptr[i]); } } } @@ -1821,10 +2209,10 @@ f_select(argc, argv, obj) for (i=0; i< RARRAY(write)->len; i++) { GetOpenFile(RARRAY(write)->ptr[i], fptr); if (FD_ISSET(fileno(fptr->f), wp)) { - ary_push(list, RARRAY(write)->ptr[i]); + rb_ary_push(list, RARRAY(write)->ptr[i]); } else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), wp)) { - ary_push(list, RARRAY(write)->ptr[i]); + rb_ary_push(list, RARRAY(write)->ptr[i]); } } } @@ -1834,10 +2222,10 @@ f_select(argc, argv, obj) for (i=0; i< RARRAY(except)->len; i++) { GetOpenFile(RARRAY(except)->ptr[i], fptr); if (FD_ISSET(fileno(fptr->f), ep)) { - ary_push(list, RARRAY(except)->ptr[i]); + rb_ary_push(list, RARRAY(except)->ptr[i]); } else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), ep)) { - ary_push(list, RARRAY(except)->ptr[i]); + rb_ary_push(list, RARRAY(except)->ptr[i]); } } } @@ -1847,27 +2235,28 @@ f_select(argc, argv, obj) } static VALUE -io_ctl(io, req, arg, io_p) +rb_io_ctl(io, req, arg, io_p) VALUE io, req, arg; int io_p; { #if !defined(MSDOS) && !defined(__human68k__) int cmd = NUM2INT(req); OpenFile *fptr; - int len, fd; + int len = 0; + int fd; long narg = 0; int retval; rb_secure(2); GetOpenFile(io, fptr); - if (NIL_P(arg) || (VALUE)arg == FALSE) { + if (NIL_P(arg) || arg == Qfalse) { narg = 0; } else if (FIXNUM_P(arg)) { narg = FIX2INT(arg); } - else if ((VALUE)arg == TRUE) { + else if (arg == Qtrue) { narg = 1; } else { @@ -1883,38 +2272,47 @@ io_ctl(io, req, arg, io_p) #else len = 256; /* otherwise guess at what's safe */ #endif - str_modify(arg); + rb_str_modify(arg); if (len <= RSTRING(arg)->len) { len = RSTRING(arg)->len; } if (RSTRING(arg)->len < len) { - str_resize(arg, len+1); + rb_str_resize(arg, len+1); } RSTRING(arg)->ptr[len] = 17; /* a little sanity check here */ narg = (long)RSTRING(arg)->ptr; } fd = fileno(fptr->f); #ifdef HAVE_FCNTL + TRAP_BEG; +# ifdef USE_CWGUSI + retval = io_p?ioctl(fd, cmd, (void*) narg):fcntl(fd, cmd, narg); +# else retval = io_p?ioctl(fd, cmd, narg):fcntl(fd, cmd, narg); +# endif + TRAP_END; #else if (!io_p) { rb_notimplement(); } + TRAP_BEG; retval = ioctl(fd, cmd, narg); + TRAP_END; #endif if (retval < 0) rb_sys_fail(fptr->path); if (TYPE(arg) == T_STRING && RSTRING(arg)->ptr[len] != 17) { - ArgError("return value overflowed string"); + rb_raise(rb_eArgError, "return value overflowed string"); } return INT2NUM(retval); #else rb_notimplement(); + return Qnil; /* not reached */ #endif } static VALUE -io_ioctl(argc, argv, io) +rb_io_ioctl(argc, argv, io) int argc; VALUE *argv; VALUE io; @@ -1922,11 +2320,11 @@ io_ioctl(argc, argv, io) VALUE req, arg; rb_scan_args(argc, argv, "11", &req, &arg); - return io_ctl(io, req, arg, 1); + return rb_io_ctl(io, req, arg, 1); } static VALUE -io_fcntl(argc, argv, io) +rb_io_fcntl(argc, argv, io) int argc; VALUE *argv; VALUE io; @@ -1935,14 +2333,15 @@ io_fcntl(argc, argv, io) VALUE req, arg; rb_scan_args(argc, argv, "11", &req, &arg); - return io_ctl(io, req, arg, 0); + return rb_io_ctl(io, req, arg, 0); #else rb_notimplement(); + return Qnil; /* not reached */ #endif } static VALUE -f_syscall(argc, argv) +rb_f_syscall(argc, argv) int argc; VALUE *argv; { @@ -1962,6 +2361,8 @@ f_syscall(argc, argv) */ rb_secure(2); + if (argc == 0) + rb_raise(rb_eArgError, "too few arguments for syscall"); arg[0] = NUM2INT(argv[0]); argv++; while (items--) { if (FIXNUM_P(*argv)) { @@ -1969,14 +2370,13 @@ f_syscall(argc, argv) } else { Check_Type(*argv, T_STRING); - str_modify(*argv); + rb_str_modify(*argv); arg[i] = (unsigned long)RSTRING(*argv)->ptr; argv++; } i++; } + TRAP_BEG; switch (argc) { - case 0: - ArgError("Too few args to syscall"); case 1: retval = syscall(arg[0]); break; @@ -2029,15 +2429,17 @@ f_syscall(argc, argv) break; #endif /* atarist */ } + TRAP_END; if (retval == -1) rb_sys_fail(0); return INT2FIX(0); #else rb_notimplement(); + return Qnil; /* not reached */ #endif } static VALUE -io_s_pipe() +rb_io_s_pipe() { #ifndef __human68k__ int pipes[2]; @@ -2050,16 +2452,17 @@ io_s_pipe() #endif rb_sys_fail(0); - r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE); - w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE); + r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE, rb_cIO); + w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE, rb_cIO); - ary = ary_new2(2); - ary_push(ary, r); - ary_push(ary, w); + ary = rb_ary_new2(2); + rb_ary_push(ary, r); + rb_ary_push(ary, w); return ary; #else rb_notimplement(); + return Qnil; /* not reached */ #endif } @@ -2070,19 +2473,19 @@ struct foreach_arg { }; static VALUE -io_foreach_line(arg) +rb_io_foreach_line(arg) struct foreach_arg *arg; { VALUE str; - while (!NIL_P(str = io_gets_method(arg->argc, &arg->sep, arg->io))) { + while (!NIL_P(str = rb_io_gets_internal(arg->argc, &arg->sep, arg->io))) { rb_yield(str); } return Qnil; } static VALUE -io_s_foreach(argc, argv, io) +rb_io_s_foreach(argc, argv, io) int argc; VALUE *argv; VALUE io; @@ -2094,26 +2497,26 @@ io_s_foreach(argc, argv, io) Check_SafeStr(fname); arg.argc = argc - 1; - arg.io = io_open(RSTRING(fname)->ptr, "r"); - return rb_ensure(io_foreach_line, &arg, io_close, arg.io); + arg.io = rb_io_open(RSTRING(fname)->ptr, "r"); + return rb_ensure(rb_io_foreach_line, (VALUE)&arg, rb_io_close, arg.io); } static VALUE -io_readline_line(arg) +rb_io_readline_line(arg) struct foreach_arg *arg; { VALUE line, ary; - ary = ary_new(); - while (!NIL_P(line = io_gets_method(arg->argc, &arg->sep, arg->io))) { - ary_push(ary, line); + ary = rb_ary_new(); + while (!NIL_P(line = rb_io_gets_internal(arg->argc, &arg->sep, arg->io))) { + rb_ary_push(ary, line); } return ary; } static VALUE -io_s_readlines(argc, argv, io) +rb_io_s_readlines(argc, argv, io) int argc; VALUE *argv; VALUE io; @@ -2125,14 +2528,20 @@ io_s_readlines(argc, argv, io) Check_SafeStr(fname); arg.argc = argc - 1; - arg.io = io_open(RSTRING(fname)->ptr, "r"); - return rb_ensure(io_readline_line, &arg, io_close, arg.io); + arg.io = rb_io_open(RSTRING(fname)->ptr, "r"); + return rb_ensure(rb_io_readline_line, (VALUE)&arg, rb_io_close, arg.io); } static VALUE arg_fileno() { - return io_fileno(file); + return rb_io_fileno(file); +} + +static VALUE +arg_to_io() +{ + return file; } static VALUE @@ -2141,22 +2550,22 @@ arg_read(argc, argv) VALUE *argv; { VALUE tmp, str; - int len; + size_t len; if (argc == 1) len = NUM2INT(argv[0]); str = Qnil; retry: if (!next_argv()) return str; - tmp = io_read(argc, argv, file); + tmp = rb_io_read(argc, argv, file); if (NIL_P(tmp) && next_p != -1) { - io_close(file); + rb_io_close(file); next_p = 1; goto retry; } - if (NIL_P(tmp)) return str; + if (NIL_P(tmp) || RSTRING(tmp)->len == 0) return str; else if (NIL_P(str)) str = tmp; - else str_cat(str, RSTRING(tmp)->ptr, RSTRING(tmp)->len); + else rb_str_cat(str, RSTRING(tmp)->ptr, RSTRING(tmp)->len); if (argc == 0) { goto retry; } @@ -2176,9 +2585,9 @@ arg_getc() retry: if (!next_argv()) return Qnil; - byte = io_getc(file); + byte = rb_io_getc(file); if (NIL_P(byte) && next_p != -1) { - io_close(file); + rb_io_close(file); next_p = 1; goto retry; } @@ -2189,10 +2598,10 @@ arg_getc() static VALUE arg_readchar() { - VALUE c = io_getc(file); + VALUE c = rb_io_getc(file); if (NIL_P(c)) { - eof_error(); + rb_eof_error(); } return c; } @@ -2200,11 +2609,11 @@ arg_readchar() static VALUE arg_each_line(argc, argv) int argc; - VALUE argv; + VALUE *argv; { VALUE str; - while (RTEST(str = f_gets_method(argc, argv))) { + while (RTEST(str = rb_f_gets_internal(argc, argv))) { rb_yield(str); } return Qnil; @@ -2237,7 +2646,7 @@ static VALUE arg_skip() { if (next_p != -1) { - io_close(file); + rb_io_close(file); next_p = 1; } return argf; @@ -2246,7 +2655,7 @@ arg_skip() static VALUE arg_close() { - io_close(file); + rb_io_close(file); if (next_p != -1) { next_p = 1; } @@ -2257,162 +2666,186 @@ arg_close() static VALUE arg_closed() { - return io_closed(file); + return rb_io_closed(file); } static VALUE opt_i_get() { - if (!inplace) return Qnil; - return str_new2(inplace); + if (!ruby_inplace_mode) return Qnil; + return rb_str_new2(ruby_inplace_mode); } static void opt_i_set(val) VALUE val; { - if (NIL_P(val)) { - inplace = 0; + if (!RTEST(val)) { + ruby_inplace_mode = 0; return; } - Check_Type(val, T_STRING); - inplace = RSTRING(val)->ptr; + ruby_inplace_mode = STR2CSTR(val); } void Init_IO() { - extern VALUE mEnumerable; - extern VALUE eException; - - eEOFError = rb_define_class("EOFError", eException); + rb_eIOError = rb_define_class("IOError", rb_eStandardError); + rb_eEOFError = rb_define_class("EOFError", rb_eIOError); id_write = rb_intern("write"); - rb_define_global_function("syscall", f_syscall, -1); - - rb_define_global_function("open", f_open, -1); - rb_define_global_function("printf", f_printf, -1); - rb_define_global_function("print", f_print, -1); - rb_define_global_function("puts", f_puts, -1); - rb_define_global_function("gets", f_gets_method, -1); - rb_define_global_function("readline", f_readline, -1); - rb_define_global_function("eof", f_eof, 0); - rb_define_global_function("eof?", f_eof, 0); - rb_define_global_function("getc", f_getc, 0); - rb_define_global_function("readchar", f_readchar, 0); - rb_define_global_function("select", f_select, -1); - rb_define_global_function("ungetc", f_ungetc, 1); - - rb_define_global_function("readlines", f_readlines, -1); - - rb_define_global_function("`", f_backquote, 1); - rb_define_global_function("pipe", io_s_pipe, 0); - - rb_define_global_function("p", f_p, 1); - - cIO = rb_define_class("IO", cObject); - rb_include_module(cIO, mEnumerable); - - rb_define_singleton_method(cIO, "new", io_s_new, -1); - rb_define_singleton_method(cIO, "popen", io_s_popen, -1); - rb_define_singleton_method(cIO, "foreach", io_s_foreach, -1); - rb_define_singleton_method(cIO, "readlines", io_s_readlines, -1); - rb_define_singleton_method(cIO, "select", f_select, -1); - - FS = OFS = Qnil; - rb_define_hooked_variable("$;", &FS, 0, rb_str_setter); - rb_define_hooked_variable("$-F", &FS, 0, rb_str_setter); - rb_define_hooked_variable("$,", &OFS, 0, rb_str_setter); - - RS = RS_default = str_new2("\n"); ORS = Qnil; - rb_global_variable(&RS_default); - rb_define_hooked_variable("$/", &RS, 0, rb_str_setter); - rb_define_hooked_variable("$-0", &RS, 0, rb_str_setter); - rb_define_hooked_variable("$\\", &ORS, 0, rb_str_setter); - - rb_define_variable("$.", &lineno); - rb_define_virtual_variable("$_", lastline_get, lastline_set); - - rb_define_method(cIO, "clone", io_clone, 0); - rb_define_method(cIO, "reopen", io_reopen, 1); - - rb_define_method(cIO, "print", io_print, -1); - rb_define_method(cIO, "puts", io_puts, -1); - rb_define_method(cIO, "printf", io_printf, -1); - - rb_define_method(cIO, "each", io_each_line, -1); - rb_define_method(cIO, "each_line", io_each_line, -1); - rb_define_method(cIO, "each_byte", io_each_byte, 0); - - rb_define_method(cIO, "syswrite", io_syswrite, 1); - rb_define_method(cIO, "sysread", io_sysread, 1); - - rb_define_method(cIO, "fileno", io_fileno, 0); - rb_define_alias(cIO, "to_i", "fileno"); - - rb_define_method(cIO, "sync", io_sync, 0); - rb_define_method(cIO, "sync=", io_set_sync, 1); - - rb_define_method(cIO, "readlines", io_readlines, -1); - - rb_define_method(cIO, "read", io_read, -1); - rb_define_method(cIO, "write", io_write, 1); - rb_define_method(cIO, "gets", io_gets_method, -1); - rb_define_method(cIO, "readline", io_readline, -1); - rb_define_method(cIO, "getc", io_getc, 0); - rb_define_method(cIO, "readchar", io_readchar, 0); - rb_define_method(cIO, "ungetc",io_ungetc, 1); - rb_define_method(cIO, "<<", io_addstr, 1); - rb_define_method(cIO, "flush", io_flush, 0); - rb_define_method(cIO, "eof", io_eof, 0); - rb_define_method(cIO, "eof?", io_eof, 0); - - rb_define_method(cIO, "close", io_close, 0); - rb_define_method(cIO, "closed?", io_closed, 0); - - rb_define_method(cIO, "isatty", io_isatty, 0); - rb_define_method(cIO, "tty?", io_isatty, 0); - rb_define_method(cIO, "binmode", io_binmode, 0); - - rb_define_method(cIO, "ioctl", io_ioctl, -1); - rb_define_method(cIO, "fcntl", io_fcntl, -1); - - rb_stdin = prep_stdio(stdin, FMODE_READABLE); - rb_define_readonly_variable("$stdin", &rb_stdin); - rb_stdout = prep_stdio(stdout, FMODE_WRITABLE); - rb_define_readonly_variable("$stdout", &rb_stdout); - rb_stderr = prep_stdio(stderr, FMODE_WRITABLE); - rb_define_hooked_variable("$stderr", &rb_stderr, 0, io_errset); + rb_define_global_function("syscall", rb_f_syscall, -1); + + rb_define_global_function("open", rb_f_open, -1); + rb_define_global_function("printf", rb_rb_f_printf, -1); + rb_define_global_function("print", rb_f_print, -1); + rb_define_global_function("putc", rb_f_putc, 1); + rb_define_global_function("puts", rb_f_puts, -1); + rb_define_global_function("gets", rb_f_gets, -1); + rb_define_global_function("readline", rb_f_readline, -1); + rb_define_global_function("tell", rb_f_tell, 0); + rb_define_global_function("seek", rb_f_seek, 2); + rb_define_global_function("rewind", rb_f_rewind, 0); + rb_define_global_function("eof", rb_f_eof, 0); + rb_define_global_function("eof?", rb_f_eof, 0); + rb_define_global_function("getc", rb_f_getc, 0); + rb_define_global_function("readchar", rb_f_readchar, 0); + rb_define_global_function("select", rb_f_select, -1); + rb_define_global_function("ungetc", rb_f_ungetc, 1); + + rb_define_global_function("readlines", rb_f_readlines, -1); + + rb_define_global_function("`", rb_f_backquote, 1); + rb_define_global_function("pipe", rb_io_s_pipe, 0); + + rb_define_global_function("p", rb_f_p, -1); + rb_define_method(rb_mKernel, "display", rb_obj_display, -1); + + rb_cIO = rb_define_class("IO", rb_cObject); + rb_include_module(rb_cIO, rb_mEnumerable); + + rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1); + rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1); + rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1); + rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1); + rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1); + + rb_fs = rb_output_fs = Qnil; + rb_define_hooked_variable("$;", &rb_fs, 0, rb_str_setter); + rb_define_hooked_variable("$-F", &rb_fs, 0, rb_str_setter); + rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter); + + rb_rs = rb_default_rs = rb_str_new2("\n"); rb_output_rs = Qnil; + rb_global_variable(&rb_default_rs); + rb_str_freeze(rb_default_rs); /* avoid modifying RS_default */ + rb_define_hooked_variable("$/", &rb_rs, 0, rb_str_setter); + rb_define_hooked_variable("$-0", &rb_rs, 0, rb_str_setter); + rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_str_setter); + + rb_define_hooked_variable("$.", &lineno, 0, lineno_setter); + rb_define_virtual_variable("$_", rb_lastline_get, rb_lastline_set); + + rb_define_method(rb_cIO, "clone", rb_io_clone, 0); + rb_define_method(rb_cIO, "reopen", rb_io_reopen, 1); + + rb_define_method(rb_cIO, "print", rb_io_print, -1); + rb_define_method(rb_cIO, "putc", rb_io_putc, 1); + rb_define_method(rb_cIO, "puts", rb_io_puts, -1); + rb_define_method(rb_cIO, "printf", rb_io_printf, -1); + + rb_define_method(rb_cIO, "each", rb_io_each_line, -1); + rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1); + rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0); + + rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1); + rb_define_method(rb_cIO, "sysread", rb_io_sysread, 1); + + rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0); + rb_define_alias(rb_cIO, "to_i", "fileno"); + rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0); + + rb_define_method(rb_cIO, "sync", rb_io_sync, 0); + rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1); + + rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0); + rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1); + + rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1); + + rb_define_method(rb_cIO, "read", rb_io_read, -1); + rb_define_method(rb_cIO, "write", rb_io_write, 1); + rb_define_method(rb_cIO, "gets", rb_io_gets_method, -1); + rb_define_method(rb_cIO, "readline", rb_io_readline, -1); + rb_define_method(rb_cIO, "getc", rb_io_getc, 0); + rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0); + rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1); + rb_define_method(rb_cIO, "<<", rb_io_addstr, 1); + rb_define_method(rb_cIO, "flush", rb_io_flush, 0); + rb_define_method(rb_cIO, "tell", rb_io_tell, 0); + rb_define_method(rb_cIO, "seek", rb_io_seek, 2); + rb_define_const(rb_cIO, "SEEK_SET", SEEK_SET); + rb_define_const(rb_cIO, "SEEK_CUR", SEEK_CUR); + rb_define_const(rb_cIO, "SEEK_END", SEEK_END); + rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0); + rb_define_method(rb_cIO, "pos", rb_io_tell, 0); + rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1); + rb_define_method(rb_cIO, "eof", rb_io_eof, 0); + rb_define_method(rb_cIO, "eof?", rb_io_eof, 0); + + rb_define_method(rb_cIO, "close", rb_io_close_method, 0); + rb_define_method(rb_cIO, "closed?", rb_io_closed, 0); + rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0); + rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0); + + rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0); + rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0); + rb_define_method(rb_cIO, "binmode", rb_io_binmode, 0); + + rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1); + rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1); + + rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO); + rb_define_hooked_variable("$stdin", &rb_stdin, 0, rb_io_stdio_set); + rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO); + rb_define_hooked_variable("$stdout", &rb_stdout, 0, rb_io_stdio_set); + rb_stderr = prep_stdio(stderr, FMODE_WRITABLE, rb_cIO); + rb_define_hooked_variable("$stderr", &rb_stderr, 0, rb_io_stdio_set); rb_defout = rb_stdout; - rb_define_hooked_variable("$>", &rb_defout, 0, io_defset); + rb_define_hooked_variable("$>", &rb_defout, 0, rb_io_defset); rb_define_global_const("STDIN", rb_stdin); rb_define_global_const("STDOUT", rb_stdout); rb_define_global_const("STDERR", rb_stderr); - argf = obj_alloc(cObject); - rb_extend_object(argf, mEnumerable); + argf = rb_obj_alloc(rb_cObject); + rb_extend_object(argf, rb_mEnumerable); rb_define_readonly_variable("$<", &argf); rb_define_global_const("ARGF", argf); rb_define_singleton_method(argf, "fileno", arg_fileno, 0); rb_define_singleton_method(argf, "to_i", arg_fileno, 0); + rb_define_singleton_method(argf, "to_io", arg_to_io, 0); rb_define_singleton_method(argf, "each", arg_each_line, -1); rb_define_singleton_method(argf, "each_line", arg_each_line, -1); rb_define_singleton_method(argf, "each_byte", arg_each_byte, 0); rb_define_singleton_method(argf, "read", arg_read, -1); - rb_define_singleton_method(argf, "readlines", f_readlines, -1); - rb_define_singleton_method(argf, "to_a", f_readlines, -1); - rb_define_singleton_method(argf, "gets", f_gets_method, -1); - rb_define_singleton_method(argf, "readline", f_readline, -1); + rb_define_singleton_method(argf, "readlines", rb_f_readlines, -1); + rb_define_singleton_method(argf, "to_a", rb_f_readlines, -1); + rb_define_singleton_method(argf, "gets", rb_f_gets, -1); + rb_define_singleton_method(argf, "readline", rb_f_readline, -1); rb_define_singleton_method(argf, "getc", arg_getc, 0); rb_define_singleton_method(argf, "readchar", arg_readchar, 0); - rb_define_singleton_method(argf, "eof", f_eof, 0); - rb_define_singleton_method(argf, "eof?", f_eof, 0); - rb_define_singleton_method(argf, "ungetc", f_ungetc, 1); + rb_define_singleton_method(argf, "tell", rb_f_tell, 0); + rb_define_singleton_method(argf, "seek", rb_f_seek, 2); + rb_define_singleton_method(argf, "rewind", rb_f_rewind, 0); + rb_define_singleton_method(argf, "pos", rb_f_tell, 0); + rb_define_singleton_method(argf, "pos=", rb_f_set_pos, 1); + rb_define_singleton_method(argf, "eof", rb_f_eof, 0); + rb_define_singleton_method(argf, "eof?", rb_f_eof, 0); + rb_define_singleton_method(argf, "ungetc", rb_f_ungetc, 1); rb_define_singleton_method(argf, "to_s", arg_filename, 0); rb_define_singleton_method(argf, "filename", arg_filename, 0); @@ -2421,15 +2854,16 @@ Init_IO() rb_define_singleton_method(argf, "close", arg_close, 0); rb_define_singleton_method(argf, "closed?", arg_closed, 0); - filename = str_new2("-"); + filename = rb_str_new2("-"); rb_define_readonly_variable("$FILENAME", &filename); file = rb_stdin; rb_global_variable(&file); rb_define_virtual_variable("$-i", opt_i_get, opt_i_set); - Init_File(); #if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__) atexit(pipe_atexit); #endif + + Init_File(); } diff --git a/keywords b/keywords index 9e3870d1a6..1772de42b0 100644 --- a/keywords +++ b/keywords @@ -1,5 +1,7 @@ struct kwtable {char *name; int id[2]; enum lex_state state;}; %% +__LINE__, k__LINE__, k__LINE__, EXPR_END +__FILE__, k__FILE__, k__FILE__, EXPR_END BEGIN, klBEGIN, klBEGIN, EXPR_END END, klEND, klEND, EXPR_END alias, kALIAS, kALIAS, EXPR_FNAME diff --git a/lex.c b/lex.c index 390471c424..1abc048638 100644 --- a/lex.c +++ b/lex.c @@ -2,12 +2,12 @@ /* Command-line: gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$ keywords */ struct kwtable {char *name; int id[2]; enum lex_state state;}; -#define TOTAL_KEYWORDS 38 +#define TOTAL_KEYWORDS 40 #define MIN_WORD_LENGTH 2 #define MAX_WORD_LENGTH 8 #define MIN_HASH_VALUE 6 -#define MAX_HASH_VALUE 52 -/* maximum key range = 47, duplicates = 0 */ +#define MAX_HASH_VALUE 55 +/* maximum key range = 50, duplicates = 0 */ #ifdef __GNUC__ inline @@ -19,19 +19,19 @@ hash (str, len) { static unsigned char asso_values[] = { - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 11, 53, 53, 34, 53, 1, 35, - 53, 1, 53, 53, 53, 53, 53, 53, 1, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 29, 1, 2, - 1, 1, 4, 24, 53, 17, 53, 20, 9, 2, - 9, 26, 14, 53, 5, 1, 1, 16, 53, 21, - 24, 9, 53, 53, 53, 53, 53, 53, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 11, 56, 56, 36, 56, 1, 37, + 31, 1, 56, 56, 56, 56, 29, 56, 1, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 1, 56, 32, 1, 2, + 1, 1, 4, 23, 56, 17, 56, 20, 9, 2, + 9, 26, 14, 56, 5, 1, 1, 16, 56, 21, + 20, 9, 56, 56, 56, 56, 56, 56, }; register int hval = len; @@ -87,17 +87,19 @@ rb_reserved_word (str, len) {"until", kUNTIL, kUNTIL_MOD, EXPR_BEG}, {"unless", kUNLESS, kUNLESS_MOD, EXPR_BEG}, {"or", kOR, kOR, EXPR_BEG}, - {"and", kAND, kAND, EXPR_BEG}, + {"next", kNEXT, kNEXT, EXPR_END}, {"when", kWHEN, kWHEN, EXPR_BEG}, {"redo", kREDO, kREDO, EXPR_END}, - {"class", kCLASS, kCLASS, EXPR_CLASS}, - {"next", kNEXT, kNEXT, EXPR_END}, + {"and", kAND, kAND, EXPR_BEG}, {"begin", kBEGIN, kBEGIN, EXPR_BEG}, + {"__LINE__", k__LINE__, k__LINE__, EXPR_END}, + {"class", kCLASS, kCLASS, EXPR_CLASS}, + {"__FILE__", k__FILE__, k__FILE__, EXPR_END}, {"END", klEND, klEND, EXPR_END}, {"BEGIN", klBEGIN, klBEGIN, EXPR_END}, - {"",}, {"",}, {"while", kWHILE, kWHILE_MOD, EXPR_BEG}, - {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"alias", kALIAS, kALIAS, EXPR_FNAME}, }; diff --git a/lib/base64.rb b/lib/base64.rb index 96208a634d..d7461d82e7 100644 --- a/lib/base64.rb +++ b/lib/base64.rb @@ -1,50 +1,25 @@ -def decode64(str) - string = '' - for line in str.split("\n") - line.delete!('^A-Za-z0-9+/') # remove non-base64 chars - line.tr!('A-Za-z0-9+/', ' -_') # convert to uuencoded format - len = ["#{32 + line.length * 3 / 4}"].pack("c") - # compute length byte - string += "#{len}#{line}".unpack("u") # uudecode and concatenate - end - return string -end +require "kconv" -def j2e(str) - while str =~ /\033\$B([^\033]*)\033\(B/ - s = $1 - pre, post = $`, $' - s.gsub!(/./) { |ch| - (ch[0]|0x80).chr - } - str = pre + s + post - end -# str.gsub!(/\033\$B([^\033]*)\033\(B/) { -# $1.gsub!(/./) { |ch| -# (ch[0]|0x80).chr -# } -# } - str +def decode64(str) + str.unpack("m")[0] end def decode_b(str) str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) { decode64($1) } + str = Kconv::toeuc(str) + str.gsub!(/=\?SHIFT_JIS\?B\?([!->@-~]+)\?=/i) { + decode64($1) + } + str = Kconv::toeuc(str) str.gsub!(/\n/, ' ') str.gsub!(/\0/, '') - j2e(str) + str end def encode64(bin) - encode = "" - pad = 0 - [bin].pack("u").each do |uu| - len = (2 + (uu[0] - 32)* 4) / 3 - encode << uu[1, len].tr('` -_', 'AA-Za-z0-9+/') - pad += uu.length - 2 - len - end - encode + "=" * (pad % 3) + [bin].pack("m") end def b64encode(bin, len = 60) diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb index 5234e046cc..7033f0f8c1 100644 --- a/lib/cgi-lib.rb +++ b/lib/cgi-lib.rb @@ -1,4 +1,3 @@ -#!/usr/local/bin/ruby # # Get CGI String # @@ -7,26 +6,26 @@ # foo = CGI.new # foo['field'] <== value of 'field' # foo.keys <== array of fields -# foo.inputs <== hash of { => } +# and foo has Hash class methods # if running on Windows(IIS or PWS) then change cwd. if ENV['SERVER_SOFTWARE'] =~ /^Microsoft-/ then Dir.chdir ENV['PATH_TRANSLATED'].sub(/[^\\]+$/, '') end -require "shellwords.rb" +require "delegate" -class CGI - include Shellwords +class CGI < SimpleDelegator attr("inputs") # original is CGI.pm def read_from_cmdline - words = shellwords(if not ARGV.empty? then + require "shellwords.rb" + words = Shellwords.shellwords(if not ARGV.empty? then ARGV.join(' ') else - print "(offline mode: enter name=value pairs on standard input)\n" + STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty? readlines.join(' ').gsub(/\n/, '') end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26')) @@ -47,32 +46,32 @@ class CGI end module_function :escape, :unescape - def initialize - # exception messages should be printed to stdout. - STDERR.reopen(STDOUT) + def initialize(input = $stdin) @inputs = {} case ENV['REQUEST_METHOD'] when "GET" + # exception messages should be printed to stdout. + STDERR.reopen(STDOUT) ENV['QUERY_STRING'] or "" when "POST" - $stdin.read ENV['CONTENT_LENGTH'].to_i + # exception messages should be printed to stdout. + STDERR.reopen(STDOUT) + input.read Integer(ENV['CONTENT_LENGTH']) else read_from_cmdline end.split(/&/).each do |x| key, val = x.split(/=/,2).collect{|x|unescape(x)} - @inputs[key] += ("\0" if @inputs[key]) + (val or "") + if @inputs.include?(key) + @inputs[key] += "\0" + (val or "") + else + @inputs[key] = (val or "") + end end - end - def keys - @inputs.keys + super(@inputs) end - def [](key) - @inputs[key] - end - def CGI.message(msg, title = "") print "Content-type: text/html\n\n" print "" @@ -84,7 +83,7 @@ class CGI end def CGI.error - m = $!.dup + m = $!.to_s.dup m.gsub!(/&/, '&') m.gsub!(/</, '<') m.gsub!(/>/, '>') diff --git a/lib/complex.rb b/lib/complex.rb index aa5d219d2f..59caad6ebc 100644 --- a/lib/complex.rb +++ b/lib/complex.rb @@ -1,8 +1,8 @@ # # complex.rb - # $Release Version: 0.5 $ -# $Revision: 1.1 $ -# $Date: 1996/11/11 04:25:19 $ +# $Revision: 1.3 $ +# $Date: 1998/07/08 10:05:28 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # -- @@ -59,6 +59,7 @@ def Complex(a, b = 0) end class Complex < Numeric + @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-' def Complex.generic?(other) other.kind_of?(Integer) or @@ -284,6 +285,11 @@ class Complex < Numeric @real ^ @image end + def inspect + sprintf("Complex(%s, %s)", @real.inspect, @image.inspect) + end + + I = Complex(0,1) attr :real @@ -396,7 +402,7 @@ module Math cos!(z) else Complex(cos!(z.real)*cosh!(z.image), - sin!(z.real)*sinh!(z.image)) + -sin!(z.real)*sinh!(z.image)) end end @@ -405,7 +411,7 @@ module Math sin!(z) else Complex(sin!(z.real)*cosh!(z.image), - -cos!(z.real)*sinh!(z.image)) + cos!(z.real)*sinh!(z.image)) end end diff --git a/lib/date.rb b/lib/date.rb index 998c2e8152..9de49bcbc7 100644 --- a/lib/date.rb +++ b/lib/date.rb @@ -1,8 +1,8 @@ # # Date.rb - # $Release Version: $ -# $Revision: 1.2 $ -# $Date: 1997/02/14 11:05:29 $ +# $Revision: 1.1.1.1.4.5 $ +# $Date: 1998/03/03 02:39:34 $ # by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- @@ -17,15 +17,34 @@ class Date include Comparable + Weektag = [ + "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday" + ] + + Monthtag = [ + "January","February","March","April", "May", "June","July", + "August", "September", "October", "November", "December" + ] + + Monthtab = { + "jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6, + "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12 + } + def initialize(y = 1, m = 1, d = 1) - if y.kind_of?(String) && y.size == 8 - @year = y[0,4].to_i - @month = y[4,2].to_i - @day = y[6,2].to_i + if y.kind_of?(String) + case y + when /(\d\d\d\d)-?(?:(\d\d)-?(\d\d)?)?/ + @year = $1.to_i + @month = if $2 then $2.to_i else 1 end + @day = if $3 then $3.to_i else 1 end + else + require 'parsedate' + @year, @month, @day = ParseDate.parsedate(y) + end else if m.kind_of?(String) - ml = {"jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6, "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12} - m = ml[m.downcase] + m = Monthtab[m.downcase] if m.nil? raise ArgumentError, "Wrong argument. (month)" end @@ -53,25 +72,35 @@ class Date def period return Date.period!(@year, @month, @day) end - + + def jd + return period + 1721423 + end + + def mjd + return jd - 2400000.5 + end + + def to_s + format("%.3s, %.3s %2d %4d", name_of_week, name_of_month, @day, @year) + end + + def inspect + to_s + end + def day_of_week - dl = Date.daylist(@year) - d = Date.jan1!(@year) - for m in 1..(@month - 1) - d += dl[m] - end - d += @day - 1 - if @year == 1752 && @month == 9 && @day >= 14 - d -= (14 - 3) - end - return (d % 7) + return (period + 5) % 7 end - Weektag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] def name_of_week return Weektag[self.day_of_week] end + def name_of_month + return Monthtag[@month-1] + end + def +(o) if o.kind_of?(Numeric) d = Integer(self.period + o) @@ -80,6 +109,9 @@ class Date else raise TypeError, "Illegal type. (Integer or Date)" end + if d <= 0 + raise ArgumentError, "argument out of range. (self > other)" + end return Date.at(d) end @@ -117,14 +149,13 @@ class Date end def leapyear? - if Date.leapyear(@year) == 1 - return FALSE - else - return TRUE - end + Date.leapyear(@year) != 1 end def _check_date + if @year == nil or @month == nil or @day == nil + raise ArgumentError, "argument contains nil" + end m = Date.daylist(@year) if @month < 1 || @month > 12 raise ArgumentError, "argument(month) out of range." @@ -151,7 +182,7 @@ end def Date.at(d) if d.kind_of? Time - return Date.new(1900+d.year, d.mon+1, d.mday) + return Date.new(d.year, d.mon, d.mday) end if d.kind_of? Date return Date.at(d.period) @@ -189,10 +220,10 @@ def Date.period!(y, m, d) p += dl[mm] end p += (y - 1) * 365 + ((y - 1) / 4.0).to_i - if (y - 1) > 1752 - p -= ((y - 1 - 1752) / 100.0).to_i - p += ((y - 1 - 1752) / 400.0).to_i - p -= (14 - 3) + if y > 1752 + p -= ((y - 1) / 100.0).to_i + p += ((y - 1) / 400.0).to_i + p += 2 elsif y == 1752 && m == 9 && d >= 14 && d <= 30 p -= (14 - 3) end diff --git a/lib/debug.rb b/lib/debug.rb index 432c7b4d19..90270a3fe7 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -11,6 +11,8 @@ class DEBUGGER__ @scripts = {} end + DEBUG_LAST_CMD = [] + def interrupt @stop_next = 1 end @@ -40,6 +42,11 @@ class DEBUGGER__ STDOUT.flush while input = STDIN.gets input.chop! + if input == "" + input = DEBUG_LAST_CMD[0] + else + DEBUG_LAST_CMD[0] = input + end case input when /^b(reak)?\s+(([^:\n]+:)?.+)/ pos = $2 @@ -169,7 +176,7 @@ class DEBUGGER__ printf "no sourcefile available for %s\n", file end when /^p\s+/ - p debug_eval($', binding) + p debug_eval($', binding) #' else v = debug_eval(input, binding) p v unless v == nil @@ -187,10 +194,13 @@ class DEBUGGER__ return "\n" unless line return line end + save = $DEBUG begin + $DEBUG = FALSE f = open(file) lines = @scripts[file] = f.readlines rescue + $DEBUG = save @scripts[file] = TRUE return "\n" end diff --git a/lib/delegate.rb b/lib/delegate.rb index e5943cead8..0771f2feeb 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -1,26 +1,51 @@ # Delegation class that delegates even methods defined in super class, # which can not be covered with normal method_missing hack. # -# Delegater is the abstract delegation class. Need to redefine -# `__getobj__' method in the subclass. SimpleDelegater is the +# Delegator is the abstract delegation class. Need to redefine +# `__getobj__' method in the subclass. SimpleDelegator is the # concrete subclass for simple delegation. # # Usage: # foo = Object.new -# foo = SimpleDelegater.new(foo) -# foo.type # => Object +# foo2 = SimpleDelegator.new(foo) +# foo.hash == foo2.hash # => true +# +# Foo = DelegateClass(Array) +# +# class ExtArray<DelegateClass(Array) +# ... +# end -class Delegater +class Delegator def initialize(obj) - preserved = ["id", "equal?", "__getobj__"] + preserved = ::Kernel.instance_methods + preserved -= ["to_s","to_a","inspect","==","=~","==="] for t in self.type.ancestors preserved |= t.instance_methods - break if t == Delegater + preserved |= t.private_instance_methods + preserved |= t.protected_instance_methods + break if t == Delegator end for method in obj.methods next if preserved.include? method - eval "def self.#{method}(*args); __getobj__.send :#{method}, *args; end" + eval <<-EOS + def self.#{method}(*args, &block) + begin + __getobj__.__send__(:#{method}, *args, &block) + rescue Exception + c = -caller(0).size + if /:in `__getobj__'$/ =~ $@[c-1] #` + n = 1 + else + c -= 1 + n = 2 + end + $@[c,n] = nil + raise + end + end + EOS end end @@ -30,7 +55,7 @@ class Delegater end -class SimpleDelegater<Delegater +class SimpleDelegator<Delegator def initialize(obj) super @@ -41,4 +66,61 @@ class SimpleDelegater<Delegater @obj end + def __setobj__(obj) + @obj = obj + end +end + +# backward compatibility ^_^;;; +Delegater = Delegator +SimpleDelegater = SimpleDelegator + +# +def DelegateClass(superclass) + klass = Class.new + methods = superclass.instance_methods + methods -= ::Kernel.instance_methods + methods |= ["to_s","to_a","inspect","==","=~","==="] + klass.module_eval <<-EOS + def initialize(obj) + @obj = obj + end + EOS + for method in methods + klass.module_eval <<-EOS + def #{method}(*args, &block) + begin + @obj.__send__(:#{method}, *args, &block) + rescue + $@[0,2] = nil + raise + end + end + EOS + end + return klass; + end + +if __FILE__ == $0 + class ExtArray<DelegateClass(Array) + def initialize() + super([]) + end + end + + ary = ExtArray.new + p ary.type + ary.push 25 + p ary + + foo = Object.new + def foo.test + 25 + end + def foo.error + raise 'this is OK' + end + foo2 = SimpleDelegator.new(foo) + p foo.test == foo2.test # => true + foo2.error # raise error! end diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb index d10657bbad..bf860dc5c1 100644 --- a/lib/e2mmap.rb +++ b/lib/e2mmap.rb @@ -1,11 +1,22 @@ # # e2mmap.rb - for ruby 1.1 -# $Release Version: 1.1$ -# $Revision: 1.4 $ -# $Date: 1997/08/18 07:12:12 $ +# $Release Version: 1.2$ +# $Revision: 1.8 $ +# $Date: 1998/08/19 15:22:22 $ # by Keiju ISHITSUKA # # -- +# Usage: +# +# class Foo +# extend Exception2MassageMapper +# def_exception :NewExceptionClass, "message..."[, superclass] +# def_e2meggage ExistingExceptionClass, "message..." +# ... +# end +# +# Foo.Fail NewExceptionClass, arg... +# Foo.Fail ExistingExceptionClass, arg... # # if VERSION < "1.1" @@ -13,40 +24,60 @@ if VERSION < "1.1" else module Exception2MessageMapper - RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-' + @RCS_ID='-$Id: e2mmap.rb,v 1.8 1998/08/19 15:22:22 keiju Exp keiju $-' E2MM = Exception2MessageMapper - + def E2MM.extend_object(cl) super cl.bind(self) end - # °ĘÁ°¤Č¤Î¸ß´ąŔ­¤Î¤ż¤á¤Ë»Ä¤·¤Ć¤˘¤ë. + # backward compatibility def E2MM.extend_to(b) c = eval("self", b) c.extend(self) end -# public :fail - # alias e2mm_fail fail + # public :fail + alias fail! fail + + #def fail(err = nil, *rest) + # super + #end - def fail(err = nil, *rest) - Exception2MessageMapper.fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s + def Fail(err = nil, *rest) + Exception2MessageMapper.Fail Exception2MessageMapper::ErrNotRegisteredException, err.inspect end def bind(cl) self.module_eval %q^ - E2MM_ErrorMSG = {} + E2MM_ErrorMSG = {} unless self.const_defined?(:E2MM_ErrorMSG) # fail(err, *rest) - # err: Îăł° - # rest: ĄáĄĂĄ»ˇĽĄ¸¤ËĹϤąĄŃĄéĄáˇĽĄż + # err: Exception + # rest: Parameter accompanied with the exception # + def self.Fail(err = nil, *rest) + if form = E2MM_ErrorMSG[err] + $! = err.new(sprintf(form, *rest)) + $@ = caller(0) if $@.nil? + $@.shift + # e2mm_fail() + raise() +# elsif self == Exception2MessageMapper +# fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s + else +# print "super\n" + super + end + end + + # ˛áµî¤Î¸ß´ąŔ­¤Î¤ż¤á def self.fail(err = nil, *rest) - $@ = caller(0) if $@.nil? - $@.shift if form = E2MM_ErrorMSG[err] $! = err.new(sprintf(form, *rest)) + $@ = caller(0) if $@.nil? + $@.shift # e2mm_fail() raise() # elsif self == Exception2MessageMapper @@ -63,7 +94,6 @@ else # def_exception(c, m) # c: exception # m: message_form - # Îăł°c¤ÎĄáĄĂĄ»ˇĽĄ¸¤ňm¤Č¤ą¤ë. # def self.def_e2message(c, m) E2MM_ErrorMSG[c] = m @@ -72,13 +102,21 @@ else # def_exception(c, m) # n: exception_name # m: message_form - # s: Îăł°ĄąˇĽĄŃˇĽĄŻĄéĄą(ĄÇĄŐĄ©ĄëĄČ: Exception) - # Îăł°Ěľ``c''¤ň¤â¤ÄÎăł°¤ňÄęµÁ¤·, ¤˝¤ÎĄáĄĂĄ»ˇĽĄ¸¤ňm¤Č¤ą¤ë. + # s: superclass_of_exception (default: Exception) + # defines excaption named ``c'', whose message is ``m''. # #def def_exception(n, m) - def self.def_exception(n, m, s = Exception) + def self.def_exception(n, m, s = nil) n = n.id2name if n.kind_of?(Fixnum) + unless s + if defined?(StandardError) + s = StandardError + else + s = Exception + end + end e = Class.new(s) + const_set(n, e) E2MM_ErrorMSG[e] = m # const_get(:E2MM_ErrorMSG)[e] = m @@ -91,4 +129,3 @@ else def_exception(:ErrNotRegisteredException, "not registerd exception(%s)") end end - diff --git a/lib/eregex.rb b/lib/eregex.rb index f214f6a2d4..384d531e0f 100644 --- a/lib/eregex.rb +++ b/lib/eregex.rb @@ -30,10 +30,7 @@ class Regexp end end -p "abc" =~ /b/|/c/ -p "abc" =~ /b/&/c/ - - - - - +if __FILE__ == $0 + p "abc" =~ /b/|/c/ + p "abc" =~ /b/&/c/ +end diff --git a/lib/finalize.rb b/lib/finalize.rb index 9b2ffefcf5..a07e67d093 100644 --- a/lib/finalize.rb +++ b/lib/finalize.rb @@ -1,8 +1,8 @@ # # finalizer.rb - -# $Release Version: 0.2$ -# $Revision: 1.3 $ -# $Date: 1998/01/09 08:09:49 $ +# $Release Version: 0.3$ +# $Revision: 1.4 $ +# $Date: 1998/02/27 05:34:33 $ # by Keiju ISHITSUKA # # -- @@ -11,44 +11,42 @@ # # add(obj, dependant, method = :finalize, *opt) # add_dependency(obj, dependant, method = :finalize, *opt) -# °Í¸´Ř·¸ R_method(obj, dependant) ¤ÎÄɲà +# add dependency R_method(obj, dependant) # # delete(obj_or_id, dependant, method = :finalize) # delete_dependency(obj_or_id, dependant, method = :finalize) -# °Í¸´Ř·¸ R_method(obj, dependant) ¤Îşď˝ü +# delete dependency R_method(obj, dependant) # delete_all_dependency(obj_or_id, dependant) -# °Í¸´Ř·¸ R_*(obj, dependant) ¤Îşď˝ü +# delete dependency R_*(obj, dependant) # delete_by_dependant(dependant, method = :finalize) -# °Í¸´Ř·¸ R_method(*, dependant) ¤Îşď˝ü +# delete dependency R_method(*, dependant) # delete_all_by_dependant(dependant) -# °Í¸´Ř·¸ R_*(*, dependant) ¤Îşď˝ü +# delete dependency R_*(*, dependant) # delete_all -# Á´¤Ć¤Î°Í¸´Ř·¸¤Îşď˝ü. +# delete all dependency R_*(*, *) # # finalize(obj_or_id, dependant, method = :finalize) # finalize_dependency(obj_or_id, dependant, method = :finalize) -# °Í¸´ŘϢ R_method(obj, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ň -# finalize¤ą¤ë. +# finalize the dependant connected by dependency R_method(obj, dependtant). # finalize_all_dependency(obj_or_id, dependant) -# °Í¸´ŘϢ R_*(obj, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą¤ë. +# finalize all dependants connected by dependency R_*(obj, dependtant). # finalize_by_dependant(dependant, method = :finalize) -# °Í¸´ŘϢ R_method(*, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą¤ë. +# finalize the dependant connected by dependency R_method(*, dependtant). # fainalize_all_by_dependant(dependant) -# °Í¸´ŘϢ R_*(*, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą¤ë. +# finalize all dependants connected by dependency R_*(*, dependant). # finalize_all -# Finalizer¤ËĹĐĎż¤µ¤ě¤ëÁ´¤Ć¤Îdependant¤ňfinalize¤ą¤ë +# finalize all dependency registered to the Finalizer. # # safe{..} -# gc»ţ¤ËFinalizer¤¬µŻĆ°¤ą¤ë¤Î¤ň»ß¤á¤ë. -# +# stop invoking Finalizer on GC. # module Finalizer - RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/finalize.rb,v 1.3 1998/01/09 08:09:49 keiju Exp keiju $-' + RCS_ID='-$Id: finalize.rb,v 1.4 1998/02/27 05:34:33 keiju Exp keiju $-' # @dependency: {id => [[dependant, method, *opt], ...], ...} - # °Í¸´Ř·¸ R_method(obj, dependant) ¤ÎÄɲà + # add dependency R_method(obj, dependant) def add_dependency(obj, dependant, method = :finalize, *opt) ObjectSpace.call_finalizer(obj) method = method.intern unless method.kind_of?(Integer) @@ -61,7 +59,7 @@ module Finalizer end alias add add_dependency - # °Í¸´Ř·¸ R_method(obj, dependant) ¤Îşď˝ü + # delete dependency R_method(obj, dependant) def delete_dependency(id, dependant, method = :finalize) id = id.id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) @@ -75,7 +73,7 @@ module Finalizer end alias delete delete_dependency - # °Í¸´Ř·¸ R_*(obj, dependant) ¤Îşď˝ü + # delete dependency R_*(obj, dependant) def delete_all_dependency(id, dependant) id = id.id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) @@ -88,30 +86,29 @@ module Finalizer end end - # °Í¸´Ř·¸ R_method(*, dependant) ¤Îşď˝ü + # delete dependency R_method(*, dependant) def delete_by_dependant(dependant, method = :finalize) method = method.intern unless method.kind_of?(Integer) - for id in Dependency.keys + for id in @dependency.keys delete(id, dependant, method) end end - # °Í¸´Ř·¸ R_*(*, dependant) ¤Îşď˝ü + # delete dependency R_*(*, dependant) def delete_all_by_dependant(dependant) for id in @dependency.keys delete_all_dependency(id, dependant) end end - # °Í¸´ŘϢ R_method(obj, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą - # ¤ë. + # finalize the depandant connected by dependency R_method(obj, dependtant) def finalize_dependency(id, dependant, method = :finalize) id = id.id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) for assocs in @dependency[id] assocs.delete_if do |d, m, *o| - d.send(m, *o) if ret = d == dependant && m == method + d.send(m, id, *o) if ret = d == dependant && m == method ret end @dependency.delete(id) if assoc.empty? @@ -119,20 +116,20 @@ module Finalizer end alias finalize finalize_dependency - # °Í¸´ŘϢ R_*(obj, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą¤ë. + # finalize all dependants connected by dependency R_*(obj, dependtant) def finalize_all_dependency(id, dependant) id = id.id unless id.kind_of?(Integer) method = method.intern unless method.kind_of?(Integer) for assoc in @dependency[id] assoc.delete_if do |d, m, *o| - d.send(m, *o) if ret = d == dependant + d.send(m, id, *o) if ret = d == dependant end @dependency.delete(id) if assoc.empty? end end - # °Í¸´ŘϢ R_method(*, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą¤ë. + # finalize the dependant connected by dependency R_method(*, dependtant) def finalize_by_dependant(dependant, method = :finalize) method = method.intern unless method.kind_of?(Integer) for id in @dependency.keys @@ -140,14 +137,14 @@ module Finalizer end end - # °Í¸´ŘϢ R_*(*, dependtant) ¤Ç·ë¤Đ¤ě¤ëdependant¤ňfinalize¤ą¤ë. + # finalize all dependants connected by dependency R_*(*, dependtant) def fainalize_all_by_dependant(dependant) for id in @dependency.keys finalize_all_dependency(id, dependant) end end - # Finalizer¤ËĹĐĎż¤µ¤ě¤Ć¤¤¤ëÁ´¤Ć¤Îdependant¤ňfinalize¤ą¤ë + # finalize all dependants registered to the Finalizer. def finalize_all for id, assocs in @dependency for dependant, method, *opt in assocs @@ -157,7 +154,7 @@ module Finalizer end end - # finalize_* ¤ň°ÂÁ´¤Ë¸Ć¤Ó˝Đ¤ą¤ż¤á¤ÎĄ¤ĄĆĄěˇĽĄż + # method to call finalize_* safely. def safe old_status = Thread.critical Thread.critical = TRUE @@ -167,7 +164,7 @@ module Finalizer Thread.critical = old_status end - # ObjectSpace#add_finalizer¤Ř¤ÎĹĐĎż´Řżô + # registering function to ObjectSpace#add_finalizer def final_of(id) if assocs = @dependency.delete(id) for dependant, method, *opt in assocs @@ -202,4 +199,3 @@ module Finalizer private_class_method :final_of end - diff --git a/lib/find.rb b/lib/find.rb index 5ecc54329c..3f1b82d2b3 100644 --- a/lib/find.rb +++ b/lib/find.rb @@ -1,5 +1,5 @@ # Usage: -# require "find.rb" +# require "find" # # Find.find('/foo','/bar') {|f| ...} # or @@ -12,7 +12,7 @@ module Find while file = path.shift catch(:prune) { yield file - if File.directory? file and not File.symlink? file then + if File.directory? file then d = Dir.open(file) begin for f in d diff --git a/lib/ftools.rb b/lib/ftools.rb index 59bc81b365..7ccc7a4468 100644 --- a/lib/ftools.rb +++ b/lib/ftools.rb @@ -30,7 +30,7 @@ class << File to.binmode begin - while TRUE + while true r = from.sysread(fsize) rsize = r.size w = 0 @@ -40,9 +40,9 @@ class << File end end rescue EOFError - ret = TRUE + ret = true rescue - ret = FALSE + ret = false ensure to.close from.close @@ -50,7 +50,7 @@ class << File ret end - def copy from, to, verbose = FALSE + def copy from, to, verbose = false $stderr.print from, " -> ", catname(from, to), "\n" if verbose syscopy from, to end @@ -59,11 +59,11 @@ class << File # move file - def move from, to, verbose = FALSE + def move from, to, verbose = false to = catname(from, to) $stderr.print from, " -> ", to, "\n" if verbose - if PLATFORM =~ /djgpp|cygwin32|mswin32/ and FileTest.file? to + if PLATFORM =~ /djgpp|cygwin|mswin32/ and FileTest.file? to unlink to end begin @@ -76,10 +76,10 @@ class << File alias mv move # compare two files -# TRUE: identical -# FALSE: not identical +# true: identical +# false: not identical - def compare from, to, verbose = FALSE + def compare from, to, verbose = false $stderr.print from, " <=> ", to, "\n" if verbose fsize = size(from) fsize = 1024 if fsize < 512 @@ -90,7 +90,7 @@ class << File to = open(to, "r") to.binmode - ret = FALSE + ret = false fr = tr = '' begin @@ -103,7 +103,7 @@ class << File end end rescue - ret = FALSE + ret = false ensure to.close from.close @@ -116,7 +116,7 @@ class << File # unlink files safely def safe_unlink(*files) - verbose = if files[-1].is_a? String then FALSE else files.pop end + verbose = if files[-1].is_a? String then false else files.pop end begin $stderr.print files.join(" "), "\n" if verbose chmod 0777, *files @@ -129,7 +129,7 @@ class << File alias rm_f safe_unlink def makedirs(*dirs) - verbose = if dirs[-1].is_a? String then FALSE else dirs.pop end + verbose = if dirs[-1].is_a? String then false else dirs.pop end # mode = if dirs[-1].is_a? Fixnum then dirs.pop else 0755 end mode = 0755 for dir in dirs @@ -146,14 +146,15 @@ class << File alias o_chmod chmod def chmod(mode, *files) - verbose = if files[-1].is_a? String then FALSE else files.pop end + verbose = if files[-1].is_a? String then false else files.pop end $stderr.printf "chmod %04o %s\n", mode, files.join(" ") if verbose o_chmod mode, *files end - def install(from, to, mode, verbose) + def install(from, to, mode = nil, verbose = false) to = catname(from, to) unless FileTest.exist? to and cmp from, to + unlink to if FileTest.exist? to cp from, to, verbose chmod mode, to, verbose if mode end diff --git a/lib/ftplib.rb b/lib/ftplib.rb index 34ee2f8d62..617d85899b 100644 --- a/lib/ftplib.rb +++ b/lib/ftplib.rb @@ -1,617 +1,574 @@ -### ftplib.rb -*- Mode: ruby; tab-width: 8; -*- +## ftplib.rb -## $Revision: 1.5 $ -## $Date: 1997/09/16 08:03:31 $ -## by maeda shugo <shugo@po.aianet.ne.jp> +# Author: Shugo Maeda <shugo@po.aianet.ne.jp> +# Version: $Revision: 1.7 $ -### Code: +## Code: require "socket" -require "sync" if defined? Thread +require "monitor" -class FTPError < Exception; end +class FTPError < StandardError; end class FTPReplyError < FTPError; end class FTPTempError < FTPError; end class FTPPermError < FTPError; end class FTPProtoError < FTPError; end class FTP - - RCS_ID = '$Id: ftplib.rb,v 1.5 1997/09/16 08:03:31 shugo Exp $' - - FTP_PORT = 21 - CRLF = "\r\n" - - attr :passive, TRUE - attr :return_code, TRUE - attr :debug_mode, TRUE - attr :welcome - attr :lastresp - - THREAD_SAFE = defined?(Thread) != FALSE - - if THREAD_SAFE - def synchronize(mode = :EX) - if @sync - @sync.synchronize(mode) do - yield - end - end - end - - def sock_synchronize(mode = :EX) - if @sock - @sock.synchronize(mode) do - yield - end - end - end - else - def synchronize(mode = :EX) - yield - end - - def sock_synchronize(mode = :EX) - yield - end - end - private :sock_synchronize - - def FTP.open(host, user = nil, passwd = nil, acct = nil) - new(host, user, passwd, acct) - end + + RCS_ID = %q$Id: ftplib.rb,v 1.7 1998/04/13 12:34:24 shugo Exp shugo $ + + include MonitorMixin + + FTP_PORT = 21 + CRLF = "\r\n" + + attr_accessor :passive, :return_code, :debug_mode + attr_reader :welcome, :lastresp + + def FTP.open(host, user = nil, passwd = nil, acct = nil) + new(host, user, passwd, acct) + end - def initialize(host = nil, user = nil, - passwd = nil, acct = nil) - if THREAD_SAFE - @sync = Sync.new - end - @passive = FALSE - @return_code = "\n" - @debug_mode = FALSE - if host - connect(host) - if user - login(user, passwd, acct) - end - end - end - - def open_socket(host, port) - if defined? SOCKSsocket and ENV["SOCKS_SERVER"] - @passive = TRUE - SOCKSsocket.open(host, port) - else - TCPsocket.open(host, port) - end - end - private :open_socket - - def connect(host, port = FTP_PORT) - if @debug_mode - print "connect: ", host, ", ", port, "\n" - end - synchronize do - @sock = open_socket(host, port) - if THREAD_SAFE - @sock.extend Sync_m - end - voidresp - end - end - - def sanitize(s) - if s =~ /^PASS /i - s[0, 5] + "*" * (s.length - 5) - else - s - end - end - private :sanitize - - def putline(line) - if @debug_mode - print "put: ", sanitize(line), "\n" - end - line = line + CRLF - @sock.write(line) - end - private :putline - - def getline - line = @sock.readline # if get EOF, raise EOFError - if line[-2, 2] == CRLF - line = line[0 .. -3] - elsif line[-1] == ?\r or - line[-1] == ?\n - line = line[0 .. -2] - end - if @debug_mode - print "get: ", sanitize(line), "\n" - end - line - end - private :getline - - def getmultiline - line = getline - buff = line - if line[3] == ?- - code = line[0, 3] - begin - line = getline - buff << "\n" << line - end until line[0, 3] == code and line[3] != ?- - end - buff << "\n" - end - private :getmultiline - - def getresp - resp = getmultiline - @lastresp = resp[0, 3] - c = resp[0] - case c - when ?1, ?2, ?3 - return resp - when ?4 - raise FTPTempError, resp - when ?5 - raise FTPPermError, resp - else - raise FTPProtoError, resp - end - end - private :getresp - - def voidresp - resp = getresp - if resp[0] != ?2 - raise FTPReplyError, resp - end - end - private :voidresp - - def sendcmd(cmd) - synchronize do - sock_synchronize do - putline(cmd) - getresp - end - end - end - - def voidcmd(cmd) - synchronize do - sock_synchronize do - putline(cmd) - voidresp - end - end - nil - end - - def sendport(host, port) - hbytes = host.split(".") - pbytes = [port / 256, port % 256] - bytes = hbytes + pbytes - cmd = "PORT " + bytes.join(",") - voidcmd(cmd) - end - private :sendport - - def makeport - sock = TCPserver.open(0) - port = sock.addr[1] - host = TCPsocket.getaddress(@sock.addr[2]) - resp = sendport(host, port) - sock - end - private :makeport - - def transfercmd(cmd) - if @passive - host, port = parse227(sendcmd("PASV")) - conn = open_socket(host, port) - resp = sendcmd(cmd) - if resp[0] != ?1 - raise FTPReplyError, resp - end - else - sock = makeport - resp = sendcmd(cmd) - if resp[0] != ?1 - raise FTPReplyError, resp - end - conn = sock.accept - end - conn - end - private :transfercmd - - def getaddress - thishost = Socket.gethostname - if not thishost.index(".") - thishost = Socket.gethostbyname(thishost)[0] - end - if ENV.has_key?("LOGNAME") - realuser = ENV["LOGNAME"] - elsif ENV.has_key?("USER") - realuser = ENV["USER"] - else - realuser = "anonymous" - end - realuser + "@" + thishost - end - private :getaddress - - def login(user = "anonymous", passwd = nil, acct = nil) - if user == "anonymous" and passwd == nil - passwd = getaddress - end - - resp = "" - synchronize do - resp = sendcmd('USER ' + user) - if resp[0] == ?3 - resp = sendcmd('PASS ' + passwd) - end - if resp[0] == ?3 - resp = sendcmd('ACCT ' + acct) - end - end - if resp[0] != ?2 - raise FTPReplyError, resp - end - @welcome = resp - end + def initialize(host = nil, user = nil, passwd = nil, acct = nil) + super + @passive = false + @return_code = "\n" + @debug_mode = false + if host + connect(host) + if user + login(user, passwd, acct) + end + end + end + + def open_socket(host, port) + if defined? SOCKSsocket and ENV["SOCKS_SERVER"] + @passive = true + return SOCKSsocket.open(host, port) + else + return TCPsocket.open(host, port) + end + end + private :open_socket + + def connect(host, port = FTP_PORT) + if @debug_mode + print "connect: ", host, ", ", port, "\n" + end + synchronize do + @sock = open_socket(host, port) + voidresp + end + end + + def sanitize(s) + if s =~ /^PASS /i + return s[0, 5] + "*" * (s.length - 5) + else + return s + end + end + private :sanitize + + def putline(line) + if @debug_mode + print "put: ", sanitize(line), "\n" + end + line = line + CRLF + @sock.write(line) + end + private :putline + + def getline + line = @sock.readline # if get EOF, raise EOFError + if line[-2, 2] == CRLF + line = line[0 .. -3] + elsif line[-1] == ?\r or + line[-1] == ?\n + line = line[0 .. -2] + end + if @debug_mode + print "get: ", sanitize(line), "\n" + end + return line + end + private :getline + + def getmultiline + line = getline + buff = line + if line[3] == ?- + code = line[0, 3] + begin + line = getline + buff << "\n" << line + end until line[0, 3] == code and line[3] != ?- + end + return buff << "\n" + end + private :getmultiline + + def getresp + resp = getmultiline + @lastresp = resp[0, 3] + c = resp[0] + case c + when ?1, ?2, ?3 + return resp + when ?4 + raise FTPTempError, resp + when ?5 + raise FTPPermError, resp + else + raise FTPProtoError, resp + end + end + private :getresp + + def voidresp + resp = getresp + if resp[0] != ?2 + raise FTPReplyError, resp + end + end + private :voidresp + + def sendcmd(cmd) + synchronize do + putline(cmd) + return getresp + end + end - def retrbinary(cmd, blocksize, callback = Proc.new) - synchronize do - voidcmd("TYPE I") - conn = transfercmd(cmd) - while TRUE - data = conn.read(blocksize) - break if data == nil - callback.call(data) - end - conn.close - voidresp - end - end + def voidcmd(cmd) + synchronize do + putline(cmd) + voidresp + end + end - def retrlines(cmd, callback = nil) - if iterator? - callback = Proc.new - elsif not callback.is_a?(Proc) - callback = Proc.new {|line| print line, "\n"} - end - synchronize do - voidcmd("TYPE A") - conn = transfercmd(cmd) - while TRUE - line = conn.gets - break if line == nil - if line[-2, 2] == CRLF - line = line[0 .. -3] - elsif line[-1] == ?\n - line = line[0 .. -2] - end - callback.call(line) - end - conn.close - voidresp - end - end + def sendport(host, port) + hbytes = host.split(".") + pbytes = [port / 256, port % 256] + bytes = hbytes + pbytes + cmd = "PORT " + bytes.join(",") + voidcmd(cmd) + end + private :sendport + + def makeport + sock = TCPserver.open(0) + port = sock.addr[1] + host = TCPsocket.getaddress(@sock.addr[2]) + resp = sendport(host, port) + return sock + end + private :makeport + + def transfercmd(cmd) + if @passive + host, port = parse227(sendcmd("PASV")) + conn = open_socket(host, port) + resp = sendcmd(cmd) + if resp[0] != ?1 + raise FTPReplyError, resp + end + else + sock = makeport + resp = sendcmd(cmd) + if resp[0] != ?1 + raise FTPReplyError, resp + end + conn = sock.accept + end + return conn + end + private :transfercmd + + def getaddress + thishost = Socket.gethostname + if not thishost.index(".") + thishost = Socket.gethostbyname(thishost)[0] + end + if ENV.has_key?("LOGNAME") + realuser = ENV["LOGNAME"] + elsif ENV.has_key?("USER") + realuser = ENV["USER"] + else + realuser = "anonymous" + end + return realuser + "@" + thishost + end + private :getaddress - def storbinary(cmd, file, blocksize, callback = nil) - if iterator? - callback = Proc.new - end - use_callback = callback.is_a?(Proc) - synchronize do - voidcmd("TYPE I") - conn = transfercmd(cmd) - while TRUE - buf = file.read(blocksize) - break if buf == nil - conn.write(buf) - if use_callback - callback.call(buf) - end - end - conn.close - voidresp - end - end + def login(user = "anonymous", passwd = nil, acct = nil) + if user == "anonymous" and passwd == nil + passwd = getaddress + end + + resp = "" + synchronize do + resp = sendcmd('USER ' + user) + if resp[0] == ?3 + resp = sendcmd('PASS ' + passwd) + end + if resp[0] == ?3 + resp = sendcmd('ACCT ' + acct) + end + end + if resp[0] != ?2 + raise FTPReplyError, resp + end + @welcome = resp + end + + def retrbinary(cmd, blocksize, callback = Proc.new) + synchronize do + voidcmd("TYPE I") + conn = transfercmd(cmd) + loop do + data = conn.read(blocksize) + break if data == nil + callback.call(data) + end + conn.close + voidresp + end + end - def storlines(cmd, file, callback = nil) - if iterator? - callback = Proc.new - end - use_callback = callback.is_a?(Proc) - synchronize do - voidcmd("TYPE A") - conn = transfercmd(cmd) - while TRUE - buf = file.gets - break if buf == nil - if buf[-2, 2] != CRLF - if buf[-1] == ?\r or - buf[-1] == ?\n - buf = buf[0 .. -2] - end - buf = buf + CRLF - end - conn.write(buf) - if use_callback - callback.call(buf) - end - end - conn.close - voidresp - end - end + def retrlines(cmd, callback = nil) + if iterator? + callback = Proc.new + elsif not callback.is_a?(Proc) + callback = Proc.new {|line| print line, "\n"} + end + synchronize do + voidcmd("TYPE A") + conn = transfercmd(cmd) + loop do + line = conn.gets + break if line == nil + if line[-2, 2] == CRLF + line = line[0 .. -3] + elsif line[-1] == ?\n + line = line[0 .. -2] + end + callback.call(line) + end + conn.close + voidresp + end + end + + def storbinary(cmd, file, blocksize, callback = nil) + if iterator? + callback = Proc.new + end + use_callback = callback.is_a?(Proc) + synchronize do + voidcmd("TYPE I") + conn = transfercmd(cmd) + loop do + buf = file.read(blocksize) + break if buf == nil + conn.write(buf) + callback.call(buf) if use_callback + end + conn.close + voidresp + end + end - def getbinaryfile(remotefile, localfile, - blocksize, callback = nil) - if iterator? - callback = Proc.new - end - use_callback = callback.is_a?(Proc) - f = open(localfile, "w") - begin + def storlines(cmd, file, callback = nil) + if iterator? + callback = Proc.new + end + use_callback = callback.is_a?(Proc) + synchronize do + voidcmd("TYPE A") + conn = transfercmd(cmd) + loop do + buf = file.gets + break if buf == nil + if buf[-2, 2] != CRLF + if buf[-1] == ?\r or + buf[-1] == ?\n + buf = buf[0 .. -2] + end + buf = buf + CRLF + end + conn.write(buf) + callback.call(buf) if use_callback + end + conn.close + voidresp + end + end + + def getbinaryfile(remotefile, localfile, blocksize, callback = nil) + if iterator? + callback = Proc.new + end + use_callback = callback.is_a?(Proc) + f = open(localfile, "w") + begin f.binmode - retrbinary("RETR " + remotefile, blocksize) do |data| - f.write(data) - if use_callback - callback.call(data) - end - end - ensure - f.close + retrbinary("RETR " + remotefile, blocksize) do |data| + f.write(data) + callback.call(data) if use_callback end - end + ensure + f.close + end + end - def gettextfile(remotefile, localfile, callback = nil) - if iterator? - callback = Proc.new - end - use_callback = callback.is_a?(Proc) - f = open(localfile, "w") - begin - retrlines("RETR " + remotefile) do |line| - line = line + @return_code - f.write(line) - if use_callback - callback.call(line) - end - end - ensure - f.close - end - end + def gettextfile(remotefile, localfile, callback = nil) + if iterator? + callback = Proc.new + end + use_callback = callback.is_a?(Proc) + f = open(localfile, "w") + begin + retrlines("RETR " + remotefile) do |line| + line = line + @return_code + f.write(line) + callback.call(line) if use_callback + end + ensure + f.close + end + end - def putbinaryfile(localfile, remotefile, - blocksize, callback = nil) - if iterator? - callback = Proc.new - end - use_callback = callback.is_a?(Proc) - f = open(localfile) - begin + def putbinaryfile(localfile, remotefile, blocksize, callback = nil) + if iterator? + callback = Proc.new + end + use_callback = callback.is_a?(Proc) + f = open(localfile) + begin f.binmode - storbinary("STOR " + remotefile, f, blocksize) do |data| - if use_callback - callback.call(data) - end - end - ensure - f.close + storbinary("STOR " + remotefile, f, blocksize) do |data| + callback.call(data) if use_callback end - end - - def puttextfile(localfile, remotefile, callback = nil) - if iterator? - callback = Proc.new - end - use_callback = callback.is_a?(Proc) - f = open(localfile) - begin - storlines("STOR " + remotefile, f) do |line| - if use_callback - callback.call(line) - end - end - ensure - f.close - end - end - - def acct(account) - cmd = "ACCT " + account - voidcmd(cmd) - end + ensure + f.close + end + end + + def puttextfile(localfile, remotefile, callback = nil) + if iterator? + callback = Proc.new + end + use_callback = callback.is_a?(Proc) + f = open(localfile) + begin + storlines("STOR " + remotefile, f) do |line| + callback.call(line) if use_callback + end + ensure + f.close + end + end - def nlst(dir = nil) - cmd = "NLST" - if dir - cmd = cmd + " " + dir - end - files = [] + def acct(account) + cmd = "ACCT " + account + voidcmd(cmd) + end + + def nlst(dir = nil) + cmd = "NLST" + if dir + cmd = cmd + " " + dir + end + files = [] + retrlines(cmd) do |line| + files.push(line) + end + return files + end + + def list(*args, &block) + cmd = "LIST" + args.each do |arg| + cmd = cmd + " " + arg + end + if block + retrlines(cmd, &block) + else + lines = [] retrlines(cmd) do |line| - files.push(line) + lines << line end - files - end - - def list(*args) - cmd = "LIST" - if iterator? - callback = Proc.new - elsif args[-1].is_a?(Proc) - callback = args.pop - else - callback = nil - end - args.each do |arg| - cmd = cmd + " " + arg - end - retrlines(cmd, callback) - end - alias ls list - alias dir list - - def rename(fromname, toname) - resp = sendcmd("RNFR " + fromname) - if resp[0] != ?3 - raise FTPReplyError, resp - end - voidcmd("RNTO " + toname) - end - - def delete(filename) - resp = sendcmd("DELE " + filename) - if resp[0, 3] == "250" - return - elsif resp[0] == ?5 - raise FTPPermError, resp - else - raise FTPReplyError, resp - end - end - - def chdir(dirname) - if dirname == ".." - begin - voidcmd("CDUP") - return - rescue FTPPermError - if $![0, 3] != "500" - raise FTPPermError, $! - end - end - end - cmd = "CWD " + dirname - voidcmd(cmd) - end - - def size(filename) - resp = sendcmd("SIZE " + filename) - if resp[0, 3] == "213" - return Integer(resp[3 .. -1].strip) - end - end - - def mkdir(dirname) - resp = sendcmd("MKD " + dirname) - return parse257(resp) - end - - def rmdir(dirname) - voidcmd("RMD " + dirname) - end + return lines + end + end + alias ls list + alias dir list + + def rename(fromname, toname) + resp = sendcmd("RNFR " + fromname) + if resp[0] != ?3 + raise FTPReplyError, resp + end + voidcmd("RNTO " + toname) + end + + def delete(filename) + resp = sendcmd("DELE " + filename) + if resp[0, 3] == "250" + return + elsif resp[0] == ?5 + raise FTPPermError, resp + else + raise FTPReplyError, resp + end + end + + def chdir(dirname) + if dirname == ".." + begin + voidcmd("CDUP") + return + rescue FTPPermError + if $![0, 3] != "500" + raise FTPPermError, $! + end + end + end + cmd = "CWD " + dirname + voidcmd(cmd) + end - def pwd - resp = sendcmd("PWD") + def size(filename) + voidcmd("TYPE I") + resp = sendcmd("SIZE " + filename) + if resp[0, 3] != "213" + raise FTPReplyError, resp + end + return resp[3..-1].strip + end + + MDTM_REGEXP = /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/ + + def mtime(filename, local = false) + str = mdtm(filename) + ary = str.scan(MDTM_REGEXP)[0].collect {|i| i.to_i} + return local ? Time.local(*ary) : Time.gm(*ary) + end + + def mkdir(dirname) + resp = sendcmd("MKD " + dirname) + return parse257(resp) + end + + def rmdir(dirname) + voidcmd("RMD " + dirname) + end + + def pwd + resp = sendcmd("PWD") return parse257(resp) - end - alias getdir pwd - - def system - resp = sendcmd("SYST") - if resp[0, 3] != "215" - raise FTPReplyError, resp - end - return resp[4 .. -1] - end - - def abort - line = "ABOR" + CRLF - resp = "" - sock_synchronize do - print "put: ABOR\n" if @debug_mode - @sock.send(line, Socket::MSG_OOB) - resp = getmultiline - end - unless ["426", "226", "225"].include?(resp[0, 3]) - raise FTPProtoError, resp - end - resp - end - - def status - line = "STAT" + CRLF - resp = "" - sock_synchronize do - print "put: STAT\n" if @debug_mode - @sock.send(line, Socket::MSG_OOB) - resp = getresp - end - resp - end - - def help(arg = nil) - cmd = "HELP" - if arg - cmd = cmd + " " + arg - end - sendcmd(cmd) - end - - def quit - voidcmd("QUIT") - end - - def close - @sock.close if @sock and not @sock.closed? - end + end + alias getdir pwd + + def system + resp = sendcmd("SYST") + if resp[0, 3] != "215" + raise FTPReplyError, resp + end + return resp[4 .. -1] + end + + def abort + line = "ABOR" + CRLF + print "put: ABOR\n" if @debug_mode + @sock.send(line, Socket::MSG_OOB) + resp = getmultiline + unless ["426", "226", "225"].include?(resp[0, 3]) + raise FTPProtoError, resp + end + return resp + end + def status + line = "STAT" + CRLF + print "put: STAT\n" if @debug_mode + @sock.send(line, Socket::MSG_OOB) + return getresp + end + + def mdtm(filename) + resp = sendcmd("MDTM " + filename) + if resp[0, 3] == "213" + return resp[3 .. -1].strip + end + end + + def help(arg = nil) + cmd = "HELP" + if arg + cmd = cmd + " " + arg + end + sendcmd(cmd) + end + + def quit + voidcmd("QUIT") + end + + def close + @sock.close if @sock and not @sock.closed? + end + def closed? @sock == nil or @sock.closed? end - def parse227(resp) - if resp[0, 3] != "227" - raise FTPReplyError, resp - end - left = resp.index("(") - right = resp.index(")") - if left == nil or right == nil - raise FTPProtoError, resp - end - numbers = resp[left + 1 .. right - 1].split(",") - if numbers.length != 6 - raise FTPProtoError, resp - end - host = numbers[0, 4].join(".") - port = (Integer(numbers[4]) << 8) + Integer(numbers[5]) - return host, port - end - private :parse227 - - def parse257(resp) - if resp[0, 3] != "257" - raise FTPReplyError, resp - end - if resp[3, 2] != ' "' - return "" - end - dirname = "" - i = 5 - n = resp.length - while i < n - c = resp[i, 1] - i = i + 1 - if c == '"' - if i > n or resp[i, 1] != '"' - break - end - i = i + 1 - end - dirname = dirname + c - end - return dirname - end - private :parse257 + def parse227(resp) + if resp[0, 3] != "227" + raise FTPReplyError, resp + end + left = resp.index("(") + right = resp.index(")") + if left == nil or right == nil + raise FTPProtoError, resp + end + numbers = resp[left + 1 .. right - 1].split(",") + if numbers.length != 6 + raise FTPProtoError, resp + end + host = numbers[0, 4].join(".") + port = (numbers[4].to_i << 8) + numbers[5].to_i + return host, port + end + private :parse227 + + def parse257(resp) + if resp[0, 3] != "257" + raise FTPReplyError, resp + end + if resp[3, 2] != ' "' + return "" + end + dirname = "" + i = 5 + n = resp.length + while i < n + c = resp[i, 1] + i = i + 1 + if c == '"' + if i > n or resp[i, 1] != '"' + break + end + i = i + 1 + end + dirname = dirname + c + end + return dirname + end + private :parse257 end + +## ftplib.rb ends here diff --git a/lib/getopts.rb b/lib/getopts.rb index 6929f7e4fd..9e1e8a2cf6 100644 --- a/lib/getopts.rb +++ b/lib/getopts.rb @@ -1,4 +1,3 @@ -#!/usr/local/bin/ruby # # getopts.rb - # $Release Version: $ @@ -11,7 +10,7 @@ # # -$RCS_ID="$Header$" +$RCS_ID=%q$Header$ def isSingle(lopt) if lopt.index(":") diff --git a/lib/importenv.rb b/lib/importenv.rb index 41253765ea..10b289199c 100644 --- a/lib/importenv.rb +++ b/lib/importenv.rb @@ -21,9 +21,12 @@ for k,v in ENV EOS end -p $TERM -$TERM = nil -p $TERM -p ENV["TERM"] -$TERM = "foo" -p ENV["TERM"] +if __FILE__ == $0 + p $TERM + $TERM = nil + p $TERM + p ENV["TERM"] + $TERM = "foo" + p ENV["TERM"] +end + diff --git a/lib/jcode.rb b/lib/jcode.rb index 40ab48ddac..50b7beee9d 100644 --- a/lib/jcode.rb +++ b/lib/jcode.rb @@ -11,13 +11,13 @@ class String alias original_succ succ private :original_succ - def mbchar?(c) + def mbchar? if $KCODE =~ /^s/i - c =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n + self =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n elsif $KCODE =~ /^e/i - c =~ /[\xa1-\xfe][\xa1-\xfe]/n + self =~ /[\xa1-\xfe][\xa1-\xfe]/n else - FALSE + false end end @@ -25,12 +25,13 @@ class String if self[-2] && self[-2] & 0x80 != 0 s = self.dup s[-1] += 1 - s[-1] += 1 if !mbchar?(s) + s[-1] += 1 if !s.mbchar? return s else original_succ end end + alias next succ def upto(to) return if self > to @@ -41,7 +42,7 @@ class String if self[0..-2] == to[0..-2] first = self[-2].chr for c in self[-1] .. to[-1] - if mbchar?(first+c.chr) + if (first+c.chr).mbchar? yield self[0..-2]+c.chr end end @@ -103,7 +104,7 @@ class String end def tr(from, to) - self.dup.tr!(from, to) + (str = self.dup).tr!(from, to) or str end def delete!(del) @@ -126,7 +127,7 @@ class String end def delete(del) - self.dup.delete!(del) + (str = self.dup).delete!(del) or str end def squeeze!(del=nil) @@ -154,7 +155,7 @@ class String end def squeeze(del=nil) - self.dup.squeeze!(del) + (str = self.dup).squeeze!(del) or str end def tr_s!(from, to) @@ -187,7 +188,7 @@ class String end def tr_s(from, to) - self.dup.tr_s!(from,to) + (str = self.dup).tr_s!(from,to) or str end alias original_chop! chop! @@ -201,7 +202,7 @@ class String end def chop - self.dup.chop! + (str = self.dup).chop! or str end end $VERBOSE = $vsave diff --git a/lib/mailread.rb b/lib/mailread.rb index a5d60c84b4..5e46606c09 100644 --- a/lib/mailread.rb +++ b/lib/mailread.rb @@ -1,7 +1,7 @@ class Mail def initialize(f) - unless f.kind_of?(IO) + unless defined? f.gets f = open(f, "r") opened = true end @@ -15,7 +15,8 @@ class Mail break if /^$/ # end of header if /^(\S+):\s*(.*)/ - @header[attr = $1.capitalize!] = $2 + (attr = $1).capitalize! + @header[attr] = $2 elsif attr sub!(/^\s*/, '') @header[attr] += "\n" + $_ diff --git a/lib/mathn.rb b/lib/mathn.rb index fdf27f6771..265ef1337f 100644 --- a/lib/mathn.rb +++ b/lib/mathn.rb @@ -1,8 +1,8 @@ # # mathn.rb - # $Release Version: 0.5 $ -# $Revision: 1.1 $ -# $Date: 1997/07/03 04:43:47 $ +# $Revision: 1.1.1.1.4.1 $ +# $Date: 1998/01/16 12:36:05 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # -- @@ -96,6 +96,7 @@ class Prime @counts.push @seed + @seed return @seed end + alias next succ def each loop do diff --git a/lib/matrix.rb b/lib/matrix.rb index 394c66f098..64b0738e1b 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -1,9 +1,8 @@ -#!/usr/local/bin/ruby # # matrix.rb - # $Release Version: 1.0$ -# $Revision: 1.0 $ -# $Date: 97/05/23 11:35:28 $ +# $Revision: 1.6 $ +# $Date: 1998/07/31 03:39:49 $ # Original Version from Smalltalk-80 version # on July 23, 1985 at 8:37:17 am # by Keiju ISHITSUKA @@ -18,9 +17,158 @@ # : # rown] # -# column: Îó -# row: ąÔ # +# module ExceptionForMatrix:: +# Exceptions: +# ErrDimensionMismatch +# number of column/row do not match +# ErrNotRegular +# not a regular matrix +# ErrOperationNotDefined +# specified operator is not defined (yet) +# +# class Matrix +# include ExceptionForMatrix +# +# Methods: +# class methods: +# Matrix.[](*rows) +# creates a matrix where `rows' indicates rows. +# `rows' is an array of arrays, +# e.g, Matrix[[11, 12], [21, 22]] +# Matrix.rows(rows, copy = TRUE) +# creates a matrix where `rows' indicates rows. +# if optional argument `copy' is false, use the array as +# internal structure of the metrix without copying. +# Matrix.columns(columns) +# creates a new matrix using `columns` as set of colums vectors. +# Matrix.diagonal(*values) +# creates a matrix where `columns' indicates columns. +# Matrix.scalar(n, value) +# creates a diagonal matrix such that the diagal compornents is +# given by `values'. +# Matrix.scalar(n, value) +# creates an n-by-n scalar matrix such that the diagal compornent is +# given by `value'. +# Matrix.identity(n) +# Matrix.unit(n) +# Matrix.I(n) +# creates an n-by-n unit matrix. +# Matrix.zero(n) +# creates an n-by-n zero matrix. +# Matrix.row_vector(row) +# creates a 1-by-n matrix such the row vector is `row'. +# `row' is specifed as a Vector or an Array. +# Matrix.column_vector(column) +# creates a 1-by-n matrix such that column vector is `column'. +# `column' is specifed as a Vector or an Array. +# accessing: +# [](i, j) +# returns (i,j) compornent +# row_size +# returns the number of rows +# column_size +# returns the number of columns +# row(i) +# returns the i-th row vector. +# when the block is supplied for the method, the block is iterated +# over all row vectors. +# column(j) +# returns the jth column vector. +# when the block is supplied for the method, the block is iterated +# over all column vectors. +# collect +# map +# creates a matrix which is the result of iteration of given +# block over all compornents. +# minor(*param) +# returns sub matrix. parameter is specified as the following: +# 1. from_row, row_size, from_col, size_col +# 2. from_row..to_row, from_col..to_col +# TESTING: +# regular? +# Is regular? +# singular? +# Is singular? i.e. Is non-regular? +# square? +# Is square? +# ARITHMETIC: +# *(m) +# times +# +(m) +# plus +# -(m) +# minus +# /(m) +# self * m.inv +# inverse +# inv +# inverse +# ** +# power +# Matrix functions: +# determinant +# det +# returns the determinant +# rank +# returns the rank +# trace +# tr +# returns the trace +# transpose +# t +# returns the transposed +# CONVERTING: +# coerce(other) +# row_vectors +# array of row vectors +# column_vectors +# array of column vectors +# to_a +# converts each element to Array +# to_f +# converts each element to Float +# to_i +# converts each element to Integer +# to_r +# converts each element to Rational +# PRINTING: +# to_s +# returns string representation +# inspect +# +# class Vector +# include ExceptionForMatrix +# +# INSTANCE CREATION: +# Vector.[](*array) +# Vector.elements(array, copy = TRUE) +# ACCSESSING: +# [](i) +# size +# ENUMRATIONS: +# each2(v) +# collect2(v) +# ARITHMETIC: +# *(x) "is matrix or number" +# +(v) +# -(v) +# VECTOR FUNCTIONS: +# inner_product(v) +# collect +# map +# map2(v) +# r +# CONVERTING: +# covector +# to_a +# to_f +# to_i +# to_r +# coerce(other) +# PRINTING: +# to_s +# inspect require "e2mmap.rb" @@ -36,8 +184,8 @@ module ExceptionForMatrix end class Matrix - RCS_ID='-$Header: ruby-mode,v 1.2 91/04/20 17:24:57 keiju Locked $-' - + @RCS_ID='-$Id: matrix.rb,v 1.6 1998/07/31 03:39:49 keiju Exp keiju $-' + include ExceptionForMatrix # instance creations @@ -144,6 +292,7 @@ class Matrix if iterator? for e in @rows[i] yield e + end else Vector.elements(@rows[i]) @@ -211,6 +360,38 @@ class Matrix column_size == row_size end + # COMPARING + def ==(other) + return FALSE unless Matrix === other + + other.compare_by_row_vectors(@rows) + end + alias eql? == + + def compare_by_row_vectors(rows) + return FALSE unless @rows.size == rows.size + + 0.upto(@rows.size - 1) do + |i| + return FALSE unless @rows[i] == rows[i] + end + TRUE + end + + def clone + Matrix.rows(@rows) + end + + def hash + value = 0 + for row in @rows + for e in row + value ^= e.hash + end + end + return value + end + # ARITHMETIC def *(m) #is matrix or vector or number" @@ -297,6 +478,25 @@ class Matrix } Matrix.rows(rows, FALSE) end + + def /(other) + case other + when Numeric + rows = @rows.collect { + |row| + row.collect { + |e| + e / other + } + } + return Matrix.rows(rows, FALSE) + when Matrix + return self * other.inverse + else + x, y = other.coerce(self) + rerurn x / y + end + end def inverse Matrix.fail ErrDimensionMismatch unless square? @@ -597,13 +797,12 @@ end #---------------------------------------------------------------------- class Vector include ExceptionForMatrix - #INSTANCE CREATION private_class_method :new def Vector.[](*array) - new(:init_elements, array, copy = FALSE) + new(:init_elements, array, FALSE) end def Vector.elements(array, copy = TRUE) @@ -649,6 +848,26 @@ class Vector end end + # COMPARING + def ==(other) + return FALSE unless Vector === other + + other.compare_by(@elements) + end + alias eqn? == + + def compare_by(elements) + @elements == elements + end + + def clone + Vector.elements(@elements) + end + + def hash + @elements.hash + end + # ARITHMETIC def *(x) "is matrix or number" @@ -733,7 +952,7 @@ class Vector for e in @elements v += e*e end - return v.sqrt + return Math.sqrt(v) end # CONVERTING diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 2bf3684920..7e131fe890 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -1,7 +1,8 @@ -# module to create Makefile for extention modules +# module to create Makefile for extension modules # invoke like: ruby -r mkmf extconf.rb require 'rbconfig' +require 'find' include Config @@ -36,6 +37,7 @@ $install = CONFIG["INSTALL_PROGRAM"] $install_data = CONFIG["INSTALL_DATA"] if $install !~ /^\// then $install = CONFIG["srcdir"]+"/"+$install + $install_data = CONFIG["srcdir"]+"/"+$install_data end if File.exist? $archdir + "/ruby.h" @@ -47,28 +49,60 @@ else exit 1 end -nul = "> /dev/null" - CFLAGS = CONFIG["CFLAGS"] if PLATFORM == "m68k-human" - nul = "> nul" CFLAGS.gsub!(/-c..-stack=[0-9]+ */, '') end -if $DEBUG - nul = "" +if /win32|djgpp|mingw32|m68k-human/i =~ PLATFORM + $null = open("nul", "w") +else + $null = open("/dev/null", "w") +end +LINK = "#{CONFIG['CC']} -o conftest -I#{$srcdir} -I#{CONFIG['includedir']} #{CFLAGS} %s #{CONFIG['LDFLAGS']} %s conftest.c #{CONFIG['LIBS']} %s" +CPP = "#{CONFIG['CPP']} -E -I#{$srcdir} -I#{CONFIG['includedir']} #{CFLAGS} %s conftest.c" + +$orgerr = $stderr.dup +$orgout = $stdout.dup +def xsystem command + if $DEBUG + print command, "\n" + return system(command) + end + $stderr.reopen($null) + $stdout.reopen($null) + r = system(command) + $stderr.reopen($orgerr) + $stdout.reopen($orgout) + return r end -LINK = CONFIG["CC"]+" -o conftest -I#{$srcdir} " + CFLAGS + " %s " + CONFIG["LDFLAGS"] + " %s conftest.c " + CONFIG["LIBS"] + "%s " + nul + " 2>&1" -CPP = CONFIG["CPP"] + " -E -I#{$srcdir} " + CFLAGS + " %s conftest.c " + nul + " 2>&1" def try_link(libs) - system(format(LINK, $CFLAGS, $LDFLAGS, libs)) + xsystem(format(LINK, $CFLAGS, $LDFLAGS, libs)) end def try_cpp - system(format(CPP, $CFLAGS)) + xsystem(format(CPP, $CFLAGS)) +end + +def install_rb(mfile) + path = [] + dir = [] + Find.find("lib") do |f| + next unless /\.rb$/ =~ f + f = f[4..-1] + path.push f + dir |= File.dirname(f) + end + for f in dir + next if f == "." + mfile.printf "\t@test -d $(libdir)/%s || mkdir $(libdir)/%s\n", f, f + end + for f in path + mfile.printf "\t$(INSTALL_DATA) lib/%s $(libdir)/%s\n", f, f + end end -def have_library(lib, func) +def have_library(lib, func="main") printf "checking for %s() in -l%s... ", func, lib STDOUT.flush if $lib_cache[lib] @@ -86,32 +120,40 @@ def have_library(lib, func) end end - cfile = open("conftest.c", "w") - cfile.printf "\ + if func && func != "" + cfile = open("conftest.c", "w") + cfile.printf "\ int main() { return 0; } int t() { %s(); return 0; } ", func - cfile.close + cfile.close - begin + begin + if $libs + libs = "-l" + lib + " " + $libs + else + libs = "-l" + lib + end + unless try_link(libs) + $lib_cache[lib] = 'no' + $cache_mod = TRUE + print "no\n" + return FALSE + end + ensure + system "rm -f conftest*" + end + else if $libs libs = "-l" + lib + " " + $libs else libs = "-l" + lib end - unless try_link(libs) - $lib_found[lib] = 'no' - $found = TRUE - print "no\n" - return FALSE - end - ensure - system "rm -f conftest*" end $libs = libs - $lib_found[lib] = 'yes' - $found = TRUE + $lib_cache[lib] = 'yes' + $cache_mod = TRUE print "yes\n" return TRUE end @@ -221,9 +263,15 @@ def create_makefile(target) $defs.push(format("-DEXTLIB='%s'", libs.join(","))) end $libs = "" unless $libs + $DLDFLAGS = CONFIG["DLDFLAGS"] + + if PLATFORM =~ /beos/ + $libs = $libs + " -lruby" + $DLDFLAGS = $DLDFLAGS + " -L" + CONFIG["prefix"] + "/lib" + end - if !$objs then - $objs = Dir["*.c"] + unless $objs then + $objs = Dir["*.{c,cc}"] for f in $objs f.sub!(/\.(c|cc)$/, ".o") end @@ -239,15 +287,18 @@ SHELL = /bin/sh srcdir = #{$srcdir} hdrdir = #{$hdrdir} -CC = gcc +CC = #{CONFIG["CC"]} -CFLAGS = #{CONFIG["CCDLFLAGS"]} -I#{$hdrdir} #{CFLAGS} #{$CFLAGS} #{$defs.join(" ")} -DLDFLAGS = #{CONFIG["DLDFLAGS"]} #{$LDFLAGS} +prefix = #{CONFIG["prefix"]} +CFLAGS = #{CONFIG["CCDLFLAGS"]} -I$(hdrdir) -I#{CONFIG["includedir"]} #{CFLAGS} #{$CFLAGS} #{$defs.join(" ")} +CXXFLAGS = $(CFLAGS) +DLDFLAGS = #{$DLDFLAGS} #{$LDFLAGS} LDSHARED = #{CONFIG["LDSHARED"]} prefix = #{CONFIG["prefix"]} exec_prefix = #{CONFIG["exec_prefix"]} -libdir = #{$archdir} +libdir = #{$libdir} +archdir = #{$archdir} #### End of system configuration section. #### @@ -258,6 +309,7 @@ OBJS = #{$objs} TARGET = #{target}.#{CONFIG["DLEXT"]} INSTALL = #{$install} +INSTALL_DATA = #{$install_data} binsuffix = #{CONFIG["binsuffix"]} @@ -269,21 +321,20 @@ clean:; @rm -f *.o *.so *.sl realclean: clean -install: $(libdir)/$(TARGET) +install: $(archdir)/$(TARGET) -$(libdir)/$(TARGET): $(TARGET) +$(archdir)/$(TARGET): $(TARGET) @test -d $(libdir) || mkdir $(libdir) - $(INSTALL) $(TARGET) $(libdir)/$(TARGET) + @test -d $(archdir) || mkdir $(archdir) + $(INSTALL) $(TARGET) $(archdir)/$(TARGET) EOMF - for rb in Dir["lib/*.rb"] - mfile.printf "\t$(INSTALL) %s %s\n", rb, $libdir - end + install_rb(mfile) mfile.printf "\n" if CONFIG["DLEXT"] != "o" mfile.printf <<EOMF $(TARGET): $(OBJS) - $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS) + $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) $(LOCAL_LIBS) EOMF elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc") or mfile.print "$(TARGET): $(OBJS)\n" @@ -332,12 +383,19 @@ EOMF rescue end end + + if PLATFORM =~ /beos/ + print "creating ruby.def\n" + open("ruby.def", "w") do |file| + file.print("EXPORTS\n") if PLATFORM =~ /^i/ + file.print("Init_#{target}\n") + end + end end -$local_libs = nil -$libs = nil +$libs = PLATFORM =~ /cygwin32|beos/ ? nil : "-lc" $objs = nil -$CFLAGS = nil -$LDFLAGS = nil +$local_libs = "" +$CFLAGS = "" +$LDFLAGS = "" $defs = [] - diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb index 823888e72f..4b8d64438e 100644 --- a/lib/mutex_m.rb +++ b/lib/mutex_m.rb @@ -1,8 +1,8 @@ # # mutex_m.rb - # $Release Version: 2.0$ -# $Revision: 1.2 $ -# $Date: 1997/07/25 02:43:21 $ +# $Revision: 1.7 $ +# $Date: 1998/02/27 04:28:57 $ # Original from mutex.rb # by Keiju ISHITSUKA(SHL Japan Inc.) # @@ -18,21 +18,50 @@ require "finalize" module Mutex_m - def Mutex_m.extend_object(obj) + def Mutex_m.extendable_module(obj) if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj raise TypeError, "Mutex_m can't extend to this class(#{obj.type})" else begin - eval "class << obj - @mu_locked - end" - obj.extend(For_primitive_object) + obj.instance_eval "@mu_locked" + For_general_object rescue TypeError - obj.extend(For_general_object) + For_primitive_object end end end + def Mutex_m.includable_module(cl) + begin + dummy = cl.new + Mutex_m.extendable_module(dummy) + rescue NameError + # new¤¬ÄęµÁ¤µ¤ě¤Ć¤¤¤Ę¤¤»ţ¤Ď, DATA¤Č¤ß¤Ę¤ą. + For_primitive_object + end + end + + def Mutex_m.extend_class(cl) + return super if cl.instance_of?(Module) + + # ĄâĄ¸ĄĺˇĽĄë¤Î»ţ¤Ď˛ż¤â¤·¤Ę¤¤. ĄŻĄéĄą¤Îľěąç, ŬŔڤʥ⥸ĄĺˇĽĄë¤Î·čÄę + # ¤Čalias¤ňąÔ¤¦. + real = includable_module(cl) + cl.module_eval %q{ + include real + + alias locked? mu_locked? + alias lock mu_lock + alias unlock mu_unlock + alias try_lock mu_try_lock + alias synchronize mu_synchronize + } + end + + def Mutex_m.extend_object(obj) + obj.extend(Mutex_m.extendable_module(obj)) + end + def mu_extended unless (defined? locked? and defined? lock and @@ -40,7 +69,7 @@ module Mutex_m defined? try_lock and defined? synchronize) eval "class << self - alias locked mu_locked? + alias locked? mu_locked? alias lock mu_lock alias unlock mu_unlock alias try_lock mu_try_lock @@ -49,6 +78,7 @@ module Mutex_m end end + # locking def mu_synchronize begin mu_lock @@ -58,6 +88,7 @@ module Mutex_m end end + # internal class module For_general_object include Mutex_m @@ -118,10 +149,16 @@ module Mutex_m def For_primitive_object.extend_object(obj) super + obj.mu_extended Finalizer.add(obj, For_primitive_object, :mu_finalize) end + def mu_extended + super + initialize + end + def For_primitive_object.mu_finalize(id) Thread.critical = TRUE if wait = Mu_Locked.delete(id) @@ -146,7 +183,7 @@ module Mutex_m ret = FALSE else Mu_Locked[self.id] = [] - Finalizer.set(self, For_primitive_object, :mu_delete_Locked) + Finalizer.add(self, For_primitive_object, :mu_finalize) ret = TRUE end Thread.critical = FALSE @@ -159,7 +196,7 @@ module Mutex_m Thread.stop end Mu_Locked[self.id] = [] - Finalizer.add(self, For_primitive_object, :mu_delete_Locked) + Finalizer.add(self, For_primitive_object, :mu_finalize) Thread.critical = FALSE self end @@ -180,4 +217,3 @@ module Mutex_m end end - diff --git a/lib/observer.rb b/lib/observer.rb index b802dac633..5928367a7d 100644 --- a/lib/observer.rb +++ b/lib/observer.rb @@ -30,9 +30,11 @@ module Observable @observer_state end def notify_observers(*arg) - if @observer_peers and @observer_state - for i in @observer_peers - i.update(*arg) + if @observer_state + if @observer_peers + for i in @observer_peers + i.update(*arg) + end end @observer_state = FALSE end diff --git a/lib/parsearg.rb b/lib/parsearg.rb index a0ef90f018..b9f41d5e5f 100644 --- a/lib/parsearg.rb +++ b/lib/parsearg.rb @@ -1,4 +1,3 @@ -#!/usr/local/bin/ruby # # parsearg.rb - parse arguments # $Release Version: $ @@ -11,9 +10,9 @@ # # -$RCS_ID="$Header$" +$RCS_ID=%q$Header$ -load("getopts.rb") +require "getopts" def printUsageAndExit() if $USAGE diff --git a/lib/parsedate.rb b/lib/parsedate.rb index 1c1dda76bc..68550c6505 100644 --- a/lib/parsedate.rb +++ b/lib/parsedate.rb @@ -4,39 +4,68 @@ module ParseDate 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8, 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12 } MONTHPAT = MONTHS.keys.join('|') - DAYPAT = 'mon|tue|wed|thu|fri|sat|sun' + DAYS = { + 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, + 'thu' => 4, 'fri' => 5, 'sat' => 6 } + DAYPAT = DAYS.keys.join('|') def parsedate(date) - if date.sub!(/(#{DAYPAT})/i, ' ') - dayofweek = $1 + # part of ISO 8601 + # yyyy-mm-dd | yyyy-mm | yyyy + # date hh:mm:ss | date Thh:mm:ss + if date =~ /^(\d\d\d\d)-?(?:(\d\d)-?(\d\d)?)? *T?(?:(\d\d):?(\d\d):?(\d\d)?)?$/ + return $1.to_i, + if $2 then $2.to_i else 1 end, + if $3 then $3.to_i else 1 end, + if $4 then $4.to_i end, + if $5 then $5.to_i end, + if $6 then $6.to_i end, + nil, + nil end - if date.sub!(/\s+(\d+:\d+(:\d+)?)/, ' ') - time = $1 + date = date.dup + if date.sub!(/(#{DAYPAT})[a-z]*,?/i, ' ') + wday = DAYS[$1.downcase] end - if date =~ /19(\d\d)/ - year = Integer($1) + if date.sub!(/(\d+):(\d+)(?::(\d+))?\s*(am|pm)?\s*(?:\s+([a-z]{1,4}(?:\s+[a-z]{1,4})?|[-+]\d{4}))?/i, ' ') + hour = $1.to_i + min = $2.to_i + if $3 + sec = $3.to_i + end + if $4 == 'pm' + hour += 12 + end + if $5 + zone = $5 + end end - if date.sub!(/\s*(\d+)\s+(#{MONTHPAT})\S*\s+/i, ' ') - dayofmonth = $1.to_i - monthname = $2 - elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\s+/i, ' ') - monthname = $1 - dayofmonth = $2.to_i - elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\D+/i, ' ') - monthname = $1 - dayofmonth = $2.to_i - elsif date.sub!(/\s*(\d\d?)\/(\d\d?)/, ' ') - month = $1 - dayofmonth = $2.to_i + if date.sub!(/(\d+)\S*\s+(#{MONTHPAT})\S*(?:\s+(\d+))?/i, ' ') + mday = $1.to_i + mon = MONTHS[$2.downcase] + if $3 + year = $3.to_i + end + elsif date.sub!(/(#{MONTHPAT})\S*\s+(\d+)\S*\s*,?(?:\s+(\d+))?/i, ' ') + mon = MONTHS[$1.downcase] + mday = $2.to_i + if $3 + year = $3.to_i + end + elsif date.sub!(/(\d+)\/(\d+)(?:\/(\d+))/, ' ') + mon = $1.to_i + mday = $2.to_i + if $3 + year = $3.to_i + end end - if monthname - month = MONTHS[monthname.downcase] - end - if ! year && date =~ /\d\d/ - year = Integer($&) - end - return year, month, dayofmonth + return year, mon, mday, hour, min, sec, zone, wday end module_function :parsedate end + +if __FILE__ == $0 + p Time.now.asctime + p ParseDate.parsedate(Time.now.asctime) +end diff --git a/lib/ping.rb b/lib/ping.rb index d742a50f99..065b1d2303 100644 --- a/lib/ping.rb +++ b/lib/ping.rb @@ -26,6 +26,10 @@ # # The timeout in seconds. If not specified it will default to 5 seconds. # +# : service +# +# The service port to connect. The default is "echo". +# #= WARNING # # pingecho() uses user-level thread to implement the timeout, so it may block @@ -33,23 +37,26 @@ # #=end +require 'timeout' + module Ping require "socket" - def pingecho(host, timeout=5) + def pingecho(host, timeout=5, service="echo") begin - x = Thread.current - y = Thread.start { - sleep timeout - x.raise RuntimeError if x.status - } - s = TCPsocket.new(host, "echo") - s.close - return TRUE + timeout(timeout) do + s = TCPsocket.new(host, service) + s.close + end rescue - return FALSE; - ensure - Thread.kill y if y.status + return false end + return true end - module_function "pingecho" + module_function :pingecho +end + +if $0 == __FILE__ + host = ARGV[0] + host ||= "localhost" + printf("%s alive? - %s\n", host, Ping::pingecho(host, 5)) end diff --git a/lib/pstore.rb b/lib/pstore.rb index 86f086d226..2aa9864b58 100644 --- a/lib/pstore.rb +++ b/lib/pstore.rb @@ -1,5 +1,4 @@ -#!/usr/local/bin/ruby - +# # How to use: # # db = PStore.new("/tmp/foo") @@ -16,7 +15,8 @@ require "marshal" class PStore - Exception(:Error) + class Error < StandardError + end def initialize(file) dir = File::dirname(file) @@ -89,33 +89,46 @@ class PStore catch(:pstore_abort_transaction) do value = yield(self) end + rescue Exception + @abort = true + raise ensure unless @abort - File::rename @filename, @filename+"~" + begin + File::rename @filename, @filename+"~" + rescue Errno::ENOENT + no_orig = true + end begin File::open(@filename, "w") do |file| Marshal::dump(@table, file) end rescue - File::rename @filename+"~", @filename + File::rename @filename+"~", @filename unless no_orig end end @abort = false end ensure + @table = nil @transaction = false end value end end -db = PStore.new("/tmp/foo") -db.transaction do - p db.roots - ary = db["root"] = [1,2,3,4] - ary[0] = [1,1.5] -end +if __FILE__ == $0 + db = PStore.new("/tmp/foo") + db.transaction do + p db.roots + ary = db["root"] = [1,2,3,4] + ary[1] = [1,1.5] + end -db.transaction do - p db["root"] + 1000.times do + db.transaction do + db["root"][0] += 1 + p db["root"][0] + end + end end diff --git a/lib/rational.rb b/lib/rational.rb index d4112c2956..1282f56410 100644 --- a/lib/rational.rb +++ b/lib/rational.rb @@ -1,8 +1,8 @@ # # rational.rb - # $Release Version: 0.5 $ -# $Revision: 1.1 $ -# $Date: 1996/11/11 04:25:14 $ +# $Revision: 1.3 $ +# $Date: 1998/03/11 14:09:03 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # -- @@ -44,7 +44,11 @@ def Rational(a, b = 1) end class Rational < Numeric + @RCS_ID='-$Id: rational.rb,v 1.3 1998/03/11 14:09:03 keiju Exp keiju $-' + def Rational.reduce(num, den = 1) + raise ZeroDivisionError, "denometor is 0" if den == 0 + if den < 0 num = -num den = -den @@ -128,6 +132,7 @@ class Rational < Numeric den = @denominator * a.numerator Rational(num, den) elsif a.kind_of?(Integer) + raise ZeroDivisionError, "devided by 0" if a == 0 self / Rational.new!(a, 1) elsif a.kind_of?(Float) Float(self) / a diff --git a/lib/shellwords.rb b/lib/shellwords.rb index 9632f1222a..9154cd84c1 100644 --- a/lib/shellwords.rb +++ b/lib/shellwords.rb @@ -18,21 +18,19 @@ module Shellwords while line != '' field = '' while TRUE - if line.sub! /^"(([^"\\]|\\.)*)"/, '' then + if line.sub! /^"(([^"\\]|\\.)*)"/, '' then #" snippet = $1 snippet.gsub! /\\(.)/, '\1' - elsif line =~ /^"/ then - STDOUT.print "Unmatched double quote: $_\n" - exit - elsif line.sub! /^'(([^'\\]|\\.)*)'/, '' then + elsif line =~ /^"/ then #" + raise ArgError, "Unmatched double quote: #{line}" + elsif line.sub! /^'(([^'\\]|\\.)*)'/, '' then #' snippet = $1 snippet.gsub! /\\(.)/, '\1' - elsif line =~ /^'/ then - STDOUT.print "Unmatched single quote: $_\n" - exit + elsif line =~ /^'/ then #' + raise ArgError, "Unmatched single quote: #{line}" elsif line.sub! /^\\(.)/, '' then snippet = $1 - elsif line.sub! /^([^\s\\'"]+)/, '' then + elsif line.sub! /^([^\s\\'"]+)/, '' then #' snippet = $1 else line.sub! /^\s+/, '' diff --git a/lib/sync.rb b/lib/sync.rb index b5a3fc32b3..9f9706d9ee 100644 --- a/lib/sync.rb +++ b/lib/sync.rb @@ -4,6 +4,7 @@ # $Revision$ # $Date$ # by Keiju ISHITSUKA +# modified by matz # # -- # Sync_m, Synchronizer_m @@ -43,7 +44,7 @@ unless defined? Thread fail "Thread not available for this ruby interpreter" end -require "finalize" +require "final" module Sync_m RCS_ID='-$Header$-' @@ -54,7 +55,7 @@ module Sync_m EX = :EX # Îăł°ÄęµÁ - class Err < Exception + class Err < StandardError def Err.Fail(*opt) fail self, sprintf(self::Message, *opt) end @@ -296,8 +297,8 @@ module Sync_m private :sync_try_lock_sub def sync_synchronize(mode = EX) + sync_lock(mode) begin - sync_lock(mode) yield ensure sync_unlock @@ -321,7 +322,11 @@ module Sync_m def For_primitive_object.extend_object(obj) super obj.sync_extended - Finalizer.add(obj, For_primitive_object, :sync_finalize) + # Changed to use `final.rb'. + # Finalizer.add(obj, For_primitive_object, :sync_finalize) + ObjectSpace.define_finalizer(obj) do |id| + For_primitive_object.sync_finalize(id) + end end def initialize diff --git a/lib/thread.rb b/lib/thread.rb index 4f294cc9a3..ec75144374 100644 --- a/lib/thread.rb +++ b/lib/thread.rb @@ -9,14 +9,20 @@ unless defined? Thread end unless defined? ThreadError - class ThreadError<Exception + class ThreadError<StandardError end end +if $DEBUG + Thread.abort_on_exception = true +end + class Mutex def initialize @waiting = [] - @locked = FALSE; + @locked = false; + @waiting.taint # enable tainted comunication + self.taint end def locked? @@ -24,42 +30,39 @@ class Mutex end def try_lock - result = FALSE - Thread.critical = TRUE + result = false + Thread.critical = true unless @locked - @locked = TRUE - result = TRUE + @locked = true + result = true end - Thread.critical = FALSE + Thread.critical = false result end def lock - while (Thread.critical = TRUE; @locked) + while (Thread.critical = true; @locked) @waiting.push Thread.current Thread.stop end - @locked = TRUE - Thread.critical = FALSE + @locked = true + Thread.critical = false self end def unlock return unless @locked Thread.critical = TRUE - wait = @waiting - @waiting = [] + t = @waiting.shift @locked = FALSE Thread.critical = FALSE - for w in wait - w.run - end + t.run if t self end def synchronize + lock begin - lock yield ensure unlock @@ -67,37 +70,74 @@ class Mutex end end +class ConditionVariable + def initialize + @waiters = [] + @waiters_mutex = Mutex.new + @waiters.taint # enable tainted comunication + self.taint + end + + def wait(mutex) + mutex.unlock + @waiters_mutex.synchronize { + @waiters.push(Thread.current) + } + Thread.stop + mutex.lock + end + + def signal + @waiters_mutex.synchronize { + t = @waiters.shift + t.run if t + } + end + + def broadcast + @waiters_mutex.synchronize { + for t in @waiters + t.run + end + @waiters.clear + } + end +end + class Queue def initialize @que = [] @waiting = [] + @que.taint # enable tainted comunication + @waiting.taint + self.taint end def push(obj) - Thread.critical = TRUE + Thread.critical = true @que.push obj t = @waiting.shift - Thread.critical = FALSE + Thread.critical = false t.run if t end - def pop non_block=FALSE - item = nil - until item - Thread.critical = TRUE - if @que.length == 0 - if non_block - Thread.critical = FALSE - raise ThreadError, "queue empty" + def pop non_block=false + Thread.critical = true + begin + loop do + if @que.length == 0 + if non_block + raise ThreadError, "queue empty" + end + @waiting.push Thread.current + Thread.stop + else + return @que.shift end - @waiting.push Thread.current - Thread.stop - else - item = @que.shift end + ensure + Thread.critical = false end - Thread.critical = FALSE - item end def empty? @@ -107,4 +147,63 @@ class Queue def length @que.length end + alias size length + + + def num_waiting + @waiting.size + end +end + +class SizedQueue<Queue + def initialize(max) + @max = max + @queue_wait = [] + @queue_wait.taint # enable tainted comunication + super() + end + + def max + @max + end + + def max=(max) + Thread.critical = TRUE + if @max >= max + @max = max + Thread.critical = FALSE + else + diff = max - @max + @max = max + Thread.critical = FALSE + diff.times do + t = @queue_wait.shift + t.run if t + end + end + max + end + + def push(obj) + Thread.critical = true + while @que.length >= @max + @queue_wait.push Thread.current + Thread.stop + Thread.critical = true + end + super + end + + def pop(*args) + Thread.critical = true + if @que.length < @max + t = @queue_wait.shift + t.run if t + end + super + end + + def num_waiting + @waiting.size + @queue_wait.size + end end diff --git a/lib/thwait.rb b/lib/thwait.rb index c638335f5d..958163edef 100644 --- a/lib/thwait.rb +++ b/lib/thwait.rb @@ -1,34 +1,53 @@ # -# thwait.rb - -# $Release Version: $ -# $Revision: 1.1 $ -# $Date: 1997/08/18 03:13:14 $ -# by Keiju ISHITSUKA(Nippon Rational Inc.) +# thwait.rb - thread synchronization class +# $Release Version: 0.9 $ +# $Revision: 1.3 $ +# $Date: 1998/06/26 03:19:34 $ +# by Keiju ISHITSUKA(Nihpon Rational Software Co.,Ltd.) # # -- +# feature: +# provides synchronization for multiple threads. # -# +# class methods: +# * ThreadsWait.all_waits(thread1,...) +# waits until all of specified threads are terminated. +# if a block is supplied for the method, evaluates it for +# each thread termination. +# * th = ThreadsWait.new(thread1,...) +# creates synchronization object, specifying thread(s) to wait. +# +# methods: +# * th.threads +# list threads to be synchronized +# * th.empty? +# is there any thread to be synchronized. +# * th.finished? +# is there already terminated thread. +# * th.join(thread1,...) +# wait for specified thread(s). +# * th.join_nowait(threa1,...) +# specifies thread(s) to wait. non-blocking. +# * th.next_wait +# waits until any of specified threads is terminated. +# * th.all_waits +# waits until all of specified threads are terminated. +# if a block is supplied for the method, evaluates it for +# each thread termination. # require "thread.rb" require "e2mmap.rb" class ThreadsWait - RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/thwait.rb,v 1.1 1997/08/18 03:13:14 keiju Exp keiju $-' + RCS_ID='-$Id: thwait.rb,v 1.3 1998/06/26 03:19:34 keiju Exp keiju $-' Exception2MessageMapper.extend_to(binding) - def_exception("ErrWaitThreadsNothing", "Wait threads nothing.") - def_exception("FinshedThreadsNothing", "finished thread nothing.") + def_exception("ErrNoWaitingThread", "No threads for waiting.") + def_exception("ErrNoFinshedThread", "No finished threads.") - # class mthods - # all_waits - - # - # »ŘÄꤷ¤żĄąĄěĄĂĄÉ¤¬Á´¤Ć˝ŞÎ»¤ą¤ë¤Ţ¤ÇÂÔ¤Ä. Ą¤ĄĆĄěˇĽĄż¤Č¤·¤Ć¸Ć¤Đ¤ě¤ë¤Č - # »ŘÄꤷ¤żĄąĄěĄĂĄÉ¤¬˝ŞÎ»¤ą¤ë¤ČĄ¤ĄĆĄěˇĽĄż¤ň¸Ć¤Ó˝Đ¤ą. - # def ThreadsWait.all_waits(*threads) - tw = ThreadsWait.new(th1, th2, th3, th4, th5) + tw = ThreadsWait.new(*threads) if iterator? tw.all_waits do |th| @@ -39,12 +58,6 @@ class ThreadsWait end end - # initialize and terminating: - # initialize - - # - # ˝é´ü˛˝. ÂԤĥąĄěĄĂĄÉ¤Î»ŘÄ꤬¤Ç¤­¤ë. - # def initialize(*threads) @threads = [] @wait_queue = Queue.new @@ -52,24 +65,19 @@ class ThreadsWait end # accessing - # threads - - # ÂÔ¤ÁĄąĄěĄĂĄÉ¤Î°ěÍ÷¤ňĘÖ¤ą. + # threads - list threads to be synchronized attr :threads # testing # empty? # finished? - # - - # - # ÂÔ¤ÁĄąĄěĄĂĄÉ¤¬Â¸şß¤ą¤ë¤«¤É¤¦¤«¤ňĘÖ¤ą. + + # is there any thread to be synchronized. def empty? @threads.empty? end - # - # ¤ą¤Ç¤Ë˝ŞÎ»¤·¤żĄąĄěĄĂĄÉ¤¬¤˘¤ë¤«¤É¤¦¤«ĘÖ¤ą + # is there already terminated thread. def finished? !@wait_queue.empty? end @@ -80,45 +88,40 @@ class ThreadsWait # next_wait # all_wait - # - # ÂԤäƤ¤¤ëĄąĄěĄĂĄÉ¤ňÄɲä·ÂÔ¤Á¤Ë¤Ď¤¤¤ë. - # + # adds thread(s) to join, waits for any of waiting threads to terminate. def join(*threads) join_nowait(*threads) next_wait end - # - # ÂԤäƤ¤¤ëĄąĄěĄĂĄÉ¤ňÄɲ乤ë. ÂÔ¤Á¤Ë¤ĎĆţ¤é¤Ę¤¤. - # + # adds thread(s) to join, no wait. def join_nowait(*threads) @threads.concat threads for th in threads Thread.start do - th = Thread.join(th) + th = th.join @wait_queue.push th end end end - # - # Ľˇ¤ÎÂÔ¤Á¤Ë¤Ď¤¤¤ë. - # ÂԤĤ٤­ĄąĄěĄĂĄÉ¤¬¤Ę¤±¤ě¤Đ, Îăł°ErrWaitThreadsNothing ¤ňĘÖ¤ą. - # nonnlock¤¬żż¤Î»ţ¤Ë¤Ď, nonblocking¤ÇÄ´¤Ů¤ë. ¸şß¤·¤Ę¤±¤ě¤Đ, Îăł° - # FinishedThreadNothing¤ňĘÖ¤ą. - # + # waits for any of waiting threads to terminate + # if there is no thread to wait, raises ErrNoWaitingThread. + # if `nonblock' is true, and there is no terminated thread, + # raises ErrNoFinishedThread. def next_wait(nonblock = nil) - Threads.Wait.fail ErrWaitThreadsNothing if @threads.empty? - - th = @wait_queue.pop(nonblock) - @threads.delete th - th + ThreadsWait.fail ErrNoWaitingThread if @threads.empty? + begin + @threads.delete(th = @wait_queue.pop(nonblock)) + th + rescue ThreadError + ThreadsWait.fail ErrNoFinshedThread + end end - # - # Á´¤Ć¤ÎĄąĄěĄĂĄÉ¤¬˝ŞÎ»¤ą¤ë¤Ţ¤ÇÂÔ¤Ä. Ą¤ĄĆĄěˇĽĄż¤Č¤·¤Ć¸Ć¤Đ¤ě¤ż»ţ¤Ď, Ąą - # ĄěĄĂĄÉ¤¬˝ŞÎ»¤ą¤ëĹ٤Ë, Ą¤ĄĆĄěˇĽĄż¤ň¸Ć¤Ó˝Đ¤ą. - # + # waits until all of specified threads are terminated. + # if a block is supplied for the method, evaluates it for + # each thread termination. def all_waits until @threads.empty? th = next_wait @@ -126,3 +129,5 @@ class ThreadsWait end end end + +ThWait = ThreadsWait diff --git a/lib/tracer.rb b/lib/tracer.rb index d37339fd62..fbfca24fe5 100644 --- a/lib/tracer.rb +++ b/lib/tracer.rb @@ -1,7 +1,28 @@ +# +# tracer.rb - +# $Release Version: 0.2$ +# $Revision: 1.8 $ +# $Date: 1998/05/19 03:42:49 $ +# by Keiju ISHITSUKA(Nippon Rational Inc.) +# +# -- +# +# +# + +# +# tracer main class +# class Tracer - MY_FILE_NAME_PATTERN = /^tracer\.(rb)?/ - Threads = Hash.new - Sources = Hash.new + @RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-' + + class << self + attr :verbose, TRUE + alias verbose? verbose + end + verbose = TRUE + + MY_FILE_NAME = caller(0)[0].scan(/^(.*):[0-9]+$/)[0][0] EVENT_SYMBOL = { "line" => "-", @@ -10,39 +31,89 @@ class Tracer "class" => "C", "end" => "E"} + def initialize + @threads = Hash.new + if defined? Thread.main + @threads[Thread.main.id] = 0 + else + @threads[Thread.current.id] = 0 + end + + @get_line_procs = {} + @sources = {} + + @filters = [] + end + def on - set_trace_func proc{|event, file, line, id, binding| - trace_func event, file, line, id, binding - } - print "Trace on\n" + if iterator? + on + begin + yield + ensure + off + end + else + set_trace_func proc{|event, file, line, id, binding| + trace_func event, file, line, id, binding + } + print "Trace on\n" if Tracer.verbose? + end end def off set_trace_func nil - print "Trace off\n" + print "Trace off\n" if Tracer.verbose? end - - def get_thread_no - unless no = Threads[Thread.current.id] - Threads[Thread.current.id] = no = Threads.size - end - no + + def add_filter(p = proc) + @filters.push p + end + + def set_get_line_procs(file, p = proc) + @get_line_procs[file] = p end def get_line(file, line) - unless list = Sources[file] - f =open(file) - begin - Sources[file] = list = f.readlines - ensure - f.close + if p = @get_line_procs[file] + return p.call line + end + + unless list = @sources[file] +# print file if $DEBUG + begin + f = open(file) + begin + @sources[file] = list = f.readlines + ensure + f.close + end + rescue + @sources[file] = list = [] end end - list[line - 1] + if l = list[line - 1] + l + else + "-\n" + end + end + + def get_thread_no + if no = @threads[Thread.current.id] + no + else + @threads[Thread.current.id] = @threads.size + end end def trace_func(event, file, line, id, binding) - return if File.basename(file) =~ MY_FILE_NAME_PATTERN + return if file == MY_FILE_NAME + #printf "Th: %s\n", Thread.current.inspect + + for p in @filters + return unless p.call event, file, line, id, binding + end Thread.critical = TRUE printf("#%d:%s:%d:%s: %s", @@ -56,20 +127,36 @@ class Tracer Single = new def Tracer.on - Single.on + if iterator? + Single.on{yield} + else + Single.on + end end def Tracer.off Single.off end -end + def Tracer.set_get_line_procs(file_name, p = proc) + Single.set_get_line_procs(file_name, p) + end -if File.basename($0) =~ Tracer::MY_FILE_NAME_PATTERN - $0 = ARGV.shift + def Tracer.add_filter(p = proc) + Single.add_filter(p) + end - Tracer.on - load $0 -else - Tracer.on +end + +if caller(0).size == 1 + if $0 == Tracer::MY_FILE_NAME + # direct call + + $0 = ARGV[0] + ARGV.shift + Tracer.on + require $0 + else + Tracer.on + end end diff --git a/lib/weakref.rb b/lib/weakref.rb index 93b2c65ecd..c31e959e74 100644 --- a/lib/weakref.rb +++ b/lib/weakref.rb @@ -10,9 +10,10 @@ require "delegate" -class WeakRef<Delegater +class WeakRef<Delegator - Exception :RefError + class RefError<StandardError + end ID_MAP = {} ID_REV_MAP = {} @@ -31,26 +32,22 @@ class WeakRef<Delegater def initialize(orig) super - @id = orig.id + @__id = orig.__id__ ObjectSpace.call_finalizer orig - ID_MAP[@id] = self.id - ID_REV_MAP[self.id] = @id + ObjectSpace.call_finalizer self + ID_MAP[@__id] = self.__id__ + ID_REV_MAP[self.id] = @__id end def __getobj__ - unless ID_MAP[@id] - $@ = caller(1) - $! = RefError.new("Illegal Reference - probably recycled") - raise + unless ID_MAP[@__id] + raise RefError, "Illegal Reference - probably recycled", caller(2) end - ObjectSpace.id2ref(@id) -# ObjectSpace.each_object do |obj| -# return obj if obj.id == @id -# end + ObjectSpace._id2ref(@__id) end def weakref_alive? - if ID_MAP[@id] + if ID_MAP[@__id] true else false @@ -62,9 +59,11 @@ class WeakRef<Delegater end end -foo = Object.new -p foo.hash -foo = WeakRef.new(foo) -p foo.hash -ObjectSpace.garbage_collect -p foo.hash +if __FILE__ == $0 + foo = Object.new + p foo.hash # original's hash value + foo = WeakRef.new(foo) + p foo.hash # should be same hash value + ObjectSpace.garbage_collect + p foo.hash # should raise exception (recycled) +end diff --git a/main.c b/main.c index 4741f646e8..5fd27cba4c 100644 --- a/main.c +++ b/main.c @@ -30,4 +30,5 @@ main(argc, argv, envp) ruby_init(); ruby_options(argc, argv); ruby_run(); + return 0; } diff --git a/marshal.c b/marshal.c index ac95e438ae..6a68b04352 100644 --- a/marshal.c +++ b/marshal.c @@ -3,14 +3,13 @@ marshal.c - $Author$ - $Revision$ $Date$ created at: Thu Apr 27 16:30:01 JST 1995 ************************************************/ #include "ruby.h" -#include "io.h" +#include "rubyio.h" #include "st.h" #define MARSHAL_MAJOR 4 @@ -38,12 +37,7 @@ #define TYPE_LINK '@' -extern VALUE cString; -extern VALUE cRegexp; -extern VALUE cArray; -extern VALUE cHash; - -VALUE rb_path2class(); +VALUE rb_path2class _((char*)); static ID s_dump, s_load; @@ -69,7 +63,7 @@ w_byte(c, arg) struct dump_arg *arg; { if (arg->fp) putc(c, arg->fp); - else str_cat(arg->str, (UCHAR*)&c, 1); + else rb_str_cat(arg->str, &c, 1); } static void @@ -83,7 +77,7 @@ w_bytes(s, n, arg) fwrite(s, 1, n, arg->fp); } else { - str_cat(arg->str, s, n); + rb_str_cat(arg->str, s, n); } } @@ -94,7 +88,7 @@ w_short(x, arg) { int i; - for (i=0; i<sizeof(USHORT); i++) { + for (i=0; i<sizeof(short); i++) { w_byte((x >> (i*8)) & 0xff, arg); } } @@ -155,7 +149,7 @@ w_symbol(id, arg) else { w_byte(TYPE_SYMBOL, arg); w_bytes(sym, strlen(sym), arg); - st_insert(arg->symbol, id, arg->symbol->num_entries); + st_add_direct(arg->symbol, id, arg->symbol->num_entries); } } @@ -168,10 +162,9 @@ w_unique(s, arg) } static void w_object _((VALUE,struct dump_arg*,int)); -extern VALUE cIO, cBignum, cStruct; static int -hash_each(key, value, arg) +rb_hash_each(key, value, arg) VALUE key, value; struct dump_call_arg *arg; { @@ -181,7 +174,7 @@ hash_each(key, value, arg) } static int -obj_each(id, value, arg) +rb_obj_each(id, value, arg) ID id; VALUE value; struct dump_call_arg *arg; @@ -192,11 +185,11 @@ obj_each(id, value, arg) } static void -w_uclass(obj, class, arg) - VALUE obj, class; +w_uclass(obj, klass, arg) + VALUE obj, klass; struct dump_arg *arg; { - if (CLASS_OF(obj) != class) { + if (CLASS_OF(obj) != klass) { w_byte(TYPE_UCLASS, arg); w_unique(rb_class2name(CLASS_OF(obj)), arg); } @@ -208,23 +201,18 @@ w_object(obj, arg, limit) struct dump_arg *arg; int limit; { - int n; struct dump_call_arg c_arg; if (limit == 0) { - Fail("exceed depth limit"); + rb_raise(rb_eRuntimeError, "exceed depth limit"); } - limit--; - c_arg.limit = limit; - c_arg.arg = arg; - if (obj == Qnil) { w_byte(TYPE_NIL, arg); } - else if (obj == TRUE) { + else if (obj == Qtrue) { w_byte(TYPE_TRUE, arg); } - else if (obj == FALSE) { + else if (obj == Qfalse) { w_byte(TYPE_FALSE, arg); } else if (FIXNUM_P(obj)) { @@ -232,26 +220,30 @@ w_object(obj, arg, limit) w_byte(TYPE_FIXNUM, arg); w_long(FIX2INT(obj), arg); #else - if (RSHIFT(obj, 32) == 0 || RSHIFT(obj, 32) == -1) { + if (RSHIFT((long)obj, 32) == 0 || RSHIFT((long)obj, 32) == -1) { w_byte(TYPE_FIXNUM, arg); - w_long(FIX2INT(obj), arg); + w_long(FIX2LONG(obj), arg); } else { - obj = int2big(FIX2INT(obj)); - goto write_bignum; + w_object(rb_int2big(FIX2LONG(obj)), arg, limit); + return; } #endif } else { int num; + limit--; + c_arg.limit = limit; + c_arg.arg = arg; + if (st_lookup(arg->data, obj, &num)) { w_byte(TYPE_LINK, arg); w_long(num, arg); return; } - st_insert(arg->data, obj, arg->data->num_entries); + st_add_direct(arg->data, obj, arg->data->num_entries); if (rb_respond_to(obj, s_dump)) { VALUE v; @@ -259,7 +251,7 @@ w_object(obj, arg, limit) w_unique(rb_class2name(CLASS_OF(obj)), arg); v = rb_funcall(obj, s_dump, 1, limit); if (TYPE(v) != T_STRING) { - TypeError("_dump_to must return String"); + rb_raise(rb_eTypeError, "_dump_to must return String"); } w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg); return; @@ -281,12 +273,11 @@ w_object(obj, arg, limit) return; case T_BIGNUM: - write_bignum: w_byte(TYPE_BIGNUM, arg); { char sign = RBIGNUM(obj)->sign?'+':'-'; int len = RBIGNUM(obj)->len; - USHORT *d = RBIGNUM(obj)->digits; + unsigned short *d = RBIGNUM(obj)->digits; w_byte(sign, arg); w_long(len, arg); @@ -298,20 +289,20 @@ w_object(obj, arg, limit) return; case T_STRING: - w_uclass(obj, cString, arg); + w_uclass(obj, rb_cString, arg); w_byte(TYPE_STRING, arg); w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, arg); return; case T_REGEXP: - w_uclass(obj, cRegexp, arg); + w_uclass(obj, rb_cRegexp, arg); w_byte(TYPE_REGEXP, arg); w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg); - w_byte(FL_TEST(obj, FL_USER1), arg); + w_byte(rb_reg_options(obj), arg); return; case T_ARRAY: - w_uclass(obj, cArray, arg); + w_uclass(obj, rb_cArray, arg); w_byte(TYPE_ARRAY, arg); { int len = RARRAY(obj)->len; @@ -326,10 +317,10 @@ w_object(obj, arg, limit) break; case T_HASH: - w_uclass(obj, cHash, arg); + w_uclass(obj, rb_cHash, arg); w_byte(TYPE_HASH, arg); w_long(RHASH(obj)->tbl->num_entries, arg); - st_foreach(RHASH(obj)->tbl, hash_each, &c_arg); + st_foreach(RHASH(obj)->tbl, rb_hash_each, &c_arg); break; case T_STRUCT: @@ -344,10 +335,10 @@ w_object(obj, arg, limit) w_long(len, arg); mem = rb_ivar_get(CLASS_OF(obj), rb_intern("__member__")); if (mem == Qnil) { - Fatal("non-initialized struct"); + rb_raise(rb_eTypeError, "non-initialized struct"); } for (i=0; i<len; i++) { - w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), arg); + w_symbol(FIX2LONG(RARRAY(mem)->ptr[i]), arg); w_object(RSTRUCT(obj)->ptr[i], arg, limit); } } @@ -356,17 +347,17 @@ w_object(obj, arg, limit) case T_OBJECT: w_byte(TYPE_OBJECT, arg); { - VALUE class = CLASS_OF(obj); + VALUE klass = CLASS_OF(obj); char *path; - if (FL_TEST(class, FL_SINGLETON)) { - TypeError("singleton can't be dumped"); + if (FL_TEST(klass, FL_SINGLETON)) { + rb_raise(rb_eTypeError, "singleton can't be dumped"); } - path = rb_class2name(class); + path = rb_class2name(klass); w_unique(path, arg); if (ROBJECT(obj)->iv_tbl) { w_long(ROBJECT(obj)->iv_tbl->num_entries, arg); - st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &c_arg); + st_foreach(ROBJECT(obj)->iv_tbl, rb_obj_each, &c_arg); } else { w_long(0, arg); @@ -375,7 +366,8 @@ w_object(obj, arg, limit) break; default: - TypeError("can't dump %s", rb_class2name(CLASS_OF(obj))); + rb_raise(rb_eTypeError, "can't dump %s", + rb_class2name(CLASS_OF(obj))); break; } } @@ -386,6 +378,7 @@ dump(arg) struct dump_call_arg *arg; { w_object(arg->obj, arg->arg, arg->limit); + return 0; } static VALUE @@ -394,6 +387,7 @@ dump_ensure(arg) { st_free_table(arg->symbol); st_free_table(arg->data); + return 0; } static VALUE @@ -403,7 +397,6 @@ marshal_dump(argc, argv) { VALUE obj, port, a1, a2; int limit = -1; - extern VALUE cIO; struct dump_arg arg; struct dump_call_arg c_arg; @@ -418,21 +411,21 @@ marshal_dump(argc, argv) else port = a1; } if (port) { - if (obj_is_kind_of(port, cIO)) { + if (rb_obj_is_kind_of(port, rb_cIO)) { OpenFile *fptr; - io_binmode(port); + rb_io_binmode(port); GetOpenFile(port, fptr); - io_writable(fptr); + rb_io_check_writable(fptr); arg.fp = (fptr->f2) ? fptr->f2 : fptr->f; } else { - TypeError("instance of IO needed"); + rb_raise(rb_eTypeError, "instance of IO needed"); } } else { arg.fp = 0; - port = str_new(0, 0); + port = rb_str_new(0, 0); arg.str = port; } @@ -445,14 +438,14 @@ marshal_dump(argc, argv) w_byte(MARSHAL_MAJOR, &arg); w_byte(MARSHAL_MINOR, &arg); - rb_ensure(dump, &c_arg, dump_ensure, &arg); + rb_ensure(dump, (VALUE)&c_arg, dump_ensure, (VALUE)&arg); return port; } struct load_arg { FILE *fp; - UCHAR *ptr, *end; + char *ptr, *end; st_table *symbol; st_table *data; VALUE proc; @@ -463,19 +456,19 @@ r_byte(arg) struct load_arg *arg; { if (arg->fp) return getc(arg->fp); - if (arg->ptr < arg->end) return *arg->ptr++; + if (arg->ptr < arg->end) return *(unsigned char*)arg->ptr++; return EOF; } -static USHORT +static unsigned short r_short(arg) struct load_arg *arg; { - USHORT x; + unsigned short x; int i; x = 0; - for (i=0; i<sizeof(USHORT); i++) { + for (i=0; i<sizeof(short); i++) { x |= r_byte(arg)<<(i*8); } @@ -486,16 +479,17 @@ static void long_toobig(size) int size; { - TypeError("long too big for this architecture (size %d, given %d)", - sizeof(long), size); + rb_raise(rb_eTypeError, "long too big for this architecture (size %d, given %d)", + sizeof(long), size); } static long r_long(arg) struct load_arg *arg; { - int c = r_byte(arg), i; register long x; + int c = (char)r_byte(arg); + int i; if (c == 0) return 0; if (c > 0) { @@ -505,7 +499,7 @@ r_long(arg) x |= (long)r_byte(arg) << (8*i); } } - else if (c < 0) { + else { c = -c; if (c > sizeof(long)) long_toobig((int)c); x = -1; @@ -517,12 +511,20 @@ r_long(arg) return x; } -#define r_bytes(s, arg) \ - (s = (char*)r_long(arg), r_bytes0(&s,ALLOCA_N(char,(long)s),(long)s,arg)) +#define r_bytes2(s, len, arg) do { \ + (len) = r_long(arg); \ + (s) = ALLOCA_N(char,(len)+1); \ + r_bytes0((s),(len),(arg)); \ +} while (0) -static int -r_bytes0(sp, s, len, arg) - char **sp, *s; +#define r_bytes(s, arg) do { \ + int r_bytes_len; \ + r_bytes2((s), r_bytes_len, (arg)); \ +} while (0) + +static void +r_bytes0(s, len, arg) + char *s; int len; struct load_arg *arg; { @@ -536,11 +538,7 @@ r_bytes0(sp, s, len, arg) memcpy(s, arg->ptr, len); arg->ptr += len; } - - (s)[len] = '\0'; - *sp = s; - - return len; + s[len] = '\0'; } static ID @@ -549,7 +547,6 @@ r_symbol(arg) { char *buf; ID id; - char type; if (r_byte(arg) == TYPE_SYMLINK) { int num = r_long(arg); @@ -557,7 +554,7 @@ r_symbol(arg) if (st_lookup(arg->symbol, num, &id)) { return id; } - TypeError("bad symbol"); + rb_raise(rb_eTypeError, "bad symbol"); } r_bytes(buf, arg); id = rb_intern(buf); @@ -578,9 +575,10 @@ r_string(arg) struct load_arg *arg; { char *buf; - int len = r_bytes(buf, arg); + int len; - return str_taint(str_new(buf, len)); + r_bytes2(buf, len, arg); + return rb_str_new(buf, len); } static VALUE @@ -588,6 +586,7 @@ r_regist(v, arg) VALUE v; struct load_arg *arg; { + OBJ_TAINT(v); if (arg->proc) { rb_funcall(arg->proc, rb_intern("call"), 1, v); } @@ -604,14 +603,14 @@ r_object(arg) switch (type) { case EOF: - eof_error(); + rb_eof_error(); return Qnil; case TYPE_LINK: if (st_lookup(arg->data, r_long(arg), &v)) { return v; } - ArgError("dump format error (unlinked)"); + rb_raise(rb_eArgError, "dump format error (unlinked)"); break; case TYPE_UCLASS: @@ -619,9 +618,9 @@ r_object(arg) VALUE c = rb_path2class(r_unique(arg)); v = r_object(arg); if (rb_special_const_p(v)) { - ArgError("dump format error (user class)"); + rb_raise(rb_eArgError, "dump format error (user class)"); } - RBASIC(v)->class = c; + RBASIC(v)->klass = c; return v; } @@ -629,10 +628,10 @@ r_object(arg) return Qnil; case TYPE_TRUE: - return TRUE; + return Qtrue; case TYPE_FALSE: - return FALSE; + return Qfalse; case TYPE_FIXNUM: { @@ -648,26 +647,26 @@ r_object(arg) char *buf; r_bytes(buf, arg); - v = float_new(atof(buf)); + v = rb_float_new(atof(buf)); return r_regist(v, arg); } case TYPE_BIGNUM: { int len; - USHORT *digits; + unsigned short *digits; NEWOBJ(big, struct RBignum); - OBJSETUP(big, cBignum, T_BIGNUM); + OBJSETUP(big, rb_cBignum, T_BIGNUM); big->sign = (r_byte(arg) == '+'); big->len = len = r_long(arg); - big->digits = digits = ALLOC_N(USHORT, len); + big->digits = digits = ALLOC_N(unsigned short, len); while (len--) { *digits++ = r_short(arg); } - big = RBIGNUM(big_norm((VALUE)big)); + big = RBIGNUM(rb_big_norm((VALUE)big)); if (TYPE(big) == T_BIGNUM) { - r_regist(big, arg); + r_regist((VALUE)big, arg); } return (VALUE)big; } @@ -678,18 +677,21 @@ r_object(arg) case TYPE_REGEXP: { char *buf; - int len = r_bytes(buf, arg); - int ci = r_byte(arg); - return r_regist(reg_new(buf, len, ci), arg); + int len; + int options; + + r_bytes2(buf, len, arg); + options = r_byte(arg); + return r_regist(rb_reg_new(buf, len, options), arg); } case TYPE_ARRAY: { volatile int len = r_long(arg); - v = ary_new2(len); + v = rb_ary_new2(len); r_regist(v, arg); while (len--) { - ary_push(v, r_object(arg)); + rb_ary_push(v, r_object(arg)); } return v; } @@ -698,46 +700,46 @@ r_object(arg) { int len = r_long(arg); - v = hash_new(); + v = rb_hash_new(); r_regist(v, arg); while (len--) { VALUE key = r_object(arg); VALUE value = r_object(arg); - hash_aset(v, key, value); + rb_hash_aset(v, key, value); } return v; } case TYPE_STRUCT: { - VALUE class, mem, values; + VALUE klass, mem, values; volatile int i; /* gcc 2.7.2.3 -O2 bug?? */ int len; ID slot; - class = rb_path2class(r_unique(arg)); - mem = rb_ivar_get(class, rb_intern("__member__")); + klass = rb_path2class(r_unique(arg)); + mem = rb_ivar_get(klass, rb_intern("__member__")); if (mem == Qnil) { - Fatal("non-initialized struct"); + rb_raise(rb_eTypeError, "non-initialized struct"); } len = r_long(arg); - values = ary_new2(len); + values = rb_ary_new2(len); for (i=0; i<len; i++) { - ary_push(values, Qnil); + rb_ary_push(values, Qnil); } - v = struct_alloc(class, values); + v = rb_struct_alloc(klass, values); r_regist(v, arg); for (i=0; i<len; i++) { slot = r_symbol(arg); if (RARRAY(mem)->ptr[i] != INT2FIX(slot)) { - TypeError("struct %s not compatible (:%s for :%s)", - rb_class2name(class), - rb_id2name(slot), - rb_id2name(FIX2INT(RARRAY(mem)->ptr[i]))); + rb_raise(rb_eTypeError, "struct %s not compatible (:%s for :%s)", + rb_class2name(klass), + rb_id2name(slot), + rb_id2name(FIX2INT(RARRAY(mem)->ptr[i]))); } - struct_aset(v, INT2FIX(i), r_object(arg)); + rb_struct_aset(v, INT2FIX(i), r_object(arg)); } return v; } @@ -745,27 +747,26 @@ r_object(arg) case TYPE_USERDEF: { - VALUE class; - int len; + VALUE klass; - class = rb_path2class(r_unique(arg)); - if (rb_respond_to(class, s_load)) { - v = rb_funcall(class, s_load, 1, r_string(arg)); + klass = rb_path2class(r_unique(arg)); + if (rb_respond_to(klass, s_load)) { + v = rb_funcall(klass, s_load, 1, r_string(arg)); return r_regist(v, arg); } - TypeError("class %s needs to have method `_load_from'", - rb_class2name(class)); + rb_raise(rb_eTypeError, "class %s needs to have method `_load_from'", + rb_class2name(klass)); } break; case TYPE_OBJECT: { - VALUE class; + VALUE klass; int len; - class = rb_path2class(r_unique(arg)); + klass = rb_path2class(r_unique(arg)); len = r_long(arg); - v = obj_alloc(class); + v = rb_obj_alloc(klass); r_regist(v, arg); if (len > 0) { while (len--) { @@ -786,9 +787,10 @@ r_object(arg) } default: - ArgError("dump format error(0x%x)", type); + rb_raise(rb_eArgError, "dump format error(0x%x)", type); break; } + return Qnil; /* not reached */ } static VALUE @@ -804,6 +806,7 @@ load_ensure(arg) { st_free_table(arg->symbol); st_free_table(arg->data); + return 0; } static VALUE @@ -812,57 +815,57 @@ marshal_load(argc, argv) VALUE *argv; { VALUE port, proc; - FILE *fp; int major; VALUE v; OpenFile *fptr; struct load_arg arg; rb_scan_args(argc, argv, "11", &port, &proc); - if (TYPE(port) == T_STRING) { + if (rb_obj_is_kind_of(port, rb_cIO)) { + rb_io_binmode(port); + GetOpenFile(port, fptr); + rb_io_check_readable(fptr); + arg.fp = fptr->f; + } + else if (rb_respond_to(port, rb_intern("to_str"))) { + int len; + arg.fp = 0; - arg.ptr = RSTRING(port)->ptr; - arg.end = arg.ptr + RSTRING(port)->len; + arg.ptr = str2cstr(port, &len); + arg.end = arg.ptr + len; } else { - if (obj_is_kind_of(port, cIO)) { - io_binmode(port); - GetOpenFile(port, fptr); - io_readable(fptr); - arg.fp = fptr->f; - } - else { - TypeError("instance of IO needed"); - } + rb_raise(rb_eTypeError, "instance of IO needed"); } major = r_byte(&arg); if (major == MARSHAL_MAJOR) { if (r_byte(&arg) != MARSHAL_MINOR) { - Warning("Old marshal file format (can be read)"); + rb_warn("Old marshal file format (can be read)"); } arg.symbol = st_init_numtable(); arg.data = st_init_numtable(); if (NIL_P(proc)) arg.proc = 0; else arg.proc = proc; - v = rb_ensure(load, &arg, load_ensure, &arg); + v = rb_ensure(load, (VALUE)&arg, load_ensure, (VALUE)&arg); } else { - TypeError("Old marshal file format (can't read)"); + rb_raise(rb_eTypeError, "Old marshal file format (can't read)"); } return v; } +void Init_marshal() { - VALUE mMarshal = rb_define_module("Marshal"); + VALUE rb_mMarshal = rb_define_module("Marshal"); - s_dump = rb_intern("_dump_to"); - s_load = rb_intern("_load_from"); - rb_define_module_function(mMarshal, "dump", marshal_dump, -1); - rb_define_module_function(mMarshal, "load", marshal_load, -1); - rb_define_module_function(mMarshal, "restore", marshal_load, 1); + s_dump = rb_intern("_dump"); + s_load = rb_intern("_load"); + rb_define_module_function(rb_mMarshal, "dump", marshal_dump, -1); + rb_define_module_function(rb_mMarshal, "load", marshal_load, -1); + rb_define_module_function(rb_mMarshal, "restore", marshal_load, 1); - rb_provide("marshal.o"); /* for backward compatibility */ + rb_provide("marshal.so"); /* for backward compatibility */ } diff --git a/math.c b/math.c index 0e427035f4..3ea30bdbba 100644 --- a/math.c +++ b/math.c @@ -6,14 +6,14 @@ $Date$ created at: Tue Jan 25 14:12:56 JST 1994 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include <math.h> -VALUE mMath; +VALUE rb_mMath; #define Need_Float(x) (x) = rb_Float(x) #define Need_Float2(x,y) {\ @@ -26,7 +26,7 @@ math_atan2(obj, x, y) VALUE obj, x, y; { Need_Float2(x, y); - return float_new(atan2(RFLOAT(x)->value, RFLOAT(y)->value)); + return rb_float_new(atan2(RFLOAT(x)->value, RFLOAT(y)->value)); } static VALUE @@ -35,7 +35,7 @@ math_cos(obj, x) { Need_Float(x); - return float_new(cos(RFLOAT(x)->value)); + return rb_float_new(cos(RFLOAT(x)->value)); } static VALUE @@ -44,7 +44,7 @@ math_sin(obj, x) { Need_Float(x); - return float_new(sin(RFLOAT(x)->value)); + return rb_float_new(sin(RFLOAT(x)->value)); } static VALUE @@ -53,7 +53,7 @@ math_tan(obj, x) { Need_Float(x); - return float_new(tan(RFLOAT(x)->value)); + return rb_float_new(tan(RFLOAT(x)->value)); } static VALUE @@ -61,7 +61,7 @@ math_exp(obj, x) VALUE obj, x; { Need_Float(x); - return float_new(exp(RFLOAT(x)->value)); + return rb_float_new(exp(RFLOAT(x)->value)); } static VALUE @@ -69,7 +69,7 @@ math_log(obj, x) VALUE obj, x; { Need_Float(x); - return float_new(log(RFLOAT(x)->value)); + return rb_float_new(log(RFLOAT(x)->value)); } static VALUE @@ -77,7 +77,7 @@ math_log10(obj, x) VALUE obj, x; { Need_Float(x); - return float_new(log10(RFLOAT(x)->value)); + return rb_float_new(log10(RFLOAT(x)->value)); } static VALUE @@ -86,34 +86,60 @@ math_sqrt(obj, x) { Need_Float(x); - if (RFLOAT(x)->value < 0.0) ArgError("square root for negative number"); - return float_new(sqrt(RFLOAT(x)->value)); + if (RFLOAT(x)->value < 0.0) rb_raise(rb_eArgError, "square root for negative number"); + return rb_float_new(sqrt(RFLOAT(x)->value)); +} + +static VALUE +math_frexp(obj, x) + VALUE obj, x; +{ + double d; + int exp; + + Need_Float(x); + d = frexp(RFLOAT(x)->value, &exp); + + return rb_assoc_new(rb_float_new(d), INT2NUM(exp)); +} + +static VALUE +math_ldexp(obj, x, n) + VALUE obj, x, n; +{ + double d; + + Need_Float(x); + return rb_float_new(d = ldexp(RFLOAT(x)->value, NUM2INT(n))); } void Init_Math() { - mMath = rb_define_module("Math"); + rb_mMath = rb_define_module("Math"); #ifdef M_PI - rb_define_const(mMath, "PI", float_new(M_PI)); + rb_define_const(rb_mMath, "PI", rb_float_new(M_PI)); #else - rb_define_const(mMath, "PI", float_new(atan(1.0)*4.0)); + rb_define_const(rb_mMath, "PI", rb_float_new(atan(1.0)*4.0)); #endif #ifdef M_E - rb_define_const(mMath, "E", float_new(M_E)); + rb_define_const(rb_mMath, "E", rb_float_new(M_E)); #else - rb_define_const(mMath, "E", float_new(exp(1.0))); + rb_define_const(rb_mMath, "E", rb_float_new(exp(1.0))); #endif - rb_define_module_function(mMath, "atan2", math_atan2, 2); - rb_define_module_function(mMath, "cos", math_cos, 1); - rb_define_module_function(mMath, "sin", math_sin, 1); - rb_define_module_function(mMath, "tan", math_tan, 1); + rb_define_module_function(rb_mMath, "atan2", math_atan2, 2); + rb_define_module_function(rb_mMath, "cos", math_cos, 1); + rb_define_module_function(rb_mMath, "sin", math_sin, 1); + rb_define_module_function(rb_mMath, "tan", math_tan, 1); + + rb_define_module_function(rb_mMath, "exp", math_exp, 1); + rb_define_module_function(rb_mMath, "log", math_log, 1); + rb_define_module_function(rb_mMath, "log10", math_log10, 1); + rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1); - rb_define_module_function(mMath, "exp", math_exp, 1); - rb_define_module_function(mMath, "log", math_log, 1); - rb_define_module_function(mMath, "log10", math_log10, 1); - rb_define_module_function(mMath, "sqrt", math_sqrt, 1); + rb_define_module_function(rb_mMath, "frexp", math_frexp, 1); + rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2); } diff --git a/missing/dir.h b/missing/dir.h index 34be77b9c0..2e61f04443 100644 --- a/missing/dir.h +++ b/missing/dir.h @@ -1,11 +1,11 @@ -/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $ +/* $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 $ + * $Log: dir.h,v $ * Revision 4.0.1.1 91/06/07 11:22:10 lwall * patch4: new copyright notice * @@ -61,125 +61,3 @@ void rewinddir(DIR *dirp); void closedir(DIR *dirp); #endif /* __DIR_INCLUDED */ -/* $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 - -/*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 */ - 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 /* __DIR_INCLUDED */ -/* $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 - -/*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 */ - 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 /* __DIR_INCLUDED */ diff --git a/missing/file.h b/missing/file.h index 0207dddb3a..79f5f65f5d 100644 --- a/missing/file.h +++ b/missing/file.h @@ -24,7 +24,6 @@ #define F_OK 0 /* does file exist */ - #define X_OK 1 /* is it executable by caller */ #define W_OK 2 /* is it writable by caller */ #define R_OK 4 /* is it readable by caller */ diff --git a/missing/x68.c b/missing/x68.c index 8fd9c3e879..dbfe662874 100644 --- a/missing/x68.c +++ b/missing/x68.c @@ -10,3 +10,27 @@ #include "x68/_round.c" #include "x68/fconvert.c" #endif + +/* missing some basic syscalls */ +int +link(const char *src, const char *dst) +{ + return symlink(src, dst); +} + +#include <time.h> +#include <sys/time.h> + +struct timezone { + int tz_minueswest; + int tz_dsttime; +}; + +int +gettimeofday(struct timeval *tv, struct timezone *tz) +{ + tv->tv_sec = (long)time((time_t*)0); + tv->tv_usec = 0; + + return 0; +} diff --git a/mkconfig.rb b/mkconfig.rb index 5232943d8d..903cddad3c 100644 --- a/mkconfig.rb +++ b/mkconfig.rb @@ -26,14 +26,14 @@ v_others = [] File.foreach "config.status" do |$_| next if /^#/ if /^s%@program_transform_name@%s,(.*)%g$/ - ptn = $1.sub(/\$\$/, '$').split(/,/) + ptn = $1.sub(/\$\$/, '$').split(/,/) #' v_fast << " CONFIG[\"ruby_install_name\"] = \"" + "ruby".sub(ptn[0],ptn[1]) + "\"\n" elsif /^s%@(\w+)@%(.*)%g/ name = $1 val = $2 || "" next if name =~ /^(INSTALL|DEFS|configure_input|srcdir|top_srcdir)$/ v = " CONFIG[\"" + name + "\"] = " + - val.sub(/^\s*(.*)\s*$/, '"\1"').gsub(/\$\{?([^}]*)\}?/) { + val.sub(/^\s*(.*)\s*$/, '"\1"').gsub(/\$[{(]?([^})]+)[})]?/) { "\#{CONFIG[\\\"#{$1}\\\"]}" } + "\n" if fast[name] diff --git a/node.h b/node.h index cdb354c007..c1923fba75 100644 --- a/node.h +++ b/node.h @@ -6,7 +6,7 @@ $Date$ created at: Fri May 28 15:14:02 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -41,11 +41,14 @@ enum node_type { NODE_MASGN, NODE_LASGN, NODE_DASGN, + NODE_DASGN_PUSH, NODE_GASGN, NODE_IASGN, NODE_CASGN, NODE_OP_ASGN1, NODE_OP_ASGN2, + NODE_OP_ASGN_AND, + NODE_OP_ASGN_OR, NODE_CALL, NODE_FCALL, NODE_VCALL, @@ -63,8 +66,6 @@ enum node_type { NODE_CVAR, NODE_NTH_REF, NODE_BACK_REF, - NODE_MATCH_REF, - NODE_LASTLINE, NODE_MATCH, NODE_MATCH2, NODE_MATCH3, @@ -77,6 +78,10 @@ enum node_type { NODE_DREGX, NODE_DREGX_ONCE, NODE_ARGS, + NODE_ARGSCAT, + NODE_RESTARGS, + NODE_BLOCK_ARG, + NODE_BLOCK_PASS, NODE_DEFN, NODE_DEFS, NODE_ALIAS, @@ -86,6 +91,7 @@ enum node_type { NODE_MODULE, NODE_SCLASS, NODE_COLON2, + NODE_COLON3, NODE_CNAME, NODE_CREF, NODE_DOT2, @@ -98,13 +104,15 @@ enum node_type { NODE_TRUE, NODE_FALSE, NODE_DEFINED, - NODE_TAG, NODE_NEWLINE, NODE_POSTEXE, +#ifdef C_ALLOCA + NODE_ALLOCA, +#endif }; typedef struct RNode { - UINT flags; + unsigned long flags; char *nd_file; union { struct RNode *node; @@ -131,13 +139,15 @@ typedef struct RNode { #define RNODE(obj) (R_CAST(RNode)(obj)) -#define nd_type(n) (((RNODE(n))->flags>>FL_USHIFT)&0x7f) +#define nd_type(n) (((RNODE(n))->flags>>FL_USHIFT)&0xff) #define nd_set_type(n,t) \ RNODE(n)->flags=((RNODE(n)->flags&~FL_UMASK)|(((t)<<FL_USHIFT)&FL_UMASK)) -#define nd_line(n) (((RNODE(n))->flags>>18)&0x3fff) +#define NODE_LSHIFT (FL_USHIFT+8) +#define NODE_LMASK ((1<<(sizeof(NODE*)*CHAR_BIT-NODE_LSHIFT))-1) +#define nd_line(n) (((RNODE(n))->flags>>NODE_LSHIFT)&NODE_LMASK) #define nd_set_line(n,l) \ - RNODE(n)->flags=((RNODE(n)->flags&~(-1<<18))|(((l)&0x7fff)<<18)) + RNODE(n)->flags=((RNODE(n)->flags&~(-1<<NODE_LSHIFT))|(((l)&NODE_LMASK)<<NODE_LSHIFT)) #define nd_head u1.node #define nd_alen u2.argc @@ -185,8 +195,8 @@ typedef struct RNode { #define nd_noex u1.id #define nd_defn u3.node +#define nd_old u1.id #define nd_new u2.id -#define nd_old u3.id #define nd_cfnc u1.cfunc #define nd_argc u2.argc @@ -200,114 +210,133 @@ typedef struct RNode { #define nd_beg u1.node #define nd_end u2.node #define nd_state u3.state -#define nd_rval u3.value +#define nd_rval u2.value #define nd_nth u2.argc #define nd_tag u1.id -#define nd_tlev u3.cnt #define nd_tval u2.value -#define NEW_METHOD(n,x) node_newnode(NODE_METHOD,x,n,0) -#define NEW_FBODY(n,i,o) node_newnode(NODE_FBODY,n,i,o) -#define NEW_DEFN(i,a,d,p) node_newnode(NODE_DEFN,p,i,NEW_RFUNC(a,d)) -#define NEW_DEFS(r,i,a,d) node_newnode(NODE_DEFS,r,i,NEW_RFUNC(a,d)) -#define NEW_CFUNC(f,c) node_newnode(NODE_CFUNC,f,c,0) +#define NEW_METHOD(n,x) rb_node_newnode(NODE_METHOD,x,n,0) +#define NEW_FBODY(n,i,o) rb_node_newnode(NODE_FBODY,n,i,o) +#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_RFUNC(b1,b2) NEW_SCOPE(block_append(b1,b2)) -#define NEW_SCOPE(b) node_newnode(NODE_SCOPE,local_tbl(),(b),cur_cref) -#define NEW_BLOCK(a) node_newnode(NODE_BLOCK,a,0,0) -#define NEW_IF(c,t,e) node_newnode(NODE_IF,c,t,e) -#define NEW_UNLESS(c,t,e) node_newnode(NODE_IF,c,e,t) -#define NEW_CASE(h,b) node_newnode(NODE_CASE,h,b,0) -#define NEW_WHEN(c,t,e) node_newnode(NODE_WHEN,c,t,e) -#define NEW_OPT_N(b) node_newnode(NODE_OPT_N,0,b,0) -#define NEW_WHILE(c,b,n) node_newnode(NODE_WHILE,c,b,n) -#define NEW_UNTIL(c,b,n) node_newnode(NODE_UNTIL,c,b,n) -#define NEW_FOR(v,i,b) node_newnode(NODE_FOR,v,b,i) -#define NEW_ITER(v,i,b) node_newnode(NODE_ITER,v,b,i) -#define NEW_BREAK() node_newnode(NODE_BREAK,0,0,0) -#define NEW_NEXT() node_newnode(NODE_NEXT,0,0,0) -#define NEW_REDO() node_newnode(NODE_REDO,0,0,0) -#define NEW_RETRY() node_newnode(NODE_RETRY,0,0,0) -#define NEW_BEGIN(b) node_newnode(NODE_BEGIN,0,b,0) -#define NEW_RESCUE(b,res) node_newnode(NODE_RESCUE,b,res,0) -#define NEW_RESBODY(a,ex,n) node_newnode(NODE_RESBODY,n,ex,a) -#define NEW_ENSURE(b,en) node_newnode(NODE_ENSURE,b,0,en) -#define NEW_RET(s) node_newnode(NODE_RETURN,s,0,0) -#define NEW_YIELD(a) node_newnode(NODE_YIELD,a,0,0) +#define NEW_SCOPE(b) rb_node_newnode(NODE_SCOPE,local_tbl(),cur_cref,(b)) +#define NEW_BLOCK(a) rb_node_newnode(NODE_BLOCK,a,0,0) +#ifdef NOBLOCK_RECUR +#define NEW_IF(c,t,e) block_append(c,rb_node_newnode(NODE_IF,0,t,e)) +#else +#define NEW_IF(c,t,e) rb_node_newnode(NODE_IF,c,t,e) +#endif +#define NEW_UNLESS(c,t,e) NEW_IF(c,e,t) +#ifdef NOBLOCK_RECUR +#define NEW_CASE(h,b) block_append(h,rb_node_newnode(NODE_CASE,0,b,0)) +#else +#define NEW_CASE(h,b) rb_node_newnode(NODE_CASE,h,b,0) +#endif +#define NEW_WHEN(c,t,e) rb_node_newnode(NODE_WHEN,c,t,e) +#define NEW_OPT_N(b) rb_node_newnode(NODE_OPT_N,0,b,0) +#define NEW_WHILE(c,b,n) rb_node_newnode(NODE_WHILE,c,b,n) +#define NEW_UNTIL(c,b,n) rb_node_newnode(NODE_UNTIL,c,b,n) +#define NEW_FOR(v,i,b) rb_node_newnode(NODE_FOR,v,b,i) +#define NEW_ITER(v,i,b) rb_node_newnode(NODE_ITER,v,b,i) +#define NEW_BREAK() rb_node_newnode(NODE_BREAK,0,0,0) +#define NEW_NEXT() rb_node_newnode(NODE_NEXT,0,0,0) +#define NEW_REDO() rb_node_newnode(NODE_REDO,0,0,0) +#define NEW_RETRY() rb_node_newnode(NODE_RETRY,0,0,0) +#define NEW_BEGIN(b) rb_node_newnode(NODE_BEGIN,0,b,0) +#define NEW_RESCUE(b,res,e) rb_node_newnode(NODE_RESCUE,b,res,e) +#define NEW_RESBODY(a,ex,n) rb_node_newnode(NODE_RESBODY,n,ex,a) +#define NEW_ENSURE(b,en) rb_node_newnode(NODE_ENSURE,b,0,en) +#define NEW_RETURN(s) rb_node_newnode(NODE_RETURN,s,0,0) +#define NEW_YIELD(a) rb_node_newnode(NODE_YIELD,a,0,0) #define NEW_LIST(a) NEW_ARRAY(a) -#define NEW_ARRAY(a) node_newnode(NODE_ARRAY,a,1,0) -#define NEW_ZARRAY() node_newnode(NODE_ZARRAY,0,0,0) -#define NEW_HASH(a) node_newnode(NODE_HASH,a,0,0) -#define NEW_NOT(a) node_newnode(NODE_NOT,0,a,0) -#define NEW_MASGN(l,r) node_newnode(NODE_MASGN,l,0,r) -#define NEW_GASGN(v,val) node_newnode(NODE_GASGN,v,val,rb_global_entry(v)) -#define NEW_LASGN(v,val) node_newnode(NODE_LASGN,v,val,local_cnt(v)) -#define NEW_DASGN(v,val) node_newnode(NODE_DASGN,v,val,0); -#define NEW_IASGN(v,val) node_newnode(NODE_IASGN,v,val,0) -#define NEW_CASGN(v,val) node_newnode(NODE_CASGN,v,val,0) -#define NEW_OP_ASGN1(p,id,a) node_newnode(NODE_OP_ASGN1,p,id,a) -#define NEW_OP_ASGN2(r,i,o,val) node_newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN3(i,o)) -#define NEW_OP_ASGN3(i,o) node_newnode(NODE_OP_ASGN2,i,o,0) -#define NEW_GVAR(v) node_newnode(NODE_GVAR,v,0,rb_global_entry(v)) -#define NEW_LVAR(v) node_newnode(NODE_LVAR,v,0,local_cnt(v)) -#define NEW_DVAR(v) node_newnode(NODE_DVAR,v,0,0); -#define NEW_IVAR(v) node_newnode(NODE_IVAR,v,0,0) -#define NEW_CVAR(v) node_newnode(NODE_CVAR,v,0,0) -#define NEW_NTH_REF(n) node_newnode(NODE_NTH_REF,0,n,local_cnt('~')) -#define NEW_BACK_REF(n) node_newnode(NODE_BACK_REF,0,n,local_cnt('~')) -#define NEW_MATCH(c) node_newnode(NODE_MATCH,c,0,0) -#define NEW_MATCH2(n1,n2) node_newnode(NODE_MATCH2,n1,n2,0) -#define NEW_MATCH3(r,n2) node_newnode(NODE_MATCH3,r,n2,0) -#define NEW_LIT(l) node_newnode(NODE_LIT,l,0,0) -#define NEW_STR(s) node_newnode(NODE_STR,s,0,0) -#define NEW_DSTR(s) node_newnode(NODE_DSTR,s,0,0) -#define NEW_XSTR(s) node_newnode(NODE_XSTR,s,0,0) -#define NEW_DXSTR(s) node_newnode(NODE_DXSTR,s,0,0) -#define NEW_EVSTR(s,l) node_newnode(NODE_EVSTR,str_new(s,l),0,0) -#define NEW_CALL(r,m,a) node_newnode(NODE_CALL,r,m,a) -#define NEW_FCALL(m,a) node_newnode(NODE_FCALL,0,m,a) -#define NEW_VCALL(m) node_newnode(NODE_VCALL,0,m,0) -#define NEW_SUPER(a) node_newnode(NODE_SUPER,0,0,a) -#define NEW_ZSUPER() node_newnode(NODE_ZSUPER,0,0,0) -#define NEW_ARGS(f,o,r) node_newnode(NODE_ARGS,o,r,f) -#define NEW_ALIAS(n,o) node_newnode(NODE_ALIAS,0,n,o) -#define NEW_VALIAS(n,o) node_newnode(NODE_VALIAS,0,n,o) -#define NEW_UNDEF(i) node_newnode(NODE_UNDEF,0,i,0) -#define NEW_CLASS(n,b,s) node_newnode(NODE_CLASS,n,NEW_CBODY(b),s) -#define NEW_SCLASS(r,b) node_newnode(NODE_SCLASS,r,NEW_CBODY(b),0) -#define NEW_MODULE(n,b) node_newnode(NODE_MODULE,n,NEW_CBODY(b),0) -#define NEW_COLON2(c,i) node_newnode(NODE_COLON2,c,i,0) -#define NEW_CREF0() (cur_cref=node_newnode(NODE_CREF,RNODE(the_frame->cbase)->nd_clss,0,0)) -#define NEW_CREF() (cur_cref=node_newnode(NODE_CREF,0,0,cur_cref)) +#define NEW_ARRAY(a) rb_node_newnode(NODE_ARRAY,a,1,0) +#define NEW_ZARRAY() rb_node_newnode(NODE_ZARRAY,0,0,0) +#define NEW_HASH(a) rb_node_newnode(NODE_HASH,a,0,0) +#define NEW_NOT(a) rb_node_newnode(NODE_NOT,0,a,0) +#define NEW_MASGN(l,r) rb_node_newnode(NODE_MASGN,l,0,r) +#define NEW_GASGN(v,val) rb_node_newnode(NODE_GASGN,v,val,rb_global_entry(v)) +#define NEW_LASGN(v,val) rb_node_newnode(NODE_LASGN,v,val,local_cnt(v)) +#define NEW_DASGN(v,val) rb_node_newnode(NODE_DASGN,v,val,0); +#define NEW_DASGN_PUSH(v,val) rb_node_newnode(NODE_DASGN_PUSH,v,val,0); +#define NEW_IASGN(v,val) rb_node_newnode(NODE_IASGN,v,val,0) +#define NEW_CASGN(v,val) rb_node_newnode(NODE_CASGN,v,val,0) +#define NEW_OP_ASGN1(p,id,a) rb_node_newnode(NODE_OP_ASGN1,p,id,a) +#define NEW_OP_ASGN2(r,i,o,val) rb_node_newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN22(i,o)) +#define NEW_OP_ASGN22(i,o) rb_node_newnode(NODE_OP_ASGN2,i,o,rb_id_attrset(i)) +#define NEW_OP_ASGN_OR(i,val) rb_node_newnode(NODE_OP_ASGN_OR,i,val,0) +#define NEW_OP_ASGN_AND(i,val) rb_node_newnode(NODE_OP_ASGN_AND,i,val,0) +#define NEW_GVAR(v) rb_node_newnode(NODE_GVAR,v,0,rb_global_entry(v)) +#define NEW_LVAR(v) rb_node_newnode(NODE_LVAR,v,0,local_cnt(v)) +#define NEW_DVAR(v) rb_node_newnode(NODE_DVAR,v,0,0); +#define NEW_IVAR(v) rb_node_newnode(NODE_IVAR,v,0,0) +#define NEW_CVAR(v) rb_node_newnode(NODE_CVAR,v,0,0) +#define NEW_NTH_REF(n) rb_node_newnode(NODE_NTH_REF,0,n,local_cnt('~')) +#define NEW_BACK_REF(n) rb_node_newnode(NODE_BACK_REF,0,n,local_cnt('~')) +#define NEW_MATCH(c) rb_node_newnode(NODE_MATCH,c,0,0) +#define NEW_MATCH2(n1,n2) rb_node_newnode(NODE_MATCH2,n1,n2,0) +#define NEW_MATCH3(r,n2) rb_node_newnode(NODE_MATCH3,r,n2,0) +#define NEW_LIT(l) rb_node_newnode(NODE_LIT,l,0,0) +#define NEW_STR(s) rb_node_newnode(NODE_STR,s,0,0) +#define NEW_DSTR(s) rb_node_newnode(NODE_DSTR,s,0,0) +#define NEW_XSTR(s) rb_node_newnode(NODE_XSTR,s,0,0) +#define NEW_DXSTR(s) rb_node_newnode(NODE_DXSTR,s,0,0) +#define NEW_EVSTR(s,l) rb_node_newnode(NODE_EVSTR,rb_str_new(s,l),0,0) +#ifdef NOBLOCK_RECUR_incomplete +#define NEW_CALL(r,m,a) block_append(r,rb_node_newnode(NODE_CALL,0,m,a)) +#else +#define NEW_CALL(r,m,a) rb_node_newnode(NODE_CALL,r,m,a) +#endif +#define NEW_FCALL(m,a) rb_node_newnode(NODE_FCALL,0,m,a) +#define NEW_VCALL(m) rb_node_newnode(NODE_VCALL,0,m,0) +#define NEW_SUPER(a) rb_node_newnode(NODE_SUPER,0,0,a) +#define NEW_ZSUPER() rb_node_newnode(NODE_ZSUPER,0,0,0) +#define NEW_ARGS(f,o,r) rb_node_newnode(NODE_ARGS,o,r,f) +#define NEW_ARGSCAT(a,b) rb_node_newnode(NODE_ARGSCAT,a,b,0) +#define NEW_RESTARGS(a) rb_node_newnode(NODE_RESTARGS,a,0,0) +#define NEW_BLOCK_ARG(v) rb_node_newnode(NODE_BLOCK_ARG,v,0,local_cnt(v)) +#define NEW_BLOCK_PASS(b) rb_node_newnode(NODE_BLOCK_PASS,0,b,0) +#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_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=rb_node_newnode(NODE_CREF,RNODE(ruby_frame->cbase)->nd_clss,0,0)) +#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_DOT2(b,e) node_newnode(NODE_DOT2,b,e,0) -#define NEW_DOT3(b,e) node_newnode(NODE_DOT3,b,e,0) -#define NEW_ATTRSET(a) node_newnode(NODE_ATTRSET,a,0,0) -#define NEW_SELF() node_newnode(NODE_SELF,0,0,0) -#define NEW_NIL() node_newnode(NODE_NIL,0,0,0) -#define NEW_TRUE() node_newnode(NODE_TRUE,0,0,0) -#define NEW_FALSE() node_newnode(NODE_FALSE,0,0,0) -#define NEW_DEFINED(e) node_newnode(NODE_DEFINED,e,0,0) -#define NEW_NEWLINE(n) node_newnode(NODE_NEWLINE,0,0,n) +#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) +#define NEW_SELF() rb_node_newnode(NODE_SELF,0,0,0) +#define NEW_NIL() rb_node_newnode(NODE_NIL,0,0,0) +#define NEW_TRUE() rb_node_newnode(NODE_TRUE,0,0,0) +#define NEW_FALSE() rb_node_newnode(NODE_FALSE,0,0,0) +#define NEW_DEFINED(e) rb_node_newnode(NODE_DEFINED,e,0,0) +#define NEW_NEWLINE(n) rb_node_newnode(NODE_NEWLINE,0,0,n) #define NEW_PREEXE(b) NEW_SCOPE(b) -#define NEW_POSTEXE() node_newnode(NODE_POSTEXE,0,0,0) +#define NEW_POSTEXE() rb_node_newnode(NODE_POSTEXE,0,0,0) -NODE *node_newnode(); +NODE *rb_node_newnode(); VALUE rb_method_booundp(); -#define NOEX_PUBLIC 0 -#define NOEX_PRIVATE 1 +#define NOEX_PUBLIC 0 +#define NOEX_UNDEF 1 +#define NOEX_CFUNC 1 +#define NOEX_PRIVATE 2 +#define NOEX_PROTECTED 4 -NODE *compile_string _((char *, char *, int)); -NODE *compile_file _((char *, VALUE, int)); +NODE *rb_compile_cstr _((char *, char *, int)); +NODE *rb_compile_string _((char *, VALUE)); +NODE *rb_compile_file _((char *, VALUE, int)); void rb_add_method _((VALUE, ID, NODE *, int)); -void rb_remove_method _((VALUE, ID)); -NODE *node_newnode(); - -enum node_type nodetype _((NODE *)); -int nodeline _((NODE *)); +NODE *rb_node_newnode(); struct global_entry *rb_global_entry _((ID)); VALUE rb_gvar_get _((struct global_entry *)); diff --git a/numeric.c b/numeric.c index b0d5f7f522..e8ea6075a9 100644 --- a/numeric.c +++ b/numeric.c @@ -6,57 +6,94 @@ $Date$ created at: Fri Aug 13 18:33:09 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include <math.h> +#include <stdio.h> static ID coerce; static ID to_i; -VALUE cNumeric; -VALUE cFloat; -VALUE cInteger; -VALUE cFixnum; +VALUE rb_cNumeric; +VALUE rb_cFloat; +VALUE rb_cInteger; +VALUE rb_cFixnum; -VALUE eZeroDiv; +VALUE rb_eZeroDiv; ID rb_frame_last_func(); -VALUE float_new(); -double big2dbl(); +VALUE rb_float_new(); +double rb_big2dbl(); void -num_zerodiv() +rb_num_zerodiv() { - Raise(eZeroDiv, "divided by 0"); + rb_raise(rb_eZeroDiv, "divided by 0"); } static VALUE num_coerce(x, y) VALUE x, y; { - return assoc_new(rb_Float(x),rb_Float(y)); + if (CLASS_OF(x) == CLASS_OF(y)) + return rb_assoc_new(x, y); + return rb_assoc_new(rb_Float(x), rb_Float(y)); } -VALUE -num_coerce_bin(x, y) - VALUE x, y; +static VALUE +coerce_body(x) + VALUE *x; +{ + return rb_funcall(x[1], coerce, 1, x[0]); +} + +static VALUE +coerce_rescue(x) + VALUE *x; +{ + rb_raise(rb_eTypeError, "%s can't be coerced into %s", + rb_special_const_p(x[1])? + STR2CSTR(rb_inspect(x[1])): + rb_class2name(CLASS_OF(x[1])), + rb_class2name(CLASS_OF(x[0]))); +} + +static void +do_coerce(x, y) + VALUE *x, *y; { VALUE ary; + VALUE a[2]; - ary = rb_funcall(y, coerce, 1, x); + a[0] = *x; a[1] = *y; + ary = rb_rescue(coerce_body, (VALUE)a, coerce_rescue, (VALUE)a); if (TYPE(ary) != T_ARRAY || RARRAY(ary)->len != 2) { - TypeError("coerce must return [x, y]"); + rb_raise(rb_eTypeError, "coerce must return [x, y]"); } - x = RARRAY(ary)->ptr[0]; - y = RARRAY(ary)->ptr[1]; + *x = RARRAY(ary)->ptr[0]; + *y = RARRAY(ary)->ptr[1]; +} +VALUE +rb_num_coerce_bin(x, y) + VALUE x, y; +{ + do_coerce(&x, &y); return rb_funcall(x, rb_frame_last_func(), 1, y); } +static VALUE +num_clone(x) + VALUE x; +{ + /* Numerics are immutable values, which need not to copy */ + return x; +} + static VALUE num_uplus(num) VALUE num; @@ -68,17 +105,12 @@ static VALUE num_uminus(num) VALUE num; { - VALUE ary, x, y; + VALUE zero; - ary = rb_funcall(num, coerce, 1, INT2FIX(0)); - if (TYPE(ary) != T_ARRAY || RARRAY(ary)->len != 2) { - TypeError("coerce must return [x, y]"); - } - - x = RARRAY(ary)->ptr[0]; - y = RARRAY(ary)->ptr[1]; + zero = INT2FIX(0); + do_coerce(&zero, &num); - return rb_funcall(x, '-', 1, y); + return rb_funcall(zero, '-', 1, num); } static VALUE @@ -92,49 +124,56 @@ num_divmod(x, y) double d = floor(RFLOAT(div)->value); if (RFLOAT(div)->value > d) { - div = float_new(d); + div = rb_float_new(d); } } mod = rb_funcall(x, '%', 1, y); - return assoc_new(div, mod); + return rb_assoc_new(div, mod); } static VALUE num_int_p(num) VALUE num; { - return FALSE; + return Qfalse; } static VALUE -num_chr(num) +num_abs(num) VALUE num; { - char c; - INT i = NUM2INT(num); + if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) { + return rb_funcall(num, rb_intern("-@"), 0); + } + return num; +} - if (i < 0 || 0xff < i) - Fail("%d out of char range", i); - c = i; - return str_new(&c, 1); +static VALUE +num_zero_p(num) + VALUE num; +{ + if (RTEST(rb_equal(num, INT2FIX(0)))) { + return Qtrue; + } + return Qfalse; } static VALUE -num_abs(num) +num_nonzero_p(num) VALUE num; { - if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) { - return rb_funcall(num, rb_intern("-@"), 0); + if (RTEST(rb_funcall(num, rb_intern("zero?"), 0, 0))) { + return Qfalse; } return num; } VALUE -float_new(d) +rb_float_new(d) double d; { NEWOBJ(flt, struct RFloat); - OBJSETUP(flt, cFloat, T_FLOAT); + OBJSETUP(flt, rb_cFloat, T_FLOAT); flt->value = d; return (VALUE)flt; @@ -160,21 +199,21 @@ flo_to_s(flt) } } - return str_new2(buf); + return rb_str_new2(buf); } static VALUE flo_coerce(x, y) VALUE x, y; { - return assoc_new(rb_Float(y), x); + return rb_assoc_new(rb_Float(y), x); } static VALUE flo_uminus(flt) VALUE flt; { - return float_new(-RFLOAT(flt)->value); + return rb_float_new(-RFLOAT(flt)->value); } static VALUE @@ -183,15 +222,13 @@ flo_plus(x, y) { switch (TYPE(y)) { case T_FIXNUM: - return float_new(RFLOAT(x)->value + (double)FIX2INT(y)); + return rb_float_new(RFLOAT(x)->value + (double)FIX2LONG(y)); case T_BIGNUM: - return float_new(RFLOAT(x)->value + big2dbl(y)); + return rb_float_new(RFLOAT(x)->value + rb_big2dbl(y)); case T_FLOAT: - return float_new(RFLOAT(x)->value + RFLOAT(y)->value); - case T_STRING: - return str_plus(obj_as_string(x), y); + return rb_float_new(RFLOAT(x)->value + RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -201,13 +238,13 @@ flo_minus(x, y) { switch (TYPE(y)) { case T_FIXNUM: - return float_new(RFLOAT(x)->value - (double)FIX2INT(y)); + return rb_float_new(RFLOAT(x)->value - (double)FIX2LONG(y)); case T_BIGNUM: - return float_new(RFLOAT(x)->value - big2dbl(y)); + return rb_float_new(RFLOAT(x)->value - rb_big2dbl(y)); case T_FLOAT: - return float_new(RFLOAT(x)->value - RFLOAT(y)->value); + return rb_float_new(RFLOAT(x)->value - RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -217,15 +254,13 @@ flo_mul(x, y) { switch (TYPE(y)) { case T_FIXNUM: - return float_new(RFLOAT(x)->value * (double)FIX2INT(y)); + return rb_float_new(RFLOAT(x)->value * (double)FIX2LONG(y)); case T_BIGNUM: - return float_new(RFLOAT(x)->value * big2dbl(y)); + return rb_float_new(RFLOAT(x)->value * rb_big2dbl(y)); case T_FLOAT: - return float_new(RFLOAT(x)->value * RFLOAT(y)->value); - case T_STRING: - return str_times(y, INT2FIX((int)RFLOAT(x)->value)); + return rb_float_new(RFLOAT(x)->value * RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -233,73 +268,92 @@ static VALUE flo_div(x, y) VALUE x, y; { - INT f_y; + long f_y; double d; switch (TYPE(y)) { case T_FIXNUM: - f_y = FIX2INT(y); - if (f_y == 0) num_zerodiv(); - return float_new(RFLOAT(x)->value / (double)f_y); + f_y = FIX2LONG(y); + if (f_y == 0) rb_num_zerodiv(); + return rb_float_new(RFLOAT(x)->value / (double)f_y); case T_BIGNUM: - d = big2dbl(y); - if (d == 0.0) num_zerodiv(); - return float_new(RFLOAT(x)->value / d); + d = rb_big2dbl(y); + if (d == 0.0) rb_num_zerodiv(); + return rb_float_new(RFLOAT(x)->value / d); case T_FLOAT: - if (RFLOAT(y)->value == 0.0) num_zerodiv(); - return float_new(RFLOAT(x)->value / RFLOAT(y)->value); + if (RFLOAT(y)->value == 0.0) rb_num_zerodiv(); + return rb_float_new(RFLOAT(x)->value / RFLOAT(y)->value); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } static VALUE -flo_mod(x, y) +flo_modulo(x, y, modulo) VALUE x, y; + int modulo; { - double value; + double value, result; switch (TYPE(y)) { case T_FIXNUM: - value = (double)FIX2INT(y); + value = (double)FIX2LONG(y); break; case T_BIGNUM: - value = big2dbl(y); + value = rb_big2dbl(y); break; case T_FLOAT: value = RFLOAT(y)->value; break; default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } + #ifdef HAVE_FMOD - value = fmod(RFLOAT(x)->value, value); + result = fmod(RFLOAT(x)->value, value); #else { double value1 = RFLOAT(x)->value; double value2; modf(value1/value, &value2); - value = value1 - value2 * value; + result = value1 - value2 * value; } #endif + if (modulo && + (RFLOAT(x)->value < 0.0) != (result < 0.0) && result != 0.0) { + result += value; + } + return rb_float_new(result); +} - return float_new(value); +static VALUE +flo_mod(x, y) + VALUE x, y; +{ + return flo_modulo(x,y,1); } -VALUE +static VALUE +flo_remainder(x, y) + VALUE x, y; +{ + return flo_modulo(x,y,0); +} + +static VALUE flo_pow(x, y) VALUE x, y; { switch (TYPE(y)) { case T_FIXNUM: - return float_new(pow(RFLOAT(x)->value, (double)FIX2INT(y))); + return rb_float_new(pow(RFLOAT(x)->value, (double)FIX2LONG(y))); case T_BIGNUM: - return float_new(pow(RFLOAT(x)->value, big2dbl(y))); + return rb_float_new(pow(RFLOAT(x)->value, rb_big2dbl(y))); case T_FLOAT: - return float_new(pow(RFLOAT(x)->value, RFLOAT(y)->value)); + return rb_float_new(pow(RFLOAT(x)->value, RFLOAT(y)->value)); default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -307,7 +361,7 @@ static VALUE num_eql(x, y) VALUE x, y; { - if (TYPE(x) != TYPE(y)) return FALSE; + if (TYPE(x) != TYPE(y)) return Qfalse; return rb_equal(x, y); } @@ -326,12 +380,12 @@ flo_eq(x, y) { switch (TYPE(y)) { case T_FIXNUM: - if (RFLOAT(x)->value == FIX2INT(y)) return TRUE; - return FALSE; + if (RFLOAT(x)->value == FIX2LONG(y)) return Qtrue; + return Qfalse; case T_BIGNUM: - return (RFLOAT(x)->value == big2dbl(y))?TRUE:FALSE; + return (RFLOAT(x)->value == rb_big2dbl(y))?Qtrue:Qfalse; case T_FLOAT: - return (RFLOAT(x)->value == RFLOAT(y)->value)?TRUE:FALSE; + return (RFLOAT(x)->value == RFLOAT(y)->value)?Qtrue:Qfalse; default: return num_equal(x, y); } @@ -363,11 +417,11 @@ flo_cmp(x, y) a = RFLOAT(x)->value; switch (TYPE(y)) { case T_FIXNUM: - b = (double)FIX2INT(y); + b = (double)FIX2LONG(y); break; case T_BIGNUM: - b = big2dbl(y); + b = rb_big2dbl(y); break; case T_FLOAT: @@ -375,21 +429,125 @@ flo_cmp(x, y) break; default: - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } if (a == b) return INT2FIX(0); if (a > b) return INT2FIX(1); return INT2FIX(-1); } +static VALUE +flo_gt(x, y) + VALUE x, y; +{ + double a, b; + + a = RFLOAT(x)->value; + switch (TYPE(y)) { + case T_FIXNUM: + b = (double)FIX2LONG(y); + break; + + case T_BIGNUM: + b = rb_big2dbl(y); + break; + + case T_FLOAT: + b = RFLOAT(y)->value; + break; + + default: + return rb_num_coerce_bin(x, y); + } + return (a > b)?Qtrue:Qfalse; +} + +static VALUE +flo_ge(x, y) + VALUE x, y; +{ + double a, b; + + a = RFLOAT(x)->value; + switch (TYPE(y)) { + case T_FIXNUM: + b = (double)FIX2LONG(y); + break; + + case T_BIGNUM: + b = rb_big2dbl(y); + break; + + case T_FLOAT: + b = RFLOAT(y)->value; + break; + + default: + return rb_num_coerce_bin(x, y); + } + return (a >= b)?Qtrue:Qfalse; +} + +static VALUE +flo_lt(x, y) + VALUE x, y; +{ + double a, b; + + a = RFLOAT(x)->value; + switch (TYPE(y)) { + case T_FIXNUM: + b = (double)FIX2LONG(y); + break; + + case T_BIGNUM: + b = rb_big2dbl(y); + break; + + case T_FLOAT: + b = RFLOAT(y)->value; + break; + + default: + return rb_num_coerce_bin(x, y); + } + return (a < b)?Qtrue:Qfalse; +} + +static VALUE +flo_le(x, y) + VALUE x, y; +{ + double a, b; + + a = RFLOAT(x)->value; + switch (TYPE(y)) { + case T_FIXNUM: + b = (double)FIX2LONG(y); + break; + + case T_BIGNUM: + b = rb_big2dbl(y); + break; + + case T_FLOAT: + b = RFLOAT(y)->value; + break; + + default: + return rb_num_coerce_bin(x, y); + } + return (a <= b)?Qtrue:Qfalse; +} + static VALUE flo_eql(x, y) VALUE x, y; { if (TYPE(y) == T_FLOAT) { - if (RFLOAT(x)->value == RFLOAT(y)->value) return TRUE; + if (RFLOAT(x)->value == RFLOAT(y)->value) return Qtrue; } - return FALSE; + return Qfalse; } static VALUE @@ -397,10 +555,55 @@ flo_to_i(num) VALUE num; { double f = RFLOAT(num)->value; - INT val; + long val; + + if (!FIXABLE(f)) { + return rb_dbl2big(f); + } + val = f; + return INT2FIX(val); +} + +static VALUE +flo_floor(num) + VALUE num; +{ + double f = floor(RFLOAT(num)->value); + long val; + + if (!FIXABLE(f)) { + return rb_dbl2big(f); + } + val = f; + return INT2FIX(val); +} + +static VALUE +flo_ceil(num) + VALUE num; +{ + double f = ceil(RFLOAT(num)->value); + long val; + + if (!FIXABLE(f)) { + return rb_dbl2big(f); + } + val = f; + return INT2FIX(val); +} + +static VALUE +flo_round(num) + VALUE num; +{ + double f = RFLOAT(num)->value; + long val; + + if (f > 0.0) f = floor(f+0.5); + if (f < 0.0) f = ceil(f-0.5); if (!FIXABLE(f)) { - return dbl2big(f); + return rb_dbl2big(f); } val = f; return INT2FIX(val); @@ -418,7 +621,17 @@ flo_abs(flt) VALUE flt; { double val = fabs(RFLOAT(flt)->value); - return float_new(val); + return rb_float_new(val); +} + +static VALUE +flo_zero_p(num) + VALUE num; +{ + if (RFLOAT(num)->value == 0.0) { + return Qtrue; + } + return Qfalse; } static VALUE @@ -432,64 +645,116 @@ static VALUE fail_to_integer(val) VALUE val; { - TypeError("failed to convert %s into Integer", - rb_class2name(CLASS_OF(val))); + rb_raise(rb_eTypeError, "failed to convert %s into Integer", + rb_class2name(CLASS_OF(val))); } -int -num2int(val) +long +rb_num2long(val) VALUE val; { - if (NIL_P(val)) return 0; + if (NIL_P(val)) { + rb_raise(rb_eTypeError, "no implicit conversion from nil"); + } - switch (TYPE(val)) { - case T_FIXNUM: - return FIX2INT(val); + if (FIXNUM_P(val)) return FIX2LONG(val); + switch (TYPE(val)) { case T_FLOAT: - if (RFLOAT(val)->value <= (double) LONG_MAX - && RFLOAT(val)->value >= (double) LONG_MIN) { - return (int)(RFLOAT(val)->value); + if (RFLOAT(val)->value <= (double)LONG_MAX + && RFLOAT(val)->value >= (double)LONG_MIN) { + return (long)(RFLOAT(val)->value); } else { - Fail("float %g out of rang of integer", RFLOAT(val)->value); + rb_raise(rb_eTypeError, "float %g out of rang of integer", + RFLOAT(val)->value); } case T_BIGNUM: - return big2int(val); + return rb_big2long(val); + + case T_STRING: + rb_raise(rb_eTypeError, "no implicit conversion from string"); + return Qnil; /* not reached */ default: val = rb_rescue(to_integer, val, fail_to_integer, val); - return NUM2INT(val); + if (!rb_obj_is_kind_of(val, rb_cInteger)) { + rb_raise(rb_eTypeError, "`to_i' need to return integer"); + } + return NUM2LONG(val); } } -VALUE -num2fix(val) +unsigned long +rb_num2ulong(val) VALUE val; { - INT v; + if (TYPE(val) == T_BIGNUM) { + return rb_big2ulong(val); + } + return (unsigned long)rb_num2long(val); +} - if (NIL_P(val)) return INT2FIX(0); - switch (TYPE(val)) { - case T_FIXNUM: - return val; +#if SIZEOF_INT < SIZEOF_LONG +int +rb_num2int(val) + VALUE val; +{ + long num = rb_num2long(val); - case T_FLOAT: - case T_BIGNUM: - default: - v = num2int(val); - if (!FIXABLE(v)) - Fail("integer %d out of range of Fixnum", v); - return INT2FIX(v); + if (num < INT_MIN || INT_MAX < num) { + rb_raise(rb_eArgError, "integer %d too big to convert to `int'.", num); } + return (int)num; +} + +int +rb_fix2int(val) + VALUE val; +{ + long num = FIXNUM_P(val)?FIX2LONG(val):rb_num2long(val); + + if (num < INT_MIN || INT_MAX < num) { + rb_raise(rb_eArgError, "integer %d too big to convert to `int'.", num); + } + return (int)num; +} +#else +int +rb_num2int(val) + VALUE val; +{ + return rb_num2long(val); +} + +int +rb_fix2int(val) + VALUE val; +{ + return FIX2INT(val); +} +#endif + +VALUE +rb_num2fix(val) + VALUE val; +{ + long v; + + if (FIXNUM_P(val)) return val; + + v = rb_num2long(val); + if (!FIXABLE(v)) + rb_raise(rb_eTypeError, "integer %d out of range of fixnum", v); + return INT2FIX(v); } static VALUE int_int_p(num) VALUE num; { - return TRUE; + return Qtrue; } static VALUE @@ -499,15 +764,28 @@ int_succ(num) return rb_funcall(num, '+', 1, INT2FIX(1)); } +static VALUE +int_chr(num) + VALUE num; +{ + char c; + long i = NUM2LONG(num); + + if (i < 0 || 0xff < i) + rb_raise(rb_eTypeError, "%d out of char range", i); + c = i; + return rb_str_new(&c, 1); +} + static VALUE fix_uminus(num) VALUE num; { - return int2inum(-FIX2INT(num)); + return rb_int2inum(-FIX2LONG(num)); } VALUE -fix2str(x, base) +rb_fix2str(x, base) VALUE x; int base; { @@ -517,130 +795,140 @@ fix2str(x, base) if (base == 10) fmt[2] = 'd'; else if (base == 16) fmt[2] = 'x'; else if (base == 8) fmt[2] = 'o'; - else Fatal("fixnum cannot treat base %d", base); + else rb_fatal("fixnum cannot treat base %d", base); - sprintf(buf, fmt, FIX2INT(x)); - return str_new2(buf); + sprintf(buf, fmt, FIX2LONG(x)); + return rb_str_new2(buf); } -VALUE +static VALUE fix_to_s(in) VALUE in; { - return fix2str(in, 10); + return rb_fix2str(in, 10); } static VALUE fix_plus(x, y) VALUE x, y; { - switch (TYPE(y)) { - case T_FIXNUM: - { - INT a, b, c; - VALUE r; - - a = FIX2INT(x); - b = FIX2INT(y); - c = a + b; - r = INT2FIX(c); - - if (FIX2INT(r) != c) { - r = big_plus(int2big(a), int2big(b)); - } - return r; + if (FIXNUM_P(y)) { + long a, b, c; + VALUE r; + + a = FIX2LONG(x); + b = FIX2LONG(y); + c = a + b; + r = INT2FIX(c); + + if (FIX2LONG(r) != c) { + r = rb_big_plus(rb_int2big(a), rb_int2big(b)); } - case T_FLOAT: - return float_new((double)FIX2INT(x) + RFLOAT(y)->value); - default: - return num_coerce_bin(x, y); + return r; + } + if (TYPE(y) == T_FLOAT) { + return rb_float_new((double)FIX2LONG(x) + RFLOAT(y)->value); } + return rb_num_coerce_bin(x, y); } static VALUE fix_minus(x, y) VALUE x, y; { - switch (TYPE(y)) { - case T_FIXNUM: - { - INT a, b, c; - VALUE r; - - a = FIX2INT(x); - b = FIX2INT(y); - c = a - b; - r = INT2FIX(c); - - if (FIX2INT(r) != c) { - r = big_minus(int2big(a), int2big(b)); - } - return r; + if (FIXNUM_P(y)) { + long a, b, c; + VALUE r; + + a = FIX2LONG(x); + b = FIX2LONG(y); + c = a - b; + r = INT2FIX(c); + + if (FIX2LONG(r) != c) { + r = rb_big_minus(rb_int2big(a), rb_int2big(b)); } - case T_FLOAT: - return float_new((double)FIX2INT(x) - RFLOAT(y)->value); - default: - return num_coerce_bin(x, y); + return r; + } + if (TYPE(y) == T_FLOAT) { + return rb_float_new((double)FIX2LONG(x) - RFLOAT(y)->value); } + return rb_num_coerce_bin(x, y); } static VALUE fix_mul(x, y) VALUE x, y; { - switch (TYPE(y)) { - case T_FIXNUM: - { - INT a, b, c; - VALUE r; + if (FIXNUM_P(y)) { + long a, b, c; + VALUE r; - a = FIX2INT(x); - if (a == 0) return x; + a = FIX2LONG(x); + if (a == 0) return x; - b = FIX2INT(y); - c = a * b; - r = INT2FIX(c); + b = FIX2LONG(y); + c = a * b; + r = INT2FIX(c); - if (FIX2INT(r) != c || c/a != b) { - r = big_mul(int2big(a), int2big(b)); - } - return r; + if (FIX2LONG(r) != c || c/a != b) { + r = rb_big_mul(rb_int2big(a), rb_int2big(b)); } - case T_FLOAT: - return float_new((double)FIX2INT(x) * RFLOAT(y)->value); - default: - return num_coerce_bin(x, y); + return r; + } + if (TYPE(y) == T_FLOAT) { + return rb_float_new((double)FIX2LONG(x) * RFLOAT(y)->value); } + return rb_num_coerce_bin(x, y); } static VALUE fix_div(x, y) VALUE x, y; { - INT i; + if (FIXNUM_P(y)) { + long i; - if (TYPE(y) == T_FIXNUM) { - i = FIX2INT(y); - if (i == 0) num_zerodiv(); - i = FIX2INT(x)/i; + i = FIX2LONG(y); + if (i == 0) rb_num_zerodiv(); + i = FIX2LONG(x)/i; return INT2FIX(i); } - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } static VALUE -fix_mod(x, y) +fix_modulo(x, y, modulo) VALUE x, y; { - INT i; + long i; - if (TYPE(y) == T_FIXNUM) { - i = FIX2INT(y); - if (i == 0) num_zerodiv(); - i = FIX2INT(x)%i; + if (FIXNUM_P(y)) { + i = FIX2LONG(y); + if (i == 0) rb_num_zerodiv(); + i = FIX2LONG(x)%i; + if (modulo && + (FIX2LONG(x) < 0) != (FIX2LONG(y) < 0) && + i != 0) { + i += FIX2LONG(y); + } return INT2FIX(i); } - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); +} + +static VALUE +fix_mod(x, y) + VALUE x, y; +{ + return fix_modulo(x, y, 1); +} + +static VALUE +fix_remainder(x, y) + VALUE x, y; +{ + return fix_modulo(x, y, 0); } static VALUE @@ -648,20 +936,20 @@ fix_pow(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - INT a, b; + long a, b; - b = FIX2INT(y); + b = FIX2LONG(y); if (b == 0) return INT2FIX(1); - a = FIX2INT(x); + a = FIX2LONG(x); if (b > 0) { - return big_pow(int2big(a), y); + return rb_big_pow(rb_int2big(a), y); } - return float_new(pow((double)a, (double)b)); + return rb_float_new(pow((double)a, (double)b)); } else if (NIL_P(y)) { return INT2FIX(1); } - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } static VALUE @@ -669,7 +957,7 @@ fix_equal(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - return (FIX2INT(x) == FIX2INT(y))?TRUE:FALSE; + return (FIX2LONG(x) == FIX2LONG(y))?Qtrue:Qfalse; } else { return num_equal(x, y); @@ -681,14 +969,14 @@ fix_cmp(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - INT a = FIX2INT(x), b = FIX2INT(y); + long a = FIX2LONG(x), b = FIX2LONG(y); if (a == b) return INT2FIX(0); if (a > b) return INT2FIX(1); return INT2FIX(-1); } else { - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -697,13 +985,13 @@ fix_gt(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - INT a = FIX2INT(x), b = FIX2INT(y); + long a = FIX2LONG(x), b = FIX2LONG(y); - if (a > b) return TRUE; - return FALSE; + if (a > b) return Qtrue; + return Qfalse; } else { - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -712,13 +1000,13 @@ fix_ge(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - INT a = FIX2INT(x), b = FIX2INT(y); + long a = FIX2LONG(x), b = FIX2LONG(y); - if (a >= b) return TRUE; - return FALSE; + if (a >= b) return Qtrue; + return Qfalse; } else { - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -727,13 +1015,13 @@ fix_lt(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - INT a = FIX2INT(x), b = FIX2INT(y); + long a = FIX2LONG(x), b = FIX2LONG(y); - if (a < b) return TRUE; - return FALSE; + if (a < b) return Qtrue; + return Qfalse; } else { - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -742,13 +1030,13 @@ fix_le(x, y) VALUE x, y; { if (FIXNUM_P(y)) { - INT a = FIX2INT(x), b = FIX2INT(y); + long a = FIX2LONG(x), b = FIX2LONG(y); - if (a <= b) return TRUE; - return FALSE; + if (a <= b) return Qtrue; + return Qfalse; } else { - return num_coerce_bin(x, y); + return rb_num_coerce_bin(x, y); } } @@ -756,10 +1044,10 @@ static VALUE fix_rev(num) VALUE num; { - unsigned long val = FIX2UINT(num); + unsigned long val = FIX2ULONG(num); val = ~val; - return INT2FIX(val); + return rb_int2inum(val); } static VALUE @@ -769,10 +1057,10 @@ fix_and(x, y) long val; if (TYPE(y) == T_BIGNUM) { - return big_and(y, x); + return rb_big_and(y, x); } - val = NUM2INT(x) & NUM2INT(y); - return int2inum(val); + val = FIX2LONG(x) & NUM2LONG(y); + return rb_int2inum(val); } static VALUE @@ -782,10 +1070,10 @@ fix_or(x, y) long val; if (TYPE(y) == T_BIGNUM) { - return big_or(y, x); + return rb_big_or(y, x); } - val = NUM2INT(x) | NUM2INT(y); - return INT2FIX(val); + val = FIX2LONG(x) | NUM2LONG(y); + return rb_int2inum(val); } static VALUE @@ -795,26 +1083,27 @@ fix_xor(x, y) long val; if (TYPE(y) == T_BIGNUM) { - return big_xor(y, x); + return rb_big_xor(y, x); } - val = NUM2INT(x) ^ NUM2INT(y); - return INT2FIX(val); + val = FIX2LONG(x) ^ NUM2LONG(y); + return rb_int2inum(val); } static VALUE fix_lshift(x, y) VALUE x, y; { - long val, width; + long val; + int width; - val = NUM2INT(x); + val = NUM2LONG(x); width = NUM2INT(y); if (width > (sizeof(VALUE)*CHAR_BIT-1) - || (unsigned)val>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) { - return big_lshift(int2big(val), y); + || ((unsigned long)val)>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) { + return rb_big_lshift(rb_int2big(val), y); } val = val << width; - return int2inum(val); + return rb_int2inum(val); } static VALUE @@ -823,9 +1112,9 @@ fix_rshift(x, y) { long i, val; - i = NUM2INT(y); - if (y < 32) { - val = RSHIFT(FIX2INT(x), i); + i = NUM2LONG(y); + if (i < sizeof(long) * 8) { + val = RSHIFT(FIX2LONG(x), i); return INT2FIX(val); } @@ -836,8 +1125,8 @@ static VALUE fix_aref(fix, idx) VALUE fix, idx; { - unsigned long val = FIX2INT(fix); - int i = FIX2INT(idx); + unsigned long val = FIX2LONG(fix); + int i = FIX2LONG(idx); if (i < 0 || sizeof(VALUE)*CHAR_BIT-1 < i) return INT2FIX(0); @@ -859,27 +1148,27 @@ fix_to_f(num) { double val; - val = (double)FIX2INT(num); + val = (double)FIX2LONG(num); - return float_new(val); + return rb_float_new(val); } static VALUE fix_type(fix) VALUE fix; { - return cFixnum; + return rb_cFixnum; } static VALUE fix_abs(fix) VALUE fix; { - INT i = FIX2INT(fix); + long i = FIX2LONG(fix); if (i < 0) i = -i; - return int2inum(i); + return rb_int2inum(i); } static VALUE @@ -887,7 +1176,7 @@ fix_id2name(fix) VALUE fix; { char *name = rb_id2name(FIX2UINT(fix)); - if (name) return str_new2(name); + if (name) return rb_str_new2(name); return Qnil; } @@ -895,20 +1184,20 @@ static VALUE fix_succ(fix) VALUE fix; { - INT i = FIX2INT(fix) + 1; + long i = FIX2LONG(fix) + 1; - return int2inum(i); + return rb_int2inum(i); } static VALUE fix_size(fix) VALUE fix; { - return INT2FIX(sizeof(INT)); + return INT2FIX(sizeof(long)); } -VALUE -num_upto(from, to) +static VALUE +int_upto(from, to) VALUE from, to; { VALUE i = from; @@ -922,7 +1211,7 @@ num_upto(from, to) } static VALUE -num_downto(from, to) +int_downto(from, to) VALUE from, to; { VALUE i = from; @@ -936,14 +1225,14 @@ num_downto(from, to) } static VALUE -num_step(from, to, step) +int_step(from, to, step) VALUE from, to, step; { VALUE i = from; ID cmp; - if (step == INT2FIX(0)) { - ArgError("step cannot be 0"); + if (NUM2INT(step) == 0) { + rb_raise(rb_eArgError, "step cannot be 0"); } if (RTEST(rb_funcall(step, '>', 1, INT2FIX(0)))) { @@ -961,7 +1250,7 @@ num_step(from, to, step) } static VALUE -num_dotimes(num) +int_dotimes(num) VALUE num; { VALUE i = INT2FIX(0); @@ -974,30 +1263,37 @@ num_dotimes(num) return num; } -VALUE +static VALUE fix_upto(from, to) VALUE from, to; { - INT i, end; + long i, end; - if (!FIXNUM_P(to)) return num_upto(from, to); - end = FIX2INT(to); - for (i = FIX2INT(from); i <= end; i++) { + if (!FIXNUM_P(to)) return int_upto(from, to); + end = FIX2LONG(to); + for (i = FIX2LONG(from); i <= end; i++) { rb_yield(INT2FIX(i)); } return from; } +VALUE +rb_fix_upto(from, to) + VALUE from, to; +{ + return fix_upto(from, to); +} + static VALUE fix_downto(from, to) VALUE from, to; { - INT i, end; + long i, end; - if (!FIXNUM_P(to)) return num_downto(from, to); - end = FIX2INT(to); - for (i=FIX2INT(from); i >= end; i--) { + if (!FIXNUM_P(to)) return int_downto(from, to); + end = FIX2LONG(to); + for (i=FIX2LONG(from); i >= end; i--) { rb_yield(INT2FIX(i)); } @@ -1008,24 +1304,24 @@ static VALUE fix_step(from, to, step) VALUE from, to, step; { - INT i, end, diff; + long i, end, diff; if (!FIXNUM_P(to) || !FIXNUM_P(step)) - return num_step(from, to, step); + return int_step(from, to, step); - end = FIX2INT(to); - diff = FIX2INT(step); + end = FIX2LONG(to); + diff = FIX2LONG(step); if (diff == 0) { - ArgError("step cannot be 0"); + rb_raise(rb_eArgError, "step cannot be 0"); } else if (diff > 0) { - for (i=FIX2INT(from); i <= end; i+=diff) { + for (i=FIX2LONG(from); i <= end; i+=diff) { rb_yield(INT2FIX(i)); } } else { - for (i=FIX2INT(from); i >= end; i+=diff) { + for (i=FIX2LONG(from); i >= end; i+=diff) { rb_yield(INT2FIX(i)); } } @@ -1036,17 +1332,24 @@ static VALUE fix_dotimes(num) VALUE num; { - INT i, end; + long i, end; - end = FIX2INT(num); + end = FIX2LONG(num); for (i=0; i<end; i++) { rb_yield(INT2FIX(i)); } return num; } -extern VALUE mComparable; -extern VALUE eException; +static VALUE +fix_zero_p(num) + VALUE num; +{ + if (FIX2LONG(num) == 0) { + return Qtrue; + } + return Qfalse; +} void Init_Numeric() @@ -1054,93 +1357,110 @@ Init_Numeric() coerce = rb_intern("coerce"); to_i = rb_intern("to_i"); - eZeroDiv = rb_define_class("ZeroDivisionError", eException); - cNumeric = rb_define_class("Numeric", cObject); - - rb_include_module(cNumeric, mComparable); - rb_define_method(cNumeric, "coerce", num_coerce, 1); - - rb_define_method(cNumeric, "+@", num_uplus, 0); - rb_define_method(cNumeric, "-@", num_uminus, 0); - rb_define_method(cNumeric, "eql?", num_eql, 1); - rb_define_method(cNumeric, "divmod", num_divmod, 1); - rb_define_method(cNumeric, "abs", num_abs, 0); - - rb_define_method(cNumeric, "upto", num_upto, 1); - rb_define_method(cNumeric, "downto", num_downto, 1); - rb_define_method(cNumeric, "step", num_step, 2); - rb_define_method(cNumeric, "times", num_dotimes, 0); - rb_define_method(cNumeric, "integer?", num_int_p, 0); - rb_define_method(cNumeric, "chr", num_chr, 0); - - cInteger = rb_define_class("Integer", cNumeric); - rb_define_method(cInteger, "integer?", int_int_p, 0); - rb_define_method(cInteger, "succ", int_succ, 0); - - cFixnum = rb_define_class("Fixnum", cInteger); - - rb_undef_method(CLASS_OF(cFixnum), "new"); - - rb_define_method(cFixnum, "to_s", fix_to_s, 0); - rb_define_method(cFixnum, "type", fix_type, 0); - - rb_define_method(cFixnum, "id2name", fix_id2name, 0); - - rb_define_method(cFixnum, "-@", fix_uminus, 0); - rb_define_method(cFixnum, "+", fix_plus, 1); - rb_define_method(cFixnum, "-", fix_minus, 1); - rb_define_method(cFixnum, "*", fix_mul, 1); - rb_define_method(cFixnum, "/", fix_div, 1); - rb_define_method(cFixnum, "%", fix_mod, 1); - rb_define_method(cFixnum, "**", fix_pow, 1); - - rb_define_method(cFixnum, "abs", fix_abs, 0); - - rb_define_method(cFixnum, "==", fix_equal, 1); - rb_define_method(cFixnum, "<=>", fix_cmp, 1); - rb_define_method(cFixnum, ">", fix_gt, 1); - rb_define_method(cFixnum, ">=", fix_ge, 1); - rb_define_method(cFixnum, "<", fix_lt, 1); - rb_define_method(cFixnum, "<=", fix_le, 1); - - rb_define_method(cFixnum, "~", fix_rev, 0); - rb_define_method(cFixnum, "&", fix_and, 1); - rb_define_method(cFixnum, "|", fix_or, 1); - rb_define_method(cFixnum, "^", fix_xor, 1); - rb_define_method(cFixnum, "[]", fix_aref, 1); - - rb_define_method(cFixnum, "<<", fix_lshift, 1); - rb_define_method(cFixnum, ">>", fix_rshift, 1); - - rb_define_method(cFixnum, "to_i", fix_to_i, 0); - rb_define_method(cFixnum, "to_f", fix_to_f, 0); - - rb_define_method(cFixnum, "succ", fix_succ, 0); - rb_define_method(cFixnum, "size", fix_size, 0); - - rb_define_method(cFixnum, "upto", fix_upto, 1); - rb_define_method(cFixnum, "downto", fix_downto, 1); - rb_define_method(cFixnum, "step", fix_step, 2); - rb_define_method(cFixnum, "times", fix_dotimes, 0); - - cFloat = rb_define_class("Float", cNumeric); - - rb_undef_method(CLASS_OF(cFloat), "new"); - - rb_define_method(cFloat, "to_s", flo_to_s, 0); - rb_define_method(cFloat, "coerce", flo_coerce, 1); - rb_define_method(cFloat, "-@", flo_uminus, 0); - rb_define_method(cFloat, "+", flo_plus, 1); - rb_define_method(cFloat, "-", flo_minus, 1); - rb_define_method(cFloat, "*", flo_mul, 1); - rb_define_method(cFloat, "/", flo_div, 1); - rb_define_method(cFloat, "%", flo_mod, 1); - rb_define_method(cFloat, "**", flo_pow, 1); - rb_define_method(cFloat, "==", flo_eq, 1); - rb_define_method(cFloat, "<=>", flo_cmp, 1); - rb_define_method(cFloat, "eql?", flo_eql, 1); - rb_define_method(cFloat, "hash", flo_hash, 0); - rb_define_method(cFloat, "to_i", flo_to_i, 0); - rb_define_method(cFloat, "to_f", flo_to_f, 0); - rb_define_method(cFloat, "abs", flo_abs, 0); + rb_eZeroDiv = rb_define_class("ZeroDivisionError", rb_eStandardError); + rb_cNumeric = rb_define_class("Numeric", rb_cObject); + + rb_include_module(rb_cNumeric, rb_mComparable); + rb_define_method(rb_cNumeric, "coerce", num_coerce, 1); + rb_define_method(rb_cNumeric, "clone", num_clone, 0); + + rb_define_method(rb_cNumeric, "+@", num_uplus, 0); + rb_define_method(rb_cNumeric, "-@", num_uminus, 0); + rb_define_method(rb_cNumeric, "eql?", num_eql, 1); + rb_define_method(rb_cNumeric, "divmod", num_divmod, 1); + rb_define_method(rb_cNumeric, "abs", num_abs, 0); + + rb_define_method(rb_cNumeric, "integer?", num_int_p, 0); + rb_define_method(rb_cNumeric, "zero?", num_zero_p, 0); + rb_define_method(rb_cNumeric, "nonzero?", num_nonzero_p, 0); + + rb_cInteger = rb_define_class("Integer", rb_cNumeric); + rb_define_method(rb_cInteger, "integer?", int_int_p, 0); + rb_define_method(rb_cInteger, "upto", int_upto, 1); + rb_define_method(rb_cInteger, "downto", int_downto, 1); + rb_define_method(rb_cInteger, "step", int_step, 2); + rb_define_method(rb_cInteger, "times", int_dotimes, 0); + rb_define_method(rb_cInteger, "succ", int_succ, 0); + rb_define_method(rb_cInteger, "next", int_succ, 0); + rb_define_method(rb_cInteger, "chr", int_chr, 0); + + rb_cFixnum = rb_define_class("Fixnum", rb_cInteger); + + rb_undef_method(CLASS_OF(rb_cFixnum), "new"); + + rb_define_method(rb_cFixnum, "to_s", fix_to_s, 0); + rb_define_method(rb_cFixnum, "type", fix_type, 0); + + rb_define_method(rb_cFixnum, "id2name", fix_id2name, 0); + + rb_define_method(rb_cFixnum, "-@", fix_uminus, 0); + rb_define_method(rb_cFixnum, "+", fix_plus, 1); + rb_define_method(rb_cFixnum, "-", fix_minus, 1); + rb_define_method(rb_cFixnum, "*", fix_mul, 1); + rb_define_method(rb_cFixnum, "/", fix_div, 1); + rb_define_method(rb_cFixnum, "%", fix_mod, 1); + rb_define_method(rb_cFixnum, "remainder", fix_remainder, 1); + rb_define_method(rb_cFixnum, "**", fix_pow, 1); + + rb_define_method(rb_cFixnum, "abs", fix_abs, 0); + + rb_define_method(rb_cFixnum, "==", fix_equal, 1); + rb_define_method(rb_cFixnum, "<=>", fix_cmp, 1); + rb_define_method(rb_cFixnum, ">", fix_gt, 1); + rb_define_method(rb_cFixnum, ">=", fix_ge, 1); + rb_define_method(rb_cFixnum, "<", fix_lt, 1); + rb_define_method(rb_cFixnum, "<=", fix_le, 1); + + rb_define_method(rb_cFixnum, "~", fix_rev, 0); + rb_define_method(rb_cFixnum, "&", fix_and, 1); + rb_define_method(rb_cFixnum, "|", fix_or, 1); + rb_define_method(rb_cFixnum, "^", fix_xor, 1); + rb_define_method(rb_cFixnum, "[]", fix_aref, 1); + + rb_define_method(rb_cFixnum, "<<", fix_lshift, 1); + rb_define_method(rb_cFixnum, ">>", fix_rshift, 1); + + rb_define_method(rb_cFixnum, "to_i", fix_to_i, 0); + rb_define_method(rb_cFixnum, "to_f", fix_to_f, 0); + + rb_define_method(rb_cFixnum, "succ", fix_succ, 0); + rb_define_method(rb_cFixnum, "next", fix_succ, 0); + rb_define_method(rb_cFixnum, "size", fix_size, 0); + + rb_define_method(rb_cFixnum, "upto", fix_upto, 1); + rb_define_method(rb_cFixnum, "downto", fix_downto, 1); + rb_define_method(rb_cFixnum, "step", fix_step, 2); + rb_define_method(rb_cFixnum, "times", fix_dotimes, 0); + rb_define_method(rb_cFixnum, "zero?", fix_zero_p, 0); + + rb_cFloat = rb_define_class("Float", rb_cNumeric); + + rb_undef_method(CLASS_OF(rb_cFloat), "new"); + + rb_define_method(rb_cFloat, "to_s", flo_to_s, 0); + rb_define_method(rb_cFloat, "coerce", flo_coerce, 1); + rb_define_method(rb_cFloat, "-@", flo_uminus, 0); + rb_define_method(rb_cFloat, "+", flo_plus, 1); + rb_define_method(rb_cFloat, "-", flo_minus, 1); + rb_define_method(rb_cFloat, "*", flo_mul, 1); + rb_define_method(rb_cFloat, "/", flo_div, 1); + rb_define_method(rb_cFloat, "%", flo_mod, 1); + rb_define_method(rb_cFloat, "remainder", flo_remainder, 1); + rb_define_method(rb_cFloat, "**", flo_pow, 1); + rb_define_method(rb_cFloat, "==", flo_eq, 1); + rb_define_method(rb_cFloat, "<=>", flo_cmp, 1); + rb_define_method(rb_cFloat, ">", flo_gt, 1); + rb_define_method(rb_cFloat, ">=", flo_ge, 1); + rb_define_method(rb_cFloat, "<", flo_lt, 1); + rb_define_method(rb_cFloat, "<=", flo_le, 1); + rb_define_method(rb_cFloat, "eql?", flo_eql, 1); + rb_define_method(rb_cFloat, "hash", flo_hash, 0); + rb_define_method(rb_cFloat, "to_i", flo_to_i, 0); + rb_define_method(rb_cFloat, "to_f", flo_to_f, 0); + rb_define_method(rb_cFloat, "abs", flo_abs, 0); + rb_define_method(rb_cFloat, "zero?", flo_zero_p, 0); + + rb_define_method(rb_cFloat, "floor", flo_floor, 0); + rb_define_method(rb_cFloat, "ceil", flo_ceil, 0); + rb_define_method(rb_cFloat, "round", flo_round, 0); } diff --git a/object.c b/object.c index 2e614b3a41..15e757d054 100644 --- a/object.c +++ b/object.c @@ -6,7 +6,7 @@ $Date$ created at: Thu Jul 15 12:01:24 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -14,22 +14,18 @@ #include "st.h" #include <stdio.h> -VALUE mKernel; -VALUE cObject; -VALUE cModule; -VALUE cClass; -extern VALUE cFixnum; -VALUE cData; +VALUE rb_mKernel; +VALUE rb_cObject; +VALUE rb_cModule; +VALUE rb_cClass; +VALUE rb_cData; -static VALUE cNilClass; -static VALUE cTrueClass; -static VALUE cFalseClass; +VALUE rb_cNilClass; +VALUE rb_cTrueClass; +VALUE rb_cFalseClass; -struct st_table *new_idhash(); - -VALUE f_sprintf(); - -VALUE obj_alloc(); +VALUE rb_f_sprintf(); +VALUE rb_obj_alloc(); static ID eq, eql; static ID inspect; @@ -40,10 +36,11 @@ rb_equal(obj1, obj2) { VALUE result; + if (obj1 == obj2) return Qtrue; result = rb_funcall(obj1, eq, 1, obj2); - if (result == FALSE || NIL_P(result)) - return FALSE; - return TRUE; + if (result == Qfalse || NIL_P(result)) + return Qfalse; + return Qtrue; } int @@ -53,82 +50,98 @@ rb_eql(obj1, obj2) return rb_funcall(obj1, eql, 1, obj2); } -VALUE -obj_equal(obj1, obj2) +static VALUE +rb_obj_equal(obj1, obj2) VALUE obj1, obj2; { - if (obj1 == obj2) return TRUE; - return FALSE; + if (obj1 == obj2) return Qtrue; + return Qfalse; } static VALUE -any_to_a(obj) +rb_any_to_a(obj) VALUE obj; { - return ary_new3(1, obj); + return rb_ary_new3(1, obj); } static VALUE -obj_id(obj) +rb_obj_hash(obj) VALUE obj; { - return INT2NUM((int)obj); + return (long)obj|FIXNUM_FLAG; +} + +VALUE +rb_obj_id(obj) + VALUE obj; +{ + if (rb_special_const_p(obj)) { + return INT2NUM((long)obj); + } + return (long)obj|FIXNUM_FLAG; } static VALUE -obj_type(obj) +rb_obj_type(obj) VALUE obj; { VALUE cl = CLASS_OF(obj); - if (FL_TEST(cl, FL_SINGLETON)) { + while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) { cl = RCLASS(cl)->super; } return cl; } -static VALUE -obj_clone(obj) +VALUE +rb_obj_clone(obj) VALUE obj; { VALUE clone; if (TYPE(obj) != T_OBJECT) { - TypeError("can't clone %s", rb_class2name(CLASS_OF(obj))); + rb_raise(rb_eTypeError, "can't clone %s", rb_class2name(CLASS_OF(obj))); } - clone = obj_alloc(RBASIC(obj)->class); + clone = rb_obj_alloc(RBASIC(obj)->klass); CLONESETUP(clone,obj); if (ROBJECT(obj)->iv_tbl) { ROBJECT(clone)->iv_tbl = st_copy(ROBJECT(obj)->iv_tbl); - RBASIC(clone)->class = singleton_class_clone(RBASIC(obj)->class); - RBASIC(clone)->flags = RBASIC(obj)->flags; + RBASIC(clone)->klass = rb_singleton_class_clone(RBASIC(obj)->klass); + RBASIC(clone)->flags = RBASIC(obj)->flags; } return clone; } static VALUE -obj_dup(obj) +rb_obj_dup(obj) VALUE obj; { return rb_funcall(obj, rb_intern("clone"), 0, 0); } VALUE -any_to_s(obj) +rb_any_to_s(obj) VALUE obj; { - char buf[256]; + char *s; + char *cname = rb_class2name(CLASS_OF(obj)); + VALUE str; + + s = ALLOCA_N(char, strlen(cname)+6+16+1); /* 6:tags 16:addr 1:eos */ + sprintf(s, "#<%s:0x%x>", cname, obj); + str = rb_str_new2(s); + if (OBJ_TAINTED(obj)) OBJ_TAINT(str); - sprintf(buf, "#<%s:0x%x>", rb_class2name(CLASS_OF(obj)), obj); - return str_new2(buf); + return str; } VALUE rb_inspect(obj) VALUE obj; { - return obj_as_string(rb_funcall(obj, inspect, 0, 0)); + return rb_obj_as_string(rb_funcall(obj, inspect, 0, 0)); } static int @@ -142,29 +155,35 @@ inspect_i(id, value, str) /* need not to show internal data */ if (CLASS_OF(value) == 0) return ST_CONTINUE; + if (!rb_is_instance_id(id)) return ST_CONTINUE; if (RSTRING(str)->ptr[0] == '-') { RSTRING(str)->ptr[0] = '#'; - str_cat(str, ": ", 2); + rb_str_cat(str, ": ", 2); } else { - str_cat(str, ", ", 2); + rb_str_cat(str, ", ", 2); } ivname = rb_id2name(id); - str_cat(str, ivname, strlen(ivname)); - str_cat(str, "=", 1); - if (TYPE(value) == T_OBJECT) { - str2 = any_to_s(value); - } - else { - str2 = rb_inspect(value); - } - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + rb_str_cat(str, ivname, strlen(ivname)); + rb_str_cat(str, "=", 1); + str2 = rb_inspect(value); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); return ST_CONTINUE; } static VALUE -obj_inspect(obj) +inspect_obj(obj, str) + VALUE obj, str; +{ + st_foreach(ROBJECT(obj)->iv_tbl, inspect_i, str); + rb_str_cat(str, ">", 1); + + return str; +} + +static VALUE +rb_obj_inspect(obj) VALUE obj; { if (TYPE(obj) == T_OBJECT @@ -173,19 +192,21 @@ obj_inspect(obj) VALUE str; char *b; - str = str_new2("-<"); b = rb_class2name(CLASS_OF(obj)); - str_cat(str, b, strlen(b)); - st_foreach(ROBJECT(obj)->iv_tbl, inspect_i, str); - str_cat(str, ">", 1); - - return str; + if (rb_inspecting_p(obj)) { + char *buf = ALLOCA_N(char, strlen(b)+8); + sprintf(buf, "#<%s:...>", b); + return rb_str_new2(buf); + } + str = rb_str_new2("-<"); + rb_str_cat(str, b, strlen(b)); + return rb_protect_inspect(inspect_obj, obj, str); } return rb_funcall(obj, rb_intern("to_s"), 0, 0); } VALUE -obj_is_instance_of(obj, c) +rb_obj_is_instance_of(obj, c) VALUE obj, c; { VALUE cl; @@ -196,31 +217,31 @@ obj_is_instance_of(obj, c) break; case T_NIL: - if (NIL_P(obj)) return TRUE; - return FALSE; + if (NIL_P(obj)) return Qtrue; + return Qfalse; case T_FALSE: - if (obj) return FALSE; - return TRUE; + if (obj) return Qfalse; + return Qtrue; case T_TRUE: - if (obj) return TRUE; - return FALSE; + if (obj) return Qtrue; + return Qfalse; default: - TypeError("class or module required"); + rb_raise(rb_eTypeError, "class or module required"); } cl = CLASS_OF(obj); - while (FL_TEST(cl, FL_SINGLETON)) { + while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) { cl = RCLASS(cl)->super; } - if (c == cl) return TRUE; - return FALSE; + if (c == cl) return Qtrue; + return Qfalse; } VALUE -obj_is_kind_of(obj, c) +rb_obj_is_kind_of(obj, c) VALUE obj, c; { VALUE cl = CLASS_OF(obj); @@ -230,70 +251,93 @@ obj_is_kind_of(obj, c) case T_CLASS: break; - case T_NIL: - if (NIL_P(obj)) return TRUE; - return FALSE; - - case T_FALSE: - if (obj) return FALSE; - return TRUE; - - case T_TRUE: - if (obj) return TRUE; - return FALSE; - default: - TypeError("class or module required"); + rb_raise(rb_eTypeError, "class or module required"); } while (cl) { if (cl == c || RCLASS(cl)->m_tbl == RCLASS(c)->m_tbl) - return TRUE; + return Qtrue; cl = RCLASS(cl)->super; } - return FALSE; + return Qfalse; } static VALUE -obj_dummy(obj) +rb_obj_dummy(obj) VALUE obj; { return Qnil; } +VALUE +rb_obj_tainted(obj) + VALUE obj; +{ + if (OBJ_TAINTED(obj)) + return Qtrue; + return Qfalse; +} + +VALUE +rb_obj_taint(obj) + VALUE obj; +{ + OBJ_TAINT(obj); + return obj; +} + +VALUE +rb_obj_untaint(obj) + VALUE obj; +{ + rb_secure(3); + FL_UNSET(obj, FL_TAINT); + return obj; +} + +static VALUE +nil_to_i(obj) + VALUE obj; +{ + return INT2FIX(0); +} + static VALUE nil_to_s(obj) VALUE obj; { - return str_new2(""); + return rb_str_new2(""); } static VALUE nil_to_a(obj) VALUE obj; { - return ary_new2(0); + return rb_ary_new2(0); } static VALUE nil_inspect(obj) VALUE obj; { - return str_new2("nil"); + return rb_str_new2("nil"); } static VALUE nil_type(obj) VALUE obj; { - return cNilClass; + return rb_cNilClass; } +#ifdef NIL_PLUS static VALUE nil_plus(x, y) VALUE x, y; { switch (TYPE(y)) { + case T_NIL: case T_FIXNUM: case T_FLOAT: case T_BIGNUM: @@ -301,74 +345,132 @@ nil_plus(x, y) case T_ARRAY: return y; default: - TypeError("tried to add %s(%s) to nil", - RSTRING(obj_as_string(y))->ptr, rb_class2name(CLASS_OF(y))); + rb_raise(rb_eTypeError, "tried to add %s(%s) to nil", + STR2CSTR(rb_inspect(y)), + rb_class2name(CLASS_OF(y))); } /* not reached */ } +#endif static VALUE main_to_s(obj) VALUE obj; { - return str_new2("main"); + return rb_str_new2("main"); } static VALUE true_to_s(obj) VALUE obj; { - return str_new2("true"); + return rb_str_new2("true"); +} + +static VALUE +true_to_i(obj) + VALUE obj; +{ + return INT2FIX(1); } static VALUE true_type(obj) VALUE obj; { - return cTrueClass; + return rb_cTrueClass; +} + +static VALUE +true_and(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qtrue:Qfalse; +} + +static VALUE +true_or(obj, obj2) + VALUE obj, obj2; +{ + return Qtrue; +} + +static VALUE +true_xor(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qfalse:Qtrue; } static VALUE false_to_s(obj) VALUE obj; { - return str_new2("false"); + return rb_str_new2("false"); +} + +static VALUE +false_to_i(obj) + VALUE obj; +{ + return INT2FIX(0); } static VALUE false_type(obj) VALUE obj; { - return cFalseClass; + return rb_cFalseClass; +} + +static VALUE +false_and(obj, obj2) + VALUE obj, obj2; +{ + return Qfalse; +} + +static VALUE +false_or(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qtrue:Qfalse; +} + +static VALUE +false_xor(obj, obj2) + VALUE obj, obj2; +{ + return RTEST(obj2)?Qtrue:Qfalse; } static VALUE rb_true(obj) VALUE obj; { - return TRUE; + return Qtrue; } static VALUE rb_false(obj) VALUE obj; { - return FALSE; + return Qfalse; } VALUE -obj_alloc(class) - VALUE class; +rb_obj_alloc(klass) + VALUE klass; { NEWOBJ(obj, struct RObject); - OBJSETUP(obj, class, T_OBJECT); + OBJSETUP(obj, klass, T_OBJECT); obj->iv_tbl = 0; return (VALUE)obj; } static VALUE -mod_clone(module) +rb_mod_clone(module) VALUE module; { NEWOBJ(clone, struct RClass); @@ -377,27 +479,28 @@ mod_clone(module) clone->super = RCLASS(module)->super; clone->iv_tbl = 0; clone->m_tbl = 0; /* avoid GC crashing */ + clone->iv_tbl = st_copy(RCLASS(module)->iv_tbl); clone->m_tbl = st_copy(RCLASS(module)->m_tbl); return (VALUE)clone; } static VALUE -mod_to_s(class) - VALUE class; +rb_mod_to_s(klass) + VALUE klass; { - return rb_class_path(class); + return rb_str_dup(rb_class_path(klass)); } static VALUE -mod_eqq(mod, arg) +rb_mod_eqq(mod, arg) VALUE mod, arg; { - return obj_is_kind_of(arg, mod); + return rb_obj_is_kind_of(arg, mod); } static VALUE -mod_le(mod, arg) +rb_mod_le(mod, arg) VALUE mod, arg; { switch (TYPE(arg)) { @@ -405,28 +508,28 @@ mod_le(mod, arg) case T_CLASS: break; default: - TypeError("compared with non class/module"); + rb_raise(rb_eTypeError, "compared with non class/module"); } while (mod) { if (RCLASS(mod)->m_tbl == RCLASS(arg)->m_tbl) - return TRUE; + return Qtrue; mod = RCLASS(mod)->super; } - return FALSE; + return Qfalse; } static VALUE -mod_lt(mod, arg) +rb_mod_lt(mod, arg) VALUE mod, arg; { - if (mod == arg) return FALSE; - return mod_le(mod, arg); + if (mod == arg) return Qfalse; + return rb_mod_le(mod, arg); } static VALUE -mod_ge(mod, arg) +rb_mod_ge(mod, arg) VALUE mod, arg; { switch (TYPE(arg)) { @@ -434,22 +537,22 @@ mod_ge(mod, arg) case T_CLASS: break; default: - TypeError("compared with non class/module"); + rb_raise(rb_eTypeError, "compared with non class/module"); } - return mod_lt(arg, mod); + return rb_mod_lt(arg, mod); } static VALUE -mod_gt(mod, arg) +rb_mod_gt(mod, arg) VALUE mod, arg; { - if (mod == arg) return FALSE; - return mod_ge(mod, arg); + if (mod == arg) return Qfalse; + return rb_mod_ge(mod, arg); } static VALUE -mod_cmp(mod, arg) +rb_mod_cmp(mod, arg) VALUE mod, arg; { if (mod == arg) return INT2FIX(0); @@ -459,52 +562,63 @@ mod_cmp(mod, arg) case T_CLASS: break; default: - TypeError("<=> requires Class or Module (%s given)", - rb_class2name(CLASS_OF(arg))); + rb_raise(rb_eTypeError, "<=> requires Class or Module (%s given)", + rb_class2name(CLASS_OF(arg))); break; } - if (mod_le(mod, arg)) { + if (rb_mod_le(mod, arg)) { return INT2FIX(-1); } return INT2FIX(1); } -VALUE module_new(); -VALUE class_new_instance(); +static VALUE +rb_module_s_new(klass) +{ + VALUE mod = rb_module_new(); + + RBASIC(mod)->klass = klass; + rb_obj_call_init(mod); + return mod; +} + +VALUE rb_class_new_instance(); static VALUE -class_s_new(argc, argv) +rb_class_s_new(argc, argv) int argc; VALUE *argv; { VALUE super, klass; - rb_scan_args(argc, argv, "01", &super); - if (NIL_P(super)) super = cObject; + if (rb_scan_args(argc, argv, "01", &super) == 0) { + super = rb_cObject; + } Check_Type(super, T_CLASS); if (FL_TEST(super, FL_SINGLETON)) { - TypeError("can't make subclass of virtual class"); + rb_raise(rb_eTypeError, "can't make subclass of virtual class"); } - klass = class_new(super); + klass = rb_class_new(super); /* make metaclass */ - RBASIC(klass)->class = singleton_class_new(RBASIC(super)->class); - singleton_class_attached(RBASIC(klass)->class, klass); + RBASIC(klass)->klass = rb_singleton_class_new(RBASIC(super)->klass); + rb_singleton_class_attached(RBASIC(klass)->klass, klass); + rb_obj_call_init(klass); return klass; } -VALUE mod_name(); -VALUE mod_included_modules(); -VALUE mod_ancestors(); -VALUE class_instance_methods(); -VALUE class_private_instance_methods(); +static VALUE +rb_class_s_inherited() +{ + rb_raise(rb_eTypeError, "can't make subclass of Class"); +} static VALUE -class_superclass(cl) - VALUE cl; +rb_class_superclass(klass) + VALUE klass; { - VALUE super = RCLASS(cl)->super; + VALUE super = RCLASS(klass)->super; while (TYPE(super) == T_ICLASS) { super = RCLASS(super)->super; @@ -519,79 +633,82 @@ ID rb_to_id(name) VALUE name; { + ID id; + if (TYPE(name) == T_STRING) { return rb_intern(RSTRING(name)->ptr); } - Check_Type(name, T_FIXNUM); - return FIX2UINT(name); + id = NUM2UINT(name); + if (!rb_id2name(id)) { + rb_raise(rb_eArgError, "%d is not a symbol", id); + } + return id; } static VALUE -mod_attr(argc, argv, class) +rb_mod_attr(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { VALUE name, pub; rb_scan_args(argc, argv, "11", &name, &pub); - rb_define_attr(class, rb_to_id(name), 1, RTEST(pub)); + rb_attr(klass, rb_to_id(name), 1, RTEST(pub), Qtrue); return Qnil; } static VALUE -mod_attr_reader(argc, argv, class) +rb_mod_attr_reader(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { int i; for (i=0; i<argc; i++) { - rb_define_attr(class, rb_to_id(argv[i]), 1, 0); + rb_attr(klass, rb_to_id(argv[i]), 1, 0, Qtrue); } return Qnil; } static VALUE -mod_attr_writer(argc, argv, class) +rb_mod_attr_writer(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { int i; for (i=0; i<argc; i++) { - rb_define_attr(class, rb_to_id(argv[i]), 0, 1); + rb_attr(klass, rb_to_id(argv[i]), 0, 1, Qtrue); } return Qnil; } static VALUE -mod_attr_accessor(argc, argv, class) +rb_mod_attr_accessor(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { int i; for (i=0; i<argc; i++) { - rb_define_attr(class, rb_to_id(argv[i]), 1, 1); + rb_attr(klass, rb_to_id(argv[i]), 1, 1, Qtrue); } return Qnil; } -VALUE mod_constants(); - static VALUE -mod_const_get(mod, name) +rb_mod_const_get(mod, name) VALUE mod, name; { return rb_const_get_at(mod, rb_to_id(name)); } static VALUE -mod_const_set(mod, name, value) +rb_mod_const_set(mod, name, value) VALUE mod, name, value; { rb_const_set(mod, rb_to_id(name), value); @@ -599,159 +716,201 @@ mod_const_set(mod, name, value) } static VALUE -mod_const_defined(mod, name) +rb_mod_const_defined(mod, name) VALUE mod, name; { return rb_const_defined_at(mod, rb_to_id(name)); } static VALUE -obj_methods(obj) +rb_obj_methods(obj) VALUE obj; { VALUE argv[1]; - argv[0] = TRUE; - return class_instance_methods(1, argv, CLASS_OF(obj)); + argv[0] = Qtrue; + return rb_class_instance_methods(1, argv, CLASS_OF(obj)); } -VALUE obj_singleton_methods(); +VALUE rb_obj_singleton_methods(); static VALUE -obj_private_methods(obj) +rb_obj_protected_methods(obj) VALUE obj; { VALUE argv[1]; - argv[0] = TRUE; - return class_private_instance_methods(1, argv, CLASS_OF(obj)); + argv[0] = Qtrue; + return rb_class_protected_instance_methods(1, argv, CLASS_OF(obj)); } -VALUE obj_instance_variables(); -VALUE obj_remove_instance_variable(); - static VALUE -f_integer(obj, arg) - VALUE obj, arg; +rb_obj_private_methods(obj) + VALUE obj; { - int i; + VALUE argv[1]; - switch (TYPE(arg)) { + argv[0] = Qtrue; + return rb_class_private_instance_methods(1, argv, CLASS_OF(obj)); +} + +VALUE +rb_Integer(val) + VALUE val; +{ + long i; + + switch (TYPE(val)) { case T_FLOAT: - if (RFLOAT(arg)->value <= (double)FIXNUM_MAX - && RFLOAT(arg)->value >= (double)FIXNUM_MIN) { - i = (int)RFLOAT(arg)->value; + if (RFLOAT(val)->value <= (double)FIXNUM_MAX + && RFLOAT(val)->value >= (double)FIXNUM_MIN) { + i = (long)RFLOAT(val)->value; break; } - return dbl2big(RFLOAT(arg)->value); + return rb_dbl2big(RFLOAT(val)->value); case T_BIGNUM: - return arg; + return val; case T_STRING: - return str2inum(RSTRING(arg)->ptr, 0); + return rb_str2inum(RSTRING(val)->ptr, 0); + + case T_NIL: + return INT2FIX(0); default: - i = NUM2INT(arg); + i = NUM2LONG(val); } return INT2NUM(i); } -VALUE -rb_Integer(val) - VALUE val; +static VALUE +rb_f_integer(obj, arg) + VALUE obj, arg; { - return f_integer(Qnil, val); + return rb_Integer(arg); } -static VALUE -to_flo(val) +struct arg_to { VALUE val; + char *s; +}; + +static VALUE +to_type(arg) + struct arg_to *arg; { - return rb_funcall(val, rb_intern("to_f"), 0); + return rb_funcall(arg->val, rb_intern(arg->s), 0); } static VALUE -fail_to_flo(val) +fail_to_type(arg) + struct arg_to *arg; +{ + rb_raise(rb_eTypeError, "failed to convert %s into %s", + NIL_P(arg->val) ? "nil" : + arg->val == Qtrue ? "true" : + arg->val == Qfalse ? "false" : + rb_class2name(CLASS_OF(arg->val)), + arg->s); +} + +VALUE +rb_convert_type(val, type, tname, method) VALUE val; + int type; + char *tname, *method; { - TypeError("failed to convert %s into Float", rb_class2name(CLASS_OF(val))); + struct arg_to arg1, arg2; + + if (TYPE(val) == type) return val; + arg1.val = arg2.val = val; + arg1.s = method; + arg2.s = tname; + val = rb_rescue(to_type, (VALUE)&arg1, fail_to_type, (VALUE)&arg2); + Check_Type(val, type); + return val; } -double big2dbl(); +double rb_big2dbl _((VALUE)); -static VALUE -f_float(obj, arg) - VALUE obj, arg; +VALUE +rb_Float(val) + VALUE val; { - switch (TYPE(arg)) { + switch (TYPE(val)) { case T_FIXNUM: - return float_new((double)FIX2INT(arg)); + return rb_float_new((double)FIX2LONG(val)); case T_FLOAT: - return arg; + return val; case T_BIGNUM: - return float_new(big2dbl(arg)); + return rb_float_new(rb_big2dbl(val)); default: - return rb_rescue(to_flo, arg, fail_to_flo, arg); + return rb_convert_type(val, T_FLOAT, "Float", "to_f"); } } -VALUE -rb_Float(val) - VALUE val; +static VALUE +rb_f_float(obj, arg) + VALUE obj, arg; { - return f_float(Qnil, val); + return rb_Float(arg); } double -num2dbl(val) +rb_num2dbl(val) VALUE val; { VALUE v = rb_Float(val); return RFLOAT(v)->value; } -static VALUE -f_string(obj, arg) - VALUE obj, arg; +char* +rb_str2cstr(str, len) + VALUE str; + int *len; { - return rb_funcall(arg, rb_intern("to_s"), 0); + if (TYPE(str) != T_STRING) { + str = rb_str_to_str(str); + } + if (len) *len = RSTRING(str)->len; + return RSTRING(str)->ptr; } VALUE rb_String(val) VALUE val; { - return f_string(Qnil, val); + return rb_convert_type(val, T_STRING, "String", "to_s"); } static VALUE -f_array(obj, arg) +rb_f_string(obj, arg) VALUE obj, arg; { - if (TYPE(arg) == T_ARRAY) return arg; - arg = rb_funcall(arg, rb_intern("to_a"), 0); - if (TYPE(arg) != T_ARRAY) { - TypeError("`to_a' did not return Array"); - } - return arg; + return rb_String(arg); } VALUE rb_Array(val) VALUE val; { - return f_array(Qnil, val); + if (TYPE(val) == T_ARRAY) return val; + val = rb_funcall(val, rb_intern("to_a"), 0); + if (TYPE(val) != T_ARRAY) { + rb_raise(rb_eTypeError, "`to_a' did not return Array"); + } + return val; } -VALUE -rb_to_a(val) /* backward compatibility */ - VALUE val; +static VALUE +rb_f_array(obj, arg) + VALUE obj, arg; { - return f_array(Qnil, val); + return rb_Array(arg); } static VALUE @@ -760,47 +919,36 @@ boot_defclass(name, super) VALUE super; { extern st_table *rb_class_tbl; - VALUE obj = class_new(super); + VALUE obj = rb_class_new(super); ID id = rb_intern(name); rb_name_class(obj, id); st_add_direct(rb_class_tbl, id, obj); - return (VALUE)obj; -} - -VALUE -rb_class_of(obj) - VALUE obj; -{ - if (FIXNUM_P(obj)) return cFixnum; - if (obj == Qnil) return cNilClass; - if (obj == FALSE) return cFalseClass; - if (obj == TRUE) return cTrueClass; - - return RBASIC(obj)->class; + return obj; } -VALUE TopSelf; +VALUE ruby_top_self; void Init_Object() { VALUE metaclass; - cObject = boot_defclass("Object", 0); - cModule = boot_defclass("Module", cObject); - cClass = boot_defclass("Class", cModule); + rb_cObject = boot_defclass("Object", 0); + rb_cModule = boot_defclass("Module", rb_cObject); + rb_cClass = boot_defclass("Class", rb_cModule); - metaclass = RBASIC(cObject)->class = singleton_class_new(cClass); - singleton_class_attached(metaclass, cObject); - metaclass = RBASIC(cModule)->class = singleton_class_new(metaclass); - singleton_class_attached(metaclass, cModule); - metaclass = RBASIC(cClass)->class = singleton_class_new(metaclass); - singleton_class_attached(metaclass, cClass); + metaclass = RBASIC(rb_cObject)->klass = rb_singleton_class_new(rb_cClass); + rb_singleton_class_attached(metaclass, rb_cObject); + metaclass = RBASIC(rb_cModule)->klass = rb_singleton_class_new(metaclass); + rb_singleton_class_attached(metaclass, rb_cModule); + metaclass = RBASIC(rb_cClass)->klass = rb_singleton_class_new(metaclass); + rb_singleton_class_attached(metaclass, rb_cClass); - mKernel = rb_define_module("Kernel"); - rb_include_module(cObject, mKernel); - rb_define_private_method(cClass, "inherited", obj_dummy, 1); + rb_mKernel = rb_define_module("Kernel"); + rb_include_module(rb_cObject, rb_mKernel); + rb_define_private_method(rb_cObject, "initialize", rb_obj_dummy, -1); + rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1); /* * Ruby's Class Hierarchy Chart @@ -826,111 +974,132 @@ Init_Object() * + All metaclasses are instances of the class `Class'. */ - rb_define_method(mKernel, "nil?", rb_false, 0); - rb_define_method(mKernel, "==", obj_equal, 1); - rb_define_alias(mKernel, "equal?", "=="); - rb_define_alias(mKernel, "===", "=="); - rb_define_method(mKernel, "=~", rb_false, 1); - - rb_define_method(mKernel, "eql?", obj_equal, 1); - - rb_define_method(mKernel, "hash", obj_id, 0); - rb_define_method(mKernel, "id", obj_id, 0); - rb_define_method(mKernel, "type", obj_type, 0); - - rb_define_method(mKernel, "clone", obj_clone, 0); - rb_define_method(mKernel, "dup", obj_dup, 0); - - rb_define_method(mKernel, "to_a", any_to_a, 0); - rb_define_method(mKernel, "to_s", any_to_s, 0); - rb_define_method(mKernel, "inspect", obj_inspect, 0); - rb_define_method(mKernel, "methods", obj_methods, 0); - rb_define_method(mKernel, "singleton_methods", obj_singleton_methods, 0); - rb_define_method(mKernel, "private_methods", obj_private_methods, 0); - rb_define_method(mKernel, "instance_variables", obj_instance_variables, 0); - rb_define_method(mKernel, "remove_instance_variable", obj_remove_instance_variable, 0); - - rb_define_method(mKernel, "instance_of?", obj_is_instance_of, 1); - rb_define_method(mKernel, "kind_of?", obj_is_kind_of, 1); - rb_define_method(mKernel, "is_a?", obj_is_kind_of, 1); - - rb_define_global_function("sprintf", f_sprintf, -1); - rb_define_alias(mKernel, "format", "sprintf"); - - rb_define_global_function("Integer", f_integer, 1); - rb_define_global_function("Float", f_float, 1); - - rb_define_global_function("String", f_string, 1); - rb_define_global_function("Array", f_array, 1); - - cNilClass = rb_define_class("NilClass", cObject); - rb_define_method(cNilClass, "type", nil_type, 0); - rb_define_method(cNilClass, "to_s", nil_to_s, 0); - rb_define_method(cNilClass, "to_a", nil_to_a, 0); - rb_define_method(cNilClass, "inspect", nil_inspect, 0); - - rb_define_method(cNilClass, "nil?", rb_true, 0); - rb_undef_method(CLASS_OF(cNilClass), "new"); + rb_define_method(rb_mKernel, "nil?", rb_false, 0); + rb_define_method(rb_mKernel, "==", rb_obj_equal, 1); + rb_define_alias(rb_mKernel, "equal?", "=="); + rb_define_alias(rb_mKernel, "===", "=="); + rb_define_method(rb_mKernel, "=~", rb_false, 1); + + rb_define_method(rb_mKernel, "eql?", rb_obj_equal, 1); + + rb_define_method(rb_mKernel, "hash", rb_obj_hash, 0); + rb_define_method(rb_mKernel, "id", rb_obj_id, 0); + rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0); + rb_define_method(rb_mKernel, "type", rb_obj_type, 0); + + rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0); + rb_define_method(rb_mKernel, "dup", rb_obj_dup, 0); + + rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0); + rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0); + rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0); + + rb_define_method(rb_mKernel, "to_a", rb_any_to_a, 0); + rb_define_method(rb_mKernel, "to_s", rb_any_to_s, 0); + rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); + rb_define_method(rb_mKernel, "methods", rb_obj_methods, 0); + rb_define_method(rb_mKernel, "public_methods", rb_obj_methods, 0); + rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, 0); + rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, 0); + rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, 0); + rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); + rb_define_private_method(rb_mKernel, "remove_instance_variable", + rb_obj_remove_instance_variable, 0); + + rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); + rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); + rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); + + rb_define_global_function("sprintf", rb_f_sprintf, -1); + rb_define_global_function("format", rb_f_sprintf, -1); + + rb_define_global_function("Integer", rb_f_integer, 1); + rb_define_global_function("Float", rb_f_float, 1); + + rb_define_global_function("String", rb_f_string, 1); + rb_define_global_function("Array", rb_f_array, 1); + + rb_cNilClass = rb_define_class("NilClass", rb_cObject); + rb_define_method(rb_cNilClass, "type", nil_type, 0); + rb_define_method(rb_cNilClass, "to_i", nil_to_i, 0); + rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0); + rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0); + rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0); + + rb_define_method(rb_cNilClass, "nil?", rb_true, 0); + rb_undef_method(CLASS_OF(rb_cNilClass), "new"); rb_define_global_const("NIL", Qnil); /* default addition */ - rb_define_method(cNilClass, "+", nil_plus, 1); - - rb_define_global_function("initialize", obj_dummy, -1); - rb_define_global_function("singleton_method_added", obj_dummy, 1); - - rb_define_method(cModule, "===", mod_eqq, 1); - rb_define_method(cModule, "<=>", mod_cmp, 1); - rb_define_method(cModule, "<", mod_lt, 1); - rb_define_method(cModule, "<=", mod_le, 1); - rb_define_method(cModule, ">", mod_gt, 1); - rb_define_method(cModule, ">=", mod_ge, 1); - rb_define_method(cModule, "clone", mod_clone, 0); - rb_define_method(cModule, "to_s", mod_to_s, 0); - rb_define_method(cModule, "included_modules", mod_included_modules, 0); - rb_define_method(cModule, "name", mod_name, 0); - rb_define_method(cModule, "ancestors", mod_ancestors, 0); - - rb_define_private_method(cModule, "attr", mod_attr, -1); - rb_define_private_method(cModule, "attr_reader", mod_attr_reader, -1); - rb_define_private_method(cModule, "attr_writer", mod_attr_writer, -1); - rb_define_private_method(cModule, "attr_accessor", mod_attr_accessor, -1); - - rb_define_singleton_method(cModule, "new", module_new, 0); - rb_define_method(cModule, "instance_methods", class_instance_methods, -1); - rb_define_method(cModule, "private_instance_methods", class_private_instance_methods, -1); - - rb_define_method(cModule, "constants", mod_constants, 0); - rb_define_method(cModule, "const_get", mod_const_get, 1); - rb_define_method(cModule, "const_set", mod_const_set, 2); - rb_define_method(cModule, "const_defined?", mod_const_defined, 1); - rb_define_private_method(cModule, "method_added", obj_dummy, 1); - - rb_define_method(cClass, "new", class_new_instance, -1); - rb_define_method(cClass, "superclass", class_superclass, 0); - rb_define_singleton_method(cClass, "new", class_s_new, -1); - rb_undef_method(cClass, "extend_object"); - rb_undef_method(cClass, "append_features"); - - rb_define_singleton_method(cClass, "new", class_s_new, -1); - - cData = rb_define_class("Data", cObject); - - TopSelf = obj_alloc(cObject); - rb_global_variable(&TopSelf); - rb_define_singleton_method(TopSelf, "to_s", main_to_s, 0); - - cTrueClass = rb_define_class("TrueClass", cObject); - rb_define_method(cTrueClass, "to_s", true_to_s, 0); - rb_define_method(cTrueClass, "type", true_type, 0); - rb_undef_method(CLASS_OF(cTrueClass), "new"); - rb_define_global_const("TRUE", TRUE); - - cFalseClass = rb_define_class("FalseClass", cObject); - rb_define_method(cFalseClass, "to_s", false_to_s, 0); - rb_define_method(cFalseClass, "type", false_type, 0); - rb_undef_method(CLASS_OF(cFalseClass), "new"); - rb_define_global_const("FALSE", FALSE); +#ifdef NIL_PLUS + rb_define_method(rb_cNilClass, "+", nil_plus, 1); +#endif + + rb_define_global_function("singleton_method_added", rb_obj_dummy, 1); + + rb_define_method(rb_cModule, "===", rb_mod_eqq, 1); + rb_define_method(rb_cModule, "<=>", rb_mod_cmp, 1); + rb_define_method(rb_cModule, "<", rb_mod_lt, 1); + rb_define_method(rb_cModule, "<=", rb_mod_le, 1); + rb_define_method(rb_cModule, ">", rb_mod_gt, 1); + rb_define_method(rb_cModule, ">=", rb_mod_ge, 1); + rb_define_method(rb_cModule, "clone", rb_mod_clone, 0); + rb_define_method(rb_cModule, "to_s", rb_mod_to_s, 0); + rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); + rb_define_method(rb_cModule, "name", rb_mod_name, 0); + rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); + + rb_define_private_method(rb_cModule, "attr", rb_mod_attr, -1); + rb_define_private_method(rb_cModule, "attr_reader", rb_mod_attr_reader, -1); + rb_define_private_method(rb_cModule, "attr_writer", rb_mod_attr_writer, -1); + rb_define_private_method(rb_cModule, "attr_accessor", rb_mod_attr_accessor, -1); + + rb_define_singleton_method(rb_cModule, "new", rb_module_s_new, 0); + rb_define_method(rb_cModule, "instance_methods", rb_class_instance_methods, -1); + rb_define_method(rb_cModule, "public_instance_methods", rb_class_instance_methods, -1); + rb_define_method(rb_cModule, "protected_instance_methods", rb_class_protected_instance_methods, -1); + rb_define_method(rb_cModule, "private_instance_methods", rb_class_private_instance_methods, -1); + + rb_define_method(rb_cModule, "constants", rb_mod_constants, 0); + rb_define_method(rb_cModule, "const_get", rb_mod_const_get, 1); + rb_define_method(rb_cModule, "const_set", rb_mod_const_set, 2); + rb_define_method(rb_cModule, "const_defined?", rb_mod_const_defined, 1); + rb_define_private_method(rb_cModule, "remove_const", rb_mod_remove_const, 1); + rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1); + + rb_define_method(rb_cClass, "new", rb_class_new_instance, -1); + rb_define_method(rb_cClass, "superclass", rb_class_superclass, 0); + rb_define_singleton_method(rb_cClass, "new", rb_class_s_new, -1); + rb_undef_method(rb_cClass, "extend_object"); + rb_undef_method(rb_cClass, "append_features"); + rb_define_singleton_method(rb_cClass, "inherited", rb_class_s_inherited, 1); + + rb_cData = rb_define_class("Data", rb_cObject); + rb_undef_method(CLASS_OF(rb_cData), "new"); + + ruby_top_self = rb_obj_alloc(rb_cObject); + rb_global_variable(&ruby_top_self); + rb_define_singleton_method(ruby_top_self, "to_s", main_to_s, 0); + + rb_cTrueClass = rb_define_class("TrueClass", rb_cObject); + rb_define_method(rb_cTrueClass, "to_s", true_to_s, 0); + rb_define_method(rb_cTrueClass, "to_i", true_to_i, 0); + rb_define_method(rb_cTrueClass, "type", true_type, 0); + rb_define_method(rb_cTrueClass, "&", true_and, 1); + rb_define_method(rb_cTrueClass, "|", true_or, 1); + rb_define_method(rb_cTrueClass, "^", true_xor, 1); + rb_undef_method(CLASS_OF(rb_cTrueClass), "new"); + rb_define_global_const("TRUE", Qtrue); + + rb_cFalseClass = rb_define_class("FalseClass", rb_cObject); + rb_define_method(rb_cFalseClass, "to_s", false_to_s, 0); + rb_define_method(rb_cFalseClass, "to_i", false_to_i, 0); + rb_define_method(rb_cFalseClass, "type", false_type, 0); + rb_define_method(rb_cFalseClass, "&", false_and, 1); + rb_define_method(rb_cFalseClass, "|", false_or, 1); + rb_define_method(rb_cFalseClass, "^", false_xor, 1); + rb_undef_method(CLASS_OF(rb_cFalseClass), "new"); + rb_define_global_const("FALSE", Qfalse); eq = rb_intern("=="); eql = rb_intern("eql?"); diff --git a/pack.c b/pack.c index 20d12d4003..dc393b83fe 100644 --- a/pack.c +++ b/pack.c @@ -6,13 +6,13 @@ $Date$ created at: Thu Feb 10 15:17:05 JST 1994 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" -#include <ctype.h> #include <sys/types.h> +#include <ctype.h> #define swaps(x) ((((x)&0xFF)<<8) + (((x)>>8)&0xFF)) #define swapl(x) ((((x)&0xFF)<<24) \ @@ -74,14 +74,22 @@ endian() #endif #endif -extern VALUE cString, cArray; -#ifndef atof -double atof(); -#endif - static char *toofew = "too few arguments"; -static void encodes(); +static void encodes _((VALUE,char*,int,int)); +static void qpencode _((VALUE,VALUE,int)); + +static void +pack_add_ptr(str, add) + VALUE str, add; +{ +#define STR_NO_ORIG FL_USER3 /* copied from string.c */ + if (!RSTRING(str)->orig) { + RSTRING(str)->orig = rb_ary_new(); + FL_SET(str, STR_NO_ORIG); + } + rb_ary_push(RSTRING(str)->orig, add); +} static VALUE pack_pack(ary, fmt) @@ -89,23 +97,22 @@ pack_pack(ary, fmt) { static char *nul10 = "\0\0\0\0\0\0\0\0\0\0"; static char *spc10 = " "; - UCHAR *p, *pend; + char *p, *pend; VALUE res, from; char type; int items, len, idx; - UCHAR *ptr; + char *ptr; int plen; - Check_Type(fmt, T_STRING); - - p = RSTRING(fmt)->ptr; - pend = RSTRING(fmt)->ptr + RSTRING(fmt)->len; - res = str_new(0, 0); + + p = rb_str2cstr(fmt, &plen); + pend = p + plen; + res = rb_str_new(0, 0); items = RARRAY(ary)->len; idx = 0; -#define NEXTFROM (items-- > 0 ? RARRAY(ary)->ptr[idx++] : (ArgError(toofew),0)) +#define NEXTFROM (items-- > 0 ? RARRAY(ary)->ptr[idx++] : (rb_raise(rb_eArgError, toofew),0)) while (p < pend) { type = *p++; /* get data type */ @@ -114,7 +121,7 @@ pack_pack(ary, fmt) len = strchr("@Xxu", type) ? 0 : items; p++; } - else if (isdigit(*p)) { + else if (ISDIGIT(*p)) { len = strtoul(p, (char**)&p, 10); } else { @@ -127,11 +134,11 @@ pack_pack(ary, fmt) case 'H': case 'h': from = NEXTFROM; if (NIL_P(from)) { - ptr = 0; + ptr = ""; plen = 0; } else { - from = obj_as_string(from); + from = rb_obj_as_string(from); ptr = RSTRING(from)->ptr; plen = RSTRING(from)->len; } @@ -143,15 +150,15 @@ pack_pack(ary, fmt) case 'a': case 'A': if (plen >= len) - str_cat(res, ptr, len); + rb_str_cat(res, ptr, len); else { - str_cat(res, ptr, plen); + rb_str_cat(res, ptr, plen); len -= plen; while (len >= 10) { - str_cat(res, (type == 'A')?spc10:nul10, 10); + rb_str_cat(res, (type == 'A')?spc10:nul10, 10); len -= 10; } - str_cat(res, (type == 'A')?spc10:nul10, len); + rb_str_cat(res, (type == 'A')?spc10:nul10, len); } break; @@ -167,7 +174,7 @@ pack_pack(ary, fmt) byte >>= 1; else { char c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); byte = 0; } } @@ -175,7 +182,7 @@ pack_pack(ary, fmt) char c; byte >>= 7 - (len & 7); c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); } } break; @@ -191,7 +198,7 @@ pack_pack(ary, fmt) byte <<= 1; else { char c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); byte = 0; } } @@ -199,7 +206,7 @@ pack_pack(ary, fmt) char c; byte <<= 7 - (len & 7); c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); } } break; @@ -210,8 +217,8 @@ pack_pack(ary, fmt) int i; for (i=0; i++ < len; ptr++) { - if (isxdigit(*ptr)) { - if (isalpha(*ptr)) + if (ISXDIGIT(*ptr)) { + if (ISALPHA(*ptr)) byte |= (((*ptr & 15) + 9) & 15) << 4; else byte |= (*ptr & 15) << 4; @@ -219,14 +226,14 @@ pack_pack(ary, fmt) byte >>= 4; else { char c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); byte = 0; } } } if (len & 1) { char c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); } } break; @@ -237,8 +244,8 @@ pack_pack(ary, fmt) int i; for (i=0; i++ < len; ptr++) { - if (isxdigit(*ptr)) { - if (isalpha(*ptr)) + if (ISXDIGIT(*ptr)) { + if (ISALPHA(*ptr)) byte |= ((*ptr & 15) + 9) & 15; else byte |= *ptr & 15; @@ -246,14 +253,14 @@ pack_pack(ary, fmt) byte <<= 4; else { char c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); byte = 0; } } } if (len & 1) { char c = byte & 0xff; - str_cat(res, &c, 1); + rb_str_cat(res, &c, 1); } } break; @@ -270,7 +277,7 @@ pack_pack(ary, fmt) else { c = NUM2INT(from); } - str_cat(res, &c, sizeof(char)); + rb_str_cat(res, &c, sizeof(char)); } break; @@ -284,7 +291,7 @@ pack_pack(ary, fmt) else { s = NUM2INT(from); } - str_cat(res, (UCHAR*)&s, sizeof(short)); + rb_str_cat(res, (char*)&s, sizeof(short)); } break; @@ -296,9 +303,9 @@ pack_pack(ary, fmt) from = NEXTFROM; if (NIL_P(from)) i = 0; else { - i = NUM2INT(from); + i = NUM2UINT(from); } - str_cat(res, (UCHAR*)&i, sizeof(int)); + rb_str_cat(res, (char*)&i, sizeof(int)); } break; @@ -310,9 +317,9 @@ pack_pack(ary, fmt) from = NEXTFROM; if (NIL_P(from)) l = 0; else { - l = NUM2INT(from); + l = NUM2ULONG(from); } - str_cat(res, (UCHAR*)&l, sizeof(long)); + rb_str_cat(res, (char*)&l, sizeof(long)); } break; @@ -326,7 +333,7 @@ pack_pack(ary, fmt) s = NUM2INT(from); } s = htons(s); - str_cat(res, (UCHAR*)&s, sizeof(short)); + rb_str_cat(res, (char*)&s, sizeof(short)); } break; @@ -337,10 +344,10 @@ pack_pack(ary, fmt) from = NEXTFROM; if (NIL_P(from)) l = 0; else { - l = NUM2INT(from); + l = NUM2ULONG(from); } l = htonl(l); - str_cat(res, (UCHAR*)&l, sizeof(long)); + rb_str_cat(res, (char*)&l, sizeof(long)); } break; @@ -354,7 +361,7 @@ pack_pack(ary, fmt) s = NUM2INT(from); } s = htovs(s); - str_cat(res, (UCHAR*)&s, sizeof(short)); + rb_str_cat(res, (char*)&s, sizeof(short)); } break; @@ -365,10 +372,10 @@ pack_pack(ary, fmt) from = NEXTFROM; if (NIL_P(from)) l = 0; else { - l = NUM2INT(from); + l = NUM2ULONG(from); } l = htovl(l); - str_cat(res, (UCHAR*)&l, sizeof(long)); + rb_str_cat(res, (char*)&l, sizeof(long)); } break; @@ -388,7 +395,7 @@ pack_pack(ary, fmt) f = (float)NUM2INT(from); break; } - str_cat(res, (UCHAR*)&f, sizeof(float)); + rb_str_cat(res, (char*)&f, sizeof(float)); } break; @@ -408,23 +415,23 @@ pack_pack(ary, fmt) d = (double)NUM2INT(from); break; } - str_cat(res, (UCHAR*)&d, sizeof(double)); + rb_str_cat(res, (char*)&d, sizeof(double)); } break; case 'x': grow: while (len >= 10) { - str_cat(res, nul10, 10); + rb_str_cat(res, nul10, 10); len -= 10; } - str_cat(res, nul10, len); + rb_str_cat(res, nul10, len); break; case 'X': shrink: if (RSTRING(res)->len < len) - ArgError("X outside of string"); + rb_raise(rb_eArgError, "X outside of string"); RSTRING(res)->len -= len; RSTRING(res)->ptr[RSTRING(res)->len] = '\0'; break; @@ -437,12 +444,12 @@ pack_pack(ary, fmt) break; case '%': - ArgError("% may only be used in unpack"); + rb_raise(rb_eArgError, "% may only be used in unpack"); break; case 'u': case 'm': - from = obj_as_string(NEXTFROM); + from = rb_obj_as_string(NEXTFROM); ptr = RSTRING(from)->ptr; plen = RSTRING(from)->len; @@ -463,6 +470,29 @@ pack_pack(ary, fmt) } break; + case 'M': + from = rb_obj_as_string(NEXTFROM); + if (len <= 1) + len = 72; + qpencode(res, from, len); + break; + + case 'P': + len = 1; + /* FALL THROUGH */ + case 'p': + while (len-- > 0) { + char *t; + from = NEXTFROM; + if (NIL_P(from)) t = ""; + else { + t = STR2CSTR(from); + pack_add_ptr(res, from); + } + rb_str_cat(res, (char*)&t, sizeof(char*)); + } + break; + default: break; } @@ -479,42 +509,124 @@ static char b64_table[] = static void encodes(str, s, len, type) VALUE str; - UCHAR *s; + char *s; int len; int type; { - char hunk[4]; - UCHAR *p, *pend; + char *buff = ALLOCA_N(char, len * 4 / 3 + 6); + int i = 0; char *trans = type == 'u' ? uu_table : b64_table; int padding; if (type == 'u') { - *hunk = len + ' '; - str_cat(str, hunk, 1); + buff[i++] = len + ' '; padding = '`'; } else { padding = '='; } - while (len > 0) { - hunk[0] = trans[077 & (*s >> 2)]; - hunk[1] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; - hunk[2] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))]; - hunk[3] = trans[077 & s[2]]; - str_cat(str, hunk, 4); + while (len >= 3) { + buff[i++] = trans[077 & (*s >> 2)]; + buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; + buff[i++] = trans[077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03))]; + buff[i++] = trans[077 & s[2]]; s += 3; len -= 3; } - p = RSTRING(str)->ptr; - pend = RSTRING(str)->ptr + RSTRING(str)->len; - if (len == -1) { - pend[-1] = padding; + if (len == 2) { + buff[i++] = trans[077 & (*s >> 2)]; + buff[i++] = trans[077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017))]; + buff[i++] = trans[077 & (((s[1] << 2) & 074) | (('\0' >> 6) & 03))]; + buff[i++] = padding; + } + else if (len == 1) { + buff[i++] = trans[077 & (*s >> 2)]; + buff[i++] = trans[077 & (((*s << 4) & 060) | (('\0' >> 4) & 017))]; + buff[i++] = padding; + buff[i++] = padding; + } + buff[i++] = '\n'; + rb_str_cat(str, buff, i); +} + +static char hex_table[] = "0123456789ABCDEF"; + +static void +qpencode(str, from, len) + VALUE str, from; + int len; +{ + char buff[1024]; + int i = 0, n = 0, prev = EOF; + unsigned char *s = RSTRING(from)->ptr; + unsigned char *send = s + RSTRING(from)->len; + + while (s < send) { + if ((*s > 126) || + (*s < 32 && *s != '\n' && *s != '\t') || + (*s == '=')) { + buff[i++] = '='; + buff[i++] = hex_table[*s >> 4]; + buff[i++] = hex_table[*s & 0x0f]; + n += 3; + prev = EOF; + } + else if (*s == '\n') { + if (prev == ' ' || prev == '\t') { + buff[i++] = '='; + buff[i++] = *s; + } + buff[i++] = *s; + n = 0; + prev = *s; + } + else { + buff[i++] = *s; + n++; + prev = *s; + } + if (n > len) { + buff[i++] = '='; + buff[i++] = '\n'; + n = 0; + prev = '\n'; + } + if (i > 1024 - 5) { + rb_str_cat(str, buff, i); + i = 0; + } + s++; + } + if (n > 0) { + buff[i++] = '='; + buff[i++] = '\n'; } - else if (len == -2) { - pend[-2] = padding; - pend[-1] = padding; + if (i > 0) { + rb_str_cat(str, buff, i); + } +} + +#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(RUBY_NO_INLINE) +static __inline__ int +#else +static int +#endif +hex2num(c) + char c; +{ + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return c - '0'; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + return c - 'a' + 10; + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + return c - 'A' + 10; + default: + return -1; } - str_cat(str, "\n", 1); } static VALUE @@ -522,27 +634,25 @@ pack_unpack(str, fmt) VALUE str, fmt; { static char *hexdigits = "0123456789abcdef0123456789ABCDEFx"; - UCHAR *s, *send; - UCHAR *p, *pend; + char *s, *send; + char *p, *pend; VALUE ary; char type; int len; - Check_Type(fmt, T_STRING); - - s = RSTRING(str)->ptr; - send = s + RSTRING(str)->len; - p = RSTRING(fmt)->ptr; - pend = p + RSTRING(fmt)->len; + s = rb_str2cstr(str, &len); + send = s + len; + p = rb_str2cstr(fmt, &len); + pend = p + len; - ary = ary_new(); + ary = rb_ary_new(); while (p < pend) { type = *p++; if (*p == '*') { len = send - s; p++; } - else if (isdigit(*p)) { + else if (ISDIGIT(*p)) { len = strtoul(p, (char**)&p, 10); } else { @@ -551,41 +661,41 @@ pack_unpack(str, fmt) switch (type) { case '%': - ArgError("% is not supported(yet)"); + rb_raise(rb_eArgError, "% is not supported(yet)"); break; case 'A': if (len > send - s) len = send - s; { int end = len; - UCHAR *t = s + len - 1; + char *t = s + len - 1; while (t >= s) { if (*t != ' ' && *t != '\0') break; t--; len--; } - ary_push(ary, str_new(s, len)); + rb_ary_push(ary, rb_str_new(s, len)); s += end; } break; case 'a': if (len > send - s) len = send - s; - ary_push(ary, str_new(s, len)); + rb_ary_push(ary, rb_str_new(s, len)); s += len; break; case 'b': { VALUE bitstr; - UCHAR *t; + char *t; int bits, i; if (p[-1] == '*' || len > (send - s) * 8) len = (send - s) * 8; bits = 0; - ary_push(ary, bitstr = str_new(0, len)); + rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i<len; i++) { if (i & 7) bits >>= 1; @@ -598,13 +708,13 @@ pack_unpack(str, fmt) case 'B': { VALUE bitstr; - UCHAR *t; + char *t; int bits, i; if (p[-1] == '*' || len > (send - s) * 8) len = (send - s) * 8; bits = 0; - ary_push(ary, bitstr = str_new(0, len)); + rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i<len; i++) { if (i & 7) bits <<= 1; @@ -617,13 +727,13 @@ pack_unpack(str, fmt) case 'h': { VALUE bitstr; - UCHAR *t; + char *t; int bits, i; if (p[-1] == '*' || len > (send - s) * 2) len = (send - s) * 2; bits = 0; - ary_push(ary, bitstr = str_new(0, len)); + rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i<len; i++) { if (i & 1) @@ -638,13 +748,13 @@ pack_unpack(str, fmt) case 'H': { VALUE bitstr; - UCHAR *t; + char *t; int bits, i; if (p[-1] == '*' || len > (send - s) * 2) len = (send - s) * 2; bits = 0; - ary_push(ary, bitstr = str_new(0, len)); + rb_ary_push(ary, bitstr = rb_str_new(0, len)); t = RSTRING(bitstr)->ptr; for (i=0; i<len; i++) { if (i & 1) @@ -662,7 +772,7 @@ pack_unpack(str, fmt) while (len-- > 0) { int c = *s++; if (c > (char)127) c-=256; - ary_push(ary, INT2FIX(c)); + rb_ary_push(ary, INT2FIX(c)); } break; @@ -670,8 +780,8 @@ pack_unpack(str, fmt) if (len > send - s) len = send - s; while (len-- > 0) { - UCHAR c = *s++; - ary_push(ary, INT2FIX(c)); + unsigned char c = *s++; + rb_ary_push(ary, INT2FIX(c)); } break; @@ -682,7 +792,7 @@ pack_unpack(str, fmt) short tmp; memcpy(&tmp, s, sizeof(short)); s += sizeof(short); - ary_push(ary, INT2FIX(tmp)); + rb_ary_push(ary, INT2FIX(tmp)); } break; @@ -693,7 +803,7 @@ pack_unpack(str, fmt) unsigned short tmp; memcpy(&tmp, s, sizeof(short)); s += sizeof(short); - ary_push(ary, INT2FIX(tmp)); + rb_ary_push(ary, INT2FIX(tmp)); } break; @@ -704,7 +814,7 @@ pack_unpack(str, fmt) int tmp; memcpy(&tmp, s, sizeof(int)); s += sizeof(int); - ary_push(ary, int2inum(tmp)); + rb_ary_push(ary, rb_int2inum(tmp)); } break; @@ -715,7 +825,7 @@ pack_unpack(str, fmt) unsigned int tmp; memcpy(&tmp, s, sizeof(int)); s += sizeof(int); - ary_push(ary, int2inum(tmp)); + rb_ary_push(ary, rb_uint2inum(tmp)); } break; @@ -726,7 +836,7 @@ pack_unpack(str, fmt) long tmp; memcpy(&tmp, s, sizeof(long)); s += sizeof(long); - ary_push(ary, int2inum(tmp)); + rb_ary_push(ary, rb_int2inum(tmp)); } break; @@ -737,7 +847,7 @@ pack_unpack(str, fmt) unsigned long tmp; memcpy(&tmp, s, sizeof(long)); s += sizeof(long); - ary_push(ary, uint2inum(tmp)); + rb_ary_push(ary, rb_uint2inum(tmp)); } break; @@ -749,7 +859,7 @@ pack_unpack(str, fmt) memcpy(&tmp, s, sizeof(short)); s += sizeof(short); tmp = ntohs(tmp); - ary_push(ary, uint2inum(tmp)); + rb_ary_push(ary, rb_uint2inum(tmp)); } break; @@ -761,7 +871,7 @@ pack_unpack(str, fmt) memcpy(&tmp, s, sizeof(long)); s += sizeof(long); tmp = ntohl(tmp); - ary_push(ary, uint2inum(tmp)); + rb_ary_push(ary, rb_uint2inum(tmp)); } break; @@ -773,7 +883,7 @@ pack_unpack(str, fmt) memcpy(&tmp, s, sizeof(short)); s += sizeof(short); tmp = vtohs(tmp); - ary_push(ary, uint2inum(tmp)); + rb_ary_push(ary, rb_uint2inum(tmp)); } break; @@ -785,7 +895,7 @@ pack_unpack(str, fmt) memcpy(&tmp, s, sizeof(long)); s += sizeof(long); tmp = vtohl(tmp); - ary_push(ary, uint2inum(tmp)); + rb_ary_push(ary, rb_uint2inum(tmp)); } break; @@ -797,7 +907,7 @@ pack_unpack(str, fmt) float tmp; memcpy(&tmp, s, sizeof(float)); s += sizeof(float); - ary_push(ary, float_new((double)tmp)); + rb_ary_push(ary, rb_float_new((double)tmp)); } break; @@ -809,14 +919,14 @@ pack_unpack(str, fmt) double tmp; memcpy(&tmp, s, sizeof(double)); s += sizeof(double); - ary_push(ary, float_new(tmp)); + rb_ary_push(ary, rb_float_new(tmp)); } break; case 'u': { - VALUE str = str_new(0, (send - s)*3/4); - UCHAR *ptr = RSTRING(str)->ptr; + VALUE str = rb_str_new(0, (send - s)*3/4); + char *ptr = RSTRING(str)->ptr; int total = 0; while (s < send && *s > ' ' && *s < 'a') { @@ -863,15 +973,14 @@ pack_unpack(str, fmt) s += 2; /* possible checksum byte */ } RSTRING(str)->len = total; - ary_push(ary, str); + rb_ary_push(ary, str); } break; case 'm': { - VALUE str = str_new(0, (send - s)*3/4); - UCHAR *ptr = RSTRING(str)->ptr; - int total = 0; + VALUE str = rb_str_new(0, (send - s)*3/4); + char *ptr = RSTRING(str)->ptr; int a,b,c,d; static int first = 1; static int b64_xtable[256]; @@ -906,7 +1015,33 @@ pack_unpack(str, fmt) *ptr++ = b << 4 | c >> 2; } RSTRING(str)->len = ptr - RSTRING(str)->ptr; - ary_push(ary, str); + rb_ary_push(ary, str); + } + break; + + case 'M': + { + VALUE str = rb_str_new(0, send - s); + char *ptr = RSTRING(str)->ptr; + int c1, c2; + + while (s < send) { + if (*s == '=') { + if (++s == send) break; + if (*s != '\n') { + if ((c1 = hex2num(*s)) == -1) break; + if (++s == send) break; + if ((c2 = hex2num(*s)) == -1) break; + *ptr++ = c1 << 4 | c2; + } + } + else { + *ptr++ = *s; + } + s++; + } + RSTRING(str)->len = ptr - RSTRING(str)->ptr; + rb_ary_push(ary, str); } break; @@ -916,16 +1051,46 @@ pack_unpack(str, fmt) case 'X': if (len > s - RSTRING(str)->ptr) - ArgError("X outside of string"); + rb_raise(rb_eArgError, "X outside of string"); s -= len; break; case 'x': if (len > send - s) - ArgError("x outside of string"); + rb_raise(rb_eArgError, "x outside of string"); s += len; break; + case 'P': + if (sizeof(char *) <= send - s) { + char *t; + VALUE str = rb_str_new(0, 0); + memcpy(&t, s, sizeof(char *)); + s += sizeof(char *); + if (t) + rb_str_cat(str, t, len); + rb_ary_push(ary, str); + } + break; + + case 'p': + if (len > (send - s) / sizeof(char *)) + len = (send - s) / sizeof(char *); + while (len-- > 0) { + if (send - s < sizeof(char *)) + break; + else { + char *t; + VALUE str = rb_str_new(0, 0); + memcpy(&t, s, sizeof(char *)); + s += sizeof(char *); + if (t) + rb_str_cat(str, t, strlen(t)); + rb_ary_push(ary, str); + } + } + break; + default: break; } @@ -937,6 +1102,6 @@ pack_unpack(str, fmt) void Init_pack() { - rb_define_method(cArray, "pack", pack_pack, 1); - rb_define_method(cString, "unpack", pack_unpack, 1); + rb_define_method(rb_cArray, "pack", pack_pack, 1); + rb_define_method(rb_cString, "unpack", pack_unpack, 1); } diff --git a/parse.y b/parse.y index 4bf13cf398..a4142bbe20 100644 --- a/parse.y +++ b/parse.y @@ -6,7 +6,7 @@ $Date$ created at: Fri May 28 18:02:42 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -32,23 +32,18 @@ #define ID_ATTRSET 0x04 #define ID_CONST 0x05 -#define is_id_nonop(id) ((id)>LAST_TOKEN) -#define is_local_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) -#define is_global_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) -#define is_instance_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) -#define is_attrset_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) -#define is_const_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) +#define is_id_notop(id) ((id)>LAST_TOKEN) +#define is_local_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) +#define is_global_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) +#define is_instance_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) +#define is_attrset_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) +#define is_const_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) -struct op_tbl { - ID token; - char *name; -}; - -NODE *eval_tree0 = 0; -NODE *eval_tree = 0; +NODE *ruby_eval_tree_begin = 0; +NODE *ruby_eval_tree = 0; -char *sourcefile; /* current source file */ -int sourceline; /* current line no. */ +char *ruby_sourcefile; /* current source file */ +int ruby_sourceline; /* current line no. */ static int yylex(); static int yyerror(); @@ -57,9 +52,10 @@ static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_MID, /* newline significant, +/- is a sign. */ EXPR_END, /* newline significant, +/- is a operator. */ - EXPR_ARG, /* newline significant, +/- may be a sign. */ - EXPR_FNAME, /* ignore newline, +/- is a operator. */ - EXPR_CLASS, /* immediate after `class' no here document. */ + EXPR_ARG, /* newline significant, +/- is a operator. */ + EXPR_FNAME, /* ignore newline, +/- is a operator, no reserved words. */ + EXPR_DOT, /* immediate after `.', no reserved words. */ + EXPR_CLASS, /* immediate after `class', no here document. */ } lex_state; static int class_nest = 0; @@ -80,15 +76,20 @@ static NODE *arg_add(); static NODE *call_op(); static int in_defined = 0; +static NODE *arg_blk_pass(); +static NODE *new_call(); +static NODE *new_fcall(); + static NODE *gettable(); static NODE *assignable(); static NODE *aryset(); static NODE *attrset(); -static void backref_error(); +static void rb_backref_error(); static NODE *match_gen(); static void local_push(); static void local_pop(); +static int local_append(); static int local_cnt(); static int local_id(); static ID *local_tbl(); @@ -97,9 +98,6 @@ static struct RVarmap *dyna_push(); static void dyna_pop(); static int dyna_in_block(); -VALUE dyna_var_asgn(); -VALUE dyna_var_defined(); - #define cref_push() NEW_CREF() static void cref_pop(); static NODE *cur_cref; @@ -158,46 +156,51 @@ static void top_local_setup(); kDEFINED klBEGIN klEND + k__LINE__ + k__FILE__ -%token <id> IDENTIFIER FID GVAR IVAR CONSTANT -%token <val> INTEGER FLOAT STRING XSTRING REGEXP -%token <node> DSTRING DXSTRING DREGEXP NTH_REF BACK_REF +%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT +%token <val> tINTEGER tFLOAT tSTRING tXSTRING tREGEXP +%token <node> tDSTRING tDXSTRING tDREGEXP tNTH_REF tBACK_REF %type <node> singleton %type <val> literal numeric %type <node> compstmt stmts stmt expr arg primary command_call method_call -%type <node> if_tail opt_else case_body cases rescue ensure iterator -%type <node> call_args call_args0 ret_args args mrhs opt_list var_ref -%type <node> superclass f_arglist f_args f_optarg f_opt -%type <node> array assoc_list assocs assoc undef_list +%type <node> if_tail opt_else case_body cases rescue ensure +%type <node> opt_call_args call_args ret_args args when_args +%type <node> aref_args opt_block_arg block_arg +%type <node> mrhs opt_list superclass iterator var_ref +%type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg +%type <node> array assoc_list assocs assoc undef_list backref %type <node> iter_var opt_iter_var iter_block iter_do_block -%type <node> mlhs mlhs_head mlhs_tail lhs backref -%type <id> variable symbol operation assoc_kw -%type <id> cname fname op rest_arg +%type <node> mlhs mlhs_head mlhs_tail mlhs_basic mlhs_entry mlhs_item lhs +%type <id> variable symbol operation +%type <id> cname fname op f_rest_arg %type <num> f_arg -%token oUPLUS /* unary+ */ -%token MINUS /* unary- */ -%token POW /* ** */ -%token CMP /* <=> */ -%token EQ /* == */ -%token EQQ /* === */ -%token NEQ /* != <> */ -%token GEQ /* >= */ -%token LEQ /* <= */ -%token ANDOP OROP /* && and || */ -%token MATCH NMATCH /* =~ and !~ */ -%token DOT2 DOT3 /* .. and ... */ -%token AREF ASET /* [] and []= */ -%token LSHFT RSHFT /* << and >> */ -%token COLON2 /* :: */ -%token <id> OP_ASGN /* +=, -= etc. */ -%token ASSOC /* => */ -%token KW_ASSOC /* -> */ -%token LPAREN /* ( */ -%token LBRACK /* [ */ -%token LBRACE /* { */ -%token STAR /* * */ -%token SYMBEG +%token tUPLUS /* unary+ */ +%token tUMINUS /* unary- */ +%token tPOW /* ** */ +%token tCMP /* <=> */ +%token tEQ /* == */ +%token tEQQ /* === */ +%token tNEQ /* != */ +%token tGEQ /* >= */ +%token tLEQ /* <= */ +%token tANDOP tOROP /* && and || */ +%token tMATCH tNMATCH /* =~ and !~ */ +%token tDOT2 tDOT3 /* .. and ... */ +%token tAREF tASET /* [] and []= */ +%token tLSHFT tRSHFT /* << and >> */ +%token tCOLON2 /* :: */ +%token tCOLON3 /* :: at EXPR_BEG */ +%token <id> tOP_ASGN /* +=, -= etc. */ +%token tASSOC /* => */ +%token tLPAREN /* ( */ +%token tLBRACK /* [ */ +%token tLBRACE /* { */ +%token tSTAR /* * */ +%token tAMPER /* & */ +%token tSYMBEG /* * precedence table @@ -207,36 +210,39 @@ static void top_local_setup(); %left kOR kAND %right kNOT %nonassoc kDEFINED -%right '=' OP_ASGN -%nonassoc DOT2 DOT3 -%left OROP -%left ANDOP -%nonassoc CMP EQ EQQ NEQ MATCH NMATCH -%left '>' GEQ '<' LEQ +%right '=' tOP_ASGN +%right '?' ':' +%nonassoc tDOT2 tDOT3 +%left tOROP +%left tANDOP +%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH +%left '>' tGEQ '<' tLEQ %left '|' '^' %left '&' -%left LSHFT RSHFT +%left tLSHFT tRSHFT %left '+' '-' %left '*' '/' '%' -%right '!' '~' UPLUS UMINUS -%right POW +%right '!' '~' tUPLUS tUMINUS +%right tPOW %token LAST_TOKEN %% program : { + $<vars>$ = ruby_dyna_vars; lex_state = EXPR_BEG; top_local_init(); NEW_CREF0(); /* initialize constant c-ref */ - if ((VALUE)the_class == cObject) class_nest = 0; + if ((VALUE)ruby_class == rb_cObject) class_nest = 0; else class_nest = 1; } compstmt { - eval_tree = block_append(eval_tree, $2); + ruby_eval_tree = block_append(ruby_eval_tree, $2); top_local_setup(); cur_cref = 0; class_nest = 0; + ruby_dyna_vars = $<vars>1; } compstmt : stmts opt_terms @@ -260,6 +266,9 @@ stmts : /* none */ stmt : iterator iter_do_block { + if ($1 && nd_type($1) == NODE_BLOCK_PASS) { + rb_compile_error("both block arg and actual block given"); + } $2->nd_iter = $1; $$ = $2; fixpos($$, $2); @@ -270,13 +279,13 @@ stmt : iterator iter_do_block yyerror("alias within method"); $$ = NEW_ALIAS($2, $4); } - | kALIAS GVAR GVAR + | kALIAS tGVAR tGVAR { if (cur_mid || in_single) yyerror("alias within method"); $$ = NEW_VALIAS($2, $3); } - | kALIAS GVAR BACK_REF + | kALIAS tGVAR tBACK_REF { char buf[3]; @@ -285,7 +294,7 @@ stmt : iterator iter_do_block sprintf(buf, "$%c", $3->nd_nth); $$ = NEW_VALIAS($2, rb_intern(buf)); } - | kALIAS GVAR NTH_REF + | kALIAS tGVAR tNTH_REF { yyerror("can't make alias for the number variables"); $$ = 0; @@ -299,12 +308,14 @@ stmt : iterator iter_do_block | stmt kIF_MOD expr { value_expr($3); - $$ = node_newnode(NODE_AND, cond($3), $1); + $$ = NEW_IF(cond($3), $1, 0); + fixpos($$, $3); } | stmt kUNLESS_MOD expr { value_expr($3); - $$ = node_newnode(NODE_OR, cond($3), $1); + $$ = NEW_UNLESS(cond($3), $1, 0); + fixpos($$, $3); } | stmt kWHILE_MOD expr { @@ -316,7 +327,7 @@ stmt : iterator iter_do_block $$ = NEW_WHILE(cond($3), $1, 1); } } - | expr kUNTIL_MOD expr + | stmt kUNTIL_MOD expr { value_expr($3); if (nd_type($1) == NODE_BEGIN) { @@ -326,7 +337,7 @@ stmt : iterator iter_do_block $$ = NEW_UNTIL(cond($3), $1, 1); } } - | klBEGIN + | klBEGIN { if (cur_mid || in_single) { yyerror("BEGIN in method"); @@ -336,7 +347,8 @@ stmt : iterator iter_do_block } '{' compstmt '}' { - eval_tree0 = block_append(eval_tree0,NEW_PREEXE($4)); + ruby_eval_tree_begin = block_append(ruby_eval_tree_begin, + NEW_PREEXE($4)); local_pop(); $$ = 0; } @@ -361,7 +373,7 @@ expr : mlhs '=' mrhs value_expr($2); if (!cur_mid && !in_single) yyerror("return appeared outside of method"); - $$ = NEW_RET($2); + $$ = NEW_RETURN($2); } | kYIELD ret_args { @@ -382,31 +394,31 @@ expr : mlhs '=' mrhs value_expr($2); $$ = NEW_NOT(cond($2)); } - | '!' command_call + | '!' command_call { value_expr($2); $$ = NEW_NOT(cond($2)); } | arg -command_call : operation call_args0 +command_call : operation call_args { - $$ = NEW_FCALL($1, $2); + $$ = new_fcall($1, $2); fixpos($$, $2); } - | primary '.' operation call_args0 + | primary '.' operation call_args { value_expr($1); - $$ = NEW_CALL($1, $3, $4); + $$ = new_call($1, $3, $4); fixpos($$, $1); } - | primary COLON2 operation call_args0 + | primary tCOLON2 operation call_args { value_expr($1); - $$ = NEW_CALL($1, $3, $4); + $$ = new_call($1, $3, $4); fixpos($$, $1); } - | kSUPER call_args0 + | kSUPER call_args { if (!cur_mid && !in_single && !in_defined) yyerror("super called outside of method"); @@ -414,11 +426,23 @@ command_call : operation call_args0 fixpos($$, $2); } -mlhs : mlhs_head +mlhs : mlhs_basic + | tLPAREN mlhs_entry ')' + { + $$ = $2; + } + +mlhs_entry : mlhs_basic + | tLPAREN mlhs_entry ')' + { + $$ = NEW_MASGN(NEW_LIST($2), 0); + } + +mlhs_basic : mlhs_head { $$ = NEW_MASGN(NEW_LIST($1), 0); } - | mlhs_head STAR lhs + | mlhs_head tSTAR lhs { $$ = NEW_MASGN(NEW_LIST($1), $3); } @@ -426,22 +450,31 @@ mlhs : mlhs_head { $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2), 0); } - | mlhs_head mlhs_tail ',' STAR lhs + | mlhs_head mlhs_tail ',' tSTAR lhs { $$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),$5); } - | STAR lhs + | tSTAR lhs { $$ = NEW_MASGN(0, $2); } -mlhs_head : lhs ',' +mlhs_item : lhs + | tLPAREN mlhs_entry ')' + { + $$ = $2; + } + +mlhs_head : mlhs_item ',' + { + $$ = $1; + } -mlhs_tail : lhs +mlhs_tail : mlhs_item { $$ = NEW_LIST($1); } - | mlhs_tail ',' lhs + | mlhs_tail ',' mlhs_item { $$ = list_append($1, $3); } @@ -450,38 +483,39 @@ lhs : variable { $$ = assignable($1, 0); } - | primary '[' call_args ']' + | primary '[' aref_args ']' { $$ = aryset($1, $3, 0); } - | primary '.' IDENTIFIER - { - $$ = attrset($1, $3, 0); - } - | primary '.' CONSTANT + | primary '.' tIDENTIFIER { $$ = attrset($1, $3, 0); } | backref { - backref_error($1); + rb_backref_error($1); $$ = 0; } -cname : IDENTIFIER +cname : tIDENTIFIER { yyerror("class/module name must be CONSTANT"); } - | CONSTANT + | tCONSTANT -fname : IDENTIFIER - | CONSTANT - | FID +fname : tIDENTIFIER + | tCONSTANT + | tFID | op { lex_state = EXPR_END; $$ = $1; } + | reswords + { + lex_state = EXPR_END; + $$ = $<id>1; + } undef_list : fname { @@ -492,46 +526,61 @@ undef_list : fname $$ = block_append($1, NEW_UNDEF($4)); } -op : DOT2 { $$ = DOT2; } +op : tDOT2 { $$ = tDOT2; } | '|' { $$ = '|'; } | '^' { $$ = '^'; } | '&' { $$ = '&'; } - | CMP { $$ = CMP; } - | EQ { $$ = EQ; } - | EQQ { $$ = EQQ; } - | MATCH { $$ = MATCH; } + | tCMP { $$ = tCMP; } + | tEQ { $$ = tEQ; } + | tEQQ { $$ = tEQQ; } + | tMATCH { $$ = tMATCH; } | '>' { $$ = '>'; } - | GEQ { $$ = GEQ; } + | tGEQ { $$ = tGEQ; } | '<' { $$ = '<'; } - | LEQ { $$ = LEQ; } - | LSHFT { $$ = LSHFT; } - | RSHFT { $$ = RSHFT; } + | tLEQ { $$ = tLEQ; } + | tLSHFT { $$ = tLSHFT; } + | tRSHFT { $$ = tRSHFT; } | '+' { $$ = '+'; } | '-' { $$ = '-'; } | '*' { $$ = '*'; } - | STAR { $$ = '*'; } + | tSTAR { $$ = '*'; } | '/' { $$ = '/'; } | '%' { $$ = '%'; } - | POW { $$ = POW; } + | tPOW { $$ = tPOW; } | '~' { $$ = '~'; } - | UPLUS { $$ = UMINUS; } - | UMINUS { $$ = UPLUS; } - | AREF { $$ = AREF; } - | ASET { $$ = ASET; } + | tUPLUS { $$ = tUPLUS; } + | tUMINUS { $$ = tUMINUS; } + | tAREF { $$ = tAREF; } + | tASET { $$ = tASET; } | '`' { $$ = '`'; } -arg : variable '=' arg +reswords : k__LINE__ | k__FILE__ | klBEGIN | klEND + | kALIAS | kAND | kBEGIN | kBREAK | kCASE | kCLASS | kDEF + | kDEFINED | kDO | kELSE | kELSIF | kEND | kENSURE | kFALSE + | kFOR | kIF_MOD | kIN | kMODULE | kNEXT | kNIL | kNOT + | kOR | kREDO | kRESCUE | kRETRY | kRETURN | kSELF | kSUPER + | kTHEN | kTRUE | kUNDEF | kUNLESS_MOD | kUNTIL_MOD | kWHEN + | kWHILE_MOD | kYIELD + +arg : variable '=' {$$ = assignable($1, 0);} arg { - value_expr($3); - $$ = assignable($1, $3); - fixpos($$, $3); + $$ = $<node>3; + if ($$) { + $$->nd_value = $4; + fixpos($$, $4); + } } - | primary '[' call_args ']' '=' arg + | primary '[' aref_args ']' '=' arg { $$ = aryset($1, $3, $6); fixpos($$, $1); } - | primary '.' IDENTIFIER '=' arg + | primary '.' tIDENTIFIER '=' arg + { + $$ = attrset($1, $3, $5); + fixpos($$, $5); + } + | primary '.' tCONSTANT '=' arg { $$ = attrset($1, $3, $5); fixpos($$, $5); @@ -539,46 +588,72 @@ arg : variable '=' arg | backref '=' arg { value_expr($3); - backref_error($1); + rb_backref_error($1); $$ = 0; } - | variable OP_ASGN arg + | variable tOP_ASGN {$$ = assignable($1, 0);} arg { - value_expr($3); - if (is_local_id($1)&&!local_id($1)&&dyna_in_block()) - dyna_var_asgn($1, TRUE); - $$ = assignable($1, call_op(gettable($1), $2, 1, $3)); - fixpos($$, $3); + if ($2 == tOROP) { + $<node>3->nd_value = $4; + $$ = NEW_OP_ASGN_OR(gettable($1), $<node>3); + } + else if ($2 == tANDOP) { + $<node>3->nd_value = $4; + $$ = NEW_OP_ASGN_AND(gettable($1), $<node>3); + } + else { + $$ = $<node>3; + $$->nd_value = call_op(gettable($1), $2, 1, $4); + } + fixpos($$, $4); } - | primary '[' call_args ']' OP_ASGN arg + | primary '[' aref_args ']' tOP_ASGN arg { NODE *args = NEW_LIST($6); - list_append($3, NEW_NIL()); + list_append($3, NEW_NIL()); list_concat(args, $3); + if ($5 == tOROP) { + $5 = 0; + } + else if ($5 == tANDOP) { + $5 = 1; + } $$ = NEW_OP_ASGN1($1, $5, args); fixpos($$, $1); } - | primary '.' IDENTIFIER OP_ASGN arg + | primary '.' tIDENTIFIER tOP_ASGN arg { + if ($4 == tOROP) { + $4 = 0; + } + else if ($4 == tANDOP) { + $4 = 1; + } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } - | primary '.' CONSTANT OP_ASGN arg + | primary '.' tCONSTANT tOP_ASGN arg { + if ($4 == tOROP) { + $4 = 0; + } + else if ($4 == tANDOP) { + $4 = 1; + } $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } - | backref OP_ASGN arg + | backref tOP_ASGN arg { - backref_error($1); + rb_backref_error($1); $$ = 0; } - | arg DOT2 arg + | arg tDOT2 arg { $$ = NEW_DOT2($1, $3); } - | arg DOT3 arg + | arg tDOT3 arg { $$ = NEW_DOT3($1, $3); } @@ -602,17 +677,17 @@ arg : variable '=' arg { $$ = call_op($1, '%', 1, $3); } - | arg POW arg + | arg tPOW arg { - $$ = call_op($1, POW, 1, $3); + $$ = call_op($1, tPOW, 1, $3); } - | UPLUS arg + | tUPLUS arg { - $$ = call_op($2, UPLUS, 0); + $$ = call_op($2, tUPLUS, 0); } - | UMINUS arg + | tUMINUS arg { - $$ = call_op($2, UMINUS, 0); + $$ = call_op($2, tUMINUS, 0); } | arg '|' arg { @@ -626,43 +701,43 @@ arg : variable '=' arg { $$ = call_op($1, '&', 1, $3); } - | arg CMP arg + | arg tCMP arg { - $$ = call_op($1, CMP, 1, $3); + $$ = call_op($1, tCMP, 1, $3); } | arg '>' arg { $$ = call_op($1, '>', 1, $3); } - | arg GEQ arg + | arg tGEQ arg { - $$ = call_op($1, GEQ, 1, $3); + $$ = call_op($1, tGEQ, 1, $3); } | arg '<' arg { $$ = call_op($1, '<', 1, $3); } - | arg LEQ arg + | arg tLEQ arg { - $$ = call_op($1, LEQ, 1, $3); + $$ = call_op($1, tLEQ, 1, $3); } - | arg EQ arg + | arg tEQ arg { - $$ = call_op($1, EQ, 1, $3); + $$ = call_op($1, tEQ, 1, $3); } - | arg EQQ arg + | arg tEQQ arg { - $$ = call_op($1, EQQ, 1, $3); + $$ = call_op($1, tEQQ, 1, $3); } - | arg NEQ arg + | arg tNEQ arg { - $$ = NEW_NOT(call_op($1, EQ, 1, $3)); + $$ = NEW_NOT(call_op($1, tEQ, 1, $3)); } - | arg MATCH arg + | arg tMATCH arg { $$ = match_gen($1, $3); } - | arg NMATCH arg + | arg tNMATCH arg { $$ = NEW_NOT(match_gen($1, $3)); } @@ -675,19 +750,19 @@ arg : variable '=' arg { $$ = call_op($2, '~', 0); } - | arg LSHFT arg + | arg tLSHFT arg { - $$ = call_op($1, LSHFT, 1, $3); + $$ = call_op($1, tLSHFT, 1, $3); } - | arg RSHFT arg + | arg tRSHFT arg { - $$ = call_op($1, RSHFT, 1, $3); + $$ = call_op($1, tRSHFT, 1, $3); } - | arg ANDOP arg + | arg tANDOP arg { $$ = logop(NODE_AND, $1, $3); } - | arg OROP arg + | arg tOROP arg { $$ = logop(NODE_OR, $1, $3); } @@ -696,56 +771,92 @@ arg : variable '=' arg in_defined = 0; $$ = NEW_DEFINED($4); } + | arg '?' arg ':' arg + { + value_expr($1); + $$ = NEW_IF(cond($1), $3, $5); + fixpos($$, $1); + } | primary { $$ = $1; } -call_args : /* none */ +aref_args : opt_call_args + { + if ($1 && nd_type($1) == NODE_BLOCK_PASS) { + rb_compile_error("block argument should not be given"); + } + $$ = $1; + } + +opt_call_args : /* none */ { $$ = 0; } - | call_args0 opt_nl + | call_args opt_nl -call_args0 : command_call +call_args : command_call { value_expr($1); $$ = NEW_LIST($1); } - | args - | args ',' STAR arg + | args opt_block_arg + { + $$ = arg_blk_pass($1, $2); + } + | args ',' tSTAR arg opt_block_arg { $$ = arg_add($1, $4); + $$ = arg_blk_pass($$, $5); } - | assocs + | assocs opt_block_arg { $$ = NEW_LIST(NEW_HASH($1)); + $$ = arg_blk_pass($$, $2); } - | assocs ',' STAR arg + | assocs ',' tSTAR arg opt_block_arg { - $$ = NEW_LIST(NEW_HASH($1)); - $$ = arg_add($$, $4); + $$ = arg_add(NEW_LIST(NEW_HASH($1)), $4); + $$ = arg_blk_pass($$, $5); } - | args ',' assocs + | args ',' assocs opt_block_arg { $$ = list_append($1, NEW_HASH($3)); + $$ = arg_blk_pass($$, $4); } - | args ',' assocs ',' STAR arg + | args ',' assocs ',' tSTAR arg opt_block_arg { - $$ = list_append($1, NEW_HASH($3)); - $$ = arg_add($$, $6); + $$ = arg_add(list_append($1, NEW_HASH($3)), $6); + $$ = arg_blk_pass($$, $7); } - | STAR arg + | tSTAR arg opt_block_arg { value_expr($2); + $$ = arg_blk_pass(NEW_RESTARGS($2), $3); + } + | block_arg + +block_arg : tAMPER arg + { + value_expr($2); + $$ = NEW_BLOCK_PASS($2); + } + +opt_block_arg : ',' block_arg + { $$ = $2; } + | /* none */ + { + $$ = 0; + } -opt_list : /* none */ +opt_list : args + | /* none */ { $$ = 0; } - | args args : arg { @@ -762,32 +873,36 @@ mrhs : args { if ($1 && nd_type($1) == NODE_ARRAY && - $1->nd_next == 0) { + $1->nd_next == 0) + { $$ = $1->nd_head; } else { $$ = $1; } } - | args ',' STAR arg + | args ',' tSTAR arg { + value_expr($4); $$ = arg_add($1, $4); } - | STAR arg + | tSTAR arg { value_expr($2); $$ = $2; } -ret_args : call_args0 +ret_args : call_args { - if ($1 && - nd_type($1) == NODE_ARRAY && - $1->nd_next == 0) { - $$ = $1->nd_head; - } - else { - $$ = $1; + $$ = $1; + if ($1) { + if (nd_type($1) == NODE_ARRAY && + $1->nd_next == 0) { + $$ = $1->nd_head; + } + else if (nd_type($1) == NODE_BLOCK_PASS) { + rb_compile_error("block argument should not be given"); + } } } @@ -801,29 +916,39 @@ primary : literal { $$ = NEW_LIT($1); } - | primary COLON2 cname + | primary tCOLON2 tCONSTANT { + value_expr($1); $$ = NEW_COLON2($1, $3); } - | STRING + | primary tCOLON2 tIDENTIFIER + { + value_expr($1); + $$ = new_call($1, $3, 0); + } + | tCOLON3 cname + { + $$ = NEW_COLON3($2); + } + | tSTRING { $$ = NEW_STR($1); } - | DSTRING - | XSTRING + | tDSTRING + | tXSTRING { $$ = NEW_XSTR($1); } - | DXSTRING - | DREGEXP + | tDXSTRING + | tDREGEXP | var_ref | backref - | primary '[' call_args ']' + | primary '[' aref_args ']' { value_expr($1); - $$ = NEW_CALL($1, AREF, $3); + $$ = NEW_CALL($1, tAREF, $3); } - | LBRACK array ']' + | tLBRACK array ']' { if ($2 == 0) $$ = NEW_ZARRAY(); /* zero length array*/ @@ -831,7 +956,7 @@ primary : literal $$ = $2; } } - | LBRACE assoc_list '}' + | tLBRACE assoc_list '}' { $$ = NEW_HASH($2); } @@ -840,19 +965,19 @@ primary : literal if (!cur_mid && !in_single) yyerror("return appeared outside of method"); value_expr($3); - $$ = NEW_RET($3); + $$ = NEW_RETURN($3); } | kRETURN '(' ')' { if (!cur_mid && !in_single) yyerror("return appeared outside of method"); - $$ = NEW_RET(0); + $$ = NEW_RETURN(0); } | kRETURN { if (!cur_mid && !in_single) yyerror("return appeared outside of method"); - $$ = NEW_RET(0); + $$ = NEW_RETURN(0); } | kYIELD '(' ret_args ')' { @@ -872,9 +997,9 @@ primary : literal in_defined = 0; $$ = NEW_DEFINED($5); } - | FID + | tFID { - $$ = NEW_FCALL($1, 0); + $$ = NEW_VCALL($1); } | operation iter_block { @@ -884,6 +1009,9 @@ primary : literal | method_call | method_call iter_block { + if ($1 && nd_type($1) == NODE_BLOCK_PASS) { + rb_compile_error("both block arg and actual block given"); + } $2->nd_iter = $1; $$ = $2; fixpos($$, $1); @@ -941,19 +1069,24 @@ primary : literal | kBEGIN compstmt rescue + opt_else ensure kEND { - if (!$3 && !$4) + if (!$3 && !$4 && !$5) $$ = NEW_BEGIN($2); else { - if ($3) $2 = NEW_RESCUE($2, $3); - if ($4) $2 = NEW_ENSURE($2, $4); + if ($3) $2 = NEW_RESCUE($2, $3, $4); + else if ($4) { + rb_warn("else without rescue is useless"); + $2 = block_append($2, $4); + } + if ($5) $2 = NEW_ENSURE($2, $5); $$ = $2; } fixpos($$, $2); } - | LPAREN compstmt ')' + | tLPAREN compstmt ')' { $$ = $2; } @@ -975,11 +1108,8 @@ primary : literal cref_pop(); class_nest--; } - | kCLASS LSHFT expr term + | kCLASS tLSHFT expr term { - if (cur_mid || in_single) - yyerror("class definition in method body"); - class_nest++; cref_push(); local_push(); @@ -1027,7 +1157,7 @@ primary : literal local_pop(); cur_mid = 0; } - | kDEF singleton '.' {lex_state = EXPR_FNAME;} fname + | kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname { value_expr($2); in_single++; @@ -1066,7 +1196,6 @@ then : term do : term | kDO - | term kDO if_tail : opt_else | kELSIF expr then @@ -1094,11 +1223,11 @@ opt_iter_var : /* node */ { $$ = 0; } - | '|' /* none */ '|' + | '|' /* none */ '|' { $$ = 0; } - | OROP + | tOROP { $$ = 0; } @@ -1120,7 +1249,7 @@ iter_do_block : kDO dyna_pop($<vars>2); } -iter_block : '{' +iter_block : '{' { $<vars>$ = dyna_push(); } @@ -1132,44 +1261,45 @@ iter_block : '{' dyna_pop($<vars>2); } -iterator : IDENTIFIER +iterator : tIDENTIFIER { - $$ = NEW_FCALL($1, 0); + $$ = NEW_VCALL($1); } - | CONSTANT + | tCONSTANT { - $$ = NEW_FCALL($1, 0); + $$ = NEW_VCALL($1); } - | FID + | tFID { - $$ = NEW_FCALL($1, 0); + $$ = NEW_VCALL($1); } | method_call | command_call -method_call : operation '(' call_args ')' +method_call : operation '(' opt_call_args ')' { - $$ = NEW_FCALL($1, $3); + $$ = new_fcall($1, $3); fixpos($$, $3); } - | primary '.' operation '(' call_args ')' + | primary '.' operation '(' opt_call_args ')' { value_expr($1); - $$ = NEW_CALL($1, $3, $5); + $$ = new_call($1, $3, $5); fixpos($$, $1); } | primary '.' operation { value_expr($1); - $$ = NEW_CALL($1, $3, 0); + $$ = new_call($1, $3, 0); + fixpos($$, $1); } - | primary COLON2 operation '(' call_args ')' + | primary tCOLON2 operation '(' opt_call_args ')' { value_expr($1); - $$ = NEW_CALL($1, $3, $5); + $$ = new_call($1, $3, $5); fixpos($$, $1); } - | kSUPER '(' call_args ')' + | kSUPER '(' opt_call_args ')' { if (!cur_mid && !in_single && !in_defined) yyerror("super called outside of method"); @@ -1183,19 +1313,31 @@ method_call : operation '(' call_args ')' } -case_body : kWHEN args then +case_body : kWHEN when_args then compstmt cases { $$ = NEW_WHEN($2, $4, $5); } +when_args : args + | args ',' tSTAR arg + { + value_expr($4); + $$ = list_append($1, NEW_WHEN($4, 0, 0)); + } + | tSTAR arg + { + value_expr($2); + $$ = NEW_LIST(NEW_WHEN($2, 0, 0)); + } + cases : opt_else | case_body rescue : kRESCUE opt_list do compstmt - rescue + rescue { $$ = NEW_RESBODY($2, $4, $5); fixpos($$, $2?$2:$4); @@ -1215,35 +1357,37 @@ ensure : /* none */ } literal : numeric - | SYMBEG symbol + | tSYMBEG symbol { $$ = INT2FIX($2); } - | REGEXP + | tREGEXP symbol : fname - | IVAR - | GVAR + | tIVAR + | tGVAR -numeric : INTEGER - | FLOAT +numeric : tINTEGER + | tFLOAT -variable : IDENTIFIER - | IVAR - | GVAR - | CONSTANT +variable : tIDENTIFIER + | tIVAR + | tGVAR + | tCONSTANT | kNIL {$$ = kNIL;} | kSELF {$$ = kSELF;} - | kTRUE {$$ = kTRUE;} + | kTRUE {$$ = kTRUE;} | kFALSE {$$ = kFALSE;} + | k__FILE__ {$$ = k__FILE__;} + | k__LINE__ {$$ = k__LINE__;} var_ref : variable { $$ = gettable($1); } -backref : NTH_REF - | BACK_REF +backref : tNTH_REF + | tBACK_REF superclass : term { @@ -1257,9 +1401,9 @@ superclass : term { $$ = $3; } - | error term {yyerrok;} + | error term {yyerrok; $$ = 0;} -f_arglist : '(' f_args ')' +f_arglist : '(' f_args opt_nl ')' { $$ = $2; lex_state = EXPR_BEG; @@ -1269,47 +1413,51 @@ f_arglist : '(' f_args ')' $$ = $1; } -f_args : /* no arg */ +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg { - $$ = NEW_ARGS(0, 0, -1); + $$ = block_append(NEW_ARGS($1, $3, $5), $6); } - | f_arg + | f_arg ',' f_optarg opt_f_block_arg { - $$ = NEW_ARGS($1, 0, -1); + $$ = block_append(NEW_ARGS($1, $3, -1), $4); } - | f_arg ',' rest_arg + | f_arg ',' f_rest_arg opt_f_block_arg { - $$ = NEW_ARGS($1, 0, $3); + $$ = block_append(NEW_ARGS($1, 0, $3), $4); } - | f_arg ',' f_optarg + | f_arg opt_f_block_arg { - $$ = NEW_ARGS($1, $3, -1); + $$ = block_append(NEW_ARGS($1, 0, -1), $2); } - | f_arg ',' f_optarg ',' rest_arg + | f_optarg ',' f_rest_arg opt_f_block_arg { - $$ = NEW_ARGS($1, $3, $5); + $$ = block_append(NEW_ARGS(0, $1, $3), $4); } - | f_optarg + | f_optarg opt_f_block_arg { - $$ = NEW_ARGS(0, $1, -1); + $$ = block_append(NEW_ARGS(0, $1, -1), $2); } - | f_optarg ',' rest_arg + | f_rest_arg opt_f_block_arg { - $$ = NEW_ARGS(0, $1, $3); + $$ = block_append(NEW_ARGS(0, 0, $1), $2); } - | rest_arg + | f_block_arg { - $$ = NEW_ARGS(0, 0, $1); + $$ = block_append(NEW_ARGS(0, 0, -1), $1); + } + | /* none */ + { + $$ = NEW_ARGS(0, 0, -1); } -f_arg : IDENTIFIER +f_arg : tIDENTIFIER { if (!is_local_id($1)) yyerror("formal argument must be local variable"); local_cnt($1); $$ = 1; } - | f_arg ',' IDENTIFIER + | f_arg ',' tIDENTIFIER { if (!is_local_id($3)) yyerror("formal argument must be local variable"); @@ -1317,7 +1465,7 @@ f_arg : IDENTIFIER $$ += 1; } -f_opt : IDENTIFIER '=' arg +f_opt : tIDENTIFIER '=' arg { if (!is_local_id($1)) yyerror("formal argument must be local variable"); @@ -1334,13 +1482,27 @@ f_optarg : f_opt $$ = block_append($1, $3); } -rest_arg : STAR IDENTIFIER +f_rest_arg : tSTAR tIDENTIFIER { if (!is_local_id($2)) yyerror("rest argument must be local variable"); $$ = local_cnt($2); } +f_block_arg : tAMPER tIDENTIFIER + { + $$ = NEW_BLOCK_ARG($2); + } + +opt_f_block_arg : ',' f_block_arg + { + $$ = $2; + } + | /* none */ + { + $$ = 0; + } + singleton : var_ref { if (nd_type($1) == NODE_SELF) { @@ -1354,7 +1516,7 @@ singleton : var_ref $$ = $1; } } - | LPAREN expr opt_nl ')' + | tLPAREN expr opt_nl ')' { switch (nd_type($2)) { case NODE_STR: @@ -1394,21 +1556,17 @@ assocs : assoc $$ = list_concat($1, $3); } -assoc : arg ASSOC arg +assoc : arg tASSOC arg { $$ = list_append(NEW_LIST($1), $3); } - | assoc_kw KW_ASSOC arg - { - $$ = list_append(NEW_LIST(NEW_STR(str_new2(rb_id2name($1)))), $3); - } -assoc_kw : IDENTIFIER - | CONSTANT +operation : tIDENTIFIER + | tCONSTANT + | tFID -operation : IDENTIFIER - | CONSTANT - | FID +dot_or_colon : '.' + | tCOLON2 opt_terms : /* none */ | terms @@ -1431,21 +1589,18 @@ terms : term #include "regex.h" #include "util.h" -#define is_identchar(c) ((c)!=-1&&(isalnum(c) || (c) == '_' || ismbchar(c))) +#define is_identchar(c) ((c)!=-1&&(ISALNUM(c) || (c) == '_' || ismbchar(c))) static char *tokenbuf = NULL; static int tokidx, toksiz = 0; -VALUE newregexp(); -VALUE newstring(); -VALUE newfloat(); -VALUE newinteger(); char *strdup(); -static NODE *str_extend(); +static NODE *rb_str_extend(); #define LEAVE_BS 1 +static VALUE (*lex_gets)(); /* gets function */ static VALUE lex_input; /* non-nil if File */ static VALUE lex_lastline; /* gc protect */ static char *lex_pbeg; @@ -1459,7 +1614,7 @@ yyerror(msg) char *p, *pe, *buf; int len, i; - Error("%s", msg); + rb_compile_error("%s", msg); p = lex_p; while (lex_pbeg <= p) { if (*p == '\n') break; @@ -1478,7 +1633,7 @@ yyerror(msg) buf = ALLOCA_N(char, len+2); MEMCPY(buf, p, char, len); buf[len] = '\0'; - Error_Append("%s", buf); + rb_compile_error_append("%s", buf); i = lex_p - p; p = buf; pe = p + len; @@ -1489,15 +1644,17 @@ yyerror(msg) } buf[i] = '^'; buf[i+1] = '\0'; - Error_Append("%s", buf); + rb_compile_error_append("%s", buf); } return 0; } static int newline_seen; +static int heredoc_end; -int rb_in_compile = 0; +int ruby_in_compile = 0; +int ruby__end__seen; static NODE* yycompile(f) @@ -1505,41 +1662,89 @@ yycompile(f) { int n; + ruby__end__seen = 0; + ruby_eval_tree = 0; newline_seen = 0; - sourcefile = strdup(f); - rb_in_compile = 1; + ruby_sourcefile = f; + ruby_in_compile = 1; n = yyparse(); - rb_in_compile = 0; - if (n == 0) return eval_tree; + ruby_in_compile = 0; + if (n == 0) return ruby_eval_tree; return 0; } +static int lex_gets_ptr; + +static VALUE +lex_get_str(s) + VALUE s; +{ + char *beg, *end, *pend; + + beg = RSTRING(s)->ptr; + if (lex_gets_ptr) { + if (RSTRING(s)->len == lex_gets_ptr) return Qnil; + beg += lex_gets_ptr; + } + pend = RSTRING(s)->ptr + RSTRING(s)->len; + end = beg; + while (end < pend) { + if (*end++ == '\n') break; + } + lex_gets_ptr = end - RSTRING(s)->ptr; + return rb_str_new(beg, end - beg); +} + NODE* -compile_string(f, s, len) - char *f, *s; - int len; +rb_compile_string(f, s) + char *f; + VALUE s; { - lex_pbeg = lex_p = s; - lex_pend = s + len; - lex_input = 0; - if (!sourcefile || strcmp(f, sourcefile)) /* not in eval() */ - sourceline = 1; + lex_gets = lex_get_str; + lex_gets_ptr = 0; + lex_input = s; + lex_pbeg = lex_p = lex_pend = 0; + if (!ruby_sourcefile || strcmp(f, ruby_sourcefile)) /* not in eval() */ + ruby_sourceline = 1; return yycompile(f); } NODE* -compile_file(f, file, start) +rb_compile_cstr(f, s, len) + char *f, *s; + int len; +{ + return rb_compile_string(f, rb_str_new(s, len)); +} + +NODE* +rb_compile_file(f, file, start) char *f; VALUE file; int start; { + lex_gets = rb_io_gets; lex_input = file; lex_pbeg = lex_p = lex_pend = 0; - sourceline = start; + ruby_sourceline = start; - return yycompile(f); + return yycompile(strdup(f)); +} + + +static void +normalize_newline(line) + VALUE line; +{ + if (RSTRING(line)->len >= 2 && + RSTRING(line)->ptr[RSTRING(line)->len-1] == '\n' && + RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r') + { + RSTRING(line)->ptr[RSTRING(line)->len-2] = '\n'; + RSTRING(line)->len--; + } } static int @@ -1549,13 +1754,28 @@ nextc() if (lex_p == lex_pend) { if (lex_input) { - VALUE v = io_gets(lex_input); + VALUE v = (*lex_gets)(lex_input); if (NIL_P(v)) return -1; + if (heredoc_end > 0) { + ruby_sourceline = heredoc_end+1; + heredoc_end = 0; + } + normalize_newline(v); + while (RSTRING(v)->len >= 2 && + RSTRING(v)->ptr[RSTRING(v)->len-1] == '\n' && + RSTRING(v)->ptr[RSTRING(v)->len-2] == '\\') { + VALUE v2 = (*lex_gets)(lex_input); + + if (!NIL_P(v2)) { + normalize_newline(v2); + rb_str_cat(v, RSTRING(v2)->ptr, RSTRING(v2)->len); + } + } lex_pbeg = lex_p = RSTRING(v)->ptr; lex_pend = lex_p + RSTRING(v)->len; - if (RSTRING(v)->len == 8 && - strncmp(lex_pbeg, "__END__", 7) == 0) { + if (strncmp(lex_pbeg, "__END__", 7) == 0 && lex_pbeg[7] == '\n') { + ruby__end__seen = 1; lex_lastline = 0; return -1; } @@ -1571,7 +1791,7 @@ nextc() return c; } -void +static void pushback(c) int c; { @@ -1668,7 +1888,7 @@ read_escape() for (i=0; i<2; i++) { buf[i] = nextc(); if (buf[i] == -1) goto eof; - if (!isxdigit(buf[i])) { + if (!ISXDIGIT(buf[i])) { pushback(buf[i]); break; } @@ -1680,6 +1900,9 @@ read_escape() case 'b': /* backspace */ return '\b'; + case 's': /* space */ + return ' '; + case 'M': if ((c = nextc()) != '-') { yyerror("Invalid escape character syntax"); @@ -1701,7 +1924,6 @@ read_escape() return '\0'; } case 'c': - case '^': if ((c = nextc())== '\\') { c = read_escape(); } @@ -1721,24 +1943,28 @@ read_escape() } static int -parse_regx(term) +parse_regx(term, paren) int term; { register int c; char kcode = 0; int once = 0; - int casefold = 0; + int nest = 0; + int options = 0; int in_brack = 0; - int re_start = sourceline; + int re_start = ruby_sourceline; NODE *list = 0; newtok(); while ((c = nextc()) != -1) { - if (!in_brack && c == term) { + if ((!in_brack && c == term) || nest > 0) { goto regx_end; } switch (c) { + case '\n': + ruby_sourceline++; + break; case '[': in_brack = 1; break; @@ -1747,24 +1973,26 @@ parse_regx(term) break; case '#': - list = str_extend(list, term); + list = rb_str_extend(list, term); if (list == (NODE*)-1) return 0; continue; case '\\': switch (c = nextc()) { case -1: - sourceline = re_start; - Error("unterminated regexp meets end of file"); /* */ + ruby_sourceline = re_start; + rb_compile_error("unterminated regexp meets end of file"); return 0; case '\n': - sourceline++; + ruby_sourceline++; break; case '\\': + case '^': + case 's': tokadd('\\'); - tokadd('\\'); + tokadd(c); break; case '1': case '2': case '3': @@ -1775,11 +2003,6 @@ parse_regx(term) tokadd(c); break; - case '^': /* no \^ escape in regexp */ - tokadd('\\'); - tokadd('^'); - break; - case 'b': if (!in_brack) { tokadd('\\'); @@ -1788,8 +2011,10 @@ parse_regx(term) } /* fall through */ default: + if (c == paren) nest++; + if (c == term) nest--; if (c == '\n') { - sourceline++; + ruby_sourceline++; } else if (c == term) { tokadd(c); @@ -1803,13 +2028,17 @@ parse_regx(term) continue; case -1: - Error("unterminated regexp"); + rb_compile_error("unterminated regexp"); return 0; default: if (ismbchar(c)) { - tokadd(c); - c = nextc(); + int i, len = mbclen(c)-1; + + for (i = 0; i < len; i++) { + tokadd(c); + c = nextc(); + } } break; @@ -1817,19 +2046,25 @@ parse_regx(term) for (;;) { switch (c = nextc()) { case 'i': - casefold = 1; + options |= RE_OPTION_IGNORECASE; + break; + case 'x': + options |= RE_OPTION_EXTENDED; break; case 'o': once = 1; break; case 'n': - kcode = 2; + kcode = 4; break; case 'e': - kcode = 4; + kcode = 8; break; case 's': - kcode = 6; + kcode = 12; + break; + case 'u': + kcode = 16; break; default: pushback(c); @@ -1842,64 +2077,74 @@ parse_regx(term) lex_state = EXPR_END; if (list) { if (toklen() > 0) { - VALUE ss = str_new(tok(), toklen()); + VALUE ss = rb_str_new(tok(), toklen()); list_append(list, NEW_STR(ss)); } nd_set_type(list, once?NODE_DREGX_ONCE:NODE_DREGX); - list->nd_cflag = kcode | casefold; + list->nd_cflag = options | kcode; yylval.node = list; - return DREGEXP; + return tDREGEXP; } else { - yylval.val = reg_new(tok(), toklen(), kcode | casefold); - return REGEXP; + yylval.val = rb_reg_new(tok(), toklen(), options | kcode); + return tREGEXP; } } tokadd(c); } - Error("unterminated regexp"); + rb_compile_error("unterminated regexp"); return 0; } -static int parse_qstring(); +static int parse_qstring _((int,int)); static int -parse_string(func,term) - int func, term; +parse_string(func, term, paren) + int func, term, paren; { int c; NODE *list = 0; int strstart; + int nest = 0; if (func == '\'') { - return parse_qstring(term); + return parse_qstring(term, paren); + } + if (func == 0) { /* read 1 line for heredoc */ + ruby_sourceline++; + /* -1 for chomp */ + yylval.val = rb_str_new(lex_pbeg, lex_pend - lex_pbeg - 1); + return tSTRING; } - strstart = sourceline; + strstart = ruby_sourceline; newtok(); - - while ((c = nextc()) != term) { - if (c == -1) { + while ((c = nextc()) != term || nest > 0) { + if (c == -1) { unterm_str: - sourceline = strstart; - Error("unterminated string meets end of file"); + ruby_sourceline = strstart; + rb_compile_error("unterminated string meets end of file"); return 0; } if (ismbchar(c)) { - tokadd(c); - c = nextc(); + int i, len = mbclen(c)-1; + + for (i = 0; i < len; i++) { + tokadd(c); + c = nextc(); + } } else if (c == '\n') { - sourceline++; + ruby_sourceline++; } else if (c == '#') { - list = str_extend(list, term); + list = rb_str_extend(list, term); if (list == (NODE*)-1) goto unterm_str; continue; } else if (c == '\\') { c = nextc(); if (c == '\n') { - sourceline++; + ruby_sourceline++; } else if (c == term) { tokadd(c); @@ -1911,6 +2156,11 @@ parse_string(func,term) } continue; } + if (c == paren) nest++; + if (c == term) { + nest--; + if (nest == 0) break; + } tokadd(c); } @@ -1918,51 +2168,56 @@ parse_string(func,term) lex_state = EXPR_END; if (list) { if (toklen() > 0) { - VALUE ss = str_new(tok(), toklen()); + VALUE ss = rb_str_new(tok(), toklen()); list_append(list, NEW_STR(ss)); } yylval.node = list; if (func == '`') { nd_set_type(list, NODE_DXSTR); - return DXSTRING; + return tDXSTRING; } else { - return DSTRING; + return tDSTRING; } } else { - yylval.val = str_new(tok(), toklen()); - return (func == '`') ? XSTRING : STRING; + yylval.val = rb_str_new(tok(), toklen()); + return (func == '`') ? tXSTRING : tSTRING; } } static int -parse_qstring(term) - int term; +parse_qstring(term, paren) + int term, paren; { int strstart; int c; + int nest = 0; - strstart = sourceline; + strstart = ruby_sourceline; newtok(); - while ((c = nextc()) != term) { - if (c == -1) { - sourceline = strstart; - Error("unterminated string meets end of file"); + while ((c = nextc()) != term || nest > 0) { + if (c == -1) { + ruby_sourceline = strstart; + rb_compile_error("unterminated string meets end of file"); return 0; } if (ismbchar(c)) { - tokadd(c); - c = nextc(); + int i, len = mbclen(c)-1; + + for (i = 0; i < len; i++) { + tokadd(c); + c = nextc(); + } } else if (c == '\n') { - sourceline++; + ruby_sourceline++; } else if (c == '\\') { c = nextc(); switch (c) { case '\n': - sourceline++; + ruby_sourceline++; continue; case '\\': @@ -1979,27 +2234,45 @@ parse_qstring(term) tokadd('\\'); } } + if (c == paren) nest++; + if (c == term) { + nest--; + if (nest == 0) break; + } tokadd(c); } tokfix(); - yylval.val = str_new(tok(), toklen()); + yylval.val = rb_str_new(tok(), toklen()); lex_state = EXPR_END; - return STRING; + return tSTRING; +} + +static int +parse_quotedword(term, paren) + int term, paren; +{ + if (parse_qstring(term, paren) == 0) return 0; + yylval.node = NEW_CALL(NEW_STR(yylval.val), rb_intern("split"), 0); + return tDSTRING; } char *strdup(); static int -here_document(term) +here_document(term, indent) char term; + int indent; { int c; - char *eos; + char *eos, *p; int len; - VALUE str, line; - char *save_beg, *save_end, *save_lexp; + VALUE str; + volatile VALUE line; + VALUE lastline_save; + int offset_save; NODE *list = 0; + int linesave = ruby_sourceline; newtok(); switch (term) { @@ -2009,14 +2282,15 @@ here_document(term) while ((c = nextc()) != term) { tokadd(c); } + if (term == '\'') term = 0; break; default: - c = term; + c = term; term = '"'; if (!is_identchar(c)) { - yyerror("illegal here document"); - return 0; + rb_warn("Use of bare << to mean <<\"\" is deprecated"); + break; } while (is_identchar(c)) { tokadd(c); @@ -2026,44 +2300,56 @@ here_document(term) break; } tokfix(); - save_lexp = lex_p; - save_beg = lex_pbeg; - save_end = lex_pend; + lastline_save = lex_lastline; + offset_save = lex_p - lex_pbeg; eos = strdup(tok()); len = strlen(eos); - str = str_new(0,0); + str = rb_str_new(0,0); for (;;) { - line = io_gets(lex_input); + line = (*lex_gets)(lex_input); if (NIL_P(line)) { error: - Error("unterminated string meets end of file"); + ruby_sourceline = linesave; + rb_compile_error("can't find string \"%s\" anywhere before EOF", eos); free(eos); return 0; } - if (strncmp(eos, RSTRING(line)->ptr, len) == 0 && - (RSTRING(line)->ptr[len] == '\n' || - RSTRING(line)->ptr[len] == '\r')) { + normalize_newline(line); + ruby_sourceline++; + p = RSTRING(line)->ptr; + if (indent) { + while (*p && (*p == ' ' || *p == '\t')) { + p++; + } + } + if (strncmp(eos, p, len) == 0 && p[len] == '\n') { break; } lex_pbeg = lex_p = RSTRING(line)->ptr; lex_pend = lex_p + RSTRING(line)->len; - sourceline++; - switch (parse_string(term, '\n')) { - case STRING: - case XSTRING: - str_cat(yylval.val, "\n", 1); +#if 0 + if (indent) { + while (*lex_p && *lex_p == '\t') { + lex_p++; + } + } +#endif + switch (parse_string(term, '\n', '\n')) { + case tSTRING: + case tXSTRING: + rb_str_cat(yylval.val, "\n", 1); if (!list) { - str_cat(str, RSTRING(yylval.val)->ptr, RSTRING(yylval.val)->len); + rb_str_cat(str, RSTRING(yylval.val)->ptr, RSTRING(yylval.val)->len); } else { list_append(list, NEW_STR(yylval.val)); } break; - case DSTRING: - case DXSTRING: - list_append(yylval.node, NEW_STR(str_new2("\n"))); + case tDSTRING: + case tDXSTRING: + list_append(yylval.node, NEW_STR(rb_str_new2("\n"))); nd_set_type(yylval.node, NODE_STR); if (!list) list = NEW_DSTR(str); yylval.node = NEW_LIST(yylval.node); @@ -2076,22 +2362,28 @@ here_document(term) } } free(eos); - lex_p = save_lexp; - lex_pbeg = save_beg; - lex_pend = save_end; + lex_lastline = lastline_save; + lex_pbeg = RSTRING(lex_lastline)->ptr; + lex_pend = lex_pbeg + RSTRING(lex_lastline)->len; + lex_p = lex_pbeg + offset_save; + + lex_state = EXPR_END; + heredoc_end = ruby_sourceline; + ruby_sourceline = linesave; if (list) { yylval.node = list; } switch (term) { + case '\0': case '\'': case '"': - if (list) return DSTRING; - yylval.val = str; - return STRING; + if (list) return tDSTRING; + yylval.val = str; + return tSTRING; case '`': - if (list) return DXSTRING; - return XSTRING; + if (list) return tDXSTRING; + return tXSTRING; } return 0; } @@ -2101,7 +2393,7 @@ here_document(term) static void arg_ambiguous() { - Warning("ambiguous first argument; make sure"); + rb_warning("ambiguous first argument; make sure"); } #ifndef atof @@ -2116,7 +2408,7 @@ yylex() struct kwtable *kw; if (newline_seen) { - sourceline+=newline_seen; + ruby_sourceline += newline_seen; newline_seen = 0; } @@ -2140,21 +2432,30 @@ retry: return 0; if (c == '\\') { /* skip a char */ c = nextc(); - if (c == '\n') sourceline++; + if (c == '\n') ruby_sourceline++; } if (ismbchar(c)) { - c = nextc(); - if (c == '\n') { - sourceline++; - break; + int i, len = mbclen(c)-1; + + for (i = 0; i < len; i++) { + c = nextc(); + if (c == '\n') { + ruby_sourceline++; + break; + } } } } /* fall through */ case '\n': - if (lex_state == EXPR_BEG || lex_state == EXPR_FNAME) { - sourceline++; + switch (lex_state) { + case EXPR_BEG: + case EXPR_FNAME: + case EXPR_DOT: + ruby_sourceline++; goto retry; + default: + break; } newline_seen++; lex_state = EXPR_BEG; @@ -2164,25 +2465,26 @@ retry: if ((c = nextc()) == '*') { lex_state = EXPR_BEG; if (nextc() == '=') { - yylval.id = POW; - return OP_ASGN; + yylval.id = tPOW; + return tOP_ASGN; } pushback(c); - return POW; + return tPOW; } if (c == '=') { yylval.id = '*'; lex_state = EXPR_BEG; - return OP_ASGN; + return tOP_ASGN; } pushback(c); - if (lex_state == EXPR_ARG && space_seen && !isspace(c)){ + if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){ arg_ambiguous(); lex_state = EXPR_BEG; - return STAR; + return tSTAR; } if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { - return STAR; + lex_state = EXPR_BEG; + return tSTAR; } lex_state = EXPR_BEG; return '*'; @@ -2190,10 +2492,10 @@ retry: case '!': lex_state = EXPR_BEG; if ((c = nextc()) == '=') { - return NEQ; + return tNEQ; } if (c == '~') { - return NMATCH; + return tNMATCH; } pushback(c); return '!'; @@ -2201,21 +2503,21 @@ retry: case '=': if (lex_p == lex_pbeg + 1) { /* skip embedded rd document */ - if (strncmp(lex_p, "begin", 5) == 0 && isspace(lex_p[5])) { + if (strncmp(lex_p, "begin", 5) == 0 && ISSPACE(lex_p[5])) { for (;;) { - sourceline++; + ruby_sourceline++; lex_p = lex_pend; c = nextc(); if (c == -1) { - Error("embedded document meets end of file"); + rb_compile_error("embedded document meets end of file"); return 0; } if (c != '=') continue; - if (strncmp(lex_p, "end", 3) == 0 && isspace(lex_p[3])) { + if (strncmp(lex_p, "end", 3) == 0 && ISSPACE(lex_p[3])) { break; } } - sourceline++; + ruby_sourceline++; lex_p = lex_pend; goto retry; } @@ -2224,16 +2526,16 @@ retry: lex_state = EXPR_BEG; if ((c = nextc()) == '=') { if ((c = nextc()) == '=') { - return EQQ; + return tEQQ; } pushback(c); - return EQ; + return tEQ; } if (c == '~') { - return MATCH; + return tMATCH; } else if (c == '>') { - return ASSOC; + return tASSOC; } pushback(c); return '='; @@ -2241,33 +2543,34 @@ retry: case '<': c = nextc(); if (c == '<' && - lex_state != EXPR_END - && lex_state != EXPR_CLASS && + lex_state != EXPR_END && lex_state != EXPR_CLASS && (lex_state != EXPR_ARG || space_seen)) { int c2 = nextc(); - if (!isspace(c2) && (strchr("\"'`", c2) || is_identchar(c2))) { - if (!lex_input) { - ArgError("here document not available"); - } - return here_document(c2); + int indent = 0; + if (c2 == '-') { + indent = 1; + c2 = nextc(); + } + if (!ISSPACE(c2) && (strchr("\"'`", c2) || is_identchar(c2))) { + return here_document(c2, indent); } pushback(c2); } lex_state = EXPR_BEG; if (c == '=') { if ((c = nextc()) == '>') { - return CMP; + return tCMP; } pushback(c); - return LEQ; + return tLEQ; } if (c == '<') { if (nextc() == '=') { - yylval.id = LSHFT; - return OP_ASGN; + yylval.id = tLSHFT; + return tOP_ASGN; } pushback(c); - return LSHFT; + return tLSHFT; } pushback(c); return '<'; @@ -2275,57 +2578,89 @@ retry: case '>': lex_state = EXPR_BEG; if ((c = nextc()) == '=') { - return GEQ; + return tGEQ; } if (c == '>') { if ((c = nextc()) == '=') { - yylval.id = RSHFT; - return OP_ASGN; + yylval.id = tRSHFT; + return tOP_ASGN; } pushback(c); - return RSHFT; + return tRSHFT; } pushback(c); return '>'; case '"': - return parse_string(c,c); + return parse_string(c,c,c); case '`': if (lex_state == EXPR_FNAME) return c; - return parse_string(c,c); + return parse_string(c,c,c); case '\'': - return parse_qstring(c); + return parse_qstring(c,c); case '?': - if ((c = nextc()) == '\\') { + if (lex_state == EXPR_END) { + lex_state = EXPR_BEG; + return '?'; + } + c = nextc(); + if (lex_state == EXPR_ARG && ISSPACE(c)){ + pushback(c); + arg_ambiguous(); + lex_state = EXPR_BEG; + return '?'; + } + if (c == '\\') { c = read_escape(); } c &= 0xff; yylval.val = INT2FIX(c); lex_state = EXPR_END; - return INTEGER; + return tINTEGER; case '&': - lex_state = EXPR_BEG; if ((c = nextc()) == '&') { - return ANDOP; + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + yylval.id = tANDOP; + return tOP_ASGN; + } + pushback(c); + return tANDOP; } else if (c == '=') { yylval.id = '&'; - return OP_ASGN; + lex_state = EXPR_BEG; + return tOP_ASGN; } pushback(c); + if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){ + arg_ambiguous(); + lex_state = EXPR_BEG; + return tAMPER; + } + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + lex_state = EXPR_BEG; + return tAMPER; + } + lex_state = EXPR_BEG; return '&'; case '|': lex_state = EXPR_BEG; if ((c = nextc()) == '|') { - return OROP; + if ((c = nextc()) == '=') { + yylval.id = tOROP; + return tOP_ASGN; + } + pushback(c); + return tOROP; } else if (c == '=') { yylval.id = '|'; - return OP_ASGN; + return tOP_ASGN; } pushback(c); return '|'; @@ -2334,7 +2669,7 @@ retry: c = nextc(); if (lex_state == EXPR_FNAME) { if (c == '@') { - return UPLUS; + return tUPLUS; } pushback(c); return '+'; @@ -2342,23 +2677,15 @@ retry: if (c == '=') { lex_state = EXPR_BEG; yylval.id = '+'; - return OP_ASGN; - } - if (lex_state == EXPR_ARG) { - if (space_seen && !isspace(c)) { - arg_ambiguous(); - } - else { - lex_state = EXPR_END; - } + return tOP_ASGN; } - if (lex_state != EXPR_END) { - if (isdigit(c)) { + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + if (ISDIGIT(c)) { goto start_num; } pushback(c); lex_state = EXPR_BEG; - return UPLUS; + return tUPLUS; } lex_state = EXPR_BEG; pushback(c); @@ -2368,7 +2695,7 @@ retry: c = nextc(); if (lex_state == EXPR_FNAME) { if (c == '@') { - return UMINUS; + return tUMINUS; } pushback(c); return '-'; @@ -2376,29 +2703,17 @@ retry: if (c == '=') { lex_state = EXPR_BEG; yylval.id = '-'; - return OP_ASGN; - } - if (c == '>') { - lex_state = EXPR_BEG; - return KW_ASSOC; - } - if (lex_state == EXPR_ARG) { - if (space_seen && !isspace(c)) { - arg_ambiguous(); - } - else { - lex_state = EXPR_END; - } + return tOP_ASGN; } - if (lex_state != EXPR_END) { - if (isdigit(c)) { + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + if (ISDIGIT(c)) { pushback(c); c = '-'; goto start_num; } lex_state = EXPR_BEG; pushback(c); - return UMINUS; + return tUMINUS; } lex_state = EXPR_BEG; pushback(c); @@ -2408,13 +2723,14 @@ retry: lex_state = EXPR_BEG; if ((c = nextc()) == '.') { if ((c = nextc()) == '.') { - return DOT3; + return tDOT3; } pushback(c); - return DOT2; + return tDOT2; } pushback(c); - if (!isdigit(c)) { + if (!ISDIGIT(c)) { + lex_state = EXPR_DOT; return '.'; } c = '.'; @@ -2439,13 +2755,13 @@ retry: /* hexadecimal */ while (c = nextc()) { if (c == '_') continue; - if (!isxdigit(c)) break; + if (!ISXDIGIT(c)) break; tokadd(c); } pushback(c); tokfix(); - yylval.val = str2inum(tok(), 16); - return INTEGER; + yylval.val = rb_str2inum(tok(), 16); + return tINTEGER; } else if (c >= '0' && c <= '7') { /* octal */ @@ -2456,8 +2772,8 @@ retry: } while (c >= '0' && c <= '9'); pushback(c); tokfix(); - yylval.val = str2inum(tok(), 8); - return INTEGER; + yylval.val = rb_str2inum(tok(), 8); + return tINTEGER; } else if (c > '7' && c <= '9') { yyerror("Illegal octal digit"); @@ -2468,7 +2784,7 @@ retry: else { pushback(c); yylval.val = INT2FIX(0); - return INTEGER; + return tINTEGER; } } @@ -2480,12 +2796,12 @@ retry: break; case '.': - if (seen_point) { + if (seen_point || seen_e) { goto decode_num; } else { int c0 = nextc(); - if (!isdigit(c0)) { + if (!ISDIGIT(c0)) { pushback(c0); goto decode_num; } @@ -2524,11 +2840,11 @@ retry: pushback(c); tokfix(); if (is_float) { - yylval.val = float_new(atof(tok())); - return FLOAT; + yylval.val = rb_float_new(atof(tok())); + return tFLOAT; } - yylval.val = str2inum(tok(), 10); - return INTEGER; + yylval.val = rb_str2inum(tok(), 10); + return tINTEGER; } case ']': @@ -2540,29 +2856,40 @@ retry: case ':': c = nextc(); if (c == ':') { - lex_state = EXPR_BEG; - return COLON2; + if (lex_state == EXPR_BEG) { + lex_state = EXPR_BEG; + return tCOLON3; + } + if (lex_state == EXPR_ARG && space_seen) { + arg_ambiguous(); + lex_state = EXPR_BEG; + return tCOLON3; + } + lex_state = EXPR_DOT; + return tCOLON2; } pushback(c); - if (isspace(c)) + if (lex_state == EXPR_END || ISSPACE(c)) { + lex_state = EXPR_BEG; return ':'; + } lex_state = EXPR_FNAME; - return SYMBEG; + return tSYMBEG; case '/': if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { - return parse_regx('/'); + return parse_regx('/', '/'); } if ((c = nextc()) == '=') { lex_state = EXPR_BEG; yylval.id = '/'; - return OP_ASGN; + return tOP_ASGN; } if (lex_state == EXPR_ARG) { - if (space_seen && !isspace(c)) { + if (space_seen && !ISSPACE(c)) { pushback(c); arg_ambiguous(); - return parse_regx('/'); + return parse_regx('/', '/'); } } lex_state = EXPR_BEG; @@ -2573,15 +2900,12 @@ retry: lex_state = EXPR_BEG; if (nextc() == '=') { yylval.id = '^'; - return OP_ASGN; + return tOP_ASGN; } pushback(c); return c; case ',': - lex_state = EXPR_BEG; - return c; - case ';': lex_state = EXPR_BEG; return c; @@ -2597,12 +2921,7 @@ retry: case '(': if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { - c = LPAREN; - lex_state = EXPR_BEG; - } - else if (lex_state == EXPR_ARG && space_seen) { - arg_ambiguous(); - c = LPAREN; + c = tLPAREN; lex_state = EXPR_BEG; } else { @@ -2614,34 +2933,34 @@ retry: if (lex_state == EXPR_FNAME) { if ((c = nextc()) == ']') { if ((c = nextc()) == '=') { - return ASET; + return tASET; } pushback(c); - return AREF; + return tAREF; } pushback(c); return '['; } else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { - c = LBRACK; + c = tLBRACK; } else if (lex_state == EXPR_ARG && space_seen) { arg_ambiguous(); - c = LBRACK; + c = tLBRACK; } lex_state = EXPR_BEG; return c; case '{': if (lex_state != EXPR_END && lex_state != EXPR_ARG) - c = LBRACE; + c = tLBRACE; lex_state = EXPR_BEG; return c; case '\\': c = nextc(); if (c == '\n') { - sourceline++; + ruby_sourceline++; space_seen = 1; goto retry; /* skip \\n */ } @@ -2651,29 +2970,22 @@ retry: case '%': if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { int term; + int paren; c = nextc(); quotation: - if (!isalnum(c)) { + if (!ISALNUM(c)) { term = c; - switch (c) { - case '\'': - c = 'q'; break; - case '/': - c = 'r'; break; - case '`': - c = 'x'; break; - default: - c = 'Q';break; - } + c = 'Q'; } else { term = nextc(); } if (c == -1 || term == -1) { - Error("unterminated quoted string meets end of file"); + rb_compile_error("unterminated quoted string meets end of file"); return 0; } + paren = term; if (term == '(') term = ')'; else if (term == '[') term = ']'; else if (term == '{') term = '}'; @@ -2681,28 +2993,31 @@ retry: switch (c) { case 'Q': - return parse_string('"', term); + return parse_string('"', term, paren); case 'q': - return parse_qstring(term); + return parse_qstring(term, paren); + + case 'w': + return parse_quotedword(term, paren); case 'x': - return parse_string('`', term); + return parse_string('`', term, paren); case 'r': - return parse_regx(term); + return parse_regx(term, paren); default: - yyerror("unknown type of string `%c'", c); + yyerror("unknown type of %string"); return 0; } } if ((c = nextc()) == '=') { yylval.id = '%'; - return OP_ASGN; + return tOP_ASGN; } if (lex_state == EXPR_ARG) { - if (space_seen && !isspace(c)) { + if (space_seen && !ISSPACE(c)) { arg_ambiguous(); goto quotation; } @@ -2740,7 +3055,7 @@ retry: tokadd(c); tokfix(); yylval.id = rb_intern(tok()); - return GVAR; + return tGVAR; case '-': tokadd('$'); @@ -2749,26 +3064,26 @@ retry: tokadd(c); tokfix(); yylval.id = rb_intern(tok()); - return GVAR; + return tGVAR; case '&': /* $&: last match */ case '`': /* $`: string before last match */ case '\'': /* $': string after last match */ case '+': /* $+: string matches last paren. */ yylval.node = NEW_BACK_REF(c); - return BACK_REF; + return tBACK_REF; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - while (isdigit(c)) { + while (ISDIGIT(c)) { tokadd(c); c = nextc(); } pushback(c); tokfix(); yylval.node = NEW_NTH_REF(atoi(tok())); - return NTH_REF; + return tNTH_REF; default: if (!is_identchar(c)) { @@ -2791,8 +3106,8 @@ retry: break; default: - if (c != '_' && !isalpha(c) && !ismbchar(c)) { - Error("Invalid char '%c' in expression", c); + if (c != '_' && !ISALPHA(c) && !ismbchar(c)) { + rb_compile_error("Invalid char '%c' in expression", c); goto retry; } @@ -2803,12 +3118,17 @@ retry: while (is_identchar(c)) { tokadd(c); if (ismbchar(c)) { - c = nextc(); + int i, len = mbclen(c)-1; + tokadd(c); + for (i = 0; i < len; i++) { + c = nextc(); + tokadd(c); + } } c = nextc(); } - if (c == '!' || c == '?') { + if ((c == '!' || c == '?') && is_identchar(tok()[0])) { tokadd(c); } else { @@ -2822,44 +3142,51 @@ retry: switch (tok()[0]) { case '$': lex_state = EXPR_END; - result = GVAR; + result = tGVAR; break; case '@': lex_state = EXPR_END; - result = IVAR; + result = tIVAR; break; default: - /* See if it is a reserved word. */ - kw = rb_reserved_word(tok(), toklen()); - if (kw) { - enum lex_state state = lex_state; - lex_state = kw->state; - return kw->id[state != EXPR_BEG]; + if (lex_state != EXPR_DOT) { + /* See if it is a reserved word. */ + kw = rb_reserved_word(tok(), toklen()); + if (kw) { + enum lex_state state = lex_state; + if (lex_state == EXPR_FNAME) { + yylval.id = rb_intern(kw->name); + } + lex_state = kw->state; + return kw->id[state != EXPR_BEG]; + } } - if (lex_state == EXPR_FNAME) { - lex_state = EXPR_END; - if ((c = nextc()) == '=') { - tokadd(c); - } - else { - pushback(c); + if (ISUPPER(tok()[0])) { + result = tCONSTANT; + } + else if (toklast() == '!' || toklast() == '?') { + result = tFID; + } else { + result = tIDENTIFIER; + if (lex_state == EXPR_FNAME) { + lex_state = EXPR_END; + if ((c = nextc()) == '=') { + tokadd(c); + } + else { + pushback(c); + } } } - else if (lex_state == EXPR_BEG){ + if (lex_state == EXPR_BEG || + lex_state == EXPR_DOT || + lex_state == EXPR_ARG){ lex_state = EXPR_ARG; } else { lex_state = EXPR_END; } - if (isupper(tok()[0])) { - result = CONSTANT; - } - else if (toklast() == '!' || toklast() == '?') { - result = FID; - } else { - result = IDENTIFIER; - } } tokfix(); yylval.id = rb_intern(tok()); @@ -2868,11 +3195,12 @@ retry: } static NODE* -str_extend(list, term) +rb_str_extend(list, term) NODE *list; char term; { - int c, brace; + int c; + int brace = -1; VALUE ss; NODE *node; int nest; @@ -2889,7 +3217,7 @@ str_extend(list, term) return list; } - ss = str_new(tok(), toklen()); + ss = rb_str_new(tok(), toklen()); if (list == 0) { list = NEW_DSTR(ss); } @@ -2907,7 +3235,7 @@ str_extend(list, term) case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - while (isdigit(c)) { + while (ISDIGIT(c)) { tokadd(c); c = nextc(); } @@ -2926,7 +3254,7 @@ str_extend(list, term) default: if (c == term) { - list_append(list, NEW_STR(str_new2("#$"))); + list_append(list, NEW_STR(rb_str_new2("#$"))); pushback(c); newtok(); return list; @@ -2946,14 +3274,19 @@ str_extend(list, term) } /* through */ - case '@': + case '@': tokadd(c); c = nextc(); while (is_identchar(c)) { tokadd(c); if (ismbchar(c)) { - c = nextc(); + int i, len = mbclen(c)-1; + tokadd(c); + for (i = 0; i < len; i++) { + c = nextc(); + tokadd(c); + } } c = nextc(); } @@ -2975,7 +3308,6 @@ str_extend(list, term) } return (NODE*)-1; case '}': - case ')': if (c == brace) { if (nest == 0) break; nest--; @@ -2987,16 +3319,16 @@ str_extend(list, term) tokadd(c); goto loop_again; case '{': - if (brace == c) nest++; + if (brace != -1) nest++; case '\"': case '/': case '`': if (c == term) { pushback(c); - list_append(list, NEW_STR(str_new2("#"))); - Warning("bad substitution in string"); + list_append(list, NEW_STR(rb_str_new2("#"))); + rb_warning("bad substitution in string"); tokfix(); - list_append(list, NEW_STR(str_new(tok(), toklen()))); + list_append(list, NEW_STR(rb_str_new(tok(), toklen()))); newtok(); return list; } @@ -3017,7 +3349,7 @@ str_extend(list, term) } NODE* -node_newnode(type, a0, a1, a2) +rb_node_newnode(type, a0, a1, a2) enum node_type type; NODE *a0, *a1, *a2; { @@ -3025,8 +3357,8 @@ node_newnode(type, a0, a1, a2) n->flags |= T_NODE; nd_set_type(n, type); - nd_set_line(n, sourceline); - n->nd_file = sourcefile; + nd_set_line(n, ruby_sourceline); + n->nd_file = ruby_sourcefile; n->u1.node = a0; n->u2.node = a1; @@ -3035,14 +3367,14 @@ node_newnode(type, a0, a1, a2) return n; } -enum node_type +static enum node_type nodetype(node) /* for debug */ NODE *node; { return (enum node_type)nd_type(node); } -int +static int nodeline(node) NODE *node; { @@ -3091,7 +3423,7 @@ block_append(head, tail) end = head->nd_end; } - if (RTEST(verbose)) { + if (RTEST(rb_verbose)) { NODE *nd = end->nd_head; newline: switch (nd_type(nd)) { @@ -3100,7 +3432,7 @@ block_append(head, tail) case NODE_NEXT: case NODE_REDO: case NODE_RETRY: - Warning("statement not reached"); + rb_warning("statement not reached"); break; case NODE_NEWLINE: @@ -3133,7 +3465,7 @@ list_append(head, tail) while (last->nd_next) { last = last->nd_next; } - + last->nd_next = NEW_LIST(tail); head->nd_alen += 1; return head; @@ -3200,7 +3532,7 @@ match_gen(node1, node2) } } - return NEW_CALL(node1, MATCH, NEW_LIST(node2)); + return NEW_CALL(node1, tMATCH, NEW_LIST(node2)); } static NODE* @@ -3219,9 +3551,15 @@ gettable(id) else if (id == kFALSE) { return NEW_FALSE(); } + else if (id == k__FILE__) { + return NEW_STR(rb_str_new2(ruby_sourcefile)); + } + else if (id == k__LINE__) { + return NEW_LIT(INT2FIX(ruby_sourceline)); + } else if (is_local_id(id)) { + if (dyna_in_block() && rb_dvar_defined(id)) return NEW_DVAR(id); if (local_id(id)) return NEW_LVAR(id); - if (dyna_var_defined(id)) return NEW_DVAR(id); /* method call without arguments */ return NEW_VCALL(id); } @@ -3234,7 +3572,7 @@ gettable(id) else if (is_const_id(id)) { return NEW_CVAR(id); } - Bug("invalid id for gettable"); + rb_bug("invalid id for gettable"); return 0; } @@ -3245,6 +3583,7 @@ assignable(id, val) { NODE *lhs = 0; + value_expr(val); if (id == kSELF) { yyerror("Can't change the value of self"); } @@ -3257,13 +3596,22 @@ assignable(id, val) else if (id == kFALSE) { yyerror("Can't assign to false"); } + else if (id == k__FILE__) { + yyerror("Can't assign to __FILE__"); + } + else if (id == k__LINE__) { + yyerror("Can't assign to __LINE__"); + } else if (is_local_id(id)) { - if (local_id(id) || !dyna_in_block()) { + if (rb_dvar_defined(id)) { + lhs = NEW_DASGN(id, val); + } + else if (local_id(id) || !dyna_in_block()) { lhs = NEW_LASGN(id, val); } else{ - dyna_var_asgn(id, TRUE); - lhs = NEW_DASGN(id, val); + rb_dvar_push(id, 0); + lhs = NEW_DASGN_PUSH(id, val); } } else if (is_global_id(id)) { @@ -3278,7 +3626,7 @@ assignable(id, val) lhs = NEW_CASGN(id, val); } else { - Bug("bad id for variable"); + rb_bug("bad id for variable"); } return lhs; } @@ -3288,7 +3636,7 @@ arg_add(node1, node2) NODE *node1; NODE *node2; { - return call_op(node1, rb_intern("concat"), 1, node2); + return NEW_ARGSCAT(node1, node2); } static NODE * @@ -3305,11 +3653,11 @@ aryset(recv, idx, val) idx = arg_add(idx, val); } } - return NEW_CALL(recv, ASET, idx); + return NEW_CALL(recv, tASET, idx); } ID -id_attrset(id) +rb_id_attrset(id) ID id; { id &= ~ID_SCOPE_MASK; @@ -3324,23 +3672,20 @@ attrset(recv, id, val) { value_expr(recv); value_expr(val); - - id &= ~ID_SCOPE_MASK; - id |= ID_ATTRSET; - return NEW_CALL(recv, id, NEW_LIST(val)); + return NEW_CALL(recv, rb_id_attrset(id), NEW_LIST(val)); } static void -backref_error(node) +rb_backref_error(node) NODE *node; { switch (nd_type(node)) { case NODE_NTH_REF: - Error("Can't set variable $%d", node->nd_nth); + rb_compile_error("Can't set variable $%d", node->nd_nth); break; case NODE_BACK_REF: - Error("Can't set variable $%c", node->nd_nth); + rb_compile_error("Can't set variable $%c", node->nd_nth); break; } } @@ -3349,7 +3694,7 @@ static int value_expr(node) NODE *node; { - if (node == 0) return TRUE; + if (node == 0) return Qtrue; switch (nd_type(node)) { case NODE_RETURN: @@ -3364,7 +3709,7 @@ value_expr(node) case NODE_DEFN: case NODE_DEFS: yyerror("void value expression"); - return FALSE; + return Qfalse; break; case NODE_BLOCK: @@ -3380,18 +3725,64 @@ value_expr(node) return value_expr(node->nd_next); default: - return TRUE; + return Qtrue; } } static NODE *cond2(); +static int +assign_in_cond(node) + NODE *node; +{ + switch (nd_type(node)) { + case NODE_MASGN: + yyerror("multiple assignment in conditional"); + return 1; + + case NODE_LASGN: + case NODE_DASGN: + case NODE_GASGN: + case NODE_IASGN: + case NODE_CASGN: + break; + + case NODE_NEWLINE: + default: + return 0; + } + + switch (nd_type(node->nd_value)) { + case NODE_LIT: + case NODE_STR: + case NODE_DSTR: + case NODE_XSTR: + case NODE_DXSTR: + case NODE_EVSTR: + case NODE_DREGX: + case NODE_NIL: + case NODE_TRUE: + case NODE_FALSE: + /* reports always */ + rb_warn("found = in conditional, should be =="); + return 1; + + default: + break; + } + if (assign_in_cond(node->nd_value) == 0) { + rb_warning("assignment in condition"); + } + return 1; +} + static NODE* cond0(node) NODE *node; { enum node_type type = nd_type(node); + assign_in_cond(node); switch (type) { case NODE_DREGX: case NODE_DREGX_ONCE: @@ -3405,6 +3796,7 @@ cond0(node) node->nd_end = cond2(node->nd_end); if (type == NODE_DOT2) nd_set_type(node,NODE_FLIP2); else if (type == NODE_DOT3) nd_set_type(node, NODE_FLIP3); + node->nd_cnt = local_append(0); return node; case NODE_LIT: @@ -3416,7 +3808,7 @@ cond0(node) if (TYPE(node->nd_lit) == T_STRING) { local_cnt('_'); local_cnt('~'); - return NEW_MATCH(reg_new(RSTRING(node)->ptr,RSTRING(node)->len,0)); + return NEW_MATCH(rb_reg_new(RSTRING(node)->ptr,RSTRING(node)->len,0)); } default: return node; @@ -3427,24 +3819,11 @@ static NODE* cond(node) NODE *node; { - enum node_type type = nd_type(node); - - switch (type) { - case NODE_MASGN: - case NODE_LASGN: - case NODE_DASGN: - case NODE_GASGN: - case NODE_IASGN: - case NODE_CASGN: - Warning("assignment in condition"); - break; - case NODE_NEWLINE: + if (node == 0) return 0; + if (nd_type(node) == NODE_NEWLINE){ node->nd_next = cond0(node->nd_next); return node; - default: - break; } - return cond0(node); } @@ -3458,7 +3837,7 @@ cond2(node) type = nd_type(node); if (type == NODE_NEWLINE) node = node->nd_next; if (type == NODE_LIT && FIXNUM_P(node->nd_lit)) { - return call_op(node,EQ,1,NEW_GVAR(rb_intern("$."))); + return call_op(node,tEQ,1,NEW_GVAR(rb_intern("$."))); } return node; } @@ -3469,11 +3848,45 @@ logop(type, left, right) NODE *left, *right; { value_expr(left); + return rb_node_newnode(type, cond(left), cond(right), 0); +} + +static NODE * +arg_blk_pass(node1, node2) + NODE *node1; + NODE *node2; +{ + if (node2) { + node2->nd_head = node1; + return node2; + } + return node1; +} - return node_newnode(type, cond(left), cond(right)); +static NODE* +new_call(r,m,a) + NODE *r; + ID m; + NODE *a; +{ + if (a && nd_type(a) == NODE_BLOCK_PASS) { + a->nd_iter = NEW_CALL(r,m,a->nd_head); + return a; + } + return NEW_CALL(r,m,a); } -st_table *new_idhash(); +static NODE* +new_fcall(m,a) + ID m; + NODE *a; +{ + if (a && nd_type(a) == NODE_BLOCK_PASS) { + a->nd_iter = NEW_FCALL(m,a->nd_head); + return a; + } + return NEW_FCALL(m,a); +} static struct local_vars { ID *tbl; @@ -3500,14 +3913,14 @@ local_push() static void local_pop() { - struct local_vars *local = lvtbl; + struct local_vars *local = lvtbl->prev; - lvtbl = local->prev; - if (local->tbl) { - local->tbl[0] = local->cnt; - if (!local->nofree) free(local->tbl); + if (lvtbl->tbl) { + if (!lvtbl->nofree) free(lvtbl->tbl); + else lvtbl->tbl[0] = lvtbl->cnt; } - free(local); + free(lvtbl); + lvtbl = local; } static ID* @@ -3518,21 +3931,17 @@ local_tbl() } static int -local_cnt(id) +local_append(id) ID id; { - int cnt, max; - - if (id == 0) return lvtbl->cnt; - - for (cnt=1, max=lvtbl->cnt+1; cnt<max ;cnt++) { - if (lvtbl->tbl[cnt] == id) return cnt-1; - } - - if (lvtbl->tbl == 0) { - lvtbl->tbl = ALLOC_N(ID, 2); + lvtbl->tbl = ALLOC_N(ID, 4); lvtbl->tbl[0] = 0; + lvtbl->tbl[1] = '_'; + lvtbl->tbl[2] = '~'; + lvtbl->cnt = 2; + if (id == '_') return 0; + if (id == '~') return 1; } else { REALLOC_N(lvtbl->tbl, ID, lvtbl->cnt+2); @@ -3542,32 +3951,46 @@ local_cnt(id) return lvtbl->cnt++; } +static int +local_cnt(id) + ID id; +{ + int cnt, max; + + if (id == 0) return lvtbl->cnt; + + for (cnt=1, max=lvtbl->cnt+1; cnt<max ;cnt++) { + if (lvtbl->tbl[cnt] == id) return cnt-1; + } + return local_append(id); +} + static int local_id(id) ID id; { int i, max; - if (lvtbl == 0) return FALSE; - for (i=1, max=lvtbl->cnt+1; i<max; i++) { - if (lvtbl->tbl[i] == id) return TRUE; + if (lvtbl == 0) return Qfalse; + for (i=3, max=lvtbl->cnt+1; i<max; i++) { + if (lvtbl->tbl[i] == id) return Qtrue; } - return FALSE; + return Qfalse; } static void top_local_init() { local_push(); - lvtbl->cnt = the_scope->local_tbl?the_scope->local_tbl[0]:0; + lvtbl->cnt = ruby_scope->local_tbl?ruby_scope->local_tbl[0]:0; if (lvtbl->cnt > 0) { - lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+1); - MEMCPY(lvtbl->tbl, the_scope->local_tbl, ID, lvtbl->cnt+1); + lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+3); + MEMCPY(lvtbl->tbl, ruby_scope->local_tbl, ID, lvtbl->cnt+1); } else { lvtbl->tbl = 0; } - if (the_dyna_vars && the_dyna_vars->id) + if (ruby_dyna_vars) lvtbl->dlev = 1; else lvtbl->dlev = 0; @@ -3583,33 +4006,31 @@ top_local_setup() i = lvtbl->tbl[0]; if (i < len) { - if (i == 0 || the_scope->flag == SCOPE_ALLOCA) { + if (i == 0 || ruby_scope->flag == SCOPE_ALLOCA) { VALUE *vars = ALLOC_N(VALUE, len+1); - if (the_scope->local_vars) { - *vars++ = the_scope->local_vars[-1]; - MEMCPY(vars, the_scope->local_vars, VALUE, i); - memclear(vars+i, len-i); + if (ruby_scope->local_vars) { + *vars++ = ruby_scope->local_vars[-1]; + MEMCPY(vars, ruby_scope->local_vars, VALUE, i); + rb_mem_clear(vars+i, len-i); } else { *vars++ = 0; - memclear(vars, len); + rb_mem_clear(vars, len); } - the_scope->local_vars = vars; - the_scope->flag |= SCOPE_MALLOC; + ruby_scope->local_vars = vars; + ruby_scope->flag |= SCOPE_MALLOC; } else { - VALUE *vars = the_scope->local_vars-1; + VALUE *vars = ruby_scope->local_vars-1; REALLOC_N(vars, VALUE, len+1); - the_scope->local_vars = vars+1; - memclear(the_scope->local_vars+i, len-i); + ruby_scope->local_vars = vars+1; + rb_mem_clear(ruby_scope->local_vars+i, len-i); } - lvtbl->tbl[0] = len; - if (the_scope->local_tbl && the_scope->local_vars[-1] == 0) { - free(the_scope->local_tbl); + if (ruby_scope->local_tbl && ruby_scope->local_vars[-1] == 0) { + free(ruby_scope->local_tbl); } - the_scope->local_vars[-1] = 0; - the_scope->local_tbl = lvtbl->tbl; - lvtbl->nofree = 1; + ruby_scope->local_vars[-1] = 0; + ruby_scope->local_tbl = local_tbl(); } } local_pop(); @@ -3619,7 +4040,7 @@ static struct RVarmap* dyna_push() { lvtbl->dlev++; - return the_dyna_vars; + return ruby_dyna_vars; } static void @@ -3627,7 +4048,7 @@ dyna_pop(vars) struct RVarmap* vars; { lvtbl->dlev--; - the_dyna_vars = vars; + ruby_dyna_vars = vars; } static int @@ -3643,35 +4064,38 @@ cref_pop() } void -yyappend_print() +rb_parser_append_print() { - eval_tree = - block_append(eval_tree, + ruby_eval_tree = + block_append(ruby_eval_tree, NEW_FCALL(rb_intern("print"), NEW_ARRAY(NEW_GVAR(rb_intern("$_"))))); } void -yywhile_loop(chop, split) +rb_parser_while_loop(chop, split) int chop, split; { if (split) { - eval_tree = + ruby_eval_tree = block_append(NEW_GASGN(rb_intern("$F"), NEW_CALL(NEW_GVAR(rb_intern("$_")), rb_intern("split"), 0)), - eval_tree); + ruby_eval_tree); } if (chop) { - eval_tree = + ruby_eval_tree = block_append(NEW_CALL(NEW_GVAR(rb_intern("$_")), - rb_intern("chop!"), 0), eval_tree); + rb_intern("chop!"), 0), ruby_eval_tree); } - eval_tree = NEW_OPT_N(eval_tree); + ruby_eval_tree = NEW_OPT_N(ruby_eval_tree); } -static struct op_tbl rb_op_tbl[] = { - DOT2, "..", +static struct { + ID token; + char *name; +} op_tbl[] = { + tDOT2, "..", '+', "+", '-', "-", '+', "+(binary)", @@ -3679,35 +4103,36 @@ static struct op_tbl rb_op_tbl[] = { '*', "*", '/', "/", '%', "%", - POW, "**", - UPLUS, "+@", - UMINUS, "-@", - UPLUS, "+(unary)", - UMINUS, "-(unary)", + tPOW, "**", + tUPLUS, "+@", + tUMINUS, "-@", + tUPLUS, "+(unary)", + tUMINUS, "-(unary)", '|', "|", '^', "^", '&', "&", - CMP, "<=>", + tCMP, "<=>", '>', ">", - GEQ, ">=", + tGEQ, ">=", '<', "<", - LEQ, "<=", - EQ, "==", - EQQ, "===", - NEQ, "!=", - MATCH, "=~", - NMATCH, "!~", + tLEQ, "<=", + tEQ, "==", + tEQQ, "===", + tNEQ, "!=", + tMATCH, "=~", + tNMATCH, "!~", '!', "!", '~', "~", '!', "!(unary)", '~', "~(unary)", '!', "!@", '~', "~@", - AREF, "[]", - ASET, "[]=", - LSHFT, "<<", - RSHFT, ">>", - COLON2, "::", + tAREF, "[]", + tASET, "[]=", + tLSHFT, "<<", + tRSHFT, ">>", + tCOLON2, "::", + tCOLON3, "::", '`', "`", 0, 0, }; @@ -3715,16 +4140,14 @@ static struct op_tbl rb_op_tbl[] = { char *rb_id2name(); char *rb_class2name(); -static st_table *rb_symbol_tbl; - -#define sym_tbl rb_symbol_tbl +static st_table *sym_tbl; +static st_table *sym_rev_tbl; void Init_sym() { - int strcmp(); - - sym_tbl = st_init_strtable(); + 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); } @@ -3740,8 +4163,7 @@ rb_intern(name) if (st_lookup(sym_tbl, name, &id)) return id; - id = ++last_id; - id <<= ID_SCOPE_SHIFT; + id = 0; switch (name[0]) { case '$': id |= ID_GLOBAL; @@ -3749,24 +4171,20 @@ rb_intern(name) case '@': id |= ID_INSTANCE; break; - /* fall through */ default: - if (name[0] != '_' && !isalpha(name[0]) && !ismbchar(name[0])) { + if (name[0] != '_' && !ISALPHA(name[0]) && !ismbchar(name[0])) { /* operator */ int i; - id = 0; - for (i=0; rb_op_tbl[i].token; i++) { - if (*rb_op_tbl[i].name == *name && - strcmp(rb_op_tbl[i].name, name) == 0) { - id = rb_op_tbl[i].token; - break; + for (i=0; op_tbl[i].token; i++) { + if (*op_tbl[i].name == *name && + strcmp(op_tbl[i].name, name) == 0) { + id = op_tbl[i].token; + goto id_regist; } } - if (id == 0) NameError("Unknown operator `%s'", name); - break; } - + last = strlen(name)-1; if (name[last] == '=') { /* attribute assignment */ @@ -3775,66 +4193,55 @@ rb_intern(name) strncpy(buf, name, last); buf[last] = '\0'; id = rb_intern(buf); - id &= ~ID_SCOPE_MASK; + if (id > LAST_TOKEN) { + id = rb_id_attrset(id); + goto id_regist; + } id |= ID_ATTRSET; } - else if (isupper(name[0])) { - id |= ID_CONST; + else if (ISUPPER(name[0])) { + id = ID_CONST; } else { - id |= ID_LOCAL; + id = ID_LOCAL; } break; } - st_add_direct(sym_tbl, strdup(name), id); + id |= ++last_id << ID_SCOPE_SHIFT; + id_regist: + name = strdup(name); + st_add_direct(sym_tbl, name, id); + st_add_direct(sym_rev_tbl, id, name); return id; } -struct find_ok { - ID id; - char *name; -}; - -static int -id_find(name, id1, ok) - char *name; - ID id1; - struct find_ok *ok; -{ - if (id1 == ok->id) { - ok->name = name; - return ST_STOP; - } - return ST_CONTINUE; -} - char * rb_id2name(id) ID id; { - struct find_ok ok; + char *name; if (id < LAST_TOKEN) { int i = 0; - for (i=0; rb_op_tbl[i].token; i++) { - if (rb_op_tbl[i].token == id) - return rb_op_tbl[i].name; + for (i=0; op_tbl[i].token; i++) { + if (op_tbl[i].token == id) + return op_tbl[i].name; } } - ok.name = 0; - ok.id = id; - st_foreach(sym_tbl, id_find, &ok); - if (!ok.name && is_attrset_id(id)) { + if (st_lookup(sym_rev_tbl, id, &name)) + return name; + + if (is_attrset_id(id)) { char *res; - ID id2; + ID id2; id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL; res = rb_id2name(id2); if (res) { - char *buf = ALLOCA_N(char,strlen(res)+2); + char *buf = ALLOCA_N(char, strlen(res)+2); strcpy(buf, res); strcat(buf, "="); @@ -3842,55 +4249,23 @@ rb_id2name(id) return rb_id2name(id); } } - return ok.name; + return 0; } int rb_is_const_id(id) ID id; { - if (is_const_id(id)) return TRUE; - return FALSE; + if (is_const_id(id)) return Qtrue; + return Qfalse; } int rb_is_instance_id(id) ID id; { - if (is_instance_id(id)) return TRUE; - return FALSE; -} - -void -local_var_append(id) - ID id; -{ - struct local_vars tmp; - struct local_vars *save = lvtbl; - - if (the_scope->local_tbl) { - tmp.cnt = the_scope->local_tbl[0]; - tmp.tbl = the_scope->local_tbl; - lvtbl->dlev = 0; - } - lvtbl = &tmp; - local_cnt(id); - lvtbl = save; -} - -static VALUE -special_local_get(c) - char c; -{ - int cnt, max; - - if (!the_scope->local_vars) return Qnil; - for (cnt=1, max=the_scope->local_tbl[0]+1; cnt<max ;cnt++) { - if (the_scope->local_tbl[cnt] == c) { - return the_scope->local_vars[cnt-1]; - } - } - return Qnil; + if (is_instance_id(id)) return Qtrue; + return Qfalse; } static void @@ -3898,46 +4273,52 @@ special_local_set(c, val) char c; VALUE val; { - int cnt, max; + int cnt; - if (the_scope->local_tbl) { - for (cnt=1, max=the_scope->local_tbl[0]+1; cnt<max ;cnt++) { - if (the_scope->local_tbl[cnt] == c) { - the_scope->local_vars[cnt-1] = val; - return; - } - } - } top_local_init(); cnt = local_cnt(c); top_local_setup(); - the_scope->local_vars[cnt] = val; + ruby_scope->local_vars[cnt] = val; } VALUE -backref_get() +rb_backref_get() { - return special_local_get('~'); + if (ruby_scope->local_vars) { + return ruby_scope->local_vars[1]; + } + return Qnil; } void -backref_set(val) +rb_backref_set(val) VALUE val; { - special_local_set('~', val); + if (ruby_scope->local_vars) { + ruby_scope->local_vars[1] = val; + } + else { + special_local_set('~', val); + } } VALUE -lastline_get() +rb_lastline_get() { - VALUE v = special_local_get('_'); - if (v == 1) return Qnil; /* $_ undefined */ - return v; + if (ruby_scope->local_vars) { + return ruby_scope->local_vars[0]; + } + return Qnil; } void -lastline_set(val) +rb_lastline_set(val) VALUE val; { - special_local_set('_', val); + if (ruby_scope->local_vars) { + ruby_scope->local_vars[0] = val; + } + else { + special_local_set('_', val); + } } diff --git a/process.c b/process.c index 9d50fea8bf..d3e6559ca3 100644 --- a/process.c +++ b/process.c @@ -6,15 +6,14 @@ $Date$ created at: Tue Aug 10 14:30:50 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" -#include "sig.h" +#include "rubysig.h" #include <stdio.h> #include <errno.h> -#include <ctype.h> #include <signal.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -29,8 +28,9 @@ struct timeval { }; #endif #endif /* NT */ +#include <ctype.h> -struct timeval time_timeval(); +struct timeval rb_time_timeval _((VALUE)); #ifdef HAVE_SYS_WAIT_H # include <sys/wait.h> @@ -43,6 +43,11 @@ struct timeval time_timeval(); #endif #include "st.h" +#ifdef USE_CWGUSI +# include <sys/errno.h> +# include "macruby_missing.h" +#endif + static VALUE get_pid() { @@ -59,12 +64,11 @@ get_ppid() #endif } -VALUE last_status = Qnil; +VALUE rb_last_status = Qnil; #if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4) +#define NO_WAITPID static st_table *pid_tbl; -#else -# define WAIT_CALL #endif static int @@ -74,69 +78,54 @@ rb_waitpid(pid, flags, st) int *st; { int result; -#if defined(THREAD) && (defined(HAVE_WAITPID) || defined(HAVE_WAIT4)) +#ifndef NO_WAITPID +#if defined(USE_THREAD) int oflags = flags; - if (!thread_alone()) { /* there're other threads to run */ + if (!rb_thread_alone()) { /* there're other threads to run */ flags |= WNOHANG; } #endif -#ifdef HAVE_WAITPID retry: +#ifdef HAVE_WAITPID result = waitpid(pid, st, flags); - if (result < 0) { - if (errno == EINTR) { -#ifdef THREAD - thread_schedule(); -#endif - goto retry; - } - return -1; - } -#ifdef THREAD - if (result == 0) { - if (oflags & WNOHANG) return 0; - thread_schedule(); - if (thread_alone()) flags = oflags; - goto retry; - } -#endif -#else -#ifdef HAVE_WAIT4 - retry: - +#else /* HAVE_WAIT4 */ result = wait4(pid, st, flags, NULL); +#endif if (result < 0) { if (errno == EINTR) { +#ifdef USE_THREAD + rb_thread_schedule(); +#endif goto retry; } return -1; } -#ifdef THREAD +#ifdef USE_THREAD if (result == 0) { if (oflags & WNOHANG) return 0; - thread_schedule(); - if (thread_alone()) flags = oflags; + rb_thread_schedule(); + if (rb_thread_alone()) flags = oflags; goto retry; } #endif -#else +#else /* NO_WAITPID */ if (pid_tbl && st_lookup(pid_tbl, pid, st)) { - last_status = INT2FIX(*st); + rb_last_status = INT2FIX(*st); st_delete(pid_tbl, &pid, NULL); return pid; } if (flags) { - ArgError("Can't do waitpid with flags"); + rb_raise(rb_eArgError, "Can't do waitpid with flags"); } for (;;) { result = wait(st); if (result < 0) { if (errno == EINTR) { -#ifdef THREAD - thread_schedule(); +#ifdef USE_THREAD + rb_thread_schedule(); #endif continue; } @@ -148,14 +137,16 @@ rb_waitpid(pid, flags, st) if (!pid_tbl) pid_tbl = st_init_numtable(); st_insert(pid_tbl, pid, st); - } +#ifdef USE_THREAD + if (!thread_alone()) rb_thread_schedule(); #endif + } #endif - last_status = INT2FIX(*st); + rb_last_status = INT2FIX(*st); return result; } -#ifndef WAIT_CALL +#ifdef NO_WAITPID struct wait_data { int pid; int status; @@ -175,36 +166,38 @@ wait_each(key, value, data) #endif static VALUE -f_wait() +rb_f_wait() { int pid, state; -#ifndef WAIT_CALL +#ifdef NO_WAITPID struct wait_data data; data.status = -1; st_foreach(pid_tbl, wait_each, &data); if (data.status != -1) { - last_status = data.status; + rb_last_status = data.status; return INT2FIX(data.pid); } -#endif while ((pid = wait(&state)) < 0) { - if (errno == EINTR) { -#ifdef THREAD - thread_schedule(); + if (errno == EINTR) { +#ifdef USE_THREAD + rb_thread_schedule(); #endif - continue; - } - if (errno == ECHILD) return Qnil; - rb_sys_fail(0); + continue; + } + rb_sys_fail(0); } - last_status = INT2FIX(state); + rb_last_status = INT2FIX(state); +#else + if ((pid = rb_waitpid(-1, 0, &state)) < 0) + rb_sys_fail(0); +#endif return INT2FIX(pid); } static VALUE -f_waitpid(obj, vpid, vflags) +rb_f_waitpid(obj, vpid, vflags) VALUE obj, vpid, vflags; { int pid, flags, status; @@ -219,46 +212,26 @@ f_waitpid(obj, vpid, vflags) char *strtok(); -#if defined(THREAD) && defined(HAVE_SETITIMER) -static void -before_exec() -{ - struct itimerval tval; - - tval.it_interval.tv_sec = 0; - tval.it_interval.tv_usec = 0; - tval.it_value = tval.it_interval; - setitimer(ITIMER_VIRTUAL, &tval, NULL); -} - -static void -after_exec() -{ - struct itimerval tval; - - tval.it_interval.tv_sec = 0; - tval.it_interval.tv_usec = 100000; - tval.it_value = tval.it_interval; - setitimer(ITIMER_VIRTUAL, &tval, NULL); -} +#if defined(USE_THREAD) && defined(HAVE_SETITIMER) +#define before_exec() rb_thread_stop_timer() +#define after_exec() rb_thread_start_timer() #else #define before_exec() #define after_exec() #endif extern char *dln_find_exe(); -int env_path_tainted(); static void security(str) char *str; { - extern VALUE eSecurityError; - if (rb_safe_level() > 0) { - if (env_path_tainted()) { - Raise(eSecurityError, "Insecure PATH - %s", str); +#ifndef USE_CWGUSI + if (rb_env_path_tainted()) { + rb_raise(rb_eSecurityError, "Insecure PATH - %s", str); } +#endif } } @@ -267,6 +240,7 @@ proc_exec_v(argv, prog) char **argv; char *prog; { +#ifndef USE_CWGUSI if (prog) { security(prog); } @@ -315,6 +289,9 @@ proc_exec_v(argv, prog) execv(prog, argv); after_exec(); return -1; +#else /* USE_CWGUSI */ + rb_notimplement(); +#endif /* USE_CWGUSI */ } static int @@ -328,12 +305,10 @@ proc_exec_n(argc, argv, progv) int i; if (progv) { - Check_SafeStr(progv); prog = RSTRING(progv)->ptr; } args = ALLOCA_N(char*, argc+1); for (i=0; i<argc; i++) { - Check_SafeStr(argv[i]); args[i] = RSTRING(argv[i])->ptr; } args[i] = 0; @@ -347,12 +322,13 @@ int rb_proc_exec(str) char *str; { +#ifndef USE_CWGUSI char *s = str, *t; char **argv, **a; security(str); for (s=str; *s; s++) { - if (*s != ' ' && !isalpha(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { + if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { #if defined(MSDOS) int state; before_exec(); @@ -361,7 +337,7 @@ rb_proc_exec(str) if (state != -1) exit(state); #else -#if defined(__human68k__) +#if defined(__human68k__) || defined(__CYGWIN32__) char *shell = dln_find_exe("sh", 0); int state = -1; before_exec(); @@ -395,6 +371,9 @@ rb_proc_exec(str) } errno = ENOENT; return -1; +#else /* USE_CWGUSI */ + rb_notimplement(); +#endif /* USE_CWGUSI */ } #if defined(__human68k__) @@ -466,15 +445,18 @@ proc_spawn_n(argc, argv, prog) } static int -proc_spawn(str) - char *str; +proc_spawn(sv) + VALUE sv; { - char *s = str, *t; + char *str; + char *s, *t; char **argv, **a; int state; + Check_SafeStr(sv); + str = s = RSTRING(sv)->ptr; for (s = str; *s; s++) { - if (*s != ' ' && !isalpha(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { + if (*s != ' ' && !ISALPHA(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) { char *shell = dln_find_exe("sh", 0); before_exec(); state = shell ? spawnl(P_WAIT, shell, "sh", "-c", str, (char *) NULL) : system(str) ; @@ -495,15 +477,19 @@ proc_spawn(str) #endif /* __human68k__ */ static VALUE -f_exec(argc, argv) +rb_f_exec(argc, argv) int argc; VALUE *argv; { VALUE prog = 0; + int i; + if (argc == 0) { + rb_raise(rb_eArgError, "wrong # of arguments"); + } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { - ArgError("wrong first argument"); + rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(argv[0])->ptr[0]; argv[0] = RARRAY(argv[0])->ptr[1]; @@ -511,13 +497,18 @@ f_exec(argc, argv) if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { - ArgError("wrong first argument"); + rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(argv[0])->ptr[0]; argv[0] = RARRAY(argv[0])->ptr[1]; } + if (prog) { + Check_SafeStr(prog); + } + for (i = 0; i < argc; i++) { + Check_SafeStr(argv[i]); + } if (argc == 1 && prog == 0) { - Check_SafeStr(argv[0]); rb_proc_exec(RSTRING(argv[0])->ptr); } else { @@ -527,7 +518,7 @@ f_exec(argc, argv) } static VALUE -f_fork(obj) +rb_f_fork(obj) VALUE obj; { #if !defined(__human68k__) @@ -539,7 +530,7 @@ f_fork(obj) #ifdef linux after_exec(); #endif - if (iterator_p()) { + if (rb_iterator_p()) { rb_yield(Qnil); _exit(0); } @@ -558,17 +549,21 @@ f_fork(obj) } static VALUE -f_exit_bang(obj, status) +rb_f_exit_bang(obj, status) VALUE obj, status; { int code = -1; - rb_secure(2); + rb_secure(4); if (FIXNUM_P(status)) { code = INT2FIX(status); } +#ifdef USE_CWGUSI + exit(code); +#else _exit(code); +#endif /* not reached */ } @@ -579,6 +574,7 @@ rb_syswait(pid) { RETSIGTYPE (*hfunc)(), (*qfunc)(), (*ifunc)(); int status; + int i; #ifdef SIGHUP hfunc = signal(SIGHUP, SIG_IGN); @@ -588,7 +584,9 @@ rb_syswait(pid) #endif ifunc = signal(SIGINT, SIG_IGN); - if (rb_waitpid(pid, 0, &status) < 0) rb_sys_fail("wait"); + do { + i = rb_waitpid(pid, 0, &status); + } while (i == -1 && errno == EINTR); #ifdef SIGHUP signal(SIGHUP, hfunc); @@ -600,7 +598,7 @@ rb_syswait(pid) } static VALUE -f_system(argc, argv) +rb_f_system(argc, argv) int argc; VALUE *argv; { @@ -610,18 +608,18 @@ f_system(argc, argv) if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { - ArgError("wrong first argument"); + rb_raise(rb_eArgError, "wrong first argument"); } argv[0] = RARRAY(argv[0])->ptr[0]; } - cmd = ary_join(ary_new4(argc, argv), str_new2(" ")); + cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); Check_SafeStr(cmd); state = do_spawn(RSTRING(cmd)->ptr); - last_status = INT2FIX(state); + rb_last_status = INT2FIX(state); - if (state == 0) return TRUE; - return FALSE; + if (state == 0) return Qtrue; + return Qfalse; #else #if defined(DJGPP) VALUE cmd; @@ -629,18 +627,18 @@ f_system(argc, argv) if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { - ArgError("wrong first argument"); + rb_raise(rb_eArgError, "wrong first argument"); } argv[0] = RARRAY(argv[0])->ptr[0]; } - cmd = ary_join(ary_new4(argc, argv), str_new2(" ")); + cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" ")); Check_SafeStr(cmd); state = system(RSTRING(cmd)->ptr); - last_status = INT2FIX(state); + rb_last_status = INT2FIX(state); - if (state == 0) return TRUE; - return FALSE; + if (state == 0) return Qtrue; + return Qfalse; #else #if defined(__human68k__) VALUE prog = 0; @@ -651,48 +649,52 @@ f_system(argc, argv) fflush(stdout); fflush(stderr); if (argc == 0) { - last_status = INT2FIX(0); + rb_last_status = INT2FIX(0); return INT2FIX(0); } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { - ArgError("wrong first argument"); + rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(argv[0])->ptr[0]; argv[0] = RARRAY(argv[0])->ptr[1]; } if (argc == 1 && prog == 0) { - state = proc_spawn(RSTRING(argv[0])->ptr); + state = proc_spawn(argv[0]); } else { state = proc_spawn_n(argc, argv, prog); } - last_status = state == -1 ? INT2FIX(127) : INT2FIX(state); - - return state == 0 ? TRUE : FALSE ; + rb_last_status = state == -1 ? INT2FIX(127) : INT2FIX(state); + return state == 0 ? Qtrue : Qfalse ; #else - VALUE prog = 0; - int i; + volatile VALUE prog = 0; int pid; + int i; - fflush(stdin); /* is it really needed? */ fflush(stdout); fflush(stderr); if (argc == 0) { - last_status = INT2FIX(0); + rb_last_status = INT2FIX(0); return INT2FIX(0); } if (TYPE(argv[0]) == T_ARRAY) { if (RARRAY(argv[0])->len != 2) { - ArgError("wrong first argument"); + rb_raise(rb_eArgError, "wrong first argument"); } prog = RARRAY(argv[0])->ptr[0]; argv[0] = RARRAY(argv[0])->ptr[1]; } + if (prog) { + Check_SafeStr(prog); + } + for (i = 0; i < argc; i++) { + Check_SafeStr(argv[i]); + } retry: switch (pid = vfork()) { case 0: @@ -707,8 +709,8 @@ f_system(argc, argv) case -1: if (errno == EAGAIN) { -#ifdef THREAD - thread_sleep(1); +#ifdef USE_THREAD + rb_thread_sleep(1); #else sleep(1); #endif @@ -721,27 +723,27 @@ f_system(argc, argv) rb_syswait(pid); } - if (last_status == INT2FIX(0)) return TRUE; - return FALSE; + if (rb_last_status == INT2FIX(0)) return Qtrue; + return Qfalse; #endif #endif #endif } static VALUE -f_sleep(argc, argv) +rb_f_sleep(argc, argv) int argc; VALUE *argv; { int beg, end; beg = time(0); -#ifdef THREAD +#ifdef USE_THREAD if (argc == 0) { - thread_sleep_forever(); + rb_thread_sleep_forever(); } else if (argc == 1) { - thread_wait_for(time_timeval(argv[0])); + rb_thread_wait_for(rb_time_timeval(argv[0])); } #else if (argc == 0) { @@ -753,7 +755,7 @@ f_sleep(argc, argv) struct timeval tv; int n; - tv = time_timeval(argv[0]); + tv = rb_time_timeval(argv[0]); TRAP_BEG; n = select(0, 0, 0, 0, &tv); TRAP_END; @@ -761,7 +763,7 @@ f_sleep(argc, argv) } #endif else { - ArgError("wrong # of arguments"); + rb_raise(rb_eArgError, "wrong # of arguments"); } end = time(0) - beg; @@ -769,7 +771,7 @@ f_sleep(argc, argv) return INT2FIX(end); } -#if !defined(NT) && !defined(DJGPP) && !defined(__human68k__) +#if !defined(NT) && !defined(DJGPP) && !defined(__human68k__) && !defined(USE_CWGUSI) static VALUE proc_getpgrp(argc, argv) int argc; @@ -781,7 +783,7 @@ proc_getpgrp(argc, argv) int pid; rb_scan_args(argc, argv, "01", &vpid); - pid = NUM2INT(vpid); + pid = NIL_P(vpid)?0:NUM2INT(vpid); pgrp = BSD_GETPGRP(pid); #else rb_scan_args(argc, argv, "0"); @@ -796,27 +798,45 @@ proc_setpgrp(argc, argv) int argc; VALUE *argv; { +#ifdef HAVE_SETPGRP #ifdef BSD_SETPGRP VALUE pid, pgrp; int ipid, ipgrp; rb_scan_args(argc, argv, "02", &pid, &pgrp); - ipid = NUM2INT(pid); - ipgrp = NUM2INT(pgrp); + ipid = NIL_P(pid)?0:NUM2INT(pid); + ipgrp = NIL_P(pgrp)?0:NUM2INT(pgrp); if (BSD_SETPGRP(ipid, ipgrp) < 0) rb_sys_fail(0); #else rb_scan_args(argc, argv, "0"); if (setpgrp() < 0) rb_sys_fail(0); #endif return Qnil; +#else + rb_notimplement(); +#endif +} + +static VALUE +proc_getpgid(obj, pid) + VALUE obj, pid; +{ +#ifdef HAVE_GETPGID + int i; + + i = getpgid(NUM2INT(pid)); + return INT2NUM(i); +#else + rb_notimplement(); +#endif } -#ifdef HAVE_SETPGID static VALUE proc_setpgid(obj, pid, pgrp) VALUE obj, pid, pgrp; { +#ifdef HAVE_SETPGID int ipid, ipgrp; ipid = NUM2INT(pid); @@ -824,8 +844,23 @@ proc_setpgid(obj, pid, pgrp) if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0); return Qnil; +#else + rb_notimplement(); +#endif } + +static VALUE +proc_setsid() +{ +#ifdef HAVE_SETSID + int pid = setsid(); + + if (pid < 0) rb_sys_fail(0); + return INT2FIX(pid); +#else + rb_notimplement(); #endif +} static VALUE proc_getpriority(obj, which, who) @@ -880,11 +915,11 @@ proc_setuid(obj, id) int uid; uid = NUM2INT(id); -#ifdef HAVE_SETRUID - setruid(uid); -#else #ifdef HAVE_SETREUID setreuid(uid, -1); +#else +#ifdef HAVE_SETRUID + setruid(uid); #else { if (geteuid() == uid) @@ -985,74 +1020,83 @@ proc_setegid(obj, egid) return egid; } -VALUE mProcess; - -extern VALUE f_kill(); +VALUE rb_mProcess; void Init_process() { +#ifndef USE_CWGUSI rb_define_virtual_variable("$$", get_pid, 0); - rb_define_readonly_variable("$?", &last_status); - rb_define_global_function("exec", f_exec, -1); -#ifndef NT - rb_define_global_function("fork", f_fork, 0); #endif - rb_define_global_function("exit!", f_exit_bang, 1); - rb_define_global_function("system", f_system, -1); - rb_define_global_function("sleep", f_sleep, -1); + rb_define_readonly_variable("$?", &rb_last_status); +#ifndef USE_CWGUSI + rb_define_global_function("exec", rb_f_exec, -1); +#endif +#if !defined(NT) && !defined(USE_CWGUSI) + rb_define_global_function("fork", rb_f_fork, 0); +#endif + rb_define_global_function("exit!", rb_f_exit_bang, 1); +#ifndef USE_CWGUSI + rb_define_global_function("system", rb_f_system, -1); +#endif + rb_define_global_function("sleep", rb_f_sleep, -1); - mProcess = rb_define_module("Process"); + rb_mProcess = rb_define_module("Process"); #if !defined(NT) && !defined(DJGPP) #ifdef WNOHANG - rb_define_const(mProcess, "WNOHANG", INT2FIX(WNOHANG)); + rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(WNOHANG)); #else - rb_define_const(mProcess, "WNOHANG", INT2FIX(0)); + rb_define_const(rb_mProcess, "WNOHANG", INT2FIX(0)); #endif #ifdef WUNTRACED - rb_define_const(mProcess, "WUNTRACED", INT2FIX(WUNTRACED)); + rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(WUNTRACED)); #else - rb_define_const(mProcess, "WUNTRACED", INT2FIX(0)); + rb_define_const(rb_mProcess, "WUNTRACED", INT2FIX(0)); #endif #endif -#ifndef NT - rb_define_singleton_method(mProcess, "fork", f_fork, 0); +#if !defined(NT) && !defined(USE_CWGUSI) + rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0); +#endif + rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, 1); +#ifndef USE_CWGUSI + rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1); #endif - rb_define_singleton_method(mProcess, "exit!", f_exit_bang, 1); - rb_define_module_function(mProcess, "kill", f_kill, -1); #ifndef NT - rb_define_module_function(mProcess, "wait", f_wait, 0); - rb_define_module_function(mProcess, "waitpid", f_waitpid, 2); + rb_define_module_function(rb_mProcess, "wait", rb_f_wait, 0); + rb_define_module_function(rb_mProcess, "waitpid", rb_f_waitpid, 2); - rb_define_module_function(mProcess, "pid", get_pid, 0); - rb_define_module_function(mProcess, "ppid", get_ppid, 0); -#endif +#ifndef USE_CWGUSI + rb_define_module_function(rb_mProcess, "pid", get_pid, 0); + rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0); +#endif /* ifndef USE_CWGUSI */ +#endif /* ifndef NT */ -#if !defined(NT) && !defined(DJGPP) && !defined(__human68k__) - rb_define_module_function(mProcess, "getpgrp", proc_getpgrp, -1); - rb_define_module_function(mProcess, "setpgrp", proc_setpgrp, -1); -#ifdef HAVE_SETPGID - rb_define_module_function(mProcess, "setpgid", proc_setpgid, 2); -#endif +#if !defined(NT) && !defined(DJGPP) && !defined(__human68k__) && !defined(USE_CWGUSI) + rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, -1); + rb_define_module_function(rb_mProcess, "setpgrp", proc_setpgrp, -1); + rb_define_module_function(rb_mProcess, "getpgid", proc_getpgid, 1); + rb_define_module_function(rb_mProcess, "setpgid", proc_setpgid, 2); -#ifdef HAVE_GETPRIORITY - rb_define_module_function(mProcess, "getpriority", proc_getpriority, 2); - rb_define_module_function(mProcess, "setpriority", proc_setpriority, 3); + rb_define_module_function(rb_mProcess, "setsid", proc_setsid, 0); + + rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2); + rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3); - rb_define_const(mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS)); - rb_define_const(mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP)); - rb_define_const(mProcess, "PRIO_USER", INT2FIX(PRIO_USER)); +#ifdef HAVE_GETPRIORITY + rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS)); + rb_define_const(rb_mProcess, "PRIO_PGRP", INT2FIX(PRIO_PGRP)); + rb_define_const(rb_mProcess, "PRIO_USER", INT2FIX(PRIO_USER)); #endif - rb_define_module_function(mProcess, "uid", proc_getuid, 0); - rb_define_module_function(mProcess, "uid=", proc_setuid, 1); - rb_define_module_function(mProcess, "gid", proc_getgid, 0); - rb_define_module_function(mProcess, "gid=", proc_setgid, 1); - rb_define_module_function(mProcess, "euid", proc_geteuid, 0); - rb_define_module_function(mProcess, "euid=", proc_seteuid, 1); - rb_define_module_function(mProcess, "egid", proc_getegid, 0); - rb_define_module_function(mProcess, "egid=", proc_setegid, 1); + rb_define_module_function(rb_mProcess, "uid", proc_getuid, 0); + rb_define_module_function(rb_mProcess, "uid=", proc_setuid, 1); + rb_define_module_function(rb_mProcess, "gid", proc_getgid, 0); + rb_define_module_function(rb_mProcess, "gid=", proc_setgid, 1); + rb_define_module_function(rb_mProcess, "euid", proc_geteuid, 0); + rb_define_module_function(rb_mProcess, "euid=", proc_seteuid, 1); + rb_define_module_function(rb_mProcess, "egid", proc_getegid, 0); + rb_define_module_function(rb_mProcess, "egid=", proc_setegid, 1); #endif } diff --git a/random.c b/random.c index d0a5756b69..7b57d472cd 100644 --- a/random.c +++ b/random.c @@ -6,17 +6,80 @@ $Date$ created at: Fri Dec 24 16:39:21 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" +#include <time.h> +#ifndef NT +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#else +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif +#endif /* NT */ + +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif + +/* + * Prefer to use drand48, otherwise use random, or rand as a last resort. + */ +#ifdef HAVE_DRAND48 + +#ifndef HAVE_DRAND48_DECL +double drand48 _((void)); +void srand48 _((long)); +#endif + +#define SRANDOM(s) srand48((long)(s)) +#define RANDOM_NUMBER drand48() + +#else /* not HAVE_DRAND48 */ + +/* + * The largest number returned by the random number generator is + * RANDOM_MAX. If we're using `rand' it's RAND_MAX, but if we're + * using `random' it's 2^31-1. + */ +#ifndef RANDOM_MAX +# ifndef HAVE_RANDOM +# define RANDOM_MAX RAND_MAX +# else +# define RANDOM_MAX 2147483647.0 +# endif +#endif + +#ifdef HAVE_RANDOM + +#define RANDOM random +#define SRANDOM srandom + +#else /* HAVE_RANDOM */ + +#define RANDOM rand +#define SRANDOM srand + +#endif /* HAVE_RANDOM */ + +/* 0 <= RANDOM_NUMBER <= 1 */ +#define RANDOM_NUMBER (((double)RANDOM())/(double)RANDOM_MAX) + +#endif /* not HAVE_DRAND48 */ + +#ifdef HAVE_RANDOM static int first = 1; static char state[256]; +#endif static VALUE -f_srand(argc, argv, obj) +rb_f_srand(argc, argv, obj) int argc; VALUE *argv; VALUE obj; @@ -26,10 +89,13 @@ f_srand(argc, argv, obj) static int saved_seed; if (rb_scan_args(argc, argv, "01", &seed) == 0) { - seed = time(0); + struct timeval tv; + + gettimeofday(&tv, 0); + seed = tv.tv_sec ^ tv.tv_usec; } else { - seed = NUM2INT(seed); + seed = NUM2UINT(seed); } #ifdef HAVE_RANDOM @@ -40,62 +106,44 @@ f_srand(argc, argv, obj) else { setstate(state); } +#endif - srandom(seed); - old = saved_seed; - saved_seed = seed; - - return int2inum(old); -#else - srand(seed); + SRANDOM(seed); old = saved_seed; saved_seed = seed; - return int2inum(old); -#endif + return rb_int2inum(old); } static VALUE -f_rand(obj, vmax) +rb_f_rand(obj, vmax) VALUE obj, vmax; { - int val, max; - -#ifdef HAVE_RANDOM - if (first == 1) { - initstate(1, state, sizeof state); - first = 0; - } -#endif + long val, max; switch (TYPE(vmax)) { case T_BIGNUM: - return big_rand(vmax); + return rb_big_rand(vmax); case T_FLOAT: if (RFLOAT(vmax)->value > LONG_MAX || RFLOAT(vmax)->value < LONG_MIN) - return big_rand(dbl2big(RFLOAT(vmax)->value)); + return rb_big_rand(rb_dbl2big(RFLOAT(vmax)->value)); break; } - max = NUM2INT(vmax); - if (max == 0) ArgError("rand(0)"); - -#ifdef HAVE_RANDOM - val = random() % max; -#else - val = rand() % max; -#endif + max = NUM2LONG(vmax); + if (max == 0) { + return rb_float_new(RANDOM_NUMBER); + } + val = max*RANDOM_NUMBER; if (val < 0) val = -val; - return int2inum(val); + return rb_int2inum(val); } void Init_Random() { - extern VALUE mKernel; - - rb_define_global_function("srand", f_srand, -1); - rb_define_global_function("rand", f_rand, 1); + rb_define_global_function("srand", rb_f_srand, -1); + rb_define_global_function("rand", rb_f_rand, 1); } diff --git a/range.c b/range.c index 9596e07f93..9fc363e2a8 100644 --- a/range.c +++ b/range.c @@ -6,81 +6,93 @@ $Date$ created at: Thu Aug 19 17:46:47 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" -static VALUE cRange; -extern VALUE cNumeric; +VALUE rb_cRange; +static ID id_upto, id_cmp; +static ID id_beg, id_end; -static ID upto; +static VALUE +range_check(args) + VALUE *args; +{ + rb_funcall(args[0], id_cmp, 1, args[1]); + return Qnil; +} + +static VALUE +range_failed() +{ + rb_raise(rb_eArgError, "bad value for range"); +} static VALUE -range_s_new(class, first, last) - VALUE class, first, last; +range_s_new(klass, beg, end) + VALUE klass, beg, end; { VALUE obj; - if (!(FIXNUM_P(first) && FIXNUM_P(last)) - && (TYPE(first) != TYPE(last) - || CLASS_OF(first) != CLASS_OF(last) - || !rb_respond_to(first, upto)) - && !(obj_is_kind_of(first, cNumeric) - && obj_is_kind_of(last, cNumeric))) { - ArgError("bad value for range"); + if (!FIXNUM_P(beg) || !FIXNUM_P(end)) { + VALUE args[2]; + + args[0] = beg; args[1] = end; + rb_rescue(range_check, (VALUE)args, range_failed, 0); } - obj = obj_alloc(class); + obj = rb_obj_alloc(klass); - rb_iv_set(obj, "first", first); - rb_iv_set(obj, "last", last); + rb_ivar_set(obj, id_beg, beg); + rb_ivar_set(obj, id_end, end); + rb_obj_call_init(obj); return obj; } VALUE -range_new(first, last) - VALUE first, last; +rb_range_new(beg, end) + VALUE beg, end; { - return range_s_new(cRange, first, last); + return range_s_new(rb_cRange, beg, end); } static VALUE range_eqq(rng, obj) VALUE rng, obj; { - VALUE first, last; + VALUE beg, end; - first = rb_iv_get(rng, "first"); - last = rb_iv_get(rng, "last"); + beg = rb_ivar_get(rng, id_beg); + end = rb_ivar_get(rng, id_end); - if (FIXNUM_P(first) && FIXNUM_P(obj) && FIXNUM_P(last)) { - if (FIX2INT(first) <= FIX2INT(obj) && FIX2INT(obj) <= FIX2INT(last)) { - return TRUE; + if (FIXNUM_P(beg) && FIXNUM_P(obj) && FIXNUM_P(end)) { + if (FIX2INT(beg) <= FIX2INT(obj) && FIX2INT(obj) <= FIX2INT(end)) { + return Qtrue; } - return FALSE; + return Qfalse; } else { - if (RTEST(rb_funcall(first, rb_intern("<="), 1, obj)) && - RTEST(rb_funcall(last, rb_intern(">="), 1, obj))) { - return TRUE; + if (RTEST(rb_funcall(beg, rb_intern("<="), 1, obj)) && + RTEST(rb_funcall(end, rb_intern(">="), 1, obj))) { + return Qtrue; } - return FALSE; + return Qfalse; } } struct upto_data { - VALUE first; - VALUE last; + VALUE beg; + VALUE end; }; static VALUE range_upto(data) struct upto_data *data; { - return rb_funcall(data->first, upto, 1, data->last); + return rb_funcall(data->beg, id_upto, 1, data->end); } static VALUE @@ -89,19 +101,19 @@ range_each(obj) { VALUE b, e; - b = rb_iv_get(obj, "first"); - e = rb_iv_get(obj, "last"); + b = rb_ivar_get(obj, id_beg); + e = rb_ivar_get(obj, id_end); if (FIXNUM_P(b)) { /* fixnum is a special case(for performance) */ - num_upto(b, e); + rb_fix_upto(b, e); } else { struct upto_data data; - data.first = b; - data.last = e; + data.beg = b; + data.end = e; - rb_iterate(range_upto, &data, rb_yield, 0); + rb_iterate(range_upto, (VALUE)&data, rb_yield, 0); } return Qnil; @@ -113,7 +125,7 @@ range_first(obj) { VALUE b; - b = rb_iv_get(obj, "first"); + b = rb_ivar_get(obj, id_beg); return b; } @@ -123,22 +135,22 @@ range_last(obj) { VALUE e; - e = rb_iv_get(obj, "last"); + e = rb_ivar_get(obj, id_end); return e; } VALUE -range_beg_end(range, begp, endp) +rb_range_beg_end(range, begp, endp) VALUE range; int *begp, *endp; { - VALUE first, last; + VALUE beg, end; - if (!obj_is_kind_of(range, cRange)) return FALSE; + if (!rb_obj_is_kind_of(range, rb_cRange)) return Qfalse; - first = rb_iv_get(range, "first"); *begp = NUM2INT(first); - last = rb_iv_get(range, "last"); *endp = NUM2INT(last); - return TRUE; + beg = rb_ivar_get(range, id_beg); *begp = NUM2INT(beg); + end = rb_ivar_get(range, id_end); *endp = NUM2INT(end); + return Qtrue; } static VALUE @@ -147,10 +159,10 @@ range_to_s(range) { VALUE str, str2; - str = obj_as_string(rb_iv_get(range, "first")); - str2 = obj_as_string(rb_iv_get(range, "last")); - str_cat(str, "..", 2); - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + str = rb_obj_as_string(rb_ivar_get(range, id_beg)); + str2 = rb_obj_as_string(rb_ivar_get(range, id_end)); + rb_str_cat(str, "..", 2); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); return str; } @@ -161,52 +173,56 @@ range_inspect(range) { VALUE str, str2; - str = rb_inspect(rb_iv_get(range, "first")); - str2 = rb_inspect(rb_iv_get(range, "last")); - str_cat(str, "..", 2); - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + str = rb_inspect(rb_ivar_get(range, id_beg)); + str2 = rb_inspect(rb_ivar_get(range, id_end)); + rb_str_cat(str, "..", 2); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); return str; } -VALUE enum_length(); - static VALUE range_length(rng) VALUE rng; { - VALUE first, last; + VALUE beg, end; VALUE size; - first = rb_iv_get(rng, "first"); - last = rb_iv_get(rng, "last"); + beg = rb_ivar_get(rng, id_beg); + end = rb_ivar_get(rng, id_end); - if (!obj_is_kind_of(first, cNumeric)) { - return enum_length(rng); + if (RTEST(rb_funcall(beg, '>', 1, end))) { + return INT2FIX(0); + } + if (!rb_obj_is_kind_of(beg, rb_cNumeric)) { + return rb_enum_length(rng); } - size = rb_funcall(last, '-', 1, first); + size = rb_funcall(end, '-', 1, beg); size = rb_funcall(size, '+', 1, INT2FIX(1)); return size; } -extern VALUE mEnumerable; - void Init_Range() { - cRange = rb_define_class("Range", cObject); - rb_include_module(cRange, mEnumerable); - rb_define_singleton_method(cRange, "new", range_s_new, 2); - rb_define_method(cRange, "===", range_eqq, 1); - rb_define_method(cRange, "each", range_each, 0); - rb_define_method(cRange, "first", range_first, 0); - rb_define_method(cRange, "last", range_last, 0); - rb_define_method(cRange, "to_s", range_to_s, 0); - rb_define_method(cRange, "inspect", range_inspect, 0); - - rb_define_method(cRange, "length", range_length, 0); - rb_define_method(cRange, "size", range_length, 0); - - upto = rb_intern("upto"); + rb_cRange = rb_define_class("Range", rb_cObject); + rb_include_module(rb_cRange, rb_mEnumerable); + rb_define_singleton_method(rb_cRange, "new", range_s_new, 2); + rb_define_method(rb_cRange, "===", range_eqq, 1); + rb_define_method(rb_cRange, "each", range_each, 0); + rb_define_method(rb_cRange, "first", range_first, 0); + rb_define_method(rb_cRange, "last", range_last, 0); + rb_define_method(rb_cRange, "begin", range_first, 0); + rb_define_method(rb_cRange, "end", range_last, 0); + rb_define_method(rb_cRange, "to_s", range_to_s, 0); + rb_define_method(rb_cRange, "inspect", range_inspect, 0); + + rb_define_method(rb_cRange, "length", range_length, 0); + rb_define_method(rb_cRange, "size", range_length, 0); + + id_upto = rb_intern("upto"); + id_cmp = rb_intern("<=>"); + id_beg = rb_intern("begin"); + id_end = rb_intern("end"); } diff --git a/re.c b/re.c index cb0ade9aaf..287c6c1bd4 100644 --- a/re.c +++ b/re.c @@ -3,17 +3,16 @@ re.c - $Author$ - $Date$ created at: Mon Aug 9 18:24:49 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "re.h" -static VALUE eRegxpError; +static VALUE rb_eRegxpError; #define BEG(no) regs->beg[no] #define END(no) regs->end[no] @@ -69,16 +68,16 @@ static char casetable[] = { >>> "You lose. You will need a translation table for your character set." <<< #endif -#define min(a,b) (((a)>(b))?(b):(a)) +#define MIN(a,b) (((a)>(b))?(b):(a)) int -str_cicmp(str1, str2) +rb_str_cicmp(str1, str2) VALUE str1, str2; { int len, i; char *p1, *p2; - len = min(RSTRING(str1)->len, RSTRING(str2)->len); + len = MIN(RSTRING(str1)->len, RSTRING(str2)->len); p1 = RSTRING(str1)->ptr; p2 = RSTRING(str2)->ptr; for (i = 0; i < len; i++, p1++, p2++) { @@ -89,27 +88,33 @@ str_cicmp(str1, str2) } #define REG_IGNORECASE FL_USER0 +#define REG_CASESTATE FL_USER1 #define KCODE_NONE 0 #define KCODE_EUC FL_USER2 #define KCODE_SJIS FL_USER3 -#define KCODE_FIXED FL_USER4 -#define KCODE_MASK (KCODE_EUC|KCODE_SJIS) +#define KCODE_UTF8 FL_USER4 +#define KCODE_FIXED FL_USER5 +#define KCODE_MASK (KCODE_EUC|KCODE_SJIS|KCODE_UTF8) static int reg_kcode = -#ifdef EUC +#ifdef RUBY_USE_EUC KCODE_EUC; #else -# ifdef SJIS +# ifdef RUBY_USE_SJIS KCODE_SJIS; # else +# ifdef RUBY_USE_UTF8 + KCODE_UTF8 +# else KCODE_NONE; +# endif # endif #endif static void kcode_euc(reg) - VALUE reg; + struct RRegexp *reg; { FL_UNSET(reg, KCODE_MASK); FL_SET(reg, KCODE_EUC); @@ -118,62 +123,80 @@ kcode_euc(reg) static void kcode_sjis(reg) - VALUE reg; + struct RRegexp *reg; { FL_UNSET(reg, KCODE_MASK); FL_SET(reg, KCODE_SJIS); FL_SET(reg, KCODE_FIXED); } +static void +kcode_utf8(reg) + struct RRegexp *reg; +{ + FL_UNSET(reg, KCODE_MASK); + FL_SET(reg, KCODE_UTF8); + FL_SET(reg, KCODE_FIXED); +} + static void kcode_none(reg) - VALUE reg; + struct RRegexp *reg; { FL_UNSET(reg, KCODE_MASK); FL_SET(reg, KCODE_FIXED); } +static int curr_kcode; + static void kcode_set_option(reg) VALUE reg; { if (!FL_TEST(reg, KCODE_FIXED)) return; - re_syntax_options &= ~RE_MBCTYPE_MASK; - switch ((RBASIC(reg)->flags & KCODE_MASK)) { + curr_kcode = RBASIC(reg)->flags & KCODE_MASK; + if (reg_kcode == curr_kcode) return; + switch (curr_kcode) { case KCODE_NONE: + re_mbcinit(MBCTYPE_ASCII); break; case KCODE_EUC: - re_syntax_options |= RE_MBCTYPE_EUC; + re_mbcinit(MBCTYPE_EUC); break; case KCODE_SJIS: - re_syntax_options |= RE_MBCTYPE_SJIS; + re_mbcinit(MBCTYPE_SJIS); + break; + case KCODE_UTF8: + re_mbcinit(MBCTYPE_UTF8); break; } - re_set_syntax(re_syntax_options); } -void +static void kcode_reset_option() { - re_syntax_options &= ~RE_MBCTYPE_MASK; + if (reg_kcode == curr_kcode) return; switch (reg_kcode) { case KCODE_NONE: + re_mbcinit(MBCTYPE_ASCII); break; case KCODE_EUC: - re_syntax_options |= RE_MBCTYPE_EUC; + re_mbcinit(MBCTYPE_EUC); break; case KCODE_SJIS: - re_syntax_options |= RE_MBCTYPE_SJIS; + re_mbcinit(MBCTYPE_SJIS); + break; + case KCODE_UTF8: + re_mbcinit(MBCTYPE_UTF8); break; } - re_set_syntax(re_syntax_options); } -extern int rb_in_eval; +extern int ruby_in_compile; static void -reg_expr_str(str, s, len) +rb_reg_expr_str(str, s, len) VALUE str; char *s; int len; @@ -190,18 +213,18 @@ reg_expr_str(str, s, len) p++; } if (!slash) { - str_cat(str, s, len); + rb_str_cat(str, s, len); } else { p = s; while (p<pend) { if (*p == '/') { char c = '\\'; - str_cat(str, &c, 1); - str_cat(str, p, 1); + rb_str_cat(str, &c, 1); + rb_str_cat(str, p, 1); } else { - str_cat(str, p, 1); + rb_str_cat(str, p, 1); } p++; } @@ -209,27 +232,30 @@ reg_expr_str(str, s, len) } static VALUE -reg_desc(s, len, re) +rb_reg_desc(s, len, re) char *s; int len; VALUE re; { - VALUE str = str_new2("/"); - reg_expr_str(str, s, len); - str_cat(str, "/", 1); + VALUE str = rb_str_new2("/"); + rb_reg_expr_str(str, s, len); + rb_str_cat(str, "/", 1); if (re) { - if (FL_TEST(re,REG_IGNORECASE)) - str_cat(str, "i", 1); - if (FL_TEST(re,KCODE_FIXED)) { + if (FL_TEST(re, REG_IGNORECASE)) + rb_str_cat(str, "i", 1); + if (FL_TEST(re, KCODE_FIXED)) { switch ((RBASIC(re)->flags & KCODE_MASK)) { case KCODE_NONE: - str_cat(str, "n", 1); + rb_str_cat(str, "n", 1); break; case KCODE_EUC: - str_cat(str, "e", 1); + rb_str_cat(str, "e", 1); break; case KCODE_SJIS: - str_cat(str, "s", 1); + rb_str_cat(str, "s", 1); + break; + case KCODE_UTF8: + rb_str_cat(str, "u", 1); break; } } @@ -238,47 +264,47 @@ reg_desc(s, len, re) } static VALUE -reg_source(re) +rb_reg_source(re) VALUE re; { - VALUE str = str_new(0,0); - reg_expr_str(str, RREGEXP(re)->str,RREGEXP(re)->len,re); + VALUE str = rb_str_new(0,0); + rb_reg_expr_str(str, RREGEXP(re)->str,RREGEXP(re)->len); return str; } static VALUE -reg_inspect(re) +rb_reg_inspect(re) VALUE re; { - return reg_desc(RREGEXP(re)->str, RREGEXP(re)->len, re); + return rb_reg_desc(RREGEXP(re)->str, RREGEXP(re)->len, re); } static void -reg_raise(s, len, err, re) +rb_reg_raise(s, len, err, re) char *s; int len; char *err; VALUE re; { - VALUE desc = reg_desc(s, len, re); + VALUE desc = rb_reg_desc(s, len, re); - if (rb_in_eval) - Raise(eRegxpError, "%s: %s", err, RSTRING(desc)->ptr); + if (ruby_in_compile) + rb_compile_error("%s: %s", err, RSTRING(desc)->ptr); else - Error("%s: %s", err, RSTRING(desc)->ptr); + rb_raise(rb_eRegxpError, "%s: %s", err, RSTRING(desc)->ptr); } static VALUE -reg_casefold_p(re) +rb_reg_casefold_p(re) VALUE re; { - if (FL_TEST(re, REG_IGNORECASE)) return TRUE; - return FALSE; + if (FL_TEST(re, REG_IGNORECASE)) return Qtrue; + return Qfalse; } static VALUE -reg_kcode_method(re) +rb_reg_kcode_method(re) VALUE re; { char *kcode = "$KCODE"; @@ -291,18 +317,20 @@ reg_kcode_method(re) kcode = "euc"; break; case KCODE_SJIS: kcode = "sjis"; break; + case KCODE_UTF8: + kcode = "utf8"; break; default: break; } } - return str_new2(kcode); + return rb_str_new2(kcode); } static Regexp* make_regexp(s, len, flag) char *s; - int len, flag; + size_t len, flag; { Regexp *rp; char *err; @@ -320,27 +348,26 @@ make_regexp(s, len, flag) rp->allocated = 16; rp->fastmap = ALLOC_N(char, 256); if (flag) { - rp->translate = casetable; + rp->options = flag; } - err = re_compile_pattern(s, (size_t)len, rp); - kcode_reset_option(); + err = re_compile_pattern(s, len, rp); if (err != NULL) { - reg_raise(s, len, err, 0); + rb_reg_raise(s, len, err, 0); } return rp; } -extern VALUE cData; -static VALUE cMatch; +static VALUE rb_cMatch; static VALUE match_alloc() { NEWOBJ(match, struct RMatch); - OBJSETUP(match, cMatch, T_MATCH); + OBJSETUP(match, rb_cMatch, T_MATCH); match->str = 0; + match->regs = 0; match->regs = ALLOC(struct re_registers); MEMZERO(match->regs, struct re_registers, 1); @@ -351,88 +378,91 @@ static VALUE match_clone(orig) VALUE orig; { - struct re_registers *rr; - NEWOBJ(match, struct RMatch); - OBJSETUP(match, cMatch, T_MATCH); + OBJSETUP(match, rb_cMatch, T_MATCH); match->str = RMATCH(orig)->str; + match->regs = 0; match->regs = ALLOC(struct re_registers); match->regs->allocated = 0; re_copy_registers(match->regs, RMATCH(orig)->regs); + CLONESETUP(match, orig); return (VALUE)match; } -VALUE ignorecase; +int ruby_ignorecase; +static int may_need_recompile; static VALUE matchcache; -void -reg_prepare_re(reg) +static void +rb_reg_prepare_re(reg) VALUE reg; { - int result; - int casefold = RTEST(ignorecase); int need_recompile = 0; - /* case-flag set for the object */ - if (FL_TEST(reg, REG_IGNORECASE)) { - casefold = TRUE; - } - if (casefold) { - if (RREGEXP(reg)->ptr->translate != casetable) { - RREGEXP(reg)->ptr->translate = casetable; - RREGEXP(reg)->ptr->fastmap_accurate = 0; + /* case-flag not set for the object */ + if (!FL_TEST(reg, REG_IGNORECASE)) { + int state = FL_TEST(reg, REG_CASESTATE); + + if ((ruby_ignorecase || state) && !(ruby_ignorecase && state)) { + RBASIC(reg)->flags ^= REG_CASESTATE; need_recompile = 1; } } - else if (RREGEXP(reg)->ptr->translate) { - RREGEXP(reg)->ptr->translate = NULL; - RREGEXP(reg)->ptr->fastmap_accurate = 0; - need_recompile = 1; - } - if (FL_TEST(reg, KCODE_FIXED)) { - kcode_set_option(reg); - } - else if ((RBASIC(reg)->flags & KCODE_MASK) != reg_kcode) { + if (!FL_TEST(reg, KCODE_FIXED) && + (RBASIC(reg)->flags & KCODE_MASK) != reg_kcode) { need_recompile = 1; - RBASIC(reg)->flags = RBASIC(reg)->flags & ~KCODE_MASK; + RBASIC(reg)->flags &= ~KCODE_MASK; RBASIC(reg)->flags |= reg_kcode; } if (need_recompile) { char *err; + if (FL_TEST(reg, KCODE_FIXED)) + kcode_set_option(reg); + RREGEXP(reg)->ptr->fastmap_accurate = 0; err = re_compile_pattern(RREGEXP(reg)->str, RREGEXP(reg)->len, RREGEXP(reg)->ptr); if (err != NULL) { - kcode_reset_option(); - reg_raise(RREGEXP(reg)->str, RREGEXP(reg)->len, err, reg); + rb_reg_raise(RREGEXP(reg)->str, RREGEXP(reg)->len, err, reg); } } } int -reg_search(reg, str, start, regs) +rb_reg_search(reg, str, start, reverse) VALUE reg, str; - int start; - struct re_registers *regs; + int start, reverse; { int result; - int casefold = RTEST(ignorecase); - VALUE match = 0; - struct re_registers *regs0 = 0; - int need_recompile = 0; + VALUE match; + struct re_registers *regs = 0; + int range; if (start > RSTRING(str)->len) return -1; - reg_prepare_re(reg); + if (may_need_recompile) + rb_reg_prepare_re(reg); + + if (FL_TEST(reg, KCODE_FIXED)) + kcode_set_option(reg); + else if (reg_kcode != curr_kcode) + kcode_reset_option(); - if (regs == (struct re_registers*)-1) { - regs = 0; +#ifdef USE_THREAD + if (rb_thread_scope_shared_p()) { + match = Qnil; } else { + match = rb_backref_get(); + } +#else + match = rb_backref_get(); +#endif + if (NIL_P(match)) { if (matchcache) { match = matchcache; matchcache = 0; @@ -440,45 +470,49 @@ reg_search(reg, str, start, regs) else { match = match_alloc(); } - regs0 = RMATCH(match)->regs; } + regs = RMATCH(match)->regs; + if (reverse) { + range = -start; + } + else { + range = RSTRING(str)->len - start; + } result = re_search(RREGEXP(reg)->ptr,RSTRING(str)->ptr,RSTRING(str)->len, - start,RSTRING(str)->len-start,regs0); - kcode_reset_option(); + start, range, regs); - if (start == -2) { - reg_raise(RREGEXP(reg)->str, RREGEXP(reg)->len, + if (result == -2) { + rb_reg_raise(RREGEXP(reg)->str, RREGEXP(reg)->len, "Stack overfow in regexp matcher", reg); } if (result < 0) { matchcache = match; - backref_set(Qnil); + rb_backref_set(Qnil); } - else if (match) { - RMATCH(match)->str = str_new4(str); - backref_set(match); + else { + RMATCH(match)->str = rb_str_new4(str); + rb_backref_set(match); } - if (regs && regs0) re_copy_registers(regs, regs0); return result; } VALUE -reg_nth_defined(nth, match) +rb_reg_nth_defined(nth, match) int nth; VALUE match; { if (NIL_P(match)) return Qnil; if (nth >= RMATCH(match)->regs->num_regs) { - return FALSE; + return Qfalse; } - if (RMATCH(match)->BEG(nth) == -1) return FALSE; - return TRUE; + if (RMATCH(match)->BEG(nth) == -1) return Qfalse; + return Qtrue; } VALUE -reg_nth_match(nth, match) +rb_reg_nth_match(nth, match) int nth; VALUE match; { @@ -492,37 +526,37 @@ reg_nth_match(nth, match) if (start == -1) return Qnil; end = RMATCH(match)->END(nth); len = end - start; - return str_new(RSTRING(RMATCH(match)->str)->ptr + start, len); + return rb_str_new(RSTRING(RMATCH(match)->str)->ptr + start, len); } VALUE -reg_last_match(match) +rb_reg_last_match(match) VALUE match; { - return reg_nth_match(0, match); + return rb_reg_nth_match(0, match); } VALUE -reg_match_pre(match) +rb_reg_match_pre(match) VALUE match; { if (NIL_P(match)) return Qnil; if (RMATCH(match)->BEG(0) == -1) return Qnil; - return str_new(RSTRING(RMATCH(match)->str)->ptr, RMATCH(match)->BEG(0)); + return rb_str_new(RSTRING(RMATCH(match)->str)->ptr, RMATCH(match)->BEG(0)); } VALUE -reg_match_post(match) +rb_reg_match_post(match) VALUE match; { if (NIL_P(match)) return Qnil; if (RMATCH(match)->BEG(0) == -1) return Qnil; - return str_new(RSTRING(RMATCH(match)->str)->ptr+RMATCH(match)->END(0), + return rb_str_new(RSTRING(RMATCH(match)->str)->ptr+RMATCH(match)->END(0), RSTRING(RMATCH(match)->str)->len-RMATCH(match)->END(0)); } VALUE -reg_match_last(match) +rb_reg_match_last(match) VALUE match; { int i; @@ -533,31 +567,31 @@ reg_match_last(match) for (i=RMATCH(match)->regs->num_regs-1; RMATCH(match)->BEG(i) == -1 && i > 0; i--) ; if (i == 0) return Qnil; - return reg_nth_match(i, match); + return rb_reg_nth_match(i, match); } static VALUE last_match_getter() { - return reg_last_match(backref_get()); + return rb_reg_last_match(rb_backref_get()); } static VALUE prematch_getter() { - return reg_match_pre(backref_get()); + return rb_reg_match_pre(rb_backref_get()); } static VALUE postmatch_getter() { - return reg_match_post(backref_get()); + return rb_reg_match_post(rb_backref_get()); } static VALUE last_paren_match_getter() { - return reg_match_last(backref_get()); + return rb_reg_match_last(rb_backref_get()); } static VALUE @@ -565,13 +599,13 @@ match_to_a(match) VALUE match; { struct re_registers *regs = RMATCH(match)->regs; - VALUE ary = ary_new2(regs->num_regs); + VALUE ary = rb_ary_new2(regs->num_regs); char *ptr = RSTRING(RMATCH(match)->str)->ptr; int i; for (i=0; i<regs->num_regs; i++) { - if (regs->beg[0] == -1) ary_push(ary, Qnil); - else ary_push(ary, str_new(ptr+regs->beg[i], + if (regs->beg[i] == -1) rb_ary_push(ary, Qnil); + else rb_ary_push(ary, rb_str_new(ptr+regs->beg[i], regs->end[i]-regs->beg[i])); } return ary; @@ -591,7 +625,7 @@ match_aref(argc, argv, match) rb_scan_args(argc, argv, "11", &idx, &rest); if (!NIL_P(rest) || !FIXNUM_P(idx) || FIX2INT(idx) < 0) { - return ary_aref(argc, argv, match_to_a(match)); + return rb_ary_aref(argc, argv, match_to_a(match)); } regs = RMATCH(match)->regs; @@ -600,100 +634,111 @@ match_aref(argc, argv, match) if (i>=regs->num_regs) return Qnil; ptr = RSTRING(RMATCH(match)->str)->ptr; - return str_new(ptr+regs->beg[i], regs->end[i]-regs->beg[i]); + return rb_str_new(ptr+regs->beg[i], regs->end[i]-regs->beg[i]); } static VALUE match_to_s(match) VALUE match; { - VALUE str = reg_last_match(match); + VALUE str = rb_reg_last_match(match); - if (NIL_P(str)) return str_new(0,0); + if (NIL_P(str)) return rb_str_new(0,0); return str; } -void -reg_free(rp) -Regexp *rp; -{ - free(rp->buffer); - free(rp->fastmap); - free(rp); -} - -VALUE cRegexp; +VALUE rb_cRegexp; static VALUE -reg_new_1(class, s, len, flag) - VALUE class; +rb_reg_new_1(klass, s, len, options) + VALUE klass; char *s; - int len; - int flag; /* CASEFOLD = 0x1 */ - /* CODE_NONE = 0x2 */ - /* CODE_EUC = 0x4 */ - /* CODE_SJIS = 0x6 */ + size_t len; + int options; /* CASEFOLD = 1 */ + /* EXTENDED = 2 */ + /* CODE_NONE = 4 */ + /* CODE_EUC = 8 */ + /* CODE_SJIS = 12 */ + /* CODE_UTF8 = 16 */ { NEWOBJ(re, struct RRegexp); - OBJSETUP(re, class, T_REGEXP); + OBJSETUP(re, klass, T_REGEXP); + re->ptr = 0; + re->str = 0; - if (flag & 0x1) { + if (options & RE_OPTION_IGNORECASE) { FL_SET(re, REG_IGNORECASE); } - switch (flag & ~0x1) { + switch (options & ~0x3) { case 0: default: FL_SET(re, reg_kcode); break; - case 2: + case 4: kcode_none(re); break; - case 4: + case 8: kcode_euc(re); break; - case 6: + case 12: kcode_sjis(re); break; + case 16: + kcode_utf8(re); + break; } - kcode_set_option(re); - re->ptr = make_regexp(s, len, flag & 0x1); + if (options & ~0x3) { + kcode_set_option((VALUE)re); + } + if (ruby_ignorecase) { + options |= RE_OPTION_IGNORECASE; + FL_SET(re, REG_CASESTATE); + } + re->ptr = make_regexp(s, len, options & 0x3); re->str = ALLOC_N(char, len+1); memcpy(re->str, s, len); re->str[len] = '\0'; re->len = len; + if (options & ~0x3) { + kcode_reset_option(); + } + rb_obj_call_init((VALUE)re); return (VALUE)re; } VALUE -reg_new(s, len, flag) +rb_reg_new(s, len, options) char *s; - int len, flag; + size_t len; + int options; { - return reg_new_1(cRegexp, s, len, flag); + return rb_reg_new_1(rb_cRegexp, s, len, options); } -static int ign_cache; +static int case_cache; +static int kcode_cache; static VALUE reg_cache; VALUE -reg_regcomp(str) +rb_reg_regcomp(str) VALUE str; { - int ignc = RTEST(ignorecase); - if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len - && ign_cache == ignc + && case_cache == ruby_ignorecase + && kcode_cache == reg_kcode && memcmp(RREGEXP(reg_cache)->str, RSTRING(str)->ptr, RSTRING(str)->len) == 0) return reg_cache; - ign_cache = ignc; - return reg_cache = reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ignc); + case_cache = ruby_ignorecase; + kcode_cache = reg_kcode; + return reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, + ruby_ignorecase); } static int -reg_cur_kcode(re) +rb_reg_cur_kcode(re) VALUE re; { if (FL_TEST(re, KCODE_FIXED)) { @@ -703,57 +748,58 @@ reg_cur_kcode(re) } static VALUE -reg_equal(re1, re2) +rb_reg_equal(re1, re2) VALUE re1, re2; { int min; - if (re1 == re2) return TRUE; - if (TYPE(re2) != T_REGEXP) return FALSE; - if (RREGEXP(re1)->len != RREGEXP(re2)->len) return FALSE; + if (re1 == re2) return Qtrue; + if (TYPE(re2) != T_REGEXP) return Qfalse; + if (RREGEXP(re1)->len != RREGEXP(re2)->len) return Qfalse; min = RREGEXP(re1)->len; if (min > RREGEXP(re2)->len) min = RREGEXP(re2)->len; if (memcmp(RREGEXP(re1)->str, RREGEXP(re2)->str, min) == 0 && - reg_cur_kcode(re1) == reg_cur_kcode(re2) && + rb_reg_cur_kcode(re1) == rb_reg_cur_kcode(re2) && !(FL_TEST(re1,REG_IGNORECASE) ^ FL_TEST(re2,REG_IGNORECASE))) { - return TRUE; + return Qtrue; } - return FALSE; + return Qfalse; } VALUE -reg_match(re, str) +rb_reg_match(re, str) VALUE re, str; { int start; - if (TYPE(str) != T_STRING) return FALSE; - start = reg_search(re, str, 0, 0); + if (NIL_P(str)) return Qnil; + str = rb_str_to_str(str); + start = rb_reg_search(re, str, 0, 0); if (start < 0) { - return FALSE; + return Qnil; } return INT2FIX(start); } VALUE -reg_match2(re) +rb_reg_match2(re) VALUE re; { int start; - VALUE line = lastline_get(); + VALUE line = rb_lastline_get(); if (TYPE(line) != T_STRING) - return FALSE; + return Qnil; - start = reg_search(re, line, 0, 0); + start = rb_reg_search(re, line, 0, 0); if (start < 0) { - return FALSE; + return Qnil; } return INT2FIX(start); } static VALUE -reg_s_new(argc, argv, self) +rb_reg_s_new(argc, argv, self) int argc; VALUE *argv; VALUE self; @@ -762,22 +808,23 @@ reg_s_new(argc, argv, self) int flag = 0; if (argc == 0 || argc > 3) { - ArgError("wrong # of argument"); + rb_raise(rb_eArgError, "wrong # of argument"); } if (argc >= 2 && RTEST(argv[1])) { - flag = 1; + flag = RE_OPTION_IGNORECASE; } if (argc == 3) { - Check_Type(argv[2], T_STRING); - switch (RSTRING(argv[2])->ptr[0]) { + char *kcode = STR2CSTR(argv[2]); + + switch (kcode[0]) { case 'n': case 'N': - flag |= 2; + flag |= 4; break; case 'e': case 'E': - flag |= 4; + flag |= 8; break; case 's': case 'S': - flag |= 6; + flag |= 12; break; default: break; @@ -785,37 +832,37 @@ reg_s_new(argc, argv, self) } src = argv[0]; - switch (TYPE(src)) { - case T_STRING: - return reg_new_1(self, RSTRING(src)->ptr, RSTRING(src)->len, flag); - break; - - case T_REGEXP: - return reg_new_1(self, RREGEXP(src)->str, RREGEXP(src)->len, flag); - break; - - default: - Check_Type(src, T_STRING); + if (TYPE(src) == T_REGEXP) { + return rb_reg_new_1(self, RREGEXP(src)->str, RREGEXP(src)->len, flag); } + else { + char *p; + size_t len; - return Qnil; + p = str2cstr(src, &len); + return rb_reg_new_1(self, p, len, flag); + } } static VALUE -reg_s_quote(re, str) +rb_reg_s_quote(re, str) VALUE re, str; { char *s, *send, *t; char *tmp; + int len; - Check_Type(str, T_STRING); - - tmp = ALLOCA_N(char, RSTRING(str)->len*2); - - s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; + s = str2cstr(str, &len); + send = s + len; + tmp = ALLOCA_N(char, len*2); t = tmp; for (; s != send; s++) { + if (ismbchar(*s)) { + *t++ = *s++; + *t++ = *s; + continue; + } if (*s == '[' || *s == ']' || *s == '{' || *s == '}' || *s == '(' || *s == ')' @@ -828,22 +875,36 @@ reg_s_quote(re, str) *t++ = *s; } - return str_new(tmp, t - tmp); + return rb_str_new(tmp, t - tmp); +} + +int +rb_kcode() +{ + switch (reg_kcode) { + case KCODE_EUC: + return MBCTYPE_EUC; + case KCODE_SJIS: + return MBCTYPE_SJIS; + case KCODE_NONE: + return MBCTYPE_ASCII; + } + rb_bug("wrong reg_kcode value (0x%x)", reg_kcode); } static int -reg_get_kcode(re) +rb_reg_get_kcode(re) VALUE re; { int kcode = 0; switch (RBASIC(re)->flags & KCODE_MASK) { case KCODE_NONE: - kcode |= 2; break; - case KCODE_EUC: kcode |= 4; break; + case KCODE_EUC: + kcode |= 8; break; case KCODE_SJIS: - kcode |= 6; break; + kcode |= 12; break; default: break; } @@ -851,25 +912,38 @@ reg_get_kcode(re) return kcode; } -static VALUE -reg_clone(re) +int +rb_reg_options(re) VALUE re; { - int flag = FL_TEST(re, REG_IGNORECASE)?1:0; + int options = 0; + if (FL_TEST(re, REG_IGNORECASE)) + options |= RE_OPTION_IGNORECASE; if (FL_TEST(re, KCODE_FIXED)) { - flag |= reg_get_kcode(re); + options |= rb_reg_get_kcode(re); } - return reg_new_1(CLASS_OF(re), RREGEXP(re)->str, RREGEXP(re)->len, flag); + return options; +} + +static VALUE +rb_reg_clone(orig) + VALUE orig; +{ + VALUE reg; + + reg = rb_reg_new_1(CLASS_OF(orig), RREGEXP(orig)->str, RREGEXP(orig)->len, + rb_reg_options(orig)); + CLONESETUP(reg, orig); + return reg; } VALUE -reg_regsub(str, src, regs) +rb_reg_regsub(str, src, regs) VALUE str, src; struct re_registers *regs; { VALUE val = 0; - VALUE tmp; char *p, *s, *e, c; int no; @@ -880,10 +954,14 @@ reg_regsub(str, src, regs) char *ss = s; c = *s++; - if (c != '\\') continue; + if (ismbchar(c)) { + s++; + continue; + } + if (c != '\\' || s == e) continue; - if (!val) val = str_new(p, ss-p); - else str_cat(val, p, ss-p); + if (!val) val = rb_str_new(p, ss-p); + else rb_str_cat(val, p, ss-p); c = *s++; p = s; @@ -897,11 +975,11 @@ reg_regsub(str, src, regs) break; case '`': - str_cat(val, RSTRING(src)->ptr, BEG(0)); + rb_str_cat(val, RSTRING(src)->ptr, BEG(0)); continue; case '\'': - str_cat(val, RSTRING(src)->ptr+END(0), RSTRING(src)->len-END(0)); + rb_str_cat(val, RSTRING(src)->ptr+END(0), RSTRING(src)->len-END(0)); continue; case '+': @@ -911,117 +989,110 @@ reg_regsub(str, src, regs) break; case '\\': - str_cat(val, s-1, 1); + rb_str_cat(val, s-1, 1); continue; default: - str_cat(val, s-2, 2); + rb_str_cat(val, s-2, 2); continue; } if (no >= 0) { if (BEG(no) == -1) continue; - str_cat(val, RSTRING(src)->ptr+BEG(no), END(no)-BEG(no)); + rb_str_cat(val, RSTRING(src)->ptr+BEG(no), END(no)-BEG(no)); } } if (p < e) { - if (!val) val = str_new(p, e-p); - else str_cat(val, p, e-p); + if (!val) val = rb_str_new(p, e-p); + else rb_str_cat(val, p, e-p); } - if (!val) return (VALUE)str; + if (!val) return str; return val; } -#define IS_KCODE_FIXED(re) (FL_TEST((re), KCODE_FIXED)?1:0) - -static int -reg_prepare_operation(re1, re2) - VALUE re1, re2; +char* +rb_get_kcode() { - int flag = 0; - - Check_Type(re2, T_REGEXP); - flag = IS_KCODE_FIXED(re1)+IS_KCODE_FIXED(re2)*2; - switch (IS_KCODE_FIXED(re1)+IS_KCODE_FIXED(re2)*2) { - case 3: /* both have fixed kcode (must match) */ - if (((RBASIC(re1)->flags^RBASIC(re2)->flags)&KCODE_MASK) != 0) { - Raise(eRegxpError, "kanji code mismatch"); - } - /* fall through */ - case 2: /* re2 has fixed kcode */ - flag = reg_get_kcode(re2); - break; - case 1: /* re1 has fixed kcode */ - flag = reg_get_kcode(re1); - break; - case 0: /* neither has fixed kcode */ - flag = 0; - break; - } - - if (FL_TEST(re1, REG_IGNORECASE) ^ FL_TEST(re2, REG_IGNORECASE)) { - Raise(eRegxpError, "casefold mismatch"); + switch (reg_kcode) { + case KCODE_SJIS: + return "SJIS"; + case KCODE_EUC: + return "EUC"; + case KCODE_UTF8: + return "UTF8"; + default: + return "NONE"; } - if (FL_TEST(re1, REG_IGNORECASE)) flag |= 0x1; - - return flag; } static VALUE kcode_getter() { - switch (reg_kcode) { - case KCODE_SJIS: - return str_new2("SJIS"); - case KCODE_EUC: - return str_new2("EUC"); - default: - return str_new2("NONE"); - } + return rb_str_new2(rb_get_kcode()); } void rb_set_kcode(code) char *code; { - re_syntax_options &= ~RE_MBCTYPE_MASK; if (code == 0) goto set_no_conversion; switch (code[0]) { case 'E': case 'e': reg_kcode = KCODE_EUC; - re_syntax_options |= RE_MBCTYPE_EUC; + re_mbcinit(MBCTYPE_EUC); break; case 'S': case 's': reg_kcode = KCODE_SJIS; - re_syntax_options |= RE_MBCTYPE_SJIS; + re_mbcinit(MBCTYPE_SJIS); + break; + case 'U': + case 'u': + reg_kcode = KCODE_UTF8; + re_mbcinit(MBCTYPE_UTF8); break; default: case 'N': case 'n': + case 'A': + case 'a': set_no_conversion: reg_kcode = KCODE_NONE; + re_mbcinit(MBCTYPE_ASCII); break; } - re_set_syntax(re_syntax_options); } static void kcode_setter(val) struct RString *val; { - Check_Type(val, T_STRING); - rb_set_kcode(val->ptr); + may_need_recompile = 1; + rb_set_kcode(STR2CSTR(val)); +} + +static VALUE +ignorecase_getter() +{ + return ruby_ignorecase?Qtrue:Qfalse; +} + +static void +ignorecase_setter(val) + VALUE val; +{ + may_need_recompile = 1; + ruby_ignorecase = RTEST(val); } static VALUE match_getter() { - return backref_get(); + return match_clone(rb_backref_get()); } static void @@ -1029,27 +1100,28 @@ match_setter(val) VALUE val; { Check_Type(val, T_MATCH); - backref_set(val); + rb_backref_set(val); } -VALUE any_to_s(); - void Init_Regexp() { - extern VALUE eException; + rb_eRegxpError = rb_define_class("RegxpError", rb_eStandardError); - eRegxpError = rb_define_class("RegxpError", eException); - - re_set_syntax(RE_NO_BK_PARENS | RE_NO_BK_VBAR - | RE_INTERVALS - | RE_NO_BK_BRACES - | RE_CONTEXTUAL_INVALID_OPS - | RE_BACKSLASH_ESCAPE_IN_LISTS -#ifdef DEFAULT_MBCTYPE - | DEFAULT_MBCTYPE + re_set_casetable(casetable); +#ifdef RUBY_USE_EUC + re_mbcinit(MBCTYPE_EUC); +#else +#ifdef RUBY_USE_SJIS + re_mbcinit(MBCTYPE_SJIS); +#else +#ifdef RUBY_USE_UTF8 + re_mbcinit(MBCTYPE_UTF8); +#else + re_mbcinit(MBCTYPE_ASCII); +#endif +#endif #endif - ); rb_define_virtual_variable("$~", match_getter, match_setter); rb_define_virtual_variable("$&", last_match_getter, 0); @@ -1057,31 +1129,32 @@ Init_Regexp() rb_define_virtual_variable("$'", postmatch_getter, 0); rb_define_virtual_variable("$+", last_paren_match_getter, 0); - rb_define_variable("$=", &ignorecase); + rb_define_virtual_variable("$=", ignorecase_getter, ignorecase_setter); rb_define_virtual_variable("$KCODE", kcode_getter, kcode_setter); rb_define_virtual_variable("$-K", kcode_getter, kcode_setter); - cRegexp = rb_define_class("Regexp", cObject); - rb_define_singleton_method(cRegexp, "new", reg_s_new, -1); - rb_define_singleton_method(cRegexp, "compile", reg_s_new, -1); - rb_define_singleton_method(cRegexp, "quote", reg_s_quote, 1); - - rb_define_method(cRegexp, "clone", reg_clone, 0); - rb_define_method(cRegexp, "==", reg_equal, 1); - rb_define_method(cRegexp, "=~", reg_match, 1); - rb_define_method(cRegexp, "===", reg_match, 1); - rb_define_method(cRegexp, "~", reg_match2, 0); - rb_define_method(cRegexp, "inspect", reg_inspect, 0); - rb_define_method(cRegexp, "source", reg_source, 0); - rb_define_method(cRegexp, "casefold?", reg_casefold_p, 0); - rb_define_method(cRegexp, "kcode", reg_kcode_method, 0); + rb_cRegexp = rb_define_class("Regexp", rb_cObject); + rb_define_singleton_method(rb_cRegexp, "new", rb_reg_s_new, -1); + rb_define_singleton_method(rb_cRegexp, "compile", rb_reg_s_new, -1); + rb_define_singleton_method(rb_cRegexp, "quote", rb_reg_s_quote, 1); + + rb_define_method(rb_cRegexp, "clone", rb_reg_clone, 0); + rb_define_method(rb_cRegexp, "==", rb_reg_equal, 1); + rb_define_method(rb_cRegexp, "=~", rb_reg_match, 1); + rb_define_method(rb_cRegexp, "===", rb_reg_match, 1); + rb_define_method(rb_cRegexp, "~", rb_reg_match2, 0); + rb_define_method(rb_cRegexp, "inspect", rb_reg_inspect, 0); + rb_define_method(rb_cRegexp, "source", rb_reg_source, 0); + rb_define_method(rb_cRegexp, "casefold?", rb_reg_casefold_p, 0); + rb_define_method(rb_cRegexp, "kcode", rb_reg_kcode_method, 0); rb_global_variable(®_cache); rb_global_variable(&matchcache); - cMatch = rb_define_class("MatchingData", cData); - rb_define_method(cMatch, "to_a", match_to_a, 0); - rb_define_method(cMatch, "[]", match_aref, -1); - rb_define_method(cMatch, "to_s", match_to_s, 0); - rb_define_method(cMatch, "inspect", any_to_s, 0); + rb_cMatch = rb_define_class("MatchingData", rb_cData); + rb_define_method(rb_cMatch, "clone", match_clone, 0); + rb_define_method(rb_cMatch, "to_a", match_to_a, 0); + rb_define_method(rb_cMatch, "[]", match_aref, -1); + rb_define_method(rb_cMatch, "to_s", match_to_s, 0); + rb_define_method(rb_cMatch, "inspect", rb_any_to_s, 0); } diff --git a/re.h b/re.h index 8769d6ef39..4d7220b5e6 100644 --- a/re.h +++ b/re.h @@ -3,11 +3,10 @@ re.h - $Author$ - $Revision$ $Date$ created at: Thu Sep 30 14:18:32 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -29,9 +28,12 @@ struct RMatch { #define RMATCH(obj) (R_CAST(RMatch)(obj)) -int str_cicmp _((VALUE, VALUE)); -VALUE reg_regcomp _((VALUE)); -int reg_search _((VALUE, VALUE, int, struct re_registers *)); -VALUE reg_regsub _((VALUE, VALUE, struct re_registers *)); -void reg_free _((Regexp *)); +int rb_str_cicmp _((VALUE, VALUE)); +VALUE rb_reg_regcomp _((VALUE)); +int rb_reg_search _((VALUE, VALUE, int, int)); +VALUE rb_reg_regsub _((VALUE, VALUE, struct re_registers *)); + +int rb_kcode _((void)); + +extern int ruby_ignorecase; #endif diff --git a/regex.c b/regex.c index 0fdf2c06f9..924f32b836 100644 --- a/regex.c +++ b/regex.c @@ -32,9 +32,6 @@ #include <ctype.h> #include <sys/types.h> -#include "config.h" -#include "defines.h" - #ifdef __STDC__ #define P(s) s #define MALLOC_ARG_T size_t @@ -45,21 +42,28 @@ #define const #endif +#include "config.h" + +void *xmalloc P((unsigned long)); +void *xcalloc P((unsigned long,unsigned long)); +void *xrealloc P((void*,unsigned long)); +void free P((void*)); + /* #define NO_ALLOCA /* try it out for now */ #ifndef NO_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) && !defined(__GNUC__) -#include <alloca.h> +# ifndef atarist +# ifndef alloca +# define alloca __builtin_alloca +# endif +# endif /* atarist */ #else +# if defined(HAVE_ALLOCA_H) +# include <alloca.h> +# else char *alloca(); -#endif +# endif #endif /* __GNUC__ */ #ifdef _AIX @@ -73,23 +77,29 @@ char *alloca(); #endif #define RE_ALLOCATE alloca +#ifdef C_ALLOCA #define FREE_VARIABLES() alloca(0) +#else +#define FREE_VARIABLES() +#endif #define FREE_AND_RETURN_VOID(stackb) return #define FREE_AND_RETURN(stackb,val) return(val) #define DOUBLE_STACK(stackx,stackb,len,type) \ - (stackx = (type*) alloca(2 * len * sizeof(type)), \ + (stackx = (type*)alloca(2 * len * sizeof(type)), \ /* Only copy what is in use. */ \ - (type*) memcpy(stackx, stackb, len * sizeof (type))) + (type*)memcpy(stackx, stackb, len * sizeof (type))) #else /* NO_ALLOCA defined */ -#define RE_ALLOCATE malloc +#define RE_ALLOCATE xmalloc #define FREE_VAR(var) if (var) free(var); var = NULL #define FREE_VARIABLES() \ do { \ FREE_VAR(regstart); \ FREE_VAR(regend); \ + FREE_VAR(old_regstart) \ + FREE_VAR(old_regend); \ FREE_VAR(best_regstart); \ FREE_VAR(best_regend); \ FREE_VAR(reg_info); \ @@ -113,33 +123,38 @@ char *alloca(); stackp = stackx + (stackp - stackb); \ stackb = stackx; \ stacke = stackb + 2 * len; \ - } while (0); \ + } while (0) /* Get the interface, including the syntax bits. */ #include "regex.h" /* Subroutines for re_compile_pattern. */ -static void store_jump P((char *, int, char *)); -static void insert_jump P((int, char *, char *, char *)); -static void store_jump_n P((char *, int, char *, unsigned)); -static void insert_jump_n P((int, char *, char *, char *, unsigned)); -static void insert_op P((int, char *, char *)); -static void insert_op_2 P((int, char *, char *, int, int)); -static int memcmp_translate P((unsigned char *, unsigned char *, - int, unsigned char *)); +static void store_jump P((char*, int, char*)); +static void insert_jump P((int, char*, char*, char*)); +static void store_jump_n P((char*, int, char*, unsigned)); +static void insert_jump_n P((int, char*, char*, char*, unsigned)); +static void insert_op P((int, char*, char*)); +static void insert_op_2 P((int, char*, char*, int, int)); +static int memcmp_translate P((unsigned char*, unsigned char*, int)); +static int alt_match_null_string_p (); +static int common_op_match_null_string_p (); +static int group_match_null_string_p (); /* Define the syntax stuff, so we can do the \<, \>, etc. */ /* This must be nonzero for the wordchar and notwordchar pattern - commands in re_match_2. */ -#ifndef Sword -#define Sword 1 -#endif + commands in re_match. */ +#define Sword 1 +#define Sword2 2 #define SYNTAX(c) re_syntax_table[c] static char re_syntax_table[256]; static void init_syntax_once P((void)); +static unsigned char *translate = 0; +static void init_regs P((struct re_registers*, unsigned int)); +static void bm_init_skip P((int *, unsigned char*, int, char*)); +static int current_mbctype = MBCTYPE_ASCII; #undef P @@ -156,30 +171,55 @@ init_syntax_once() memset(re_syntax_table, 0, sizeof re_syntax_table); - for (c = 'a'; c <= 'z'; c++) - re_syntax_table[c] = Sword; - - for (c = 'A'; c <= 'Z'; c++) - re_syntax_table[c] = Sword; - - for (c = '0'; c <= '9'; c++) - re_syntax_table[c] = Sword; - + for (c=0; c<0x7f; c++) + if (isalnum(c)) + re_syntax_table[c] = Sword; re_syntax_table['_'] = Sword; - /* Add specific syntax for ISO Latin-1. */ - for (c = 0300; c <= 0377; c++) - re_syntax_table[c] = Sword; - re_syntax_table[0327] = 0; - re_syntax_table[0367] = 0; - + for (c=0x80; c<=0xff; c++) + if (isalnum(c)) + re_syntax_table[c] = Sword2; done = 1; } -/* Sequents are missing isgraph. */ -#ifndef isgraph -#define isgraph(c) (isprint((c)) && !isspace((c))) +void +re_set_casetable(table) + char *table; +{ + translate = (unsigned char*)table; +} + +/* Jim Meyering writes: + + "... Some ctype macros are valid only for character codes that + isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when + using /bin/cc or gcc but without giving an ansi option). So, all + ctype uses should be through macros like ISPRINT... If + STDC_HEADERS is defined, then autoconf has verified that the ctype + macros don't need to be guarded with references to isascii. ... + Defining isascii to 1 should let any compiler worth its salt + eliminate the && through constant folding." */ +#ifdef isblank +#define ISBLANK(c) isblank ((unsigned char)c) +#else +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') #endif +#ifdef isgraph +#define ISGRAPH(c) isgraph ((unsigned char)c) +#else +#define ISGRAPH(c) (isprint ((unsigned char)c) && !isspace ((unsigned char)c)) +#endif + +#define ISPRINT(c) isprint ((unsigned char)c) +#define ISDIGIT(c) isdigit ((unsigned char)c) +#define ISALNUM(c) isalnum ((unsigned char)c) +#define ISALPHA(c) isalpha ((unsigned char)c) +#define ISCNTRL(c) iscntrl ((unsigned char)c) +#define ISLOWER(c) islower ((unsigned char)c) +#define ISPUNCT(c) ispunct ((unsigned char)c) +#define ISSPACE(c) isspace ((unsigned char)c) +#define ISUPPER(c) isupper ((unsigned char)c) +#define ISXDIGIT(c) isxdigit ((unsigned char)c) /* These are the command codes that appear in compiled regular expressions, one per byte. Some command codes are followed by @@ -200,7 +240,9 @@ enum regexpcode begbuf, /* Succeeds if at beginning of buffer (if emacs) or at beginning of string to be matched (if not). */ endbuf, /* Analogously, for end of buffer/string. */ + endbuf2, /* End of buffer/string, or newline just before it. */ jump, /* Followed by two bytes giving relative address to jump to. */ + jump_past_alt,/* Same as jump, but marks the end of an alternative. */ on_failure_jump, /* Followed by two bytes giving relative address of place to resume at in case of failure. */ finalize_jump, /* Throw away latest failure point and then jump to @@ -219,6 +261,8 @@ enum regexpcode makes this before the first repeat. Also use it as an intermediary kind of jump when compiling an or construct. */ + push_dummy_failure, /* Push a dummy failure point and continue. Used at the end of + alternatives. */ succeed_n, /* Used like on_failure_jump except has to succeed n times; then gets turned into an on_failure_jump. The relative address following it is useless until then. The @@ -251,6 +295,9 @@ enum regexpcode and store it in a memory register. Followed by one byte containing the register number. Register numbers must be in the range 0 through RE_NREGS. */ + stop_paren, /* Place holder at the end of (?:..). */ + casefold_on, /* Turn on casefold flag. */ + casefold_off, /* Turn off casefold flag. */ start_nowidth, /* Save string point to the stack. */ stop_nowidth, /* Restore string place at the point start_nowidth. */ pop_and_fail, /* Fail after popping nowidth entry from stack. */ @@ -284,29 +331,29 @@ enum regexpcode /* Store NUMBER in two contiguous bytes starting at DESTINATION. */ #define STORE_NUMBER(destination, number) \ - { (destination)[0] = (number) & 0377; \ - (destination)[1] = (number) >> 8; } + do { (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; } while (0) /* Same as STORE_NUMBER, except increment the destination pointer to the byte after where the number is stored. Watch out that values for DESTINATION such as p + 1 won't work, whereas p will. */ #define STORE_NUMBER_AND_INCR(destination, number) \ - { STORE_NUMBER(destination, number); \ - (destination) += 2; } + do { STORE_NUMBER(destination, number); \ + (destination) += 2; } while (0) /* Put into DESTINATION a number stored in two contingous bytes starting at SOURCE. */ #define EXTRACT_NUMBER(destination, source) \ - { (destination) = *(source) & 0377; \ - (destination) += SIGN_EXTEND_CHAR (*(char *)((source) + 1)) << 8; } + do { (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*(char*)((source) + 1)) << 8; } while (0) /* Same as EXTRACT_NUMBER, except increment the pointer for source to point to second byte of SOURCE. Note that SOURCE has to be a value such as p, not, e.g., p + 1. */ #define EXTRACT_NUMBER_AND_INCR(destination, source) \ - { EXTRACT_NUMBER(destination, source); \ - (source) += 2; } + do { EXTRACT_NUMBER(destination, source); \ + (source) += 2; } while (0) /* Specify the precise syntax of regexps for compilation. This provides @@ -320,19 +367,14 @@ long re_set_syntax(syntax) long syntax; { - long ret; - - ret = re_syntax_options; - re_syntax_options = syntax; - return ret; + /* obsolete */ } -/* Set by re_set_syntax to the current regexp syntax to recognize. */ -long re_syntax_options = DEFAULT_MBCTYPE; - /* Macros for re_compile_pattern, which is found below these definitions. */ +#define TRANSLATE_P() ((options&RE_OPTION_IGNORECASE) && translate) +#define MAY_TRANSLATE() ((bufp->options&(RE_OPTION_IGNORECASE|RE_MAY_IGNORECASE)) && translate) /* Fetch the next character in the uncompiled pattern---translating it if necessary. Also cast from a signed character in the constant string passed to us by the user to an unsigned char that we can use @@ -340,58 +382,117 @@ long re_syntax_options = DEFAULT_MBCTYPE; #define PATFETCH(c) \ do {if (p == pend) goto end_of_pattern; \ c = (unsigned char) *p++; \ - if (translate) c = (unsigned char)translate[c]; \ + if (TRANSLATE_P()) c = (unsigned char)translate[c]; \ } while (0) /* Fetch the next character in the uncompiled pattern, with no translation. */ #define PATFETCH_RAW(c) \ do {if (p == pend) goto end_of_pattern; \ - c = (unsigned char) *p++; \ + c = (unsigned char)*p++; \ } while (0) /* Go backwards one character in the pattern. */ #define PATUNFETCH p-- +#define MBC2WC(c, p)\ + do {\ + if (current_mbctype == MBCTYPE_UTF8) {\ + int n = ismbchar(c);\ + int c1;\ + c &= 1<<(BYTEWIDTH-2-n);\ + while (n--) {\ + c = c << 6 | *p++;\ + }\ + }\ + else {\ + c <<= 8;\ + c |= (unsigned char)*(p)++;\ + }\ + } while (0) + +#define PATFETCH_MBC(c) \ + do {\ + if (p + ismbchar(c) == pend) goto end_of_pattern;\ + MBC2WC(c, p);\ + } while(0) + +#define WC2MBC1ST(c) \ + ((current_mbctype != MBCTYPE_UTF8)?(((c)>>8)&0xff):utf8_firstbyte(c)) + +static unsigned int +utf8_firstbyte(c) + unsigned int c; +{ + if (c < 0x80) return c; + if (c < 0x7ff) return ((c>>6)&0xff)|0xc0; + if (c < 0xffff) return ((c>>12)&0xff)|0xe0; + if (c < 0x1fffff) return ((c>>18)&0xff)|0xf0; + if (c < 0x3ffffff) return ((c>>24)&0xff)|0xf8; + if (c < 0x7fffffff) return ((c>>30)&0xff)|0xfc; +} + +static void +print_mbc(c) + unsigned int c; +{ + if (current_mbctype == MBCTYPE_UTF8) { + if (c < 0x80) + printf("%c", c); + else if (c < 0x7ff) + printf("%c%c", utf8_firstbyte(c), c&0x3f); + else if (c < 0xffff) + printf("%c%c%c", utf8_firstbyte(c), (c>>6)&0x3f, c&0x3f); + else if (c < 0x1fffff) + printf("%c%c%c%c", utf8_firstbyte(c), (c>>12)&0x3f, (c>>6)&0x3f, c&0x3f); + else if (c < 0x3ffffff) + printf("%c%c%c%c%c", utf8_firstbyte(c), (c>>18)&0x3f, (c>>12)&0x3f, (c>>6)&0x3f, c&0x3f); + else if (c < 0x7fffffff) + printf("%c%c%c%c%c", utf8_firstbyte(c), (c>>24)&0x3f, (c>>18)&0x3f, (c>>12)&0x3f, (c>>6)&0x3f, c&0x3f); + } + else { + printf("%c%c", c>>BYTEWIDTH, c&0xff); + } +} /* If the buffer isn't allocated when it comes in, use this. */ #define INIT_BUF_SIZE 28 /* Make sure we have at least N more bytes of space in buffer. */ #define GET_BUFFER_SPACE(n) \ - { \ + do { \ while (b - bufp->buffer + (n) >= bufp->allocated) \ EXTEND_BUFFER; \ - } + } while (0) /* Make sure we have one more byte of buffer space and then add CH to it. */ #define BUFPUSH(ch) \ - { \ + do { \ GET_BUFFER_SPACE(1); \ *b++ = (char)(ch); \ - } + } while (0) /* Extend the buffer by twice its current size via reallociation and reset the pointers that pointed into the old allocation to point to the correct places in the new allocation. If extending the buffer results in it being larger than 1 << 16, then flag memory exhausted. */ #define EXTEND_BUFFER \ - { char *old_buffer = bufp->buffer; \ + do { char *old_buffer = bufp->buffer; \ if (bufp->allocated == (1L<<16)) goto too_big; \ bufp->allocated *= 2; \ if (bufp->allocated > (1L<<16)) bufp->allocated = (1L<<16); \ - bufp->buffer = (char *) xrealloc (bufp->buffer, bufp->allocated); \ + bufp->buffer = (char*)xrealloc (bufp->buffer, bufp->allocated); \ if (bufp->buffer == 0) \ goto memory_exhausted; \ b = (b - old_buffer) + bufp->buffer; \ - if (fixup_jump) \ - fixup_jump = (fixup_jump - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer; \ if (laststart) \ laststart = (laststart - old_buffer) + bufp->buffer; \ begalt = (begalt - old_buffer) + bufp->buffer; \ if (pending_exact) \ pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ - } + } while (0) /* Set the bit for character C in a character set list. */ @@ -401,10 +502,10 @@ long re_syntax_options = DEFAULT_MBCTYPE; /* Get the next unsigned number in the uncompiled pattern. */ #define GET_UNSIGNED_NUMBER(num) \ - { if (p != pend) \ + do { if (p != pend) \ { \ PATFETCH(c); \ - while (isdigit(c)) \ + while (ISDIGIT(c)) \ { \ if (num < 0) \ num = 0; \ @@ -414,18 +515,48 @@ long re_syntax_options = DEFAULT_MBCTYPE; PATFETCH(c); \ } \ } \ - } + } while (0) + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ +#define IS_CHAR_CLASS(string) \ + (STREQ(string, "alpha") || STREQ(string, "upper") \ + || STREQ(string, "lower") || STREQ(string, "digit") \ + || STREQ(string, "alnum") || STREQ(string, "xdigit") \ + || STREQ(string, "space") || STREQ(string, "print") \ + || STREQ(string, "punct") || STREQ(string, "graph") \ + || STREQ(string, "cntrl") || STREQ(string, "blank")) -#define STORE_MBC(p, c) \ - ((p)[0] = (unsigned char)(c >> 8), (p)[1] = (unsigned char)(c)) -#define STORE_MBC_AND_INCR(p, c) \ - (*(p)++ = (unsigned char)(c >> 8), *(p)++ = (unsigned char)(c)) +#define STORE_MBC(p, c) \ + do { \ + (p)[0] = (unsigned char)(((c) >>24) & 0xff); \ + (p)[1] = (unsigned char)(((c) >>16) & 0xff); \ + (p)[2] = (unsigned char)(((c) >> 8) & 0xff); \ + (p)[3] = (unsigned char)(((c) >> 0) & 0xff); \ + } while (0) -#define EXTRACT_MBC(p) \ - ((unsigned short)((unsigned char)(p)[0] << 8 | (unsigned char)(p)[1])) -#define EXTRACT_MBC_AND_INCR(p) \ - ((unsigned short)((p) += 2, (unsigned char)(p)[-2] << 8 | (unsigned char)(p)[-1])) +#define STORE_MBC_AND_INCR(p, c) \ + do { \ + *(p)++ = (unsigned char)(((c) >>24) & 0xff); \ + *(p)++ = (unsigned char)(((c) >>16) & 0xff); \ + *(p)++ = (unsigned char)(((c) >> 8) & 0xff); \ + *(p)++ = (unsigned char)(((c) >> 0) & 0xff); \ + } while (0) + +#define EXTRACT_MBC(p) \ + ((unsigned short)((unsigned char)(p)[0] << 24 | \ + (unsigned char)(p)[1] << 16 | \ + (unsigned char)(p)[2] << 8 | \ + (unsigned char)(p)[3])) + +#define EXTRACT_MBC_AND_INCR(p) \ + ((unsigned short)((p) += 4, \ + (unsigned char)(p)[-4] << 24 | \ + (unsigned char)(p)[-3] << 16 | \ + (unsigned char)(p)[-2] << 8 | \ + (unsigned char)(p)[-1])) #define EXTRACT_UNSIGNED(p) \ ((unsigned char)(p)[0] | (unsigned char)(p)[1] << 8) @@ -442,14 +573,14 @@ long re_syntax_options = DEFAULT_MBCTYPE; unsigned char sbc_map[sbc_size]; same as charset(_not)? up to here. unsigned short mbc_size; number of intervals. struct { - unsigned short beg; beginning of interval. - unsigned short end; end of interval. + unsigned int beg; beginning of interval. + unsigned int end; end of interval. } intervals[mbc_size]; }; */ static void set_list_bits(c1, c2, b) - unsigned short c1, c2; + unsigned int c1, c2; unsigned char *b; { unsigned char sbc_size = b[-1]; @@ -458,30 +589,12 @@ set_list_bits(c1, c2, b) if (c1 > c2) return; - if ((int)c1 < 1 << BYTEWIDTH) { - upb = c2; - if (1 << BYTEWIDTH <= (int)upb) - upb = (1 << BYTEWIDTH) - 1; /* The last single-byte char */ - if (sbc_size <= (unsigned short)(upb / BYTEWIDTH)) { - /* Allocate maximum size so it never happens again. */ - /* NOTE: memcpy() would not work here. */ - memmove(&b[(1 << BYTEWIDTH) / BYTEWIDTH], &b[sbc_size], 2 + mbc_size*4); - memset(&b[sbc_size], 0, (1 << BYTEWIDTH) / BYTEWIDTH - sbc_size); - b[-1] = sbc_size = (1 << BYTEWIDTH) / BYTEWIDTH; - } - for (; c1 <= upb; c1++) - if (!ismbchar(c1)) - SET_LIST_BIT(c1); - if ((int)c2 < 1 << BYTEWIDTH) - return; - c1 = 0x8000; /* The first wide char */ - } b = &b[sbc_size + 2]; for (beg = 0, upb = mbc_size; beg < upb; ) { unsigned short mid = (unsigned short)(beg + upb) >> 1; - if ((int)c1 - 1 > (int)EXTRACT_MBC(&b[mid*4 + 2])) + if ((int)c1 - 1 > (int)EXTRACT_MBC(&b[mid*8+4])) beg = mid + 1; else upb = mid; @@ -490,30 +603,30 @@ set_list_bits(c1, c2, b) for (end = beg, upb = mbc_size; end < upb; ) { unsigned short mid = (unsigned short)(end + upb) >> 1; - if ((int)c2 >= (int)EXTRACT_MBC(&b[mid*4]) - 1) + if ((int)c2 >= (int)EXTRACT_MBC(&b[mid*8]) - 1) end = mid + 1; else upb = mid; } if (beg != end) { - if (c1 > EXTRACT_MBC(&b[beg*4])) - c1 = EXTRACT_MBC(&b[beg*4]); - if (c2 < EXTRACT_MBC(&b[(end - 1)*4])) - c2 = EXTRACT_MBC(&b[(end - 1)*4]); + if (c1 > EXTRACT_MBC(&b[beg*8])) + c1 = EXTRACT_MBC(&b[beg*8]); + if (c2 < EXTRACT_MBC(&b[(end - 1)*8+4])) + c2 = EXTRACT_MBC(&b[(end - 1)*8+4]); } if (end < mbc_size && end != beg + 1) /* NOTE: memcpy() would not work here. */ - memmove(&b[(beg + 1)*4], &b[end*4], (mbc_size - end)*4); - STORE_MBC(&b[beg*4 + 0], c1); - STORE_MBC(&b[beg*4 + 2], c2); + memmove(&b[(beg + 1)*8], &b[end*8], (mbc_size - end)*8); + STORE_MBC(&b[beg*8 + 0], c1); + STORE_MBC(&b[beg*8 + 4], c2); mbc_size += beg - end + 1; STORE_NUMBER(&b[-2], mbc_size); } static int is_in_list(c, b) - unsigned short c; + unsigned int c; const unsigned char *b; { unsigned short size; @@ -521,39 +634,24 @@ is_in_list(c, b) int result = 0; size = *b++; - if ((int)c < 1<<BYTEWIDTH) { - if ((int)c / BYTEWIDTH < (int)size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH) { - return 1; - } + if ((int)c / BYTEWIDTH < (int)size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH) { + return 2; } b += size + 2; size = EXTRACT_UNSIGNED(&b[-2]); if (size == 0) return 0; - if (b[(size-1)*4] == 0xff) { - i = c; - if ((int)c >= 1<<BYTEWIDTH) { - i = i>>BYTEWIDTH; - } - while (size>0 && b[size*4-2] == 0xff) { - size--; - if (b[size*4+1] <= i && i <= b[size*4+3]) { - result = 2; - break; - } - } - } for (i = 0, j = size; i < j; ) { - unsigned short k = (unsigned short)(i + j) >> 1; + unsigned short k = (unsigned short)(i + j) >> 1; - if (c > EXTRACT_MBC(&b[k*4+2])) - i = k + 1; - else - j = k; + if (c > EXTRACT_MBC(&b[k*8+4])) + i = k + 1; + else + j = k; } - if (i < size && EXTRACT_MBC(&b[i*4]) <= c + if (i < size && EXTRACT_MBC(&b[i*8]) <= c && ((unsigned char)c != '\n' && (unsigned char)c != '\0')) - return 1; + return 1; return result; } @@ -575,7 +673,7 @@ print_partial_compiled_pattern(start, end) /* Loop over pattern commands. */ while (p < pend) { - switch ((enum regexpcode) *p++) + switch ((enum regexpcode)*p++) { case unused: printf ("/unused"); @@ -594,14 +692,26 @@ print_partial_compiled_pattern(start, end) case start_memory: mcnt = *p++; - printf ("/start_memory/%d", mcnt); + printf ("/start_memory/%d/%d", mcnt, *p++); break; case stop_memory: mcnt = *p++; - printf ("/stop_memory/%d", mcnt); + printf ("/stop_memory/%d/%d", mcnt, *p++); break; + case stop_paren: + printf ("/stop_paren"); + break; + + case casefold_on: + printf ("/casefold_on"); + break; + + case casefold_off: + printf ("/casefold_off"); + break; + case start_nowidth: EXTRACT_NUMBER_AND_INCR (mcnt, p); printf ("/start_nowidth//%d", mcnt); @@ -630,14 +740,14 @@ print_partial_compiled_pattern(start, end) register int c; printf ("/charset%s", - (enum regexpcode) *(p - 1) == charset_not ? "_not" : ""); + (enum regexpcode)*(p - 1) == charset_not ? "_not" : ""); - mcnt = *p; + mcnt = *p++; printf("/%d", mcnt); for (c = 0; c < mcnt; c++) { unsigned bit; - unsigned char map_byte = p[1 + c]; + unsigned char map_byte = p[c]; putchar ('/'); @@ -645,13 +755,13 @@ print_partial_compiled_pattern(start, end) if (map_byte & (1 << bit)) printf("%c", c * BYTEWIDTH + bit); } - p += mcnt + 1; - mcnt = EXTRACT_UNSIGNED(p); - p += 2; + p += mcnt; + mcnt = EXTRACT_UNSIGNED_AND_INCR(p); + printf("/"); while (mcnt--) { - int beg = *p++; - int end = *p++; - printf("/%c%c-%c%c", beg>>BYTEWIDTH, beg&0xff, end>>BYTEWIDTH, end&0xff); + print_mbc(EXTRACT_MBC_AND_INCR(p)); + printf("-"); + print_mbc(EXTRACT_MBC_AND_INCR(p)); } break; } @@ -674,6 +784,10 @@ print_partial_compiled_pattern(start, end) printf ("/dummy_failure_jump//%d", mcnt); break; + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + case finalize_jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); printf ("/finalize_jump//%d", mcnt); @@ -684,6 +798,11 @@ print_partial_compiled_pattern(start, end) printf ("/maybe_finalize_jump//%d", mcnt); break; + case jump_past_alt: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + printf ("/jump_past_alt//%d", mcnt); + break; + case jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); printf ("/jump//%d", mcnt); @@ -754,6 +873,10 @@ print_partial_compiled_pattern(start, end) printf ("/endbuf"); break; + case endbuf2: + printf ("/endbuf2"); + break; + default: printf ("?%d", *(p-1)); } @@ -766,28 +889,28 @@ static void print_compiled_pattern(bufp) struct re_pattern_buffer *bufp; { - unsigned char *buffer = bufp->buffer; + unsigned char *buffer = (unsigned char*)bufp->buffer; print_partial_compiled_pattern (buffer, buffer + bufp->used); } static char* calculate_must_string(start, end) - unsigned char *start; - unsigned char *end; + char *start; + char *end; { - int mcnt, mcnt2; + int mcnt; int max = 0; - unsigned char *p = start; - unsigned char *pend = end; - unsigned char *must = 0; + char *p = start; + char *pend = end; + char *must = 0; if (start == NULL) return 0; /* Loop over pattern commands. */ while (p < pend) { - switch ((enum regexpcode) *p++) + switch ((enum regexpcode)*p++) { case unused: break; @@ -796,18 +919,24 @@ calculate_must_string(start, end) mcnt = *p; if (mcnt > max) { must = p; + max = mcnt; } p += mcnt+1; break; case start_memory: case stop_memory: + p += 2; + break; + case duplicate: p++; break; - case start_nowidth: - case stop_nowidth: + case casefold_on: + case casefold_off: + return 0; /* should not check must_string */ + case pop_and_fail: case anychar: case begline: @@ -820,16 +949,18 @@ calculate_must_string(start, end) case notwordchar: case begbuf: case endbuf: + case endbuf2: + case push_dummy_failure: + case stop_paren: break; case charset: case charset_not: mcnt = *p++; p += mcnt; - EXTRACT_NUMBER_AND_INCR (mcnt, p); + mcnt = EXTRACT_UNSIGNED_AND_INCR(p); while (mcnt--) { - EXTRACT_NUMBER_AND_INCR (mcnt2, p); - EXTRACT_NUMBER_AND_INCR (mcnt2, p); + p += 4; } break; @@ -851,6 +982,8 @@ calculate_must_string(start, end) if (mcnt > 0) p += mcnt; break; + case start_nowidth: + case stop_nowidth: case finalize_jump: case maybe_finalize_jump: case finalize_push: @@ -910,7 +1043,7 @@ re_compile_pattern(pattern, size, bufp) the containing expression. Each alternative of an `or', except the last, ends with a forward-jump of this sort. */ - char *fixup_jump = 0; + char *fixup_alt_jump = 0; /* Address of start of the most recently finished expression. This tells postfix * where to find the start of its operand. */ @@ -929,99 +1062,90 @@ re_compile_pattern(pattern, size, bufp) char greedy; - /* Address of beginning of regexp, or inside of last \(. */ + /* Address of beginning of regexp, or inside of last (. */ char *begalt = b; + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + char *beg_interval; + /* In processing an interval, at least this many matches must be made. */ int lower_bound; /* In processing an interval, at most this many matches can be made. */ int upper_bound; - /* Stack of information saved by \( and restored by \). - Five stack elements are pushed by each \(: + /* Stack of information saved by ( and restored by ). + Five stack elements are pushed by each (: First, the value of b. - Second, the value of fixup_jump. + Second, the value of fixup_alt_jump. Third, the value of begalt. Fourth, the value of regnum. Fifth, the type of the paren. */ - int *stackb = RE_TALLOC(40, int); - int *stackp = stackb; - int *stacke = stackb + 40; - int *stackt; + size_t *stackb = RE_TALLOC(40, size_t); + size_t *stackp = stackb; + size_t *stacke = stackb + 40; + size_t *stackt; - /* Counts \('s as they are encountered. Remembered for the matching \), + /* Counts ('s as they are encountered. Remembered for the matching ), where it becomes the register number to put in the stop_memory command. */ int regnum = 1; + int range = 0; + int had_mbchar = 0; + int had_char_class = 0; - /* How to translate the characters in the pattern. */ - char *translate = bufp->translate; + int options = bufp->options; bufp->fastmap_accurate = 0; + bufp->must = 0; + bufp->must_skip = 0; + bufp->stclass = 0; /* Initialize the syntax table. */ init_syntax_once(); - if (bufp->allocated == 0) - { - bufp->allocated = INIT_BUF_SIZE; - if (bufp->buffer) - /* EXTEND_BUFFER loses when bufp->allocated is 0. */ - bufp->buffer = (char *) xrealloc (bufp->buffer, INIT_BUF_SIZE); - else - /* Caller did not allocate a buffer. Do it for them. */ - bufp->buffer = (char *) xmalloc(INIT_BUF_SIZE); + if (bufp->allocated == 0) { + bufp->allocated = INIT_BUF_SIZE; + if (bufp->buffer) + /* EXTEND_BUFFER loses when bufp->allocated is 0. */ + bufp->buffer = (char*)xrealloc (bufp->buffer, INIT_BUF_SIZE); + else + /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = (char*)xmalloc(INIT_BUF_SIZE); if (!bufp->buffer) goto memory_exhausted; begalt = b = bufp->buffer; } - while (p != pend) - { + while (p != pend) { PATFETCH(c); switch (c) { case '$': { - char *p1 = p; + p0 = p; /* When testing what follows the $, look past the \-constructs that don't consume anything. */ - if (! (re_syntax_options & RE_CONTEXT_INDEP_OPS)) - while (p1 != pend) - { - if (*p1 == '\\' && p1 + 1 != pend - && (p1[1] == 'b' || p1[1] == 'B')) - p1 += 2; - else - break; - } - if (re_syntax_options & RE_TIGHT_VBAR) + + while (p0 != pend) { - if (! (re_syntax_options & RE_CONTEXT_INDEP_OPS) && p1 != pend) - goto normal_char; - /* Make operand of last vbar end before this `$'. */ - if (fixup_jump) - store_jump(fixup_jump, jump, b); - fixup_jump = 0; - BUFPUSH(endline); - break; + if (*p0 == '\\' && p0 + 1 != pend + && (p0[1] == 'b' || p0[1] == 'B')) + p0 += 2; + else + break; } /* $ means succeed if at end of line, but only in special contexts. If validly in the middle of a pattern, it is a normal character. */ - if (p1 == pend || *p1 == '\n' - || (re_syntax_options & RE_CONTEXT_INDEP_OPS) - || (re_syntax_options & RE_NO_BK_PARENS - ? *p1 == ')' - : *p1 == '\\' && p1[1] == ')') - || (re_syntax_options & RE_NO_BK_VBAR - ? *p1 == '|' - : *p1 == '\\' && p1[1] == '|')) + if (p0 == pend || *p0 == '\n' + || *p0 == ')' + || *p0 == '|') { BUFPUSH(endline); break; @@ -1032,36 +1156,19 @@ re_compile_pattern(pattern, size, bufp) /* ^ means succeed if at beg of line, but only if no preceding pattern. */ - if ((re_syntax_options & RE_CONTEXTUAL_INVALID_OPS) && laststart) + if (laststart) goto invalid_pattern; - if (laststart && p - 2 >= pattern && p[-2] != '\n' - && !(re_syntax_options & RE_CONTEXT_INDEP_OPS)) + if (laststart && p - 2 >= pattern && p[-2] != '\n') goto normal_char; - if (re_syntax_options & RE_TIGHT_VBAR) - { - if (p != pattern + 1 - && ! (re_syntax_options & RE_CONTEXT_INDEP_OPS)) - goto normal_char; - BUFPUSH(begline); - begalt = b; - } - else - { - BUFPUSH(begline); - } + BUFPUSH(begline); break; case '+': case '?': - if (re_syntax_options & RE_LIMITED_OPS) - goto normal_char; case '*': /* If there is no previous pattern, char not special. */ if (!laststart) { - if (re_syntax_options & RE_CONTEXTUAL_INVALID_OPS) - goto invalid_pattern; - else if (! (re_syntax_options & RE_CONTEXT_INDEP_OPS)) - goto normal_char; + goto invalid_pattern; } /* If there is a sequence of repetition chars, collapse it down to just one. */ @@ -1134,8 +1241,8 @@ re_compile_pattern(pattern, size, bufp) case '[': if (p == pend) goto invalid_pattern; - while (b - bufp->buffer - > bufp->allocated - 9 - (1 << BYTEWIDTH) / BYTEWIDTH) + while ((b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH) + > bufp->allocated) EXTEND_BUFFER; laststart = b; @@ -1152,10 +1259,8 @@ re_compile_pattern(pattern, size, bufp) /* Clear the whole map */ memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); - if ((re_syntax_options & RE_HAT_NOT_NEWLINE) && b[-2] == charset_not) - SET_LIST_BIT('\n'); - - + had_mbchar = 0; + had_char_class = 0; /* Read in characters and ranges, setting map bits. */ for (;;) { @@ -1165,7 +1270,7 @@ re_compile_pattern(pattern, size, bufp) if ((size = EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH]))) { /* Ensure the space is enough to hold another interval of multi-byte chars in charset(_not)?. */ - size = (1 << BYTEWIDTH) / BYTEWIDTH + 2 + size*4 + 4; + size = (1 << BYTEWIDTH) / BYTEWIDTH + 2 + size*8 + 8; while (b + size + 1 > bufp->buffer + bufp->allocated) EXTEND_BUFFER; } @@ -1173,174 +1278,290 @@ re_compile_pattern(pattern, size, bufp) PATFETCH(c); if (c == ']') { - if (p == p0 + 1) { - /* If this is an empty bracket expression. */ - if ((re_syntax_options & RE_NO_EMPTY_BRACKETS) - && p == pend) - goto invalid_pattern; - } - else - /* Stop if this isn't merely a ] inside a bracket - expression, but rather the end of a bracket - expression. */ - break; + if (p == p0 + 1) { + if (p == pend) + goto invalid_pattern; + } + else + /* Stop if this isn't merely a ] inside a bracket + expression, but rather the end of a bracket + expression. */ + break; } + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + goto invalid_pattern; if (ismbchar(c)) { - PATFETCH(c1); - c = c << BYTEWIDTH | c1; + PATFETCH_MBC(c); + had_mbchar++; } /* \ escapes characters when inside [...]. */ if (c == '\\') { - PATFETCH(c); - switch (c) { - case 'w': - for (c = 0; c < (1 << BYTEWIDTH); c++) - if (SYNTAX(c) == Sword) - SET_LIST_BIT(c); - last = -1; - continue; - - case 'W': - for (c = 0; c < (1 << BYTEWIDTH); c++) - if (SYNTAX(c) != Sword) - SET_LIST_BIT(c); - if (re_syntax_options & RE_MBCTYPE_MASK) { - set_list_bits(0x8000, 0xffff, (unsigned char*)b); - } - last = -1; - continue; - - case 's': - for (c = 0; c < 256; c++) - if (isspace(c)) - SET_LIST_BIT(c); - last = -1; - continue; + PATFETCH(c); + switch (c) { + case 'w': + for (c = 0; c < (1 << BYTEWIDTH); c++) { + if (SYNTAX(c) == Sword || + (!current_mbctype && SYNTAX(c) == Sword2)) + SET_LIST_BIT(c); + } + last = -1; + continue; + + case 'W': + for (c = 0; c < (1 << BYTEWIDTH); c++) { + if (SYNTAX(c) != Sword && + (current_mbctype || SYNTAX(c) != Sword2)) + SET_LIST_BIT(c); + } + if (current_mbctype) { + set_list_bits(0x0, 0xffffffff, b); + } + last = -1; + continue; - case 'S': - for (c = 0; c < 256; c++) - if (!isspace(c)) - SET_LIST_BIT(c); - if (re_syntax_options & RE_MBCTYPE_MASK) { - set_list_bits(0x8000, 0xffff, (unsigned char*)b); - } - last = -1; - continue; + case 's': + for (c = 0; c < 256; c++) + if (ISSPACE(c)) + SET_LIST_BIT(c); + last = -1; + continue; + + case 'S': + for (c = 0; c < 256; c++) + if (!ISSPACE(c)) + SET_LIST_BIT(c); + if (current_mbctype) { + set_list_bits(0, 0xffffffff, b); + } + last = -1; + continue; + + case 'd': + for (c = '0'; c <= '9'; c++) + SET_LIST_BIT(c); + last = -1; + continue; + + case 'D': + for (c = 0; c < 256; c++) + if (!ISDIGIT(c)) + SET_LIST_BIT(c); + if (current_mbctype) { + set_list_bits(0, 0xffffffff, b); + } + last = -1; + continue; - case 'd': - for (c = '0'; c <= '9'; c++) - SET_LIST_BIT(c); - last = -1; - continue; + case 'x': + c = scan_hex(p, 2, &numlen); + p += numlen; + break; - case 'D': - for (c = 0; c < 256; c++) - if (!isdigit(c)) - SET_LIST_BIT(c); - if (re_syntax_options & RE_MBCTYPE_MASK) { - set_list_bits(0x8000, 0xffff, (unsigned char*)b); - } - last = -1; - continue; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + PATUNFETCH; + c = scan_oct(p, 3, &numlen); + p += numlen; + break; - case 'x': - c = scan_hex(p, 2, &numlen); - if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f) - c = 0xff00 | c; - p += numlen; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - PATUNFETCH; - c = scan_oct(p, 3, &numlen); - if ((re_syntax_options & RE_MBCTYPE_MASK) && ismbchar(c)) - c = 0xff00 | c; - p += numlen; - break; - - default: - if (ismbchar(c)) { - PATFETCH(c1); - c = c << 8 | c1; - } - break; + default: + if (ismbchar(c)) { + PATFETCH_MBC(c); + had_mbchar++; } + break; + } } /* Get a range. */ if (range) { - if (last > c) - goto invalid_pattern; - - if ((re_syntax_options & RE_NO_HYPHEN_RANGE_END) - && c == '-' && *p != ']') - goto invalid_pattern; + if (last > c) + goto invalid_pattern; - range = 0; - if (last < 1 << BYTEWIDTH && c < 1 << BYTEWIDTH) { - for (;last<=c;last++) - SET_LIST_BIT(last); - } - else { - set_list_bits(last, c, (unsigned char*)b); - } + range = 0; + if (had_mbchar == 0) { + for (;last<=c;last++) + SET_LIST_BIT(last); + } + else if (had_mbchar == 2) { + set_list_bits(last, c, b); + } + else { + /* restriction: range between sbc and mbc */ + goto invalid_pattern; + } } else if (p[0] == '-' && p[1] != ']') { - last = c; - PATFETCH(c1); - range = 1; - goto range_retry; + last = c; + PATFETCH(c1); + range = 1; + goto range_retry; + } + else if (c == '[' && *p == ':') { + /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH_RAW (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) + goto invalid_pattern; + + for (;;) { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') { + int ch; + char is_alnum = STREQ(str, "alnum"); + char is_alpha = STREQ(str, "alpha"); + char is_blank = STREQ(str, "blank"); + char is_cntrl = STREQ(str, "cntrl"); + char is_digit = STREQ(str, "digit"); + char is_graph = STREQ(str, "graph"); + char is_lower = STREQ(str, "lower"); + char is_print = STREQ(str, "print"); + char is_punct = STREQ(str, "punct"); + char is_space = STREQ(str, "space"); + char is_upper = STREQ(str, "upper"); + char is_xdigit = STREQ(str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) + goto invalid_pattern; + + /* Throw away the ] at the end of the character class. */ + PATFETCH (c); + + if (p == pend) + goto invalid_pattern; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) { + if ( (is_alnum && ISALNUM(ch)) + || (is_alpha && ISALPHA(ch)) + || (is_blank && ISBLANK(ch)) + || (is_cntrl && ISCNTRL(ch)) + || (is_digit && ISDIGIT(ch)) + || (is_graph && ISGRAPH(ch)) + || (is_lower && ISLOWER(ch)) + || (is_print && ISPRINT(ch)) + || (is_punct && ISPUNCT(ch)) + || (is_space && ISSPACE(ch)) + || (is_upper && ISUPPER(ch)) + || (is_xdigit && ISXDIGIT(ch))) + SET_LIST_BIT (ch); + } + had_char_class = 1; + } + else { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT(translate?translate['[']:'['); + SET_LIST_BIT(translate?translate[':']:':'); + had_char_class = 0; + last = ':'; + } } - else if (c < 1 << BYTEWIDTH) + else if (had_mbchar == 0) SET_LIST_BIT(c); else - set_list_bits(c, c, (unsigned char*)b); + set_list_bits(c, c, b); + had_mbchar = 0; } /* Discard any character set/class bitmap bytes that are all 0 at the end of the map. Decrement the map-length byte too. */ - while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) b[-1]--; if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH) memmove(&b[b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH], - 2 + EXTRACT_UNSIGNED (&b[(1 << BYTEWIDTH) / BYTEWIDTH])*4); - b += b[-1] + 2 + EXTRACT_UNSIGNED (&b[b[-1]])*4; + 2 + EXTRACT_UNSIGNED (&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8); + b += b[-1] + 2 + EXTRACT_UNSIGNED (&b[b[-1]])*8; break; case '(': PATFETCH(c); if (c == '?') { - PATFETCH(c); - switch (c) { - case '#': - case 'i': - case 'm': - case 's': - case 'x': - for (;;) { - PATFETCH(c); - if (c == ')') break; + int negative = 0; + PATFETCH_RAW(c); + switch (c) { + case 'x': case 'i': case '-': + for (;;) { + switch (c) { + case '-': + negative = 1; + break; + + case ':': + case ')': + break; + + case 'x': + if (negative) + options &= ~RE_OPTION_EXTENDED; + else + options |= RE_OPTION_EXTENDED; + break; + case 'i': + if (negative) { + if (options&RE_OPTION_IGNORECASE) { + options &= ~RE_OPTION_IGNORECASE; + BUFPUSH(casefold_off); + } + } + else if (!(options&RE_OPTION_IGNORECASE)) { + options |= RE_OPTION_IGNORECASE; + BUFPUSH(casefold_on); + } + break; + + default: + FREE_AND_RETURN(stackb, "undefined (?...) inline option"); } - c = '#'; - break; + if (c == ')') { + c = '#'; /* read whole in-line options */ + break; + } + if (c == ':') break; + PATFETCH_RAW(c); + } + break; - case ':': - case '=': - case '!': - break; + case '#': + for (;;) { + PATFETCH(c); + if (c == ')') break; + } + c = '#'; + break; - default: - FREE_AND_RETURN(stackb, "undefined (?...) sequence"); - } + case ':': + case '=': + case '!': + break; + + default: + FREE_AND_RETURN(stackb, "undefined (?...) sequence"); + } } else { PATUNFETCH; c = '('; } if (c == '#') break; - if (stackp+6 >= stacke) { + if (stackp+8 >= stacke) { int *stackx; unsigned int len = stacke - stackb; @@ -1355,13 +1576,15 @@ re_compile_pattern(pattern, size, bufp) to push (unless the pattern has RE_NREGS or more ('s). */ /* obsolete: now RE_NREGS is just a default register size. */ *stackp++ = b - bufp->buffer; - *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; *stackp++ = begalt - bufp->buffer; switch (c) { case '(': BUFPUSH(start_memory); BUFPUSH(regnum); *stackp++ = regnum++; + *stackp++ = b - bufp->buffer; + BUFPUSH(0); /* too many ()'s to fit in a byte. (max 254) */ if (regnum >= RE_REG_MAX) goto too_big; break; @@ -1381,23 +1604,46 @@ re_compile_pattern(pattern, size, bufp) break; case ':': + pending_exact = 0; default: break; } *stackp++ = c; - fixup_jump = 0; + *stackp++ = options; + fixup_alt_jump = 0; laststart = 0; begalt = b; break; case ')': - if (stackp == stackb) goto unmatched_close; - switch (c = *--stackp) { - case '(': - if (fixup_jump) - store_jump(fixup_jump, jump, b); - BUFPUSH(stop_memory); - BUFPUSH(stackp[-1]); + if (stackp == stackb) + FREE_AND_RETURN(stackb, "unmatched )"); + if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) { + BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on); + } + pending_exact = 0; + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `finalize_jump' to pop. See comments at + `push_dummy_failure' in `re_match'. */ + BUFPUSH(push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + store_jump(fixup_alt_jump, jump, b); + } + options = *--stackp; + switch (c = *--stackp) { + case '(': + { + char *loc = bufp->buffer + *--stackp; + *loc = regnum - stackp[-1]; + BUFPUSH(stop_memory); + BUFPUSH(stackp[-1]); + BUFPUSH(regnum - stackp[-1]); + stackp--; + } break; case '!': @@ -1412,16 +1658,19 @@ re_compile_pattern(pattern, size, bufp) STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); BUFPUSH(0); /* space to hold stack pos */ BUFPUSH(0); + stackp--; break; case ':': + BUFPUSH(stop_paren); + break; + default: break; } - stackp--; begalt = *--stackp + bufp->buffer; stackp--; - fixup_jump = *stackp ? *stackp + bufp->buffer - 1 : 0; + fixup_alt_jump = *stackp ? *stackp + bufp->buffer - 1 : 0; laststart = *--stackp + bufp->buffer; if (c == '!' || c == '=') laststart = b; break; @@ -1429,23 +1678,34 @@ re_compile_pattern(pattern, size, bufp) case '|': /* Insert before the previous alternative a jump which jumps to this alternative if the former fails. */ - GET_BUFFER_SPACE(6); + GET_BUFFER_SPACE(3); insert_jump(on_failure_jump, begalt, b + 6, b); pending_exact = 0; b += 3; - /* The alternative before the previous alternative has a - jump after it which gets executed if it gets matched. - Adjust that jump so it will jump to the previous - alternative's analogous jump (put in below, which in - turn will jump to the next (if any) alternative's such - jump, etc.). The last such jump jumps to the correct - final destination. */ - if (fixup_jump) - store_jump(fixup_jump, jump, b); - - /* Leave space for a jump after previous alternative---to be - filled in later. */ - fixup_jump = b; + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + store_jump(fixup_alt_jump, jump_past_alt, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE(3); b += 3; laststart = 0; @@ -1454,51 +1714,35 @@ re_compile_pattern(pattern, size, bufp) case '{': /* If there is no previous pattern, this isn't an interval. */ - if (!laststart) + if (!laststart || p == pend) { - if (re_syntax_options & RE_CONTEXTUAL_INVALID_OPS) - goto invalid_pattern; - else - goto normal_backsl; + goto normal_char; } - /* It also isn't an interval if not preceded by an re - matching a single character or subexpression, or if - the current type of intervals can't handle back - references and the previous thing is a back reference. */ - if (! (*laststart == anychar - || *laststart == charset - || *laststart == charset_not - || *laststart == wordchar - || *laststart == notwordchar - || *laststart == start_memory - || (*laststart == exactn - && (laststart[1] == 1 - || laststart[1] == 2 && ismbchar(laststart[2]))) - || (! (re_syntax_options & RE_NO_BK_REFS) - && *laststart == duplicate))) - { - /* Posix extended syntax is handled in previous - statement; this is for Posix basic syntax. */ - if (re_syntax_options & RE_INTERVALS) - goto invalid_pattern; - goto normal_backsl; - } + beg_interval = p - 1; + lower_bound = -1; /* So can see if are set. */ upper_bound = -1; GET_UNSIGNED_NUMBER(lower_bound); if (c == ',') { GET_UNSIGNED_NUMBER(upper_bound); - if (upper_bound < 0) - upper_bound = RE_DUP_MAX; } - if (upper_bound < 0) + else + /* Interval such as `{1}' => match exactly once. */ upper_bound = lower_bound; - if (c != '}' || lower_bound < 0 || upper_bound > RE_DUP_MAX - || lower_bound > upper_bound - || (p != pend && *p == '{')) { - goto invalid_pattern; - } + + if (lower_bound < 0 || c != '}') + goto unfetch_interval; + + if (lower_bound >= RE_DUP_MAX || upper_bound >= RE_DUP_MAX) + FREE_AND_RETURN(stackb, "too big quantifier in {,}"); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + if (lower_bound > upper_bound) + FREE_AND_RETURN(stackb, "can't do {n,m} with n > m"); + + beg_interval = 0; + pending_exact = 0; + greedy = 1; if (p != pend) { PATFETCH(c); @@ -1506,17 +1750,6 @@ re_compile_pattern(pattern, size, bufp) else PATUNFETCH; } - /* If upper_bound is zero, don't want to succeed at all; - jump from laststart to b + 3, which will be the end of - the buffer after this jump is inserted. */ - - if (upper_bound == 0) { - GET_BUFFER_SPACE(3); - insert_jump(jump, laststart, b + 3, b); - b += 3; - break; - } - if (lower_bound == 0) { zero_times_ok = 1; if (upper_bound == RE_DUP_MAX) { @@ -1528,28 +1761,49 @@ re_compile_pattern(pattern, size, bufp) goto repeat; } } - if (lower_bound == 1 && upper_bound == RE_DUP_MAX) { - many_times_ok = 1; - zero_times_ok = 0; - goto repeat; + if (lower_bound == 1) { + if (upper_bound == 1) { + /* No need to repeat */ + break; + } + if (upper_bound == RE_DUP_MAX) { + many_times_ok = 1; + zero_times_ok = 0; + goto repeat; + } } - /* Star, etc. applied to an empty pattern is equivalent - to an empty pattern. */ - if (!laststart) + /* If upper_bound is zero, don't want to succeed at all; + jump from laststart to b + 3, which will be the end of + the buffer after this jump is inserted. */ + + if (upper_bound == 0) { + GET_BUFFER_SPACE(3); + insert_jump(jump, laststart, b + 3, b); + b += 3; break; + } + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at <jump count> <upper bound> + set_number_at <succeed_n count> <lower bound> + succeed_n <after jump addr> <succed_n count> + <body of loop> + jump_n <succeed_n addr> <jump count> + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ { /* If the upper bound is > 1, we need to insert more at the end of the loop. */ - unsigned slots_needed = upper_bound == 1 ? 5 : 10; + unsigned nbytes = upper_bound == 1 ? 10 : 20; - GET_BUFFER_SPACE(5); + GET_BUFFER_SPACE(nbytes); /* Initialize lower bound of the `succeed_n', even though it will be set during matching by its attendant `set_number_at' (inserted next), because `re_compile_fastmap' needs to know. Jump to the `jump_n' we might insert below. */ - insert_jump_n(succeed_n, laststart, b + slots_needed, + insert_jump_n(succeed_n, laststart, b + (nbytes/2), b, lower_bound); b += 5; /* Just increment for the succeed_n here. */ @@ -1557,7 +1811,6 @@ re_compile_pattern(pattern, size, bufp) before the `succeed_n'. The `5' is the last two bytes of this `set_number_at', plus 3 bytes of the following `succeed_n'. */ - GET_BUFFER_SPACE(5); insert_op_2(set_number_at, laststart, b, 5, lower_bound); b += 5; @@ -1570,7 +1823,8 @@ re_compile_pattern(pattern, size, bufp) we'll have matched the interval once, so jump back only `upper_bound - 1' times. */ GET_BUFFER_SPACE(5); - store_jump_n(b, greedy?jump_n:finalize_push_n, laststart + 5, upper_bound - 1); + store_jump_n(b, greedy?jump_n:finalize_push_n, laststart + 5, + upper_bound - 1); b += 5; /* The location we want to set is the second @@ -1587,19 +1841,22 @@ re_compile_pattern(pattern, size, bufp) We insert this at the beginning of the loop so that if we fail during matching, we'll reinitialize the bounds. */ - GET_BUFFER_SPACE(5); - insert_op_2(set_number_at, laststart, b, b - laststart, upper_bound - 1); + insert_op_2(set_number_at, laststart, b, b - laststart, + upper_bound - 1); b += 5; - - GET_BUFFER_SPACE(5); - BUFPUSH(set_number_at); - STORE_NUMBER_AND_INCR(b, -5); - STORE_NUMBER_AND_INCR(b, upper_bound - 1); } - pending_exact = 0; } break; + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + p = beg_interval; + beg_interval = 0; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + goto normal_char; + case '\\': if (p == pend) goto invalid_pattern; /* Do not translate the character after the \, so that we can @@ -1612,8 +1869,8 @@ re_compile_pattern(pattern, size, bufp) case 'S': case 'd': case 'D': - while (b - bufp->buffer - > bufp->allocated - 9 - (1 << BYTEWIDTH) / BYTEWIDTH) + while (b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH + > bufp->allocated) EXTEND_BUFFER; laststart = b; @@ -1641,12 +1898,12 @@ re_compile_pattern(pattern, size, bufp) } } - while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) b[-1]--; if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH) memmove(&b[b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH], - 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*4); - b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[b[-1]])*4; + 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8); + b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[b[-1]])*8; break; case 'w': @@ -1680,25 +1937,25 @@ re_compile_pattern(pattern, size, bufp) break; case 'Z': + BUFPUSH(endbuf2); + break; + + case 'z': BUFPUSH(endbuf); break; /* hex */ case 'x': - c1 = 0; + had_mbchar = 0; c = scan_hex(p, 2, &numlen); p += numlen; - if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f) - c1 = 0xff; goto numeric_char; /* octal */ case '0': - c1 = 0; + had_mbchar = 0; c = scan_oct(p, 3, &numlen); p += numlen; - if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f) - c1 = 0xff; goto numeric_char; /* back-ref or octal */ @@ -1711,18 +1968,16 @@ re_compile_pattern(pattern, size, bufp) PATUNFETCH; p_save = p; - c1 = 0; + had_mbchar = 0; GET_UNSIGNED_NUMBER(c1); - if (p < pend) PATUNFETCH; + if (!ISDIGIT(c)) PATUNFETCH; if (c1 >= regnum) { /* need to get octal */ p = p_save; - c = scan_oct(p_save, 3, &numlen); + c = scan_oct(p_save, 3, &numlen) & 0xff; p = p_save + numlen; c1 = 0; - if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f) - c1 = 0xff; goto numeric_char; } } @@ -1737,64 +1992,135 @@ re_compile_pattern(pattern, size, bufp) break; default: - normal_backsl: goto normal_char; } break; + case '#': + if (options & RE_OPTION_EXTENDED) + { + while (p != pend) { + PATFETCH(c); + if (c == '\n') break; + } + break; + } + goto normal_char; + + case ' ': + case '\t': + case '\f': + case '\r': + case '\n': + if (options & RE_OPTION_EXTENDED) + break; + default: normal_char: /* Expects the character in `c'. */ - c1 = 0; + had_mbchar = 0; if (ismbchar(c)) { - c1 = c; - PATFETCH(c); - } - else if (c > 0x7f) { - c1 = 0xff; + had_mbchar = 0; + c1 = p - pattern; } numeric_char: if (!pending_exact || pending_exact + *pending_exact + 1 != b || *pending_exact >= (c1 ? 0176 : 0177) || *p == '+' || *p == '?' || *p == '*' || *p == '^' - || *p == '{') - { - laststart = b; - BUFPUSH(exactn); - pending_exact = b; - BUFPUSH(0); - } - if (c1) { - BUFPUSH(c1); + || *p == '{') { + laststart = b; + BUFPUSH(exactn); + pending_exact = b; + BUFPUSH(0); + } + if (!had_mbchar && c > 0x7f) { + BUFPUSH(0xff); (*pending_exact)++; } BUFPUSH(c); (*pending_exact)++; + if (had_mbchar) { + int len = ismbchar(c); + while (len--) { + PATFETCH_RAW(c); + BUFPUSH(c); + (*pending_exact)++; + } + } } } - if (fixup_jump) - store_jump(fixup_jump, jump, b); - - if (stackp != stackb) goto unmatched_open; + if (fixup_alt_jump) + store_jump(fixup_alt_jump, jump, b); + + if (stackp != stackb) + FREE_AND_RETURN(stackb, "unmatched ("); + + /* set optimize flags */ + laststart = bufp->buffer; + if (laststart != b) { + if (*laststart == start_memory) laststart += 3; + if (*laststart == dummy_failure_jump) laststart += 3; + else if (*laststart == try_next) laststart += 3; + if (*laststart == on_failure_jump) { + int mcnt; + + laststart++; + EXTRACT_NUMBER_AND_INCR(mcnt, laststart); + if (mcnt == 4 && *laststart == anychar) { + bufp->options |= RE_OPTIMIZE_ANCHOR; + } + else if (*laststart == charset || *laststart == charset_not) { + p0 = laststart; + mcnt = *++p0 ; + p0 += mcnt+1; + mcnt = EXTRACT_UNSIGNED_AND_INCR(p0); + p0 += 8*mcnt; + if (*p0 == maybe_finalize_jump) { + bufp->stclass = laststart; + } + } + } + } bufp->used = b - bufp->buffer; bufp->re_nsub = regnum; - bufp->must = calculate_must_string(bufp->buffer, b); - FREE_AND_RETURN(stackb, 0); + laststart = bufp->buffer; + if (laststart != b) { + if (*laststart == start_memory) laststart += 3; + if (*laststart == exactn) { + bufp->options |= RE_OPTIMIZE_EXACTN; + bufp->must = laststart+1; + } + } + else { + bufp->must = calculate_must_string(bufp->buffer, b); + } + if (current_mbctype == MBCTYPE_SJIS) bufp->options |= RE_OPTIMIZE_NO_BM; + else if (bufp->must) { + int i; + int len = (unsigned char)bufp->must[0]; + + for (i=1; i<len; i++) { + if ((unsigned char)bufp->must[i] == 0xff || + (current_mbctype && ismbchar(bufp->must[i]))) { + bufp->options |= RE_OPTIMIZE_NO_BM; + break; + } + } + if (!(bufp->options & RE_OPTIMIZE_NO_BM)) { + bufp->must_skip = (int *) xmalloc((1 << BYTEWIDTH)*sizeof(int)); + bm_init_skip(bufp->must_skip, bufp->must+1, + (unsigned char)bufp->must[0], + MAY_TRANSLATE()?translate:0); + } + } - invalid_char: - FREE_AND_RETURN(stackb, "invalid character in regular expression"); + FREE_AND_RETURN(stackb, 0); invalid_pattern: FREE_AND_RETURN(stackb, "invalid regular expression"); - unmatched_open: - FREE_AND_RETURN(stackb, "unmatched ("); - - unmatched_close: - FREE_AND_RETURN(stackb, "unmatched )"); - end_of_pattern: FREE_AND_RETURN(stackb, "premature end of regular expression"); @@ -1808,6 +2134,15 @@ re_compile_pattern(pattern, size, bufp) FREE_AND_RETURN(stackb, "nested *?+ in regexp"); } +void +re_free_pattern(bufp) + struct re_pattern_buffer *bufp; +{ + free(bufp->buffer); + free(bufp->fastmap); + if (bufp->must_skip) free(bufp->must_skip); + free(bufp); +} /* Store a jump of the form <OPCODE> <relative address>. Store in the location FROM a jump operation to jump to relative @@ -1933,7 +2268,7 @@ insert_op_2(op, there, current_end, num_1, num_2) #define trans_eq(c1, c2, translate) (translate?(translate[c1]==translate[c2]):((c1)==(c2))) static int -must_match(little, lend, big, bend, translate) +slow_match(little, lend, big, bend, translate) unsigned char *little, *lend; unsigned char *big, *bend; unsigned char *translate; @@ -1942,10 +2277,8 @@ must_match(little, lend, big, bend, translate) while (little < lend && big < bend) { c = *little++; - if (c == 0xff) { - if (!trans_eq(*big++, *little++, translate)) break; - continue; - } + if (c == 0xff) + c = *little++; if (!trans_eq(*big++, c, translate)) break; } if (little == lend) return 1; @@ -1953,23 +2286,21 @@ must_match(little, lend, big, bend, translate) } static int -must_instr(little, llen, big, blen, translate) +slow_search(little, llen, big, blen, translate) unsigned char *little; int llen; unsigned char *big; int blen; char *translate; { + unsigned char *bsave = big; unsigned char *bend = big + blen; register int c; int fescape = 0; - if (blen < llen) - return 0; - c = *little; if (c == 0xff) { - c = *++little; + c = little[1]; fescape = 1; } else if (translate && !ismbchar(c)) { @@ -1984,30 +2315,93 @@ must_instr(little, llen, big, blen, translate) big++; } } - else if (translate && !ismbchar(c)) { - while (big < bend) { - if (ismbchar(*big)) big++; - else if (translate[*big] == c) break; - big++; + else if (translate && !ismbchar(c)) { + while (big < bend) { + if (ismbchar(*big)) big+=ismbchar(*big); + else if (translate[*big] == c) break; + big++; + } + } + else { + while (big < bend) { + if (*big == c) break; + if (ismbchar(*big)) big+=ismbchar(*big); + big++; + } + } + + if (slow_match(little, little+llen, big, bend, translate)) + return big - bsave; + + if (ismbchar(*big)) big+=ismbchar(*big); + big++; + } + return -1; +} + +static void +bm_init_skip(skip, pat, m, translate) + int *skip; + unsigned char *pat; + int m; + char *translate; +{ + int j, c; + + for (c=0; c<256; c++) { + skip[c] = m; + } + if (translate) { + for (j=0; j<m-1; j++) { + skip[translate[pat[j]]] = m-1-j; } } else { - while (big < bend) { - if (*big == c) break; - if (ismbchar(*big)) big++; - big++; + for (j=0; j<m-1; j++) { + skip[pat[j]] = m-1-j; } } +} - if (must_match(little, little+llen, big, bend, translate)) - return 1; +static int +bm_search(little, llen, big, blen, skip, translate) + unsigned char *little; + int llen; + unsigned char *big; + int blen; + int *skip; + unsigned char *translate; +{ + int i, j, k; + + i = llen-1; + if (translate) { + while (i < blen) { + k = i; + j = llen-1; + while (j >= 0 && translate[big[k]] == translate[little[j]]) { + k--; + j--; + } + if (j < 0) return k+1; - if (ismbchar(*big)) big++; - big++; + i += skip[translate[big[i]]]; + } + return -1; } - return 0; -} + while (i < blen) { + k = i; + j = llen-1; + while (j >= 0 && big[k] == little[j]) { + k--; + j--; + } + if (j < 0) return k+1; + i += skip[big[i]]; + } + return -1; +} /* Given a pattern, compute a fastmap from it. The fastmap records which of the (1 << BYTEWIDTH) possible characters can start a string @@ -2021,18 +2415,18 @@ void re_compile_fastmap(bufp) struct re_pattern_buffer *bufp; { - unsigned char *pattern = (unsigned char *) bufp->buffer; + unsigned char *pattern = (unsigned char*)bufp->buffer; int size = bufp->used; register char *fastmap = bufp->fastmap; register unsigned char *p = pattern; register unsigned char *pend = pattern + size; register int j, k; - unsigned char *translate = (unsigned char *)bufp->translate; unsigned is_a_succeed_n; unsigned char **stackb = RE_TALLOC(NFAILURES, unsigned char*); unsigned char **stackp = stackb; unsigned char **stacke = stackb + NFAILURES; + int options = bufp->options; memset(fastmap, 0, (1 << BYTEWIDTH)); bufp->fastmap_accurate = 1; @@ -2047,19 +2441,19 @@ re_compile_fastmap(bufp) break; } #ifdef SWITCH_ENUM_BUG - switch ((int) ((enum regexpcode)*p++)) + switch ((int)((enum regexpcode)*p++)) #else switch ((enum regexpcode)*p++) #endif { case exactn: if (p[1] == 0xff) { - if (translate) - fastmap[translate[p[2]]] = 2; - else - fastmap[p[2]] = 2; + if (TRANSLATE_P()) + fastmap[translate[p[2]]] = 2; + else + fastmap[p[2]] = 2; } - else if (translate) + else if (TRANSLATE_P()) fastmap[translate[p[1]]] = 1; else fastmap[p[1]] = 1; @@ -2068,15 +2462,24 @@ re_compile_fastmap(bufp) case begline: case begbuf: case endbuf: + case endbuf2: case wordbound: case notwordbound: case wordbeg: case wordend: case pop_and_fail: + case push_dummy_failure: + case stop_paren: + continue; + + case casefold_on: + bufp->options |= RE_MAY_IGNORECASE; + case casefold_off: + options ^= RE_OPTION_IGNORECASE; continue; case endline: - if (translate) + if (TRANSLATE_P()) fastmap[translate['\n']] = 1; else fastmap['\n'] = 1; @@ -2089,6 +2492,7 @@ re_compile_fastmap(bufp) case finalize_jump: case maybe_finalize_jump: case jump: + case jump_past_alt: case dummy_failure_jump: EXTRACT_NUMBER_AND_INCR(j, p); p += j; @@ -2101,10 +2505,11 @@ re_compile_fastmap(bufp) For a * loop, it has pushed its failure point already; If so, discard that as redundant. */ - if ((enum regexpcode) *p != on_failure_jump - && (enum regexpcode) *p != try_next - && (enum regexpcode) *p != finalize_push - && (enum regexpcode) *p != finalize_push_n) + if ((enum regexpcode)*p != on_failure_jump + && (enum regexpcode)*p != try_next + && (enum regexpcode)*p != succeed_n + && (enum regexpcode)*p != finalize_push + && (enum regexpcode)*p != finalize_push_n) continue; p++; EXTRACT_NUMBER_AND_INCR(j, p); @@ -2162,7 +2567,7 @@ re_compile_fastmap(bufp) case start_memory: case stop_memory: - p++; + p += 2; continue; case duplicate: @@ -2181,17 +2586,48 @@ re_compile_fastmap(bufp) break; case wordchar: - for (j = 0; j < (1 << BYTEWIDTH); j++) + for (j = 0; j < 0x80; j++) { if (SYNTAX(j) == Sword) fastmap[j] = 1; + } + switch (current_mbctype) { + case MBCTYPE_ASCII: + for (j = 0x80; j < (1 << BYTEWIDTH); j++) { + if (SYNTAX(j) == Sword2) + fastmap[j] = 1; + } + break; + case MBCTYPE_EUC: + case MBCTYPE_SJIS: + case MBCTYPE_UTF8: + for (j = 0x80; j < (1 << BYTEWIDTH); j++) { + if (re_mbctab[j]) + fastmap[j] = 1; + } + break; + } break; case notwordchar: for (j = 0; j < 0x80; j++) if (SYNTAX(j) != Sword) fastmap[j] = 1; - for (j = 0x80; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; + switch (current_mbctype) { + case MBCTYPE_ASCII: + for (j = 0x80; j < (1 << BYTEWIDTH); j++) { + if (SYNTAX(j) != Sword2) + fastmap[j] = 1; + } + break; + case MBCTYPE_EUC: + case MBCTYPE_SJIS: + case MBCTYPE_UTF8: + for (j = 0x80; j < (1 << BYTEWIDTH); j++) { + if (!re_mbctab[j]) + fastmap[j] = 1; + } + break; + } break; case charset: @@ -2200,35 +2636,28 @@ re_compile_fastmap(bufp) for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) { - if (translate) - fastmap[translate[j]] = 1; - else - fastmap[j] = 1; + if (TRANSLATE_P()) + j = translate[j]; + fastmap[j] = (j>0x7f?2:1); } { unsigned short size; - unsigned c, end; + unsigned int c, beg, end; p += p[-1] + 2; size = EXTRACT_UNSIGNED(&p[-2]); for (j = 0; j < (int)size; j++) { - if ((unsigned char)p[j*4] == 0xff) { - for (c = (unsigned char)p[j*4+1], - end = (unsigned char)p[j*4+3]; - c <= end; c++) { - fastmap[c] = 2; - } - } - else { - /* set bits for 1st bytes of multi-byte chars. */ - for (c = (unsigned char)p[j*4], - end = (unsigned char)p[j*4 + 2]; - c <= end; c++) { - /* NOTE: Charset for multi-byte chars might contain - single-byte chars. We must reject them. */ - if (ismbchar(c)) - fastmap[c] = 1; - } + c = EXTRACT_MBC(&p[j*8]); + beg = WC2MBC1ST(c); + c = EXTRACT_MBC(&p[j*8+4]); + end = WC2MBC1ST(c); + /* set bits for 1st bytes of multi-byte chars. */ + while (beg <= end) { + /* NOTE: Charset for multi-byte chars might contain + single-byte chars. We must reject them. */ + if (ismbchar(beg)) + fastmap[beg] = 1; + beg++; } } } @@ -2256,30 +2685,39 @@ re_compile_fastmap(bufp) if (!ismbchar(j)) fastmap[j] = 1; } + if (current_mbctype) { + for (j = 0x80; j < (1 << BYTEWIDTH); j++) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 2; + } { unsigned short size; - unsigned char c, beg; + unsigned int c, beg, end; p += p[-1] + 2; size = EXTRACT_UNSIGNED(&p[-2]); if (size == 0) { - for (j = 0x80; j < (1 << BYTEWIDTH); j++) - if (ismbchar(j)) - fastmap[j] = 1; + for (j = 0x80; j < (1 << BYTEWIDTH); j++) + if (ismbchar(j)) + fastmap[j] = 1; + break; } for (j = 0,c = 0x80;j < (int)size; j++) { - if ((unsigned char)p[j*4] == 0xff) { - for (beg = (unsigned char)p[j*4+1]; c < beg; c++) - fastmap[c] = 2; - c = (unsigned char)p[j*4+3] + 1; - } - else { - for (beg = (unsigned char)p[j*4 + 0]; c < beg; c++) - if (ismbchar(c)) - fastmap[c] = 1; - c = (unsigned char)p[j*4 + 2] + 1; + int cc = EXTRACT_MBC(&p[j*8]); + beg = WC2MBC1ST(cc); + while (c < beg) { + if (ismbchar(c)) + fastmap[c] = 1; + c++; } + + cc = EXTRACT_MBC(&p[j*8+4]); + c = WC2MBC1ST(cc) + 1; } + + for (j = c; j < (1 << BYTEWIDTH); j++) + if (ismbchar(j)) + fastmap[j] = 1; } break; @@ -2316,17 +2754,21 @@ int re_search(bufp, string, size, startpos, range, regs) struct re_pattern_buffer *bufp; char *string; - int size, startpos, range; + size_t size, startpos, range; struct re_registers *regs; { register char *fastmap = bufp->fastmap; - register unsigned char *translate = (unsigned char *) bufp->translate; int val, anchor = 0; /* Check for out-of-range starting position. */ if (startpos < 0 || startpos > size) return -1; + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) { + re_compile_fastmap(bufp); + } + /* If the search isn't to be a backwards one, don't waste time in a search for a pattern that must be anchored. */ if (bufp->used>0) { @@ -2335,16 +2777,13 @@ re_search(bufp, string, size, startpos, range, regs) if (range > 0) { if (startpos > 0) return -1; - else - return re_match(bufp, string, size, 0, regs); + else if (re_match(bufp, string, size, 0, regs) >= 0) + return 0; + return -1; } break; case begline: - if (startpos == 0) { - val = re_match(bufp, string, size, 0, regs); - if (val >= 0) return 0; - } anchor = 1; break; @@ -2352,18 +2791,36 @@ re_search(bufp, string, size, startpos, range, regs) break; } } -#if 1 - if (range > 0 - && bufp->must - && !must_instr(bufp->must+1, bufp->must[0], - string+startpos, size-startpos, - translate)) { - return -1; + if (bufp->options & RE_OPTIMIZE_ANCHOR) { + anchor = 1; } -#endif - /* Update the fastmap now if not correct already. */ - if (fastmap && !bufp->fastmap_accurate) { - re_compile_fastmap(bufp); + + if (bufp->must) { + int len = ((unsigned char*)bufp->must)[0]; + int pos, pbeg, pend; + + pbeg = startpos; + pend = startpos + range; + if (pbeg > pend) { /* swap pbeg,pend */ + pos = pend; pend = pbeg; pbeg = pos; + } + if (pend > size) pend = size; + if (bufp->options & RE_OPTIMIZE_NO_BM) { + pos = slow_search(bufp->must+1, len, + string+pbeg, pend-pbeg, + MAY_TRANSLATE()?translate:0); + } + else { + pos = bm_search(bufp->must+1, len, + string+pbeg, pend-pbeg, + bufp->must_skip, + MAY_TRANSLATE()?translate:0); + } + if (pos == -1) return -1; + if (range > 0 && (bufp->options & RE_OPTIMIZE_EXACTN)) { + startpos += pos; + range -= pos; + } } for (;;) @@ -2382,7 +2839,7 @@ re_search(bufp, string, size, startpos, range, regs) register unsigned char *p, c; int irange = range; - p = (unsigned char *)string+startpos; + p = (unsigned char*)string+startpos; while (range > 0) { c = *p++; @@ -2395,7 +2852,7 @@ re_search(bufp, string, size, startpos, range, regs) break; } else - if (fastmap[translate ? translate[c] : c]) + if (fastmap[MAY_TRANSLATE() ? translate[c] : c]) break; range--; } @@ -2407,17 +2864,16 @@ re_search(bufp, string, size, startpos, range, regs) c = string[startpos]; c &= 0xff; - if (translate ? !fastmap[translate[c]] : !fastmap[c]) + if (MAY_TRANSLATE() ? !fastmap[translate[c]] : !fastmap[c]) goto advance; } } - if (anchor && startpos > 0 && startpos < size - && string[startpos-1] != '\n') goto advance; - + if (startpos > size) return -1; + if (anchor && size > 0 && startpos == size) return -1; if (fastmap && startpos == size && range >= 0 && (bufp->can_be_null == 0 || - (bufp->can_be_null == 2 && size > 0 + (bufp->can_be_null && size > 0 && string[startpos-1] == '\n'))) return -1; @@ -2428,11 +2884,44 @@ re_search(bufp, string, size, startpos, range, regs) return -2; #ifndef NO_ALLOCA -#ifdef cALLOCA +#ifdef C_ALLOCA alloca(0); -#endif /* cALLOCA */ +#endif /* C_ALLOCA */ #endif /* NO_ALLOCA */ + if (range > 0) { + if (anchor && startpos < size && startpos > 0 && string[startpos-1] != '\n') { + while (range > 0 && string[startpos] != '\n') { + range--; + startpos++; + } + } + else if (fastmap && (bufp->stclass)) { + register unsigned char *p; + unsigned int c; + int irange = range; + + p = (unsigned char*)string+startpos; + while (range > 0) { + c = *p++; + if (ismbchar(c) && fastmap[c] != 2) { + MBC2WC(c, p); + } + else if (MAY_TRANSLATE()) + c = translate[c]; + if (*bufp->stclass == charset) { + if (!is_in_list(c, bufp->stclass+1)) break; + } + else { + if (is_in_list(c, bufp->stclass+1)) break; + } + range--; + if (c > 256) range--; + } + startpos += irange - range; + } + } + advance: if (!range) break; @@ -2440,7 +2929,7 @@ re_search(bufp, string, size, startpos, range, regs) const char *d = string + startpos; if (ismbchar(*d)) { - range--, startpos++; + range-=ismbchar(*d), startpos+=ismbchar(*d); if (!range) break; } @@ -2483,56 +2972,66 @@ int re_max_failures = 2000; /* Structure and accessing macros used in re_match: */ -struct register_info +typedef union { - unsigned is_active : 1; - unsigned matched_something : 1; -}; - -#define IS_ACTIVE(R) ((R).is_active) -#define MATCHED_SOMETHING(R) ((R).matched_something) + unsigned char *word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) /* Macros used by re_match: */ /* I.e., regstart, regend, and reg_info. */ - #define NUM_REG_ITEMS 3 +/* Individual items aside from the registers. */ +#define NUM_NONREG_ITEMS 3 + /* We push at most this many things on the stack whenever we fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are arguments to the PUSH_FAILURE_POINT macro. */ - -#define MAX_NUM_FAILURE_ITEMS (num_regs * NUM_REG_ITEMS + 2) - +#define MAX_NUM_FAILURE_ITEMS (num_regs * NUM_REG_ITEMS + NUM_NONREG_ITEMS) /* We push this many things on the stack whenever we fail. */ - -#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + 2) +#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + NUM_REG_ITEMS) /* This pushes most of the information about the current state we will want if we ever fail back to it. */ #define PUSH_FAILURE_POINT(pattern_place, string_place) \ - { \ + do { \ long last_used_reg, this_reg; \ \ /* Find out how many registers are active or have been matched. \ (Aside from register zero, which is only set at the end.) */ \ for (last_used_reg = num_regs - 1; last_used_reg > 0; last_used_reg--)\ - if (regstart[last_used_reg] != (unsigned char *)(-1L)) \ + if (!REG_UNSET(regstart[last_used_reg])) \ break; \ \ if (stacke - stackp <= NUM_FAILURE_ITEMS) \ { \ unsigned char **stackx; \ unsigned int len = stacke - stackb; \ - if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \ + /* if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \ { \ FREE_VARIABLES(); \ FREE_AND_RETURN(stackb,(-2)); \ - } \ + }*/ \ \ /* Roughly double the size of the stack. */ \ EXPAND_FAIL_STACK(stackx, stackb, len); \ @@ -2543,28 +3042,32 @@ struct register_info { \ *stackp++ = regstart[this_reg]; \ *stackp++ = regend[this_reg]; \ - *stackp++ = (unsigned char *)®_info[this_reg]; \ + *stackp++ = reg_info[this_reg].word; \ } \ \ /* Push how many registers we saved. */ \ - *stackp++ = (unsigned char *)last_used_reg; \ + *stackp++ = (unsigned char*)last_used_reg; \ \ *stackp++ = pattern_place; \ *stackp++ = string_place; \ - *stackp++ = (unsigned char *)0; /* non-greedy flag */ \ - } + *stackp++ = (unsigned char*)0; /* non-greedy flag */ \ + } while(0) /* This pops what PUSH_FAILURE_POINT pushes. */ #define POP_FAILURE_POINT() \ - { \ + do { \ int temp; \ - stackp -= 3; /* Remove failure points (and flag). */ \ - temp = (int) *--stackp; /* How many regs pushed. */ \ + stackp -= NUM_NONREG_ITEMS; /* Remove failure points (and flag). */ \ + temp = (int)*--stackp; /* How many regs pushed. */ \ temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \ stackp -= temp; /* Remove the register info. */ \ - } + } while(0) + +/* Registers are set to a sentinel when they haven't yet matched. */ +#define REG_UNSET_VALUE ((unsigned char*)-1) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) #define PREFETCH if (d == dend) goto fail @@ -2572,21 +3075,20 @@ struct register_info registers corresponding to the subexpressions of which we currently are inside. */ #define SET_REGS_MATCHED \ - { unsigned this_reg; \ + do { unsigned this_reg; \ for (this_reg = 0; this_reg < num_regs; this_reg++) \ { \ if (IS_ACTIVE(reg_info[this_reg])) \ - MATCHED_SOMETHING(reg_info[this_reg]) = 1; \ + MATCHED_SOMETHING(reg_info[this_reg]) \ + = EVER_MATCHED_SOMETHING (reg_info[this_reg]) \ + = 1; \ else \ MATCHED_SOMETHING(reg_info[this_reg]) = 0; \ } \ - } + } while(0) #define AT_STRINGS_BEG(d) (d == string) -#define AT_STRINGS_END(d) (d == dend) - -#define AT_WORD_BOUNDARY(d) \ - (AT_STRINGS_BEG(d) || AT_STRINGS_END(d) || IS_A_LETTER(d - 1) != IS_A_LETTER(d)) +#define AT_STRINGS_END(d) (d == dend) /* We have two special cases to check for: 1) if we're past the end of string1, we have to look at the first @@ -2594,12 +3096,15 @@ struct register_info 2) if we're before the beginning of string2, we have to look at the last character in string1; we assume there is a string1, so use this in conjunction with AT_STRINGS_BEG. */ -#define IS_A_LETTER(d) (SYNTAX(*(d)) == Sword) +#define IS_A_LETTER(d) (SYNTAX(*(d)) == Sword || \ + (current_mbctype ? \ + re_mbctab[*(d)] == 1 : \ + SYNTAX(*(d)) == Sword2)) static void init_regs(regs, num_regs) struct re_registers *regs; - unsigned num_regs; + unsigned int num_regs; { int i; @@ -2640,22 +3145,22 @@ int re_match(bufp, string_arg, size, pos, regs) struct re_pattern_buffer *bufp; char *string_arg; - int size, pos; + size_t size, pos; struct re_registers *regs; { - register unsigned char *p = (unsigned char *) bufp->buffer; + register unsigned char *p = (unsigned char*)bufp->buffer; + unsigned char *p1; /* Pointer to beyond end of buffer. */ register unsigned char *pend = p + bufp->used; unsigned num_regs = bufp->re_nsub; - unsigned char *string = (unsigned char *) string_arg; + unsigned char *string = (unsigned char*)string_arg; register unsigned char *d, *dend; register int mcnt; /* Multipurpose. */ - unsigned char *translate = (unsigned char *) bufp->translate; - unsigned is_a_jump_n = 0; + int options = bufp->options; /* Failure point stack. Each place that can handle a failure further down the line pushes a failure point on this stack. It consists of @@ -2683,6 +3188,14 @@ re_match(bufp, string_arg, size, pos, regs) unsigned char **regstart = RE_TALLOC(num_regs, unsigned char*); unsigned char **regend = RE_TALLOC(num_regs, unsigned char*); + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ + unsigned char **old_regstart = RE_TALLOC(num_regs, unsigned char*); + unsigned char **old_regend = RE_TALLOC(num_regs, unsigned char*); + /* The is_active field of reg_info helps us keep track of which (possibly nested) subexpressions we are currently in. The matched_something field of reg_info[reg_num] helps us tell whether or not we have @@ -2690,7 +3203,7 @@ re_match(bufp, string_arg, size, pos, regs) subexpression. These two fields get reset each time through any loop their register is in. */ - struct register_info *reg_info = RE_TALLOC(num_regs, struct register_info); + register_info_type *reg_info = RE_TALLOC(num_regs, register_info_type); /* The following record the register info as found in the above variables when we find a match better than any we've seen before. @@ -2715,13 +3228,20 @@ re_match(bufp, string_arg, size, pos, regs) #endif /* Initialize subexpression text positions to -1 to mark ones that no - \( or ( and \) or ) has been seen for. Also set all registers to + ( or ( and ) or ) has been seen for. Also set all registers to inactive and mark them as not having matched anything or ever failed. */ for (mcnt = 0; mcnt < num_regs; mcnt++) { - regstart[mcnt] = regend[mcnt] = (unsigned char *) (-1L); - IS_ACTIVE(reg_info[mcnt]) = 0; - MATCHED_SOMETHING(reg_info[mcnt]) = 0; + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] + = best_regstart[mcnt] = best_regend[mcnt] = REG_UNSET_VALUE; +#ifdef __CHECKER__ + reg_info[mcnt].word = 0; +#endif + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; } /* Set up pointers to ends of strings. @@ -2747,19 +3267,20 @@ re_match(bufp, string_arg, size, pos, regs) #ifdef DEBUG_REGEX fprintf(stderr, "regex loop(%d): matching 0x%02d\n", - p - (unsigned char *) bufp->buffer, + p - (unsigned char*)bufp->buffer, *p); #endif - is_a_jump_n = 0; /* End of pattern means we might have succeeded. */ if (p == pend) { /* If not end of string, try backtracking. Otherwise done. */ if (d != dend) { + while (stackp != stackb && (int)stackp[-1] == 1) + POP_FAILURE_POINT(); if (stackp != stackb) { - /* More failure points to try. */ + /* More failure points to try. */ /* If exceeds best match so far, save it. */ if (! best_regs_set || (d > best_regend[0])) @@ -2798,7 +3319,7 @@ re_match(bufp, string_arg, size, pos, regs) regs->end[0] = d - string; for (mcnt = 1; mcnt < num_regs; mcnt++) { - if (regend[mcnt] == (unsigned char *)(-1L)) + if (REG_UNSET(regend[mcnt])) { regs->beg[mcnt] = -1; regs->end[mcnt] = -1; @@ -2820,58 +3341,110 @@ re_match(bufp, string_arg, size, pos, regs) #endif { - /* \( [or `(', as appropriate] is represented by start_memory, - \) by stop_memory. Both of those commands are followed by + /* ( [or `(', as appropriate] is represented by start_memory, + ) by stop_memory. Both of those commands are followed by a register number in the next byte. The text matched - within the \( and \) is recorded under that number. */ + within the ( and ) is recorded under that number. */ case start_memory: + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; regstart[*p] = d; IS_ACTIVE(reg_info[*p]) = 1; MATCHED_SOMETHING(reg_info[*p]) = 0; - p++; + p += 2; continue; case stop_memory: + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + regend[*p] = d; IS_ACTIVE(reg_info[*p]) = 0; /* If just failed to match something this time around with a sub- expression that's in a loop, try to force exit from the loop. */ - if ((! MATCHED_SOMETHING(reg_info[*p]) - || (enum regexpcode) p[-3] == start_memory) - && (p + 1) != pend) + if ((p + 1) != pend && + (! MATCHED_SOMETHING(reg_info[*p]) + || (enum regexpcode)p[-3] == start_memory)) { - register unsigned char *p2 = p + 1; + p1 = p + 2; mcnt = 0; - switch (*p2++) + switch (*p1++) { case jump_n: - is_a_jump_n = 1; + case finalize_push_n: case finalize_jump: case maybe_finalize_jump: case jump: case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p2); - if (is_a_jump_n) - p2 += 2; + EXTRACT_NUMBER_AND_INCR(mcnt, p1); break; } - p2 += mcnt; + p1 += mcnt; /* If the next operation is a jump backwards in the pattern to an on_failure_jump, exit from the loop by forcing a failure after pushing on the stack the on_failure_jump's jump in the pattern, and d. */ - if (mcnt < 0 && (enum regexpcode) *p2++ == on_failure_jump) + if (mcnt < 0 && (enum regexpcode)*p1 == on_failure_jump + && (enum regexpcode)p1[3] == start_memory && p1[4] == *p) { - EXTRACT_NUMBER_AND_INCR(mcnt, p2); - PUSH_FAILURE_POINT(p2 + mcnt, d); + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if ((int)old_regend[r] >= (int)regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR(mcnt, p1); + PUSH_FAILURE_POINT(p1 + mcnt, d); goto fail; } } - p++; + p += 2; continue; + case stop_paren: + break; + /* \<digit> has been turned into a `duplicate' command which is followed by the numeric value of <digit> as the register number. */ case duplicate: @@ -2879,8 +3452,11 @@ re_match(bufp, string_arg, size, pos, regs) int regno = *p++; /* Get which register to match against */ register unsigned char *d2, *dend2; + if (IS_ACTIVE(reg_info[regno])) break; + /* Where in input to try to start matching. */ d2 = regstart[regno]; + if (REG_UNSET(d2)) break; /* Where to stop matching; if both the place to start and the place to stop matching are in the same string, then @@ -2888,6 +3464,7 @@ re_match(bufp, string_arg, size, pos, regs) the end of the first string. */ dend2 = regend[regno]; + if (REG_UNSET(dend2)) break; for (;;) { /* At end of register contents => success */ @@ -2906,9 +3483,9 @@ re_match(bufp, string_arg, size, pos, regs) /* Compare that many; failure if mismatch, else move past them. */ - if (translate - ? memcmp_translate(d, d2, mcnt, translate) - : memcmp((char *)d, (char *)d2, mcnt)) + if ((options & RE_OPTION_IGNORECASE) + ? memcmp_translate(d, d2, mcnt) + : memcmp((char*)d, (char*)d2, mcnt)) goto fail; d += mcnt, d2 += mcnt; } @@ -2938,15 +3515,13 @@ re_match(bufp, string_arg, size, pos, regs) PREFETCH; /* Match anything but a newline, maybe even a null. */ if (ismbchar(*d)) { - if (d + 1 == dend || d[1] == '\n' || d[1] == '\0') + if (d + mbclen(*d) > dend || d[1] == '\n' || d[1] == '\0') goto fail; SET_REGS_MATCHED; - d += 2; + d += mbclen(*d); break; } - if ((translate ? translate[*d] : *d) == '\n' - || ((re_syntax_options & RE_DOT_NOT_NULL) - && (translate ? translate[*d] : *d) == '\000')) + if (((TRANSLATE_P()) ? translate[*d] : *d) == '\n') goto fail; SET_REGS_MATCHED; d++; @@ -2956,61 +3531,67 @@ re_match(bufp, string_arg, size, pos, regs) case charset_not: { int not; /* Nonzero for charset_not. */ - int half; /* 2 if need to match latter half of mbc */ - int c; + int part; /* 2 if matched part of mbc */ + unsigned char *dsave = d + 1; + int cc, c; PREFETCH; - c = (unsigned char)*d; + cc = c = (unsigned char)*d++; if (ismbchar(c)) { - if (d + 1 != dend) { - c <<= 8; - c |= (unsigned char)d[1]; + if (d + ismbchar(c) < dend) { + MBC2WC(c, d); } } - else if (translate) - c = (unsigned char)translate[c]; + else if (TRANSLATE_P()) + cc = c = (unsigned char)translate[c]; - half = not = is_in_list(c, p); + part = not = is_in_list(c, p); if (*(p - 1) == (unsigned char)charset_not) { not = !not; } - - p += 1 + *p + 2 + EXTRACT_UNSIGNED(&p[1 + *p])*4; - if (!not) goto fail; + + p += 1 + *p + 2 + EXTRACT_UNSIGNED(&p[1 + *p])*8; SET_REGS_MATCHED; - d++; - if (half != 2 && d != dend && c >= 1 << BYTEWIDTH) - d++; + if (part == 2) d = dsave; break; } case begline: if (size == 0 - || d == string + || AT_STRINGS_BEG(d) || (d && d[-1] == '\n')) break; else goto fail; case endline: - if (d == dend || *d == '\n') + if (AT_STRINGS_END(d) || *d == '\n') break; goto fail; - /* Match at the very beginning of the string. */ + /* Match at the very beginning of the string. */ case begbuf: if (AT_STRINGS_BEG(d)) break; goto fail; - /* Match at the very end of the data. */ + /* Match at the very end of the data. */ case endbuf: if (AT_STRINGS_END(d)) break; goto fail; + /* Match at the very end of the data. */ + case endbuf2: + if (AT_STRINGS_END(d)) + break; + /* .. or newline just before the end of the data. */ + if (*d == '\n' && AT_STRINGS_END(d+1)) + break; + goto fail; + /* `or' constructs are handled by starting each alternative with an on_failure_jump that points to the start of the next alternative. Each alternative except the last ends with a @@ -3039,13 +3620,31 @@ re_match(bufp, string_arg, size, pos, regs) EXTRACT_NUMBER_AND_INCR(mcnt, p); { register unsigned char *p2 = p; - /* Compare what follows with the beginning of the repeat. - If we can establish that there is nothing that they would - both match, we can change to finalize_jump. */ - while (p2 + 1 != pend - && (*p2 == (unsigned char)stop_memory - || *p2 == (unsigned char)start_memory)) - p2 += 2; /* Skip over reg number. */ + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. */ + while (p2 + 2 < pend) { + if ((enum regexpcode)*p2 == stop_memory || + (enum regexpcode)*p2 == start_memory) + p2 += 3; /* Skip over args, too. */ + else if ((enum regexpcode)*p2 == stop_paren) + p2 += 1; + else + break; + } + if (p2 == pend) p[-3] = (unsigned char)finalize_jump; else if (*p2 == (unsigned char)exactn @@ -3060,8 +3659,10 @@ re_match(bufp, string_arg, size, pos, regs) else if (p1[3] == (unsigned char)charset || p1[3] == (unsigned char)charset_not) { int not; - if (ismbchar(c)) - c = c << 8 | p2[3]; + if (ismbchar(c)) { + unsigned char *pp = p2+3; + MBC2WC(c, pp); + } /* `is_in_list()' is TRUE if c would match */ /* That means it is not safe to finalize. */ not = is_in_list(c, p1 + 4); @@ -3098,6 +3699,11 @@ re_match(bufp, string_arg, size, pos, regs) p += mcnt; continue; + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + goto nofinalize; + case dummy_failure_jump: /* Normally, the on_failure_jump pushes a failure point, which then gets popped at finalize_jump. We will end up at @@ -3107,6 +3713,17 @@ re_match(bufp, string_arg, size, pos, regs) PUSH_FAILURE_POINT(0, 0); goto nofinalize; + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `finalize_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT(0, 0); + break; + /* Have to succeed matching what follows at least n times. Then just handle like an on_failure_jump. */ case succeed_n: @@ -3143,15 +3760,11 @@ re_match(bufp, string_arg, size, pos, regs) continue; case set_number_at: - { - register unsigned char *p1; - - EXTRACT_NUMBER_AND_INCR(mcnt, p); - p1 = p + mcnt; - EXTRACT_NUMBER_AND_INCR(mcnt, p); - STORE_NUMBER(p1, mcnt); - continue; - } + EXTRACT_NUMBER_AND_INCR(mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR(mcnt, p); + STORE_NUMBER(p1, mcnt); + continue; case try_next: EXTRACT_NUMBER_AND_INCR(mcnt, p); @@ -3170,16 +3783,21 @@ re_match(bufp, string_arg, size, pos, regs) continue; case finalize_push_n: - EXTRACT_NUMBER(mcnt, p + 2); - /* Originally, this is how many times we CAN jump. */ + EXTRACT_NUMBER(mcnt, p + 2); + /* Originally, this is how many times we CAN jump. */ if (mcnt) { + int pos, i; + mcnt--; STORE_NUMBER(p + 2, mcnt); + EXTRACT_NUMBER(pos, p); + EXTRACT_NUMBER(i, p+pos+5); + if (i > 0) goto nofinalize; POP_FAILURE_POINT(); EXTRACT_NUMBER_AND_INCR(mcnt, p); PUSH_FAILURE_POINT(p + mcnt, d); stackp[-1] = (unsigned char*)1; - p += 7; /* skip n and set_number_at after destination */ + p += 2; /* skip n */ } /* If don't have to push any more, skip over the rest of command. */ else @@ -3191,13 +3809,37 @@ re_match(bufp, string_arg, size, pos, regs) case unused: continue; + case casefold_on: + options |= RE_OPTION_IGNORECASE; + continue; + + case casefold_off: + options &= ~RE_OPTION_IGNORECASE; + continue; + case wordbound: - if (AT_WORD_BOUNDARY(d)) + if (AT_STRINGS_BEG(d)) { + if (IS_A_LETTER(d)) break; + else goto fail; + } + if (AT_STRINGS_BEG(d)) { + if (IS_A_LETTER(d-1)) break; + else goto fail; + } + if (IS_A_LETTER(d - 1) != IS_A_LETTER(d)) break; goto fail; case notwordbound: - if (AT_WORD_BOUNDARY(d)) + if (AT_STRINGS_BEG(d)) { + if (IS_A_LETTER(d)) goto fail; + else break; + } + if (AT_STRINGS_END(d)) { + if (IS_A_LETTER(d-1)) goto fail; + else break; + } + if (IS_A_LETTER(d - 1) != IS_A_LETTER(d)) goto fail; break; @@ -3224,8 +3866,8 @@ re_match(bufp, string_arg, size, pos, regs) PREFETCH; if (IS_A_LETTER(d)) goto fail; - if (ismbchar(*d) && d + 1 != dend) - d++; + if (ismbchar(*d) && d + ismbchar(*d) < dend) + d += ismbchar(*d); d++; SET_REGS_MATCHED; break; @@ -3236,7 +3878,7 @@ re_match(bufp, string_arg, size, pos, regs) mcnt = *p++; /* This is written out as an if-else so we don't waste time testing `translate' inside the loop. */ - if (translate) + if (TRANSLATE_P()) { do { @@ -3247,7 +3889,7 @@ re_match(bufp, string_arg, size, pos, regs) if (*p == 0xff) { p++; if (!--mcnt - || d == dend + || AT_STRINGS_END(d) || (unsigned char)*d++ != (unsigned char)*p++) goto fail; continue; @@ -3256,7 +3898,7 @@ re_match(bufp, string_arg, size, pos, regs) if (c != (unsigned char)*p++ || !--mcnt /* redundant check if pattern was compiled properly. */ - || d == dend + || AT_STRINGS_END(d) || (unsigned char)*d++ != (unsigned char)*p++) goto fail; continue; @@ -3281,8 +3923,8 @@ re_match(bufp, string_arg, size, pos, regs) SET_REGS_MATCHED; break; } - if (stackp != stackb && (int)stackp[-1] == 1) - POP_FAILURE_POINT(); + while (stackp != stackb && (int)stackp[-1] == 1) + POP_FAILURE_POINT(); continue; /* Successfully executed one pattern command; keep going. */ /* Jump here if any matching operation fails. */ @@ -3302,13 +3944,13 @@ re_match(bufp, string_arg, size, pos, regs) d = *--stackp; p = *--stackp; /* Restore register info. */ - last_used_reg = (long) *--stackp; + last_used_reg = (long)*--stackp; /* Make the ones that weren't saved -1 or 0 again. */ for (this_reg = num_regs - 1; this_reg > last_used_reg; this_reg--) { - regend[this_reg] = (unsigned char *)(-1L); - regstart[this_reg] = (unsigned char *)(-1L); + regend[this_reg] = REG_UNSET_VALUE; + regstart[this_reg] = REG_UNSET_VALUE; IS_ACTIVE(reg_info[this_reg]) = 0; MATCHED_SOMETHING(reg_info[this_reg]) = 0; } @@ -3316,11 +3958,52 @@ re_match(bufp, string_arg, size, pos, regs) /* And restore the rest from the stack. */ for ( ; this_reg > 0; this_reg--) { - reg_info[this_reg] = *(struct register_info *) *--stackp; + reg_info[this_reg].word = *--stackp; regend[this_reg] = *--stackp; regstart[this_reg] = *--stackp; } - } + if (p < pend) + { + int is_a_jump_n = 0; + int failed_paren = 0; + + p1 = p; + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + pop_loop: + switch ((enum regexpcode)*p1) { + case stop_paren: + failed_paren = 1; + p1++; + goto pop_loop; + + case jump_n: + case finalize_push_n: + is_a_jump_n = 1; + case maybe_finalize_jump: + case finalize_jump: + case finalize_push: + case jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if (p1 >= pend) break; + if (( is_a_jump_n && (enum regexpcode)*p1 == succeed_n) || + (!is_a_jump_n && (enum regexpcode)*p1 == on_failure_jump)) { + if (failed_paren) { + p1++; + EXTRACT_NUMBER_AND_INCR(mcnt, p1); + PUSH_FAILURE_POINT(p1 + mcnt, d); + } + goto fail; + } + break; + default: + /* do nothing */ ; + } + } + } else break; /* Matching at this starting point really fails. */ } @@ -3332,19 +4015,258 @@ re_match(bufp, string_arg, size, pos, regs) } +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static int +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((enum regexpcode)*p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((enum regexpcode)p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return 0; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((enum regexpcode)*p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((enum regexpcode)p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); +#if 0 + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return 0; +#endif + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + *p = p1 + 2; + return 1; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return 0; + } + } /* while p1 < end */ + + return 0; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static int +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((enum regexpcode)*p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return 0; + } + } /* while p1 < end */ + + return 1; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static int +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + int ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((enum regexpcode)*p1++) + { + case unused: + case begline: + case endline: + case begbuf: + case endbuf: + case endbuf2: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return 0; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return 0; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return 0; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return 0; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return 0; + } + + *p = p1; + return 1; +} /* common_op_match_null_string_p */ + + static int -memcmp_translate(s1, s2, len, translate) +memcmp_translate(s1, s2, len) unsigned char *s1, *s2; register int len; - unsigned char *translate; { register unsigned char *p1 = s1, *p2 = s2, c; while (len) { c = *p1++; if (ismbchar(c)) { - if (c != *p2++ || !--len || *p1++ != *p2++) - return 1; + if (c != *p2++) return 1; + if (memcmp(p1, p2, ismbchar(c))) return 1; } else if (translate[c] != translate[*p2++]) @@ -3386,3 +4308,108 @@ re_free_registers(regs) if (regs->beg) free(regs->beg); if (regs->end) free(regs->end); } + +/* Functions for multi-byte support. + Created for grep multi-byte extension Jul., 1993 by t^2 (Takahiro Tanimoto) + Last change: Jul. 9, 1993 by t^2 */ +static const unsigned char mbctab_ascii[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const unsigned char mbctab_euc[] = { /* 0xA1-0xFE */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 +}; + +static const unsigned char mbctab_sjis[] = { /* 0x80-0x9f,0xE0-0xFF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static const unsigned char mbctab_utf8[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0 +}; + +const unsigned char *re_mbctab = mbctab_ascii; + +void +re_mbcinit(mbctype) + int mbctype; +{ + switch (mbctype) { + case MBCTYPE_ASCII: + re_mbctab = mbctab_ascii; + current_mbctype = MBCTYPE_ASCII; + break; + case MBCTYPE_EUC: + re_mbctab = mbctab_euc; + current_mbctype = MBCTYPE_EUC; + break; + case MBCTYPE_SJIS: + re_mbctab = mbctab_sjis; + current_mbctype = MBCTYPE_SJIS; + break; + case MBCTYPE_UTF8: + re_mbctab = mbctab_utf8; + current_mbctype = MBCTYPE_UTF8; + break; + } +} diff --git a/regex.h b/regex.h index 91442a8b2b..f61b980648 100644 --- a/regex.h +++ b/regex.h @@ -22,6 +22,8 @@ #ifndef __REGEXP_LIBRARY #define __REGEXP_LIBRARY +#include <stddef.h> + /* Define number of parens for which we record the beginnings and ends. This affects how much space the `struct re_registers' type takes up. */ #ifndef RE_NREGS @@ -38,174 +40,52 @@ #endif -/* This defines the various regexp syntaxes. */ -extern long re_syntax_options; - - -/* The following bits are used in the re_syntax_options variable to choose among - alternative regexp syntaxes. */ - -/* If this bit is set, plain parentheses serve as grouping, and backslash - parentheses are needed for literal searching. - If not set, backslash-parentheses are grouping, and plain parentheses - are for literal searching. */ -#define RE_NO_BK_PARENS 1L - -/* If this bit is set, plain | serves as the `or'-operator, and \| is a - literal. - If not set, \| serves as the `or'-operator, and | is a literal. */ -#define RE_NO_BK_VBAR (1L << 1) - -/* If this bit is set, | binds tighter than ^ or $. - If not set, the contrary. */ -#define RE_TIGHT_VBAR (1L << 3) - -/* If this bit is set, then treat newline as an OR operator. - If not set, treat it as a normal character. */ -#define RE_NEWLINE_OR (1L << 4) - -/* If this bit is set, then special characters may act as normal - characters in some contexts. Specifically, this applies to: - ^ -- only special at the beginning, or after ( or |; - $ -- only special at the end, or before ) or |; - *, +, ? -- only special when not after the beginning, (, or |. - If this bit is not set, special characters (such as *, ^, and $) - always have their special meaning regardless of the surrounding - context. */ -#define RE_CONTEXT_INDEP_OPS (1L << 5) - -/* If this bit is not set, then \ before anything inside [ and ] is taken as - a real \. - If set, then such a \ escapes the following character. This is a - special case for awk. */ -#define RE_AWK_CLASS_HACK (1L << 6) - -/* If this bit is set, then \{ and \} or { and } serve as interval operators. - If not set, then \{ and \} and { and } are treated as literals. */ -#define RE_INTERVALS (1L << 7) - -/* If this bit is not set, then \{ and \} serve as interval operators and - { and } are literals. - If set, then { and } serve as interval operators and \{ and \} are - literals. */ -#define RE_NO_BK_CURLY_BRACES (1L << 8) -#define RE_NO_BK_BRACES RE_NO_BK_CURLY_BRACES - /* If this bit is set, then character classes are supported; they are: [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. If not set, then character classes are not supported. */ #define RE_CHAR_CLASSES (1L << 9) -/* If this bit is set, then the dot re doesn't match a null byte. - If not set, it does. */ -#define RE_DOT_NOT_NULL (1L << 10) - -/* If this bit is set, then [^...] doesn't match a newline. - If not set, it does. */ -#define RE_HAT_NOT_NEWLINE (1L << 11) - -/* If this bit is set, back references are recognized. - If not set, they aren't. */ -#define RE_NO_BK_REFS (1L << 12) - -/* If this bit is set, back references must refer to a preceding - subexpression. If not set, a back reference to a nonexistent - subexpression is treated as literal characters. */ -#define RE_NO_EMPTY_BK_REF (1L << 13) - -/* If this bit is set, bracket expressions can't be empty. - If it is set, they can be empty. */ -#define RE_NO_EMPTY_BRACKETS (1L << 14) - -/* If this bit is set, then *, +, ? and { cannot be first in an re or - immediately after a |, or a (. Furthermore, a | cannot be first or - last in an re, or immediately follow another | or a (. Also, a ^ - cannot appear in a nonleading position and a $ cannot appear in a - nontrailing position (outside of bracket expressions, that is). */ -#define RE_CONTEXTUAL_INVALID_OPS (1L << 15) - -/* If this bit is set, then +, ? and | aren't recognized as operators. - If it's not, they are. */ -#define RE_LIMITED_OPS (1L << 16) - -/* If this bit is set, then an ending range point has to collate higher - or equal to the starting range point. - If it's not set, then when the ending range point collates higher - than the starting range point, the range is just considered empty. */ -#define RE_NO_EMPTY_RANGES (1L << 17) - -/* If this bit is set, then a hyphen (-) can't be an ending range point. - If it isn't, then it can. */ -#define RE_NO_HYPHEN_RANGE_END (1L << 18) - -/* If this bit is not set, then \ inside a bracket expression is literal. - If set, then such a \ quotes the following character. */ -#define RE_BACKSLASH_ESCAPE_IN_LISTS (1L << 19) - -/* Define combinations of bits for the standard possibilities. */ -#define RE_SYNTAX_POSIX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR \ - | RE_CONTEXT_INDEP_OPS) -#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_AWK_CLASS_HACK) -#define RE_SYNTAX_EGREP (RE_NO_BK_PARENS | RE_NO_BK_VBAR \ - | RE_CONTEXT_INDEP_OPS | RE_NEWLINE_OR) -#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) -#define RE_SYNTAX_EMACS 0 -#define RE_SYNTAX_POSIX_BASIC (RE_INTERVALS | RE_BK_PLUS_QM \ - | RE_CHAR_CLASSES | RE_DOT_NOT_NULL \ - | RE_HAT_NOT_NEWLINE | RE_NO_EMPTY_BK_REF \ - | RE_NO_EMPTY_BRACKETS | RE_LIMITED_OPS \ - | RE_NO_EMPTY_RANGES | RE_NO_HYPHEN_RANGE_END) - -#define RE_SYNTAX_POSIX_EXTENDED (RE_INTERVALS | RE_NO_BK_CURLY_BRACES \ - | RE_NO_BK_VBAR | RE_NO_BK_PARENS \ - | RE_HAT_NOT_NEWLINE | RE_CHAR_CLASSES \ - | RE_NO_EMPTY_BRACKETS | RE_CONTEXTUAL_INVALID_OPS \ - | RE_NO_BK_REFS | RE_NO_EMPTY_RANGES \ - | RE_NO_HYPHEN_RANGE_END) +#define RE_OPTION_EXTENDED (1L<<0) +#define RE_OPTION_IGNORECASE (1L<<1) +#define RE_MAY_IGNORECASE (1L<<2) +#define RE_OPTIMIZE_ANCHOR (1L<<4) +#define RE_OPTIMIZE_EXACTN (1L<<5) +#define RE_OPTIMIZE_NO_BM (1L<<6) /* For multi-byte char support */ -#define RE_MBCTYPE_EUC (1L << 20) -#define RE_MBCTYPE_SJIS (1L << 21) -#define RE_MBCTYPE_MASK (RE_MBCTYPE_EUC | RE_MBCTYPE_SJIS) +#define MBCTYPE_ASCII 0 +#define MBCTYPE_EUC 1 +#define MBCTYPE_SJIS 2 +#define MBCTYPE_UTF8 3 -#ifdef EUC -#define DEFAULT_MBCTYPE RE_MBCTYPE_EUC -#else -#ifdef SJIS -#define DEFAULT_MBCTYPE RE_MBCTYPE_SJIS +#ifdef __STDC__ +extern const unsigned char *re_mbctab; +void re_mbcinit (int); #else -#define DEFAULT_MBCTYPE 0 -#endif +extern unsigned char *re_mbctab; +void re_mbcinit (); #endif #undef ismbchar -#define ismbchar(c) \ - (re_syntax_options & RE_MBCTYPE_EUC \ - ? ((unsigned char) (c) >= 0x80) \ - : (re_syntax_options & RE_MBCTYPE_SJIS \ - ? (( 0x80 <= (unsigned char) (c) \ - && (unsigned char) (c) <= 0x9f) \ - || (0xe0 <= (unsigned char) (c))) \ - : 0)) +#define ismbchar(c) re_mbctab[(unsigned char)(c)] +#define mbclen(c) (re_mbctab[(unsigned char)(c)]+1) /* This data structure is used to represent a compiled pattern. */ struct re_pattern_buffer { char *buffer; /* Space holding the compiled pattern commands. */ - long allocated; /* Size of space that `buffer' points to. */ - long used; /* Length of portion of buffer actually occupied */ + size_t allocated; /* Size of space that `buffer' points to. */ + size_t used; /* Length of portion of buffer actually occupied */ char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ /* re_search uses the fastmap, if there is one, to skip over totally implausible characters. */ - char *translate; /* Translate table to apply to all characters before - comparing, or zero for no translation. - The translation is applied to a pattern when it is - compiled and to data when it is matched. */ char *must; /* Pointer to exact pattern which strings should have to be matched. */ - + int *must_skip; /* Pointer to exact pattern skip table for bm_search */ + char *stclass; /* Pointer to character class list at top */ + long options; /* Flags for options such as extended_pattern. */ long re_nsub; /* Number of subexpressions found by the compiler. */ char fastmap_accurate; /* Set to zero when a new pattern is stored, @@ -219,11 +99,7 @@ struct re_pattern_buffer listed in the fastmap. */ }; - -/* search.c (search_buffer) needs this one value. It is defined both in - regex.c and here. */ -#define RE_EXACTN_VALUE 1 - +typedef struct re_pattern_buffer regex_t; /* Structure to store register contents data in. @@ -237,12 +113,23 @@ struct re_pattern_buffer struct re_registers { - unsigned allocated; - unsigned num_regs; + size_t allocated; + size_t num_regs; int *beg; int *end; }; +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef size_t regoff_t; + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; #ifdef NeXT @@ -252,14 +139,16 @@ struct re_registers #ifdef __STDC__ extern char *re_compile_pattern (char *, size_t, struct re_pattern_buffer *); +void re_free_pattern (struct re_pattern_buffer *); /* Is this really advertised? */ extern void re_compile_fastmap (struct re_pattern_buffer *); -extern int re_search (struct re_pattern_buffer *, char*, int, int, int, +extern int re_search (struct re_pattern_buffer *, char*, size_t, size_t, size_t, struct re_registers *); -extern int re_match (struct re_pattern_buffer *, char *, int, int, +extern int re_match (struct re_pattern_buffer *, char *, size_t, size_t, struct re_registers *); -extern long re_set_syntax (long syntax); +extern void re_set_casetable (char *table); extern void re_copy_registers (struct re_registers*, struct re_registers*); +extern void re_free_registers (struct re_registers*); #ifndef RUBY /* 4.2 bsd compatibility. */ @@ -270,19 +159,15 @@ extern int re_exec (char *); #else /* !__STDC__ */ extern char *re_compile_pattern (); +void re_free_regexp (); /* Is this really advertised? */ extern void re_compile_fastmap (); extern int re_search (); extern int re_match (); -extern long re_set_syntax(); +extern void re_set_casetable (); extern void re_copy_registers (); extern void re_free_registers (); #endif /* __STDC__ */ - -#ifdef SYNTAX_TABLE -extern char *re_syntax_table; -#endif - #endif /* !__REGEXP_LIBRARY */ diff --git a/ruby.1 b/ruby.1 index fe1e76007a..8665ca79bb 100644 --- a/ruby.1 +++ b/ruby.1 @@ -1,45 +1,8 @@ -.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@ruby.club.co.jp>. -.\" -.\"This source is distributed under the conditions blow: -.\" -.\" 1. You may make and give away verbatim copies of the source form of -.\" the software without restriction, provided that you do not modify -.\" the original distribution files. -.\" -.\" If you want to distribute the modified version in any way, contact -.\" the author. -.\" -.\" 2. You may distribute the software in object code or executable -.\" form, provided that you distribute it with instructions on where -.\" to get the software. -.\" -.\" 3. You may modify the software in any way, provided that you do not -.\" distribute the modified version. -.\" -.\" 4. You may modify and include the part of the software into any other -.\" software (possibly commercial). But some files in the distribution -.\" are not written by the author, so that they are not under this terms. -.\" They are gc.c(partly)$B!$(Butils.c(partly), regex.[ch]$B!$(Bfnmatch.[ch]$B!$(B -.\" glob.c, st.[ch] and somme files under the ./missing directory. See -.\" each files for the copying condition. -.\" -.\" 5. The scripts and library files supplied as input to or produced as -.\" output from the software do not automatically fall under the -.\" copyright of the software, but belong to whomever generated them, -.\" and may be sold commercially, and may be aggregated with this -.\" software. -.\" -.\" 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR -.\" PURPOSE. -.\" -.\" $Id$ -.\" +.\"Ruby is copyrighted by Yukihiro Matsumoto <matz@netlab.co.jp>. .na -.TH RUBY 1 "ruby 1.0" "19/Sep/97" "Ruby Programmers Reference Guide" +.TH RUBY 1 "ruby 1.3" "18/Jan/99" "Ruby Programmers Reference Guide" .SH NAME -ruby - Interpreted scripting language +ruby - Interpreted object-oriented scripting language .SH SYNOPSIS .B ruby \c [ \c @@ -94,99 +57,96 @@ ruby - Interpreted scripting language ] [ programfile ] [ argument ] ... .SH PREFACE -Ruby is the interpreted scripting language for quick and easy -object-oriented programming. It has many features to process text -files and to do system management tasks (as in perl). It is simple, +Ruby is an interpreted scripting language for quick and easy +object-oriented programming. It has many features to process text +files and to do system management tasks (as in Perl). It is simple, straight-forward, and extensible. .PP If you want a language for easy object-oriented programming, or you -don't like the PERL ugliness, or you do like the concept of lisp, but -don't like too much parentheses, ruby may be the language of the +don't like the Perl ugliness, or you do like the concept of lisp, but +don't like too much parentheses, Ruby may be the language of your choice. .SH DESCRIPTION Ruby's features are as follows: .TP .B "\(bu Interpretive" -Ruby is the interpreted language, so you don't have to -recompile to execute the program written in ruby. +Ruby is an interpreted language, so you don't have to recompile +programs written in Ruby to execute them. .TP .B "\(bu Variables have no type (dynamic typing)" -Variables in ruby can contain data of any type. You don't have -to worry about variable typing. Consequently, it has weaker -compile time check. -.TP +Variables in Ruby can contain data of any type. You don't have to +worry about variable typing. Consequently, it has a weaker compile +time check. +.TP .B "\(bu No declaration needed" -You can use variables in your ruby programs without any -declarations. Variable name itself denotes its scope (local, -global, instance, etc.) +You can use variables in your Ruby programs without any declarations. +Variable names denote their scope, local, global, instance, etc. .TP .B "\(bu Simple syntax" -Ruby has simple syntax influenced slightly from Eiffel. +Ruby has a simple syntax influenced slightly from Eiffel. .TP .B "\(bu No user-level memory management" Ruby has automatic memory management. Objects no longer referenced from anywhere are automatically collected by the -garbage collector built in the interpreter. +garbage collector built into the interpreter. .TP -.B "\(bu Everything is object" -Ruby is the pure object-oriented language from the beginning. -Even basic data like integers are treated uniformly as objects. +.B "\(bu Everything is an object" +Ruby is the purely object-oriented language, and was so since its +creation. Even such basic data as integers are seen as objects. .TP .B "\(bu Class, inheritance, methods" -Of course, as a O-O language, ruby has basic features like -classes, inheritance, methods, etc. +Of course, as an object-oriented language, Ruby has such basic +features like classes, inheritance, and methods. .TP .B "\(bu Singleton methods" -Ruby has the feature to define methods for certain specified -object. For example, you can define a press-button action for -certain GUI button by defining a singleton method for the -button. Or, you can make up your own prototype based object -system using singleton methods (if you want to). +Ruby has the ability to define methods for certain objects. For +example, you can define a press-button action for certain widget by +defining a singleton method for the button. Or, you can make up your +own prototype based object system using singleton methods, if you want +to. .TP .B "\(bu Mix-in by modules" -Ruby does not have the multiple inheritance intentionally. IMO, -It is the source of confusion. Instead, ruby has modules to -share the implementation across the inheritance tree. It is -often called "Mix-in." +Ruby intentioanlly does not have the multiple inheritance as it is a +souce of confusion. Instead, Ruby has the ability to share +implementations acrss the inheritance tree. This is oftern called +`Mix-in'. .TP .B "\(bu Iterators" Ruby has iterators for loop abstraction. .TP .B "\(bu Closures" -In ruby, you can objectify the procedure. +In Ruby, you can objectify the procedure. .TP .B "\(bu Text processing and regular expression" -Ruby has bunch of text processing features like in perl. +Ruby has a bunch of text processing features like in Perl. .TP .B "\(bu Bignums" -With bu ilt-in bignums, you can calculate factorial(400), for -example. +With built-in bignums, you can for example calculate factorial(400). .TP .B "\(bu Exception handling" As in Java(tm). .TP -.B "\(bu Direct access to OS" -Ruby can call most of system calls on UNIX boxes. It can be -used in system programming. +.B "\(bu Direct access to the OS" +Ruby can use most UNIX system calls, often used in system programming. .TP .B "\(bu Dynamic loading" -You can load object files into ruby interpreter on-the-fly, on -most of UNIXes. +On most UNIX systems, you can load object files into the Ruby +interpreter on-the-fly. .PP -.SH Command line options +.SH COMMAND LINE OPTIONS Ruby interpreter accepts following command-line options (switches). -Basically they are quite similar to those of Perl. +They are quite similar to those of Perl. .TP .B -0digit -specifies the input record separator ($/) as an octal number. -If no digits given, the null character is the separator. Other -switches may follow the digits. -00 turns ruby into paragraph -mode. -0777 makes ruby read whole file at once as a single -string, since there is no legal character with that value. +pecifies the input record separator ($/) as an octal number. If no +digit is given, the null character is taken as the separator. Other +switches may follow the digits. -00 turns Ruby into paragraph mode. - +0777 makes Ruby read whole file at once as a single string since there +is no legal character with that value. .TP .B -a turns on auto-split mode when used with -n or -p. In auto-split -mode, ruby executes +mode, Ruby executes .nf .ne 1 \& $F = $_.split @@ -194,20 +154,20 @@ at beginning of each loop. .fi .TP .B -c -causes ruby to check the syntax of the script and exit without -executing. If there is no syntax error, ruby will print "Syntax +causes Ruby to check the syntax of the script and exit without +executing. If there are no syntax errors, Ruby will print "Syntax OK" to the standard output. .TP .B -Kc -specifies KANJI (Japanese character) code-set. +specifies KANJI (Japanese) code-set. .TP .B -d --debug turns on debug mode. $DEBUG will set TRUE. .TP .B -e script -specifies script from command-line. if -e switch specified, -ruby will not look for a script filename in the arguments. +specifies script from command-line while telling Ruby to not +search argv for script filenames. .TP .B -F regexp specifies input field separator ($;). @@ -229,16 +189,15 @@ example: .fi .TP .B -I directory -used to tell ruby where to load the library scripts. Directory -path will be added to the load-path variable ($:'). +used to tell Ruby where to load the library scripts. Directory path +will be added to the load-path variable ($:'). .TP .B -l -enables automatic line-ending processing, which means firstly -set $\ to the value of $/, and secondly chops every line read -using chop!. +enables automatic line-ending processing, which means to firstly set +$\ to the value of $/, and secondly chops every line read using chop!. .TP .B -n -causes ruby to assume the following loop around your script, +causes Ruby to assume the following loop around your script, which makes it iterate over filename arguments somewhat like sed -n or awk. .nf @@ -259,24 +218,23 @@ example: .fi .TP .B -r filename -causes ruby to load the file using [4]require. It is useful +causes Ruby to load the file using [4]require. It is useful with switches -n or -p. .TP .B -s -enables some switch parsing for switches after script name but -before any filename arguments (or before a --). Any switches -found there is removed from ARGV and set the corresponding -variable in the script. +enables some switch parsing for switches after script name but before +any filename arguments (or before a --). Any switches found there are +removed from ARGV and set the corresponding variable in the script. example: .nf .ne 3 \& #! /usr/local/bin/ruby -s \& # prints "true" if invoked with `-xyz' switch. -\& print "true\n" if $xyz +\& print "true\en" if $xyz .fi .TP .B -S -makes ruby uses the PATH environment variable to search for +makes Ruby use the PATH environment variable to search for script, unless if its name begins with a slash. This is used to emulate #! on machines that don't support it, in the following manner: @@ -286,44 +244,40 @@ manner: \& # This line makes the next one a comment in ruby \\ \& exec /usr/local/bin/ruby -S $0 $* .fi -On some systems $0 does not always contain the full pathname, -so you need -S switch to tell ruby to search for the script if -necessary. -To handle embedded spaces or such, A better construct than $* -would be ${1+"$@"}, but it does not work if the script is being -interpreted by csh. +On some systems $0 does not always contain the full pathname, so you +need -S switch to tell Ruby to search for the script if necessary. To +handle embedded spaces or such. A better construct than $* would be +${1+"$@"}, but it does not work if the script is being interpreted by +csh. .TP .B -v --verbose -enables verbose mode. Ruby will prints its version at the -beginning, and set the variable `$VERBOSE' to TRUE. Some -methods prints extra messages if this variable is TRUE. If this -switch is given, and no other switches present, ruby quits -after printing its version. +enables verbose mode. Ruby will print its version at the beginning, +and set the variable `$VERBOSE' to TRUE. Some methods print extra +messages if this variable is TRUE. If this switch is given, and no +other switches are present, Ruby quits after printing its version. .TP .B --version -prints the version of ruby executable. +prints the version of Ruby interpreter. .TP .B -w enables verbose mode without printing version message at the -beginning. It set the variable `$VERBOSE' to TRUE. +beginning. It set the `$VERBOSE' variable to true. .TP .B -x[directory] -tells ruby that the script is embedded in a message. Leading -garbage will be discarded until the first that starts with "#!" -and contains string "ruby". Any meaningful switches on that -line will applied. The end of script must be specified with -either EOF, ^D (control-D), ^Z (control-Z), or reserved word -__END__.If the directory name is specified, ruby will switch to -that directory before executing script. +tells Ruby that the script is embedded in a message. Leading garbage +will be discarded until the first that starts with "#!" and contains +the string, "ruby". Any meaningful switches on that line will applied. +The end of script must be specified with either EOF, ^D (control-D), +^Z (control-Z), or reserved word __END__.If the directory name is +specified, Ruby will switch to that directory before executing script. .TP .B -X directory -causes ruby to switch to the directory. +causes Ruby to switch to the directory. .TP .B -y --yydebug -turns on compiler debug mode. ruby will print bunch of internal -state messages during compiling scripts. You don't have to -specify this switch, unless you are going to debug the ruby -interpreter itself. +turns on compiler debug mode. Ruby will print a bunch of internal +state messages during compiling scripts. You don't have to specify +this switch, unless you are going to debug the Ruby interpreter. .PP .SH AUTHOR - Ruby is designed and implemented by Yukihiro Matsumoto <matz@ruby.club.co.jp>. + Ruby is designed and implemented by Yukihiro Matsumoto <matz@netlab.co.jp>. diff --git a/ruby.c b/ruby.c index 6e748f249d..9bf28022e8 100644 --- a/ruby.c +++ b/ruby.c @@ -6,7 +6,7 @@ $Date$ created at: Tue Aug 10 12:47:31 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -14,102 +14,117 @@ #include <windows.h> #endif #include "ruby.h" -#include "re.h" #include "dln.h" +#include "node.h" #include <stdio.h> -#include <ctype.h> #include <sys/types.h> #include <fcntl.h> +#include <ctype.h> + +#ifdef __hpux +#include <sys/pstat.h> +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif + +#ifdef USE_CWGUSI +#include "macruby_missing.h" +#endif + #ifndef HAVE_STRING_H -char *strchr(); -char *strrchr(); -char *strstr(); +char *strchr _((char*,char)); +char *strrchr _((char*,char)); +char *strstr _((char*,char*)); #endif +#include "util.h" + +#ifndef HAVE_STDLIB_H char *getenv(); +#endif static int version, copyright; -VALUE debug = FALSE; -VALUE verbose = FALSE; -int tainting = FALSE; -static int sflag = FALSE; +VALUE rb_debug = Qfalse; +VALUE rb_verbose = Qfalse; +int rb_tainting = Qfalse; +static int sflag = Qfalse; -char *inplace = FALSE; +char *ruby_inplace_mode = Qfalse; char *strdup(); -extern char *sourcefile; extern int yydebug; -extern int nerrs; +static int xflag = Qfalse; -static int xflag = FALSE; -extern VALUE RS, RS_default, ORS, FS; - -static void load_stdin(); +static void load_stdin _((void)); static void load_file _((char *, int)); static void forbid_setid _((char *)); -static VALUE do_loop = FALSE, do_print = FALSE; -static VALUE do_check = FALSE, do_line = FALSE; -static VALUE do_split = FALSE; +static VALUE do_loop = Qfalse, do_print = Qfalse; +static VALUE do_check = Qfalse, do_line = Qfalse; +static VALUE do_split = Qfalse; static char *script; static int origargc; static char **origargv; -extern int sourceline; -extern char *sourcefile; - #ifndef RUBY_LIB #define RUBY_LIB "/usr/local/lib/ruby" #endif - -#if defined(MSDOS) || defined(NT) -#define RUBY_LIB_SEP ';' -#else -#define RUBY_LIB_SEP ':' +#ifndef RUBY_SITE_LIB +#define RUBY_SITE_LIB "/usr/local/lib/site_ruby" #endif extern VALUE rb_load_path; -VALUE Frequire(); + +static FILE *e_fp; +static char *e_tmpname; static void addpath(path) char *path; { + const char sep = RUBY_PATH_SEP[0]; + if (path == 0) return; - if (strchr(path, RUBY_LIB_SEP)) { +#if defined(__CYGWIN32__) + { + char rubylib[FILENAME_MAX]; + conv_to_posix_path(path, rubylib); + path = rubylib; + } +#endif + if (strchr(path, sep)) { char *p, *s; - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); p = path; while (*p) { - while (*p == RUBY_LIB_SEP) p++; - if (s = strchr(p, RUBY_LIB_SEP)) { - ary_push(ary, str_new(p, (int)(s-p))); + while (*p == sep) p++; + if (s = strchr(p, sep)) { + rb_ary_push(ary, rb_str_new(p, (int)(s-p))); p = s + 1; } else { - ary_push(ary, str_new2(p)); + rb_ary_push(ary, rb_str_new2(p)); break; } } - rb_load_path = ary_plus(ary, rb_load_path); + rb_load_path = rb_ary_plus(ary, rb_load_path); } else { - ary_unshift(rb_load_path, str_new2(path)); + rb_ary_unshift(rb_load_path, rb_str_new2(path)); } } struct req_list { char *name; struct req_list *next; -} *req_list; +} req_list_head; +struct req_list *req_list_last = &req_list_head; static void add_modules(mod) @@ -119,25 +134,28 @@ add_modules(mod) list = ALLOC(struct req_list); list->name = mod; - list->next = req_list; - req_list = list; + list->next = 0; + req_list_last->next = list; + req_list_last = list; } void -rb_require_modules() +ruby_require_modules() { - struct req_list *list = req_list; + struct req_list *list = req_list_head.next; struct req_list *tmp; - req_list = 0; + req_list_last = 0; while (list) { - f_require(Qnil, str_new2(list->name)); + rb_f_require(Qnil, rb_str_new2(list->name)); tmp = list->next; free(list); list = tmp; } } +extern void Init_ext _((void)); + static void proc_options(argcp, argvp) int *argcp; @@ -150,9 +168,10 @@ proc_options(argcp, argvp) if (argc == 0) return; - version = FALSE; - do_search = FALSE; + version = Qfalse; + do_search = Qfalse; script_given = 0; + e_tmpname = NULL; for (argc--,argv++; argc > 0; argc--,argv++) { if (argv[0][0] != '-' || !argv[0][1]) break; @@ -161,20 +180,21 @@ proc_options(argcp, argvp) reswitch: switch (*s) { case 'a': - do_split = TRUE; + do_split = Qtrue; s++; goto reswitch; case 'p': - do_print = TRUE; + do_print = Qtrue; /* through */ case 'n': - do_loop = TRUE; + do_loop = Qtrue; s++; goto reswitch; case 'd': - debug = TRUE; + rb_debug = Qtrue; + rb_verbose |= 1; s++; goto reswitch; @@ -184,47 +204,52 @@ proc_options(argcp, argvp) goto reswitch; case 'v': - show_version(); - verbose = 2; + ruby_show_version(); + rb_verbose = 2; case 'w': - verbose |= 1; + rb_verbose |= 1; s++; goto reswitch; case 'c': - do_check = TRUE; + do_check = Qtrue; s++; goto reswitch; case 's': forbid_setid("-s"); - sflag = TRUE; + sflag = Qtrue; s++; goto reswitch; case 'l': - do_line = TRUE; - ORS = RS; + do_line = Qtrue; + rb_output_rs = rb_rs; s++; goto reswitch; case 'S': forbid_setid("-S"); - do_search = TRUE; + do_search = Qtrue; s++; goto reswitch; case 'e': forbid_setid("-e"); - script_given++; - if (script == 0) script = "-e"; - if (argv[1]) { - compile_string("-e", argv[1], strlen(argv[1])); - argc--,argv++; + if (!e_fp) { + e_tmpname = ruby_mktemp(); + if (!e_tmpname) rb_fatal("Can't mktemp"); + e_fp = fopen(e_tmpname, "w"); + if (!e_fp) { + rb_fatal("Cannot open temporary file: %s", e_tmpname); + } + if (script == 0) script = e_tmpname; } - else { - compile_string("-e", "", 0); + if (argv[1]) { + fputs(argv[1], e_fp); + argc--, argv++; } + putc('\n', e_fp); break; case 'r': @@ -240,15 +265,15 @@ proc_options(argcp, argvp) case 'i': forbid_setid("-i"); - if (inplace) free(inplace); - inplace = strdup(s+1); + if (ruby_inplace_mode) free(ruby_inplace_mode); + ruby_inplace_mode = strdup(s+1); break; case 'x': - xflag = TRUE; + xflag = Qtrue; s++; if (*s && chdir(s) < 0) { - Fatal("Can't chdir to %s", s); + rb_fatal("Can't chdir to %s", s); } break; @@ -259,12 +284,12 @@ proc_options(argcp, argvp) argc--,argv++; } if (*s && chdir(s) < 0) { - Fatal("Can't chdir to %s", s); + rb_fatal("Can't chdir to %s", s); } break; case 'F': - FS = str_new2(s+1); + rb_fs = rb_str_new2(s+1); break; case 'K': @@ -283,7 +308,7 @@ proc_options(argcp, argvp) if (numlen == 0) v = 1; } rb_set_safe_level(v); - tainting = TRUE; + rb_tainting = Qtrue; } break; @@ -305,13 +330,13 @@ proc_options(argcp, argvp) v = scan_oct(s, 4, &numlen); s += numlen; - if (v > 0377) RS = Qnil; + if (v > 0377) rb_rs = Qnil; else if (v == 0 && numlen >= 2) { - RS = str_new2("\n\n"); + rb_rs = rb_str_new2("\n\n"); } else { c = v & 0xff; - RS = str_new(&c, 1); + rb_rs = rb_str_new(&c, 1); } } goto reswitch; @@ -325,15 +350,15 @@ proc_options(argcp, argvp) if (strcmp("copyright", s) == 0) copyright = 1; else if (strcmp("debug", s) == 0) - debug = 1; + rb_debug = 1; else if (strcmp("version", s) == 0) version = 1; else if (strcmp("verbose", s) == 0) - verbose = 2; + rb_verbose = 2; else if (strcmp("yydebug", s) == 0) yydebug = 1; else { - Fatal("Unrecognized long option: --%s",s); + rb_fatal("Unrecognized long option: --%s",s); } break; @@ -343,7 +368,7 @@ proc_options(argcp, argvp) break; default: - Fatal("Unrecognized switch: -%s",s); + rb_fatal("Unrecognized switch: -%s",s); case 0: break; @@ -353,17 +378,26 @@ proc_options(argcp, argvp) switch_end: if (*argvp[0] == 0) return; + if (e_fp) { + if (fflush(e_fp) || ferror(e_fp) || fclose(e_fp)) + rb_fatal("Cannot write to temp file for -e"); + e_fp = NULL; + argc++, argv--; + argv[0] = e_tmpname; + } + if (version) { - show_version(); + ruby_show_version(); exit(0); } if (copyright) { - show_copyright(); + ruby_show_copyright(); } - if (script_given == FALSE) { + Init_ext(); /* should be called here for some reason :-( */ + if (script_given == Qfalse) { if (argc == 0) { /* no more args */ - if (verbose == 3) exit(0); + if (rb_verbose == 3) exit(0); script = "-"; load_stdin(); } @@ -391,9 +425,10 @@ proc_options(argcp, argvp) argc--; argv++; } } - if (verbose) verbose = TRUE; + if (rb_verbose) rb_verbose = Qtrue; + if (rb_debug) rb_debug = Qtrue; - xflag = FALSE; + xflag = Qfalse; *argvp = argv; *argcp = argc; @@ -409,17 +444,20 @@ proc_options(argcp, argvp) argv[0][0] = '$'; if (s = strchr(argv[0], '=')) { *s++ = '\0'; - rb_gvar_set2(argv[0], str_new2(s)); + rb_gvar_set2(argv[0], rb_str_new2(s)); } else { - rb_gvar_set2(argv[0], TRUE); + rb_gvar_set2(argv[0], Qtrue); } + argv[0][0] = '-'; } *argcp = argc; *argvp = argv; } } +extern int ruby__end__seen; + static void load_file(fname, script) char *fname; @@ -433,42 +471,43 @@ load_file(fname, script) f = rb_stdin; } else { - f = file_open(fname, "r"); + FILE *fp = fopen(fname, "r"); + + if (fp == NULL) { + rb_raise(rb_eLoadError, "No such file to load -- %s", fname); + } + fclose(fp); + + f = rb_file_open(fname, "r"); } if (script) { VALUE c; VALUE line; - VALUE rs = RS; + char *p; - RS = RS_default; if (xflag) { forbid_setid("-x"); - xflag = FALSE; - while (!NIL_P(line = io_gets(f))) { + xflag = Qfalse; + while (!NIL_P(line = rb_io_gets(f))) { line_start++; if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '#' && RSTRING(line)->ptr[1] == '!') { - if (strstr(RSTRING(line)->ptr, "ruby")) { + if (p = strstr(RSTRING(line)->ptr, "ruby")) { goto start_read; } } } - RS = rs; - LoadError("No Ruby script found in input"); + rb_raise(rb_eLoadError, "No Ruby script found in input"); } - c = io_getc(f); + c = rb_io_getc(f); if (c == INT2FIX('#')) { - line = io_gets(f); + line = rb_io_gets(f); line_start++; - if (RSTRING(line)->len > 2 - && RSTRING(line)->ptr[0] == '!') { - - char *p; - + if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '!') { if ((p = strstr(RSTRING(line)->ptr, "ruby")) == 0) { /* not ruby script, kick the program */ char **argv; @@ -479,10 +518,10 @@ load_file(fname, script) if (pend[-1] == '\n') pend--; /* chomp line */ if (pend[-1] == '\r') pend--; *pend = '\0'; - while (p < pend && isspace(*p)) + while (p < pend && ISSPACE(*p)) p++; path = p; /* interpreter path */ - while (p < pend && !isspace(*p)) + while (p < pend && !ISSPACE(*p)) p++; *p++ = '\0'; if (p < pend) { @@ -494,36 +533,48 @@ load_file(fname, script) argv = origargv; } argv[0] = path; +#ifndef USE_CWGUSI execv(path, argv); - sourcefile = fname; - sourceline = 1; - Fatal("Can't exec %s", path); +#endif + ruby_sourcefile = fname; + ruby_sourceline = 1; + rb_fatal("Can't exec %s", path); } start_read: - if (p = strstr(RSTRING(line)->ptr, "ruby -")) { + p += 4; + RSTRING(line)->ptr[RSTRING(line)->len-1] = '\0'; + if (RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r') + RSTRING(line)->ptr[RSTRING(line)->len-2] = '\0'; + if (p = strstr(p, " -")) { int argc; char *argv[2]; char **argvp = argv; - UCHAR *s; - - s = RSTRING(line)->ptr; - while (isspace(*s)) - s++; - *s = '\0'; - RSTRING(line)->ptr[RSTRING(line)->len-1] = '\0'; - if (RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r') - RSTRING(line)->ptr[RSTRING(line)->len-2] = '\0'; - argc = 2; argv[0] = 0; argv[1] = p + 5; - proc_options(&argc, &argvp); + char *s = ++p; + + argc = 2; argv[0] = 0; + while (*p == '-') { + while (*s && !ISSPACE(*s)) + s++; + *s = '\0'; + argv[1] = p; + proc_options(&argc, &argvp); + p = ++s; + while (*p && ISSPACE(*p)) + p++; + } } } } else if (!NIL_P(c)) { - io_ungetc(f, c); + rb_io_ungetc(f, c); } - RS = rs; } - compile_file(fname, f, line_start); - if (f != rb_stdin) io_close(f); + rb_compile_file(fname, f, line_start); + if (script && ruby__end__seen) { + rb_define_global_const("DATA", f); + } + else if (f != rb_stdin) { + rb_io_close(f); + } } void @@ -553,8 +604,8 @@ set_arg0(val, id) int i; static int len; - if (origargv == 0) Fail("$0 not initialized"); - Check_Type(val, T_STRING); + if (origargv == 0) rb_raise(rb_eRuntimeError, "$0 not initialized"); +#ifndef __hpux if (len == 0) { s = origargv[0]; s += strlen(s); @@ -565,8 +616,9 @@ set_arg0(val, id) } len = s - origargv[0]; } - s = RSTRING(val)->ptr; - i = RSTRING(val)->len; +#endif + s = rb_str2cstr(val, &i); +#ifndef __hpux if (i > len) { memcpy(origargv[0], s, len); origargv[0][len] = '\0'; @@ -578,7 +630,22 @@ set_arg0(val, id) while (++i < len) *s++ = ' '; } - rb_progname = str_taint(str_new2(origargv[0])); + rb_progname = rb_tainted_str_new2(origargv[0]); +#else + if (i >= PST_CLEN) { + union pstun j; + j.pst_command = s; + i = PST_CLEN; + RSTRING(val)->len = i; + *(s + i) = '\0'; + pstat(PSTAT_SETCMD, j, PST_CLEN, 0, 0); + } else { + union pstun j; + j.pst_command = s; + pstat(PSTAT_SETCMD, j, i, 0, 0); + } + rb_progname = rb_tainted_str_new(s, i); +#endif } void @@ -586,8 +653,8 @@ ruby_script(name) char *name; { if (name) { - rb_progname = str_taint(str_new2(name)); - sourcefile = name; + rb_progname = rb_tainted_str_new2(name); + ruby_sourcefile = name; } } @@ -614,9 +681,11 @@ forbid_setid(s) char *s; { if (euid != uid) - Fatal("No %s allowed while running setuid", s); + rb_raise(rb_eSecurityError, "No %s allowed while running setuid", s); if (egid != gid) - Fatal("No %s allowed while running setgid", s); + rb_raise(rb_eSecurityError, "No %s allowed while running setgid", s); + if (rb_safe_level() > 0) + rb_raise(rb_eSecurityError, "No %s allowed in tainted mode", s); } #if defined(_WIN32) || defined(DJGPP) @@ -658,37 +727,48 @@ ruby_prog_init() { init_ids(); - sourcefile = "ruby"; - rb_define_variable("$VERBOSE", &verbose); - rb_define_variable("$-v", &verbose); - rb_define_variable("$DEBUG", &debug); - rb_define_variable("$-d", &debug); + ruby_sourcefile = "ruby"; + rb_define_variable("$VERBOSE", &rb_verbose); + rb_define_variable("$-v", &rb_verbose); + rb_define_variable("$DEBUG", &rb_debug); + rb_define_variable("$-d", &rb_debug); rb_define_readonly_variable("$-p", &do_print); rb_define_readonly_variable("$-l", &do_line); + if (rb_safe_level() == 0) { + addpath("."); + } + + addpath(RUBY_LIB); #if defined(_WIN32) || defined(DJGPP) addpath(ruby_libpath()); #endif +#ifdef __MACOS__ + setup_macruby_libpath(); +#endif - if (rb_safe_level() == 0) { - addpath(getenv("RUBYLIB")); - } - +#ifdef RUBY_ARCHLIB + addpath(RUBY_ARCHLIB); +#endif #ifdef RUBY_THIN_ARCHLIB addpath(RUBY_THIN_ARCHLIB); #endif -#ifdef RUBY_ARCHLIB - addpath(RUBY_ARCHLIB); + addpath(RUBY_SITE_LIB); +#ifdef RUBY_SITE_ARCHLIB + addpath(RUBY_SITE_ARCHLIB); #endif - addpath(RUBY_LIB); +#ifdef RUBY_SITE_THIN_ARCHLIB + addpath(RUBY_SITE_THIN_ARCHLIB); +#endif + if (rb_safe_level() == 0) { - addpath("."); + addpath(getenv("RUBYLIB")); } rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0); - rb_argv = ary_new(); + rb_argv = rb_ary_new(); rb_define_readonly_variable("$*", &rb_argv); rb_define_global_const("ARGV", rb_argv); rb_define_readonly_variable("$-a", &do_split); @@ -716,7 +796,7 @@ ruby_set_argv(argc, argv) else dln_argv0 = argv[0]; #endif for (i=0; i < argc; i++) { - ary_push(rb_argv, str_taint(str_new2(argv[i]))); + rb_ary_push(rb_argv, rb_tainted_str_new2(argv[i])); } } @@ -725,12 +805,9 @@ ruby_process_options(argc, argv) int argc; char **argv; { - extern VALUE errat; - int i; - origargc = argc; origargv = argv; ruby_script(argv[0]); /* for the time being */ - rb_argv0 = str_taint(str_new2(argv[0])); + rb_argv0 = rb_progname; #if defined(USE_DLN_A_OUT) dln_argv0 = argv[0]; #endif @@ -738,14 +815,22 @@ ruby_process_options(argc, argv) ruby_script(script); ruby_set_argv(argc, argv); - if (do_check && nerrs == 0) { + if (do_check && ruby_nerrs == 0) { printf("Syntax OK\n"); exit(0); } if (do_print) { - yyappend_print(); + rb_parser_append_print(); } if (do_loop) { - yywhile_loop(do_line, do_split); + rb_parser_while_loop(do_line, do_split); + } + if (e_fp) { + fclose(e_fp); + e_fp = NULL; + } + if (e_tmpname) { + unlink(e_tmpname); + e_tmpname = NULL; } } diff --git a/ruby.h b/ruby.h index ac53f620a9..44c1abd2c6 100644 --- a/ruby.h +++ b/ruby.h @@ -6,17 +6,26 @@ $Date$ created at: Thu Jun 10 14:26:32 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto *************************************************/ #ifndef RUBY_H #define RUBY_H -#include "config.h" +#if defined(__cplusplus) +extern "C" { +#endif +#include "config.h" #include "defines.h" +#if 0 +#ifndef RUBY_RENAME +#include "rename2.h" +#endif +#endif + #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif @@ -27,6 +36,19 @@ # include <strings.h> #endif +#include <stddef.h> +#include <stdio.h> + +/* need to include <ctype.h> to use these macros */ +#define ISSPACE(c) isspace((unsigned char)(c)) +#define ISUPPER(c) isupper((unsigned char)(c)) +#define ISLOWER(c) islower((unsigned char)(c)) +#define ISPRINT(c) isprint((unsigned char)(c)) +#define ISALNUM(c) isalnum((unsigned char)(c)) +#define ISALPHA(c) isalpha((unsigned char)(c)) +#define ISDIGIT(c) isdigit((unsigned char)(c)) +#define ISXDIGIT(c) isxdigit((unsigned char)(c)) + #ifndef __STDC__ # define volatile # ifdef __GNUC__ @@ -34,34 +56,48 @@ # else # define const # endif +#endif + +#ifdef HAVE_PROTOTYPES +# define _(args) args +#else # define _(args) () +#endif + +#ifdef HAVE_STDARG_PROTOTYPES +# define __(args) args #else -# define _(args) args +# define __(args) () +#endif + +#ifdef HAVE_ATTR_NORETURN +# define NORETURN __attribute__ ((noreturn)) +#else +# define NORETURN #endif #if defined(HAVE_ALLOCA_H) && !defined(__GNUC__) #include <alloca.h> #endif +#if defined(__CYGWIN32__) +#if defined(DLLIMPORT) +#include "import.h" +#else +#define environ (*__imp___cygwin_environ) +#endif +#endif + #ifdef _AIX #pragma alloca #endif -typedef unsigned short USHORT; -typedef unsigned long UINT; - -#if SIZEOF_INT == SIZEOF_VOIDP -typedef int INT; -#elif SIZEOF_LONG == SIZEOF_VOIDP -typedef long INT; -#else ----->> ruby requires sizeof(void*) == sizeof(int/long) to be compiled. <<---- -#endif -typedef UINT VALUE; +#if SIZEOF_LONG != SIZEOF_VOIDP +---->> ruby requires sizeof(void*) == sizeof(long) to be compiled. <<---- +# endif +typedef unsigned long VALUE; typedef unsigned int ID; -typedef unsigned char UCHAR; - #ifdef __STDC__ # include <limits.h> #else @@ -69,15 +105,12 @@ typedef unsigned char UCHAR; # ifdef HAVE_LIMITS_H # include <limits.h> # else -# define LONG_MAX 2147483647 /* assuming 32bit(2's compliment) LONG */ + /* assuming 32bit(2's compliment) long */ +# define LONG_MAX 2147483647 # endif # endif # ifndef LONG_MIN -# if (0 != ~0) -# define LONG_MIN (-LONG_MAX-1) -# else -# define LONG_MIN (-LONG_MAX) -# endif +# define LONG_MIN (-LONG_MAX-1) # endif # ifndef CHAR_BIT # define CHAR_BIT 8 @@ -85,32 +118,21 @@ typedef unsigned char UCHAR; #endif #define FIXNUM_MAX (LONG_MAX>>1) -#define FIXNUM_MIN RSHIFT((INT)LONG_MIN,1) +#define FIXNUM_MIN RSHIFT((long)LONG_MIN,1) #define FIXNUM_FLAG 0x01 -#define INT2FIX(i) (VALUE)(((INT)(i))<<1 | FIXNUM_FLAG) -VALUE int2inum _((INT)); -#define INT2NUM(v) int2inum(v) - -#if (-1==(((-1)<<1)&FIXNUM_FLAG)>>1) -# define RSHIFT(x,y) ((x)>>y) -#else -# define RSHIFT(x,y) (((x)<0) ? ~((~(x))>>y) : (x)>>y) -#endif -#define FIX2INT(x) RSHIFT((INT)x,1) +#define INT2FIX(i) (VALUE)(((long)(i))<<1 | FIXNUM_FLAG) +VALUE rb_int2inum _((long)); +#define INT2NUM(v) rb_int2inum(v) -#define FIX2UINT(f) (((UINT)(f))>>1) +#define FIX2LONG(x) RSHIFT((long)x,1) +#define FIX2ULONG(x) (((unsigned long)(x))>>1) #define FIXNUM_P(f) (((long)(f))&FIXNUM_FLAG) #define POSFIXABLE(f) ((f) <= FIXNUM_MAX) #define NEGFIXABLE(f) ((f) >= FIXNUM_MIN) #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f)) /* special contants - i.e. non-zero and non-fixnum constants */ -#undef FALSE -#undef TRUE -#define FALSE 0 -#define TRUE 2 -#define NIL 4 #define Qfalse 0 #define Qtrue 2 #define Qnil 4 @@ -118,36 +140,35 @@ VALUE int2inum _((INT)); # define RTEST(v) rb_test_false_or_nil((VALUE)(v)) #define NIL_P(v) ((VALUE)(v) == Qnil) -extern VALUE cObject; - -VALUE rb_class_of _((VALUE)); #define CLASS_OF(v) rb_class_of((VALUE)(v)) -#define T_NIL 0x00 -#define T_OBJECT 0x01 -#define T_CLASS 0x02 -#define T_ICLASS 0x03 -#define T_MODULE 0x04 -#define T_FLOAT 0x05 -#define T_STRING 0x06 -#define T_REGEXP 0x07 -#define T_ARRAY 0x08 -#define T_FIXNUM 0x09 -#define T_HASH 0x0a -#define T_STRUCT 0x0b -#define T_BIGNUM 0x0c -#define T_FILE 0x0d +#define T_NONE 0x00 + +#define T_NIL 0x01 +#define T_OBJECT 0x02 +#define T_CLASS 0x03 +#define T_ICLASS 0x04 +#define T_MODULE 0x05 +#define T_FLOAT 0x06 +#define T_STRING 0x07 +#define T_REGEXP 0x08 +#define T_ARRAY 0x09 +#define T_FIXNUM 0x0a +#define T_HASH 0x0b +#define T_STRUCT 0x0c +#define T_BIGNUM 0x0d +#define T_FILE 0x0e #define T_TRUE 0x20 #define T_FALSE 0x21 #define T_DATA 0x22 #define T_MATCH 0x23 -#define T_VARMAP 0xfd -#define T_SCOPE 0xfe -#define T_NODE 0xff +#define T_VARMAP 0x7d +#define T_SCOPE 0x7e +#define T_NODE 0x7f -#define T_MASK 0xff +#define T_MASK 0x7f #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) @@ -159,26 +180,50 @@ void rb_check_safe_str _((VALUE)); #define Check_SafeStr(v) rb_check_safe_str((VALUE)(v)) void rb_secure _((int)); -int num2int _((VALUE)); -#define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):num2int(x)) +long rb_num2long _((VALUE)); +unsigned long rb_num2ulong _((VALUE)); +#define NUM2LONG(x) (FIXNUM_P(x)?FIX2INT(x):rb_num2long((VALUE)x)) +#define NUM2ULONG(x) rb_num2ulong((VALUE)x) +#if SIZEOF_INT < SIZEOF_LONG +int rb_num2int _((VALUE)); +#define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):rb_num2int((VALUE)x)) +int rb_fix2int _((VALUE)); +#define FIX2INT(x) rb_fix2int((VALUE)x) +#define NUM2UINT(x) ((unsigned int)NUM2ULONG(x)) +#define FIX2UINT(x) ((unsigned int)FIX2ULONG(x)) +#else +#define NUM2INT(x) NUM2LONG(x) +#define NUM2UINT(x) NUM2ULONG(x) +#define FIX2INT(x) FIX2LONG(x) +#define FIX2UINT(x) FIX2ULONG(x) +#endif + +double rb_num2dbl _((VALUE)); +#define NUM2DBL(x) rb_num2dbl((VALUE)(x)) + +char *rb_str2cstr _((VALUE,int*)); +#define str2cstr(x,l) rb_str2cstr((VALUE)(x),(l)) +#define STR2CSTR(x) rb_str2cstr((VALUE)(x),0) -double num2dbl _((VALUE)); -#define NUM2DBL(x) num2dbl((VALUE)(x)) +#define NUM2CHR(x) (((TYPE(x) == T_STRING)&&(RSTRING(x)->len>=1))?\ + RSTRING(x)->ptr[0]:(char)NUM2INT(x)) +#define CHR2FIX(x) INT2FIX((int)x) VALUE rb_newobj _((void)); #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj() #define OBJSETUP(obj,c,t) {\ - RBASIC(obj)->class = (c);\ + RBASIC(obj)->klass = (c);\ RBASIC(obj)->flags = (t);\ + if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\ } #define CLONESETUP(clone,obj) {\ - OBJSETUP(clone,singleton_class_clone(RBASIC(obj)->class),RBASIC(obj)->flags);\ - singleton_class_attached(RBASIC(clone)->class, (VALUE)clone);\ + OBJSETUP(clone,rb_singleton_class_clone(RBASIC(obj)->klass),RBASIC(obj)->flags);\ + rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);\ } struct RBasic { - UINT flags; - VALUE class; + unsigned long flags; + VALUE klass; }; struct RObject { @@ -200,33 +245,34 @@ struct RFloat { struct RString { struct RBasic basic; - UINT len; - UCHAR *ptr; + size_t len; + char *ptr; VALUE orig; }; struct RArray { struct RBasic basic; - UINT len, capa; + size_t len, capa; VALUE *ptr; }; struct RRegexp { struct RBasic basic; struct re_pattern_buffer *ptr; - UINT len; - UCHAR *str; + size_t len; + char *str; }; struct RHash { struct RBasic basic; struct st_table *tbl; int iter_lev; - UINT status; + VALUE ifnone; }; struct RFile { struct RBasic basic; + struct st_table *iv_tbl; struct OpenFile *fptr; }; @@ -237,17 +283,18 @@ struct RData { void *data; }; +extern VALUE rb_cData; #define DATA_PTR(dta) (RDATA(dta)->data) -VALUE data_object_alloc _((VALUE,void*,void (*)(),void (*)())); -#define Data_Make_Struct(class,type,mark,free,sval) (\ +VALUE rb_data_object_alloc _((VALUE,void*,void (*)(),void (*)())); +#define Data_Make_Struct(klass,type,mark,free,sval) (\ sval = ALLOC(type),\ memset(sval, 0, sizeof(type)),\ - data_object_alloc(class,sval,mark,free)\ + rb_data_object_alloc(klass,sval,mark,free)\ ) -#define Data_Wrap_Struct(class,mark,free,sval) (\ - data_object_alloc(class,sval,mark,free)\ +#define Data_Wrap_Struct(klass,mark,free,sval) (\ + rb_data_object_alloc(klass,sval,mark,free)\ ) #define Data_Get_Struct(obj,type,sval) {\ @@ -257,21 +304,22 @@ VALUE data_object_alloc _((VALUE,void*,void (*)(),void (*)())); struct RStruct { struct RBasic basic; - UINT len; + size_t len; VALUE *ptr; }; struct RBignum { struct RBasic basic; char sign; - UINT len; - USHORT *digits; + size_t len; + unsigned short *digits; }; -#define R_CAST(st) (struct st*) +#define R_CAST(st) (struct st*) #define RBASIC(obj) (R_CAST(RBasic)(obj)) #define ROBJECT(obj) (R_CAST(RObject)(obj)) #define RCLASS(obj) (R_CAST(RClass)(obj)) +#define RMODULE(obj) RCLASS(obj) #define RFLOAT(obj) (R_CAST(RFloat)(obj)) #define RSTRING(obj) (R_CAST(RString)(obj)) #define RREGEXP(obj) (R_CAST(RRegexp)(obj)) @@ -282,9 +330,11 @@ struct RBignum { #define RBIGNUM(obj) (R_CAST(RBignum)(obj)) #define RFILE(obj) (R_CAST(RFile)(obj)) -#define FL_SINGLETON (1<<8) -#define FL_MARK (1<<9) -#define FL_FINALIZE (1<<10) +#define FL_SINGLETON FL_USER0 +#define FL_MARK (1<<7) +#define FL_FINALIZE (1<<8) +#define FL_TAINT (1<<9) +#define FL_EXIVAR (1<<10) #define FL_USHIFT 11 @@ -295,8 +345,9 @@ struct RBignum { #define FL_USER4 (1<<(FL_USHIFT+4)) #define FL_USER5 (1<<(FL_USHIFT+5)) #define FL_USER6 (1<<(FL_USHIFT+6)) +#define FL_USER7 (1<<(FL_USHIFT+7)) -#define FL_UMASK (0x7f<<FL_USHIFT) +#define FL_UMASK (0xff<<FL_USHIFT) #define FL_ABLE(x) (!(FIXNUM_P(x)||rb_special_const_p((VALUE)(x)))) #define FL_TEST(x,f) (FL_ABLE(x)?(RBASIC(x)->flags&(f)):0) @@ -304,38 +355,12 @@ struct RBignum { #define FL_UNSET(x,f) if(FL_ABLE(x)){RBASIC(x)->flags &= ~(f);} #define FL_REVERSE(x,f) if(FL_ABLE(x)){RBASIC(x)->flags ^= f;} -#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(RUBY_NO_INLINE) -extern __inline__ int -rb_type(VALUE obj) -{ - if (FIXNUM_P(obj)) return T_FIXNUM; - if (obj == Qnil) return T_NIL; - if (obj == FALSE) return T_FALSE; - if (obj == TRUE) return T_TRUE; - - return BUILTIN_TYPE(obj); -} - -extern __inline__ int -rb_special_const_p(VALUE obj) -{ - return (FIXNUM_P(obj)||obj == Qnil||obj == FALSE||obj == TRUE)?TRUE:FALSE; -} - -extern __inline__ int -rb_test_false_or_nil(VALUE v) -{ - return (v != Qnil) && (v != FALSE); -} -#else -int rb_type _((VALUE)); -int rb_special_const_p _((VALUE)); -int rb_test_false_or_nil _((VALUE)); -#endif +#define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT) +#define OBJ_TAINT(x) FL_SET((x), FL_TAINT) -void *xmalloc _((unsigned long)); -void *xcalloc _((unsigned long,unsigned long)); -void *xrealloc _((void*,unsigned long)); +void *xmalloc _((size_t)); +void *xcalloc _((size_t,size_t)); +void *xrealloc _((void*,size_t)); #define ALLOC_N(type,n) (type*)xmalloc(sizeof(type)*(n)) #define ALLOC(type) (type*)xmalloc(sizeof(type)) #define REALLOC_N(var,type,n) (var)=(type*)xrealloc((char*)(var),sizeof(type)*(n)) @@ -362,13 +387,12 @@ void rb_define_const _((VALUE,char*,VALUE)); void rb_define_global_const _((char*,VALUE)); void rb_define_method _((VALUE,char*,VALUE(*)(),int)); -void rb_define_function _((VALUE,char*,VALUE(*)(),int)); void rb_define_module_function _((VALUE,char*,VALUE(*)(),int)); -void rb_define_global_function _((char *, VALUE (*)(), int)); +void rb_define_global_function _((char*,VALUE(*)(),int)); void rb_undef_method _((VALUE,char*)); void rb_define_alias _((VALUE,char*,char*)); -void rb_define_attr _((VALUE,ID,int,int)); +void rb_define_attr _((VALUE,char*,int,int)); ID rb_intern _((char*)); char *rb_id2name _((ID)); @@ -379,8 +403,9 @@ char *rb_class2name _((VALUE)); void rb_p _((VALUE)); VALUE rb_eval_string _((char*)); -VALUE rb_funcall(); -int rb_scan_args(); +VALUE rb_eval_string_protect _((char*, int*)); +VALUE rb_funcall __((VALUE, ID, int, ...)); +int rb_scan_args __((int, VALUE*, char*, ...)); VALUE rb_iv_get _((VALUE, char *)); VALUE rb_iv_set _((VALUE, char *, VALUE)); @@ -390,53 +415,140 @@ void rb_const_set _((VALUE, ID, VALUE)); VALUE rb_equal _((VALUE,VALUE)); -extern VALUE verbose, debug; +EXTERN VALUE rb_verbose, rb_debug; int rb_safe_level _((void)); void rb_set_safe_level _((int)); -#ifdef __GNUC__ -typedef void voidfn (); -volatile voidfn Raise; -volatile voidfn Fail; -volatile voidfn Fatal; -volatile voidfn Bug; -volatile voidfn WrongType; -volatile voidfn rb_sys_fail; -volatile voidfn rb_iter_break; -volatile voidfn rb_exit; -volatile voidfn rb_fatal; -volatile voidfn rb_raise; -volatile voidfn rb_notimplement; -#else -void Raise(); -void Fail(); -void Fatal(); -void Bug(); -void WrongType(); -void rb_sys_fail _((char *)); -void rb_iter_break _((void)); -void rb_exit _((int)); -void rb_raise _((VALUE)); -void rb_fatal _((VALUE)); -void rb_notimplement _((void)); -#endif +void rb_raise __((VALUE, char*, ...)) NORETURN; +void rb_fatal __((char*, ...)) NORETURN; +void rb_bug __((char*, ...)) NORETURN; +void rb_sys_fail _((char*)) NORETURN; +void rb_iter_break _((void)) NORETURN; +void rb_exit _((int)) NORETURN; +void rb_notimplement _((void)) NORETURN; -void Error(); -void Warning(); +void rb_warn __((char*, ...)); +void rb_warning __((char*, ...)); /* reports if `-w' specified */ VALUE rb_each _((VALUE)); VALUE rb_yield _((VALUE)); -int iterator_p _((void)); -VALUE rb_iterate(); -VALUE rb_rescue(); -VALUE rb_ensure(); +int rb_iterator_p _((void)); +VALUE rb_iterate _((VALUE(*)(),VALUE,VALUE(*)(),VALUE)); +VALUE rb_rescue _((VALUE(*)(),VALUE,VALUE(*)(),VALUE)); +VALUE rb_ensure _((VALUE(*)(),VALUE,VALUE(*)(),VALUE)); +VALUE rb_catch _((char*,VALUE(*)(),VALUE)); +void rb_throw _((char*,VALUE)) NORETURN; + +void ruby_init _((void)); +void ruby_options _((int, char**)); +void ruby_run _((void)); + +EXTERN VALUE rb_mKernel; +EXTERN VALUE rb_mComparable; +EXTERN VALUE rb_mEnumerable; +EXTERN VALUE rb_mErrno; +EXTERN VALUE rb_mFileTest; +EXTERN VALUE rb_mGC; +EXTERN VALUE rb_mMath; +EXTERN VALUE rb_mProcess; + +EXTERN VALUE rb_cObject; +EXTERN VALUE rb_cArray; +EXTERN VALUE rb_cBignum; +EXTERN VALUE rb_cClass; +EXTERN VALUE rb_cDir; +EXTERN VALUE rb_cData; +EXTERN VALUE rb_cFalseClass; +EXTERN VALUE rb_cFile; +EXTERN VALUE rb_cFixnum; +EXTERN VALUE rb_cFloat; +EXTERN VALUE rb_cHash; +EXTERN VALUE rb_cInteger; +EXTERN VALUE rb_cIO; +EXTERN VALUE rb_cModule; +EXTERN VALUE rb_cNilClass; +EXTERN VALUE rb_cNumeric; +EXTERN VALUE rb_cProc; +EXTERN VALUE rb_cRange; +EXTERN VALUE rb_cRegexp; +EXTERN VALUE rb_cString; +EXTERN VALUE rb_cThread; +EXTERN VALUE rb_cTime; +EXTERN VALUE rb_cTrueClass; +EXTERN VALUE rb_cStruct; + +EXTERN VALUE rb_eException; +EXTERN VALUE rb_eStandardError; +EXTERN VALUE rb_eSystemExit, rb_eInterrupt, rb_eFatal; +EXTERN VALUE rb_eArgError; +EXTERN VALUE rb_eEOFError; +EXTERN VALUE rb_eIndexError; +EXTERN VALUE rb_eIOError; +EXTERN VALUE rb_eLoadError; +EXTERN VALUE rb_eNameError; +EXTERN VALUE rb_eRuntimeError; +EXTERN VALUE rb_eSecurityError; +EXTERN VALUE rb_eSyntaxError; +EXTERN VALUE rb_eSystemCallError; +EXTERN VALUE rb_eTypeError; +EXTERN VALUE rb_eZeroDiv; +EXTERN VALUE rb_eNotImpError; + +#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__ int rb_test_false_or_nil _((VALUE)); + +extern __inline__ VALUE +rb_class_of(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; + + return RBASIC(obj)->klass; +} + +extern __inline__ int +rb_type(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; + return BUILTIN_TYPE(obj); +} + +extern __inline__ int +rb_special_const_p(VALUE obj) +{ + return (FIXNUM_P(obj)||obj == Qnil||obj == Qfalse||obj == Qtrue)?Qtrue:Qfalse; +} + +extern __inline__ int +rb_test_false_or_nil(VALUE v) +{ + return (v != Qnil) && (v != Qfalse); +} +#else +VALUE rb_class_of _((VALUE)); +int rb_type _((VALUE)); +int rb_special_const_p _((VALUE)); +int rb_test_false_or_nil _((VALUE)); +#endif #include "intern.h" #if defined(EXTLIB) && defined(USE_DLN_A_OUT) /* hook for external modules */ -static char *libs_to_be_linked[] = { EXTLIB, 0 }; +static char *dln_libs_to_be_linked[] = { EXTLIB, 0 }; #endif +#if defined(__cplusplus) +} /* extern "C" { */ #endif + +#endif /* ifndef RUBY_H */ diff --git a/rubytest.rb b/rubytest.rb index f0e4bf8c8e..cf583c1dfb 100644 --- a/rubytest.rb +++ b/rubytest.rb @@ -1,3 +1,5 @@ +#! ./miniruby -I. + require 'rbconfig' include Config diff --git a/sample/fib.scm b/sample/fib.scm index 8eba75bb9e..5c2b86e656 100644 --- a/sample/fib.scm +++ b/sample/fib.scm @@ -3,4 +3,6 @@ n (+ (fib (- n 2)) (fib (- n 1))))) -(fib 20) +(display (fib 20)) +(newline) + diff --git a/sample/freq.rb b/sample/freq.rb index d951591735..4e0206c114 100644 --- a/sample/freq.rb +++ b/sample/freq.rb @@ -1,13 +1,13 @@ # word occurrence listing # usege: ruby freq.rb file.. -freq = {} +freq = Hash.new(0) while gets while sub!(/\w+/, '') word = $& - freq[word] +=1 + freq[word] += 1 end end -for word in freq.keys.sort - printf("%s -- %d\n", word, freq[word]) +for word in freq.keys.sort! + print word, " -- ", freq[word], "\n" end diff --git a/sample/from.rb b/sample/from.rb index d39bb70084..93b6c4bade 100644 --- a/sample/from.rb +++ b/sample/from.rb @@ -9,8 +9,6 @@ include Kconv class String - public :kconv - def kconv(code = Kconv::EUC) Kconv.kconv(self, code, Kconv::AUTO) end @@ -32,13 +30,20 @@ if ARGV[0] == '-w' end if ARGV.length == 0 - user = ENV['USER'] + file = ENV['MAIL'] + user = ENV['USER'] || ENV['USERNAME'] || ENV['LOGNAME'] else - user = ARGV[0] + file = user = ARGV[0] + ARGV.clear end -[ENV['SPOOLDIR'], '/usr/spool', '/var/spool', '/usr', '/var'].each do |m| - break if File.exist? ARGV[0] = "#{m}/mail/#{user}" +if file == nil or !File.exist? file + [ENV['SPOOLDIR'], '/usr/spool', '/var/spool', '/usr', '/var'].each do |m| + if File.exist? f = "#{m}/mail/#{user}" + file = f + break + end + end end $outcount = 0; @@ -63,18 +68,23 @@ def fromout(date, from, subj) end from = from.kconv(lang).kjust(28) subj = subj.kconv(lang).kjust(40) - printf "%02d/%02d/%02d [%s] %s\n",y,m,d,from,subj + printf "%02d/%02d/%02d [%s] %s\n",y%100,m,d,from,subj $outcount += 1 end -for file in ARGV - next if !File.exist?(file) +if File.exist?(file) + atime = File.atime(file) + mtime = File.mtime(file) f = open(file, "r") - while !f.eof? - mail = Mail.new(f) - fromout mail.header['Date'], mail.header['From'], mail.header['Subject'] + begin + until f.eof? + mail = Mail.new(f) + fromout mail.header['Date'],mail.header['From'],mail.header['Subject'] + end + ensure + f.close + File.utime(atime, mtime, file) end - f.close end if $outcount == 0 diff --git a/sample/mkproto.rb b/sample/mkproto.rb index 97006f9f54..8661240085 100644 --- a/sample/mkproto.rb +++ b/sample/mkproto.rb @@ -8,17 +8,17 @@ while gets() arg.gsub! ' +', ' ' if arg =~ /,/ if arg =~ /(([^*]+) *\** *[\w\d_]+),/ - type = $2.strip! - args.push $1.strip! + type = $2.strip + args.push $1.strip arg = $' else type = "" end while arg.sub!(/(\** *[\w\d_]+)(,|$)/, "") - args.push type + " " + $1.strip! + args.push type + " " + $1.strip end else - args.push arg.strip! + args.push arg.strip end end printf "%s);\n", args.join(', ') diff --git a/sample/observ.rb b/sample/observ.rb index f7b1e73137..72e5178b38 100644 --- a/sample/observ.rb +++ b/sample/observ.rb @@ -7,25 +7,26 @@ class Tick include Observable def initialize Thread.start do - while TRUE + loop do sleep 0.999 + now = Time.now changed - notify_observers(Time.now.strftime("%H:%M:%S")) + notify_observers(now.hour, now.min, now.sec) end end end end class Clock - def initialize - @tick = Tick.new + def initialize(tick) + @tick = tick @tick.add_observer(self) end - def update(time) - print "\e[8D", time + def update(h, m, s) + printf "\e[8D%02d:%02d:%02d", h, m, s STDOUT.flush end end -clock = Clock.new +clock = Clock.new(Tick.new) sleep diff --git a/sample/occur.rb b/sample/occur.rb index 2141fade38..f489beee17 100644 --- a/sample/occur.rb +++ b/sample/occur.rb @@ -1,12 +1,12 @@ # word occurrence listing # usege: ruby occur.rb file.. -freq = {} +freq = Hash.new(0) while gets() for word in $_.split(/\W+/) - freq[word] +=1 + freq[word] += 1 end end -for word in freq.keys.sort - printf("%s -- %d\n", word, freq[word]) +for word in freq.keys.sort! + print word, " -- ", freq[word], "\n" end diff --git a/sample/rbc.rb b/sample/rbc.rb index 88a5b2d069..83796255cc 100644 --- a/sample/rbc.rb +++ b/sample/rbc.rb @@ -1,9 +1,9 @@ #!/usr/local/bin/ruby # # rbc.rb - -# $Release Version: 0.6 $ -# $Revision: 1.2 $ -# $Date: 1997/11/27 13:46:06 $ +# $Release Version: 0.8 $ +# $Revision: 1.8 $ +# $Date: 1998/03/11 05:43:00 $ # by Keiju ISHITSUKA(Nippon Rational Inc.) # # -- @@ -11,46 +11,46 @@ # # rbc.rb [options] file_name opts # options: -# -d ĄÇĄĐĄĂĄ°ĄâˇĽĄÉ(ÍřÍѤ·¤Ę¤¤Ęý¤¬Îɤ¤¤Ç¤·¤ç¤¦) -# -m bcĄâˇĽĄÉ(ʬżô, ąÔÎó¤Î·×»»¤¬¤Ç¤­¤Ţ¤ą) -# -r load-module ruby -r ¤ČƱ¤¸ -# --inspect ·ë˛Ě˝ĐÎϤËinspect¤ňÍѤ¤¤ë(bcĄâˇĽĄÉ°Ęł°¤ĎĄÇ -# ĄŐĄ©ĄëĄČ). -# --noinspect ·ë˛Ě˝ĐÎϤËinspect¤ňÍѤ¤¤Ę¤¤. -# --noreadline readlineĄéĄ¤ĄÖĄéĄę¤ňÍřÍѤ·¤Ę¤¤(ĄÇĄŐĄ©ĄëĄČ -# ¤Ç¤ĎreadlineĄéĄ¤ĄÖĄéĄę¤ňÍřÍѤ·¤č¤¦¤Č¤ą¤ë). +# -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) # -# Äɲà private method: -# exit, quit ˝ŞÎ»¤ą¤ë. -# inspect(sw = nil) Ą¤ĄóĄąĄÚĄŻĄČĄâˇĽĄÉ¤ÎĄČĄ°Ąë -# trace_load(sw = nil) load/require»ţ¤Ërbc¤ÎfileĆɤ߹ţ¤ßµˇÇ˝¤ňÍŃ -# ¤¤¤ëĄâˇĽĄÉ¤ÎĄąĄ¤ĄĂĄÁ(ĄÇĄŐĄ©ĄëĄČ¤ĎĄČĄěˇĽĄą -# ĄâˇĽĄÉ) +# 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='-$Header: /home/keiju/var/src/var.lib/ruby/ruby/RCS/rbc.rb,v 1.2 1997/11/27 13:46:06 keiju Exp keiju $-' + 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" - $DEBUG = FALSE - $INSPECT = nil - CONFIG = {} CONFIG[0] = $0 CONFIG[:USE_READLINE] = TRUE CONFIG[:LOAD_MODULES] = [] CONFIG[:INSPECT] = nil - CONFIG[:TRACE_LOAD] = TRUE + CONFIG[:TRACE_LOAD] = FALSE + CONFIG[:RC] = TRUE + + CONFIG[:DEBUG] = FALSE while opt = ARGV.shift case opt when "-d" - $DEBUG = TRUE + CONFIG[:DEBUG] = TRUE when "-m" CONFIG[:INSPECT] = FALSE if CONFIG[:INSPECT].nil? require "mathn.rb" @@ -58,6 +58,9 @@ module BC_APPLICATION__ 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" @@ -66,7 +69,7 @@ module BC_APPLICATION__ CONFIG[:USE_READLINE] = FALSE when /^-/ # print UnrecognizedSwitch.inspect, "\n" - BC.fail UnrecognizedSwitch, opt + BC_APPLICATION__.fail UnrecognizedSwitch, opt else CONFIG[:USE_READLINE] = FALSE $0 = opt @@ -104,7 +107,7 @@ module BC_APPLICATION__ line = line + l lex(l) if l != "\n" - print @quoted.inspect, "\n" if $DEBUG + print @quoted.inspect, "\n" if CONFIG[:DEBUG] if @ltype @io.prompt = format(PROMPTs, @indent, @ltype) next @@ -120,9 +123,9 @@ module BC_APPLICATION__ if line != "\n" begin if CONFIG[:INSPECT] - print (cont._=eval(line, bind)).inspect, "\n" + print((cont._=eval(line, bind)).inspect, "\n") else - print (cont._=eval(line, bind)), "\n" + print((cont._=eval(line, bind)), "\n") end rescue # $! = 'exception raised' unless $! @@ -182,7 +185,8 @@ module BC_APPLICATION__ "case", "class", "def", "do", "for", "if", "module", "unless", "until", "while", "begin" #, "when" ] - DEINDENT_CLAUSE = ["end"] + DEINDENT_CLAUSE = ["end" #, "when" + ] PARCENT_LTYPE = { "q" => "\'", @@ -197,7 +201,7 @@ module BC_APPLICATION__ "<" => ">", "(" => ")" } - + def lex_init() @OP = Trie.new @OP.def_rules("\0", "\004", "\032"){} @@ -211,7 +215,7 @@ module BC_APPLICATION__ identify_comment(rests) end @OP.def_rule("\n") do - print "\\n\n" if $DEBUG + print "\\n\n" if CONFIG[:DEBUG] if @lex_state == EXPR_BEG || @lex_state == EXPR_FNAME @continue = TRUE else @@ -220,9 +224,9 @@ module BC_APPLICATION__ 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("=", "==", "===", "=~", "<=>") {@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 @@ -268,10 +272,14 @@ module BC_APPLICATION__ if rests[0] =~ /[0-9]/ rests.unshift op identify_number(rests) + else + # obj.if ¤Ę¤É¤ÎÂбţ + identify_identifier(rests, TRUE) + @lex_state = EXPR_ARG end end @OP.def_rules("..", "...") {@lex_state = EXPR_BEG} - + lex_int2 end @@ -280,8 +288,12 @@ module BC_APPLICATION__ @lex_state = EXPR_END @indent -= 1 end - @OP.def_rule(":") {} - @OP.def_rule("::") {@lex_state = EXPR_BEG} + @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 @@ -343,16 +355,26 @@ module BC_APPLICATION__ 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", op, rests.inspect if $DEBUG + 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", op, rests.inspect if $DEBUG + printf "MATCH: end %s: %s\n", op, rests.inspect if CONFIG[:DEBUG] end + + p @OP if CONFIG[:DEBUG] end def lex(l) @@ -380,9 +402,9 @@ module BC_APPLICATION__ until chrs.empty? @space_seen = FALSE - printf "perse: %s\n", chrs.join("") if $DEBUG + printf "perse: %s\n", chrs.join("") if CONFIG[:DEBUG] @OP.match(chrs) - printf "lex_state: %s continue: %s\n", @lex_state.id2name, @continue if $DEBUG + printf "lex_state: %s continue: %s\n", @lex_state.id2name, @continue if CONFIG[:DEBUG] end end @@ -421,11 +443,11 @@ module BC_APPLICATION__ end end - def identify_identifier(chrs) + def identify_identifier(chrs, escaped = FALSE) token = "" - token.concat chrs.shift if chrs[0] =~ /[$@]/ + token.concat chrs.shift if chrs[0] =~ /[$@]/ or escaped while (ch = chrs.shift) =~ /\w|_/ - print ":", ch, ":" if $DEBUG + print ":", ch, ":" if CONFIG[:DEBUG] token.concat ch end chrs.unshift ch @@ -436,12 +458,12 @@ module BC_APPLICATION__ end # fix token - if token =~ /^[$@]/ + if token =~ /^[$@]/ or escaped @lex_state = EXPR_END return end - print token, "\n" if $DEBUG + print token, "\n" if CONFIG[:DEBUG] if state = CLAUSE_STATE_TRANS[token] if @lex_state != EXPR_BEG and token =~ /^(if|unless|while|until)/ # ˝¤ľţ»Ň @@ -624,14 +646,9 @@ module BC_APPLICATION__ @preproc = preproc @postproc = postproc end - - def preproc(p) - @preproc = p - end - - def postproc(p) - @postproc = p - end + + attr :preproc, TRUE + attr :postproc, TRUE def search(chrs, opt = nil) return self if chrs.empty? @@ -649,10 +666,29 @@ module BC_APPLICATION__ 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? - Trie.fail ErrNodeAlreadyExists + 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 @@ -669,10 +705,10 @@ module BC_APPLICATION__ end def match(chrs, op = "") - print "match: ", chrs, ":", op, "\n" if $DEBUG + 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 $DEBUG + printf "op1: %s\n", op if CONFIG[:DEBUG] @postproc.call(op, chrs) "" else @@ -683,23 +719,23 @@ module BC_APPLICATION__ if node = @Tree[ch] if ret = node.match(chrs, op+ch) return ch+ret - elsif @postproc and @preproc.nil? || @preproc.call(op, chrs) - chrs.unshift ch - printf "op2: %s\n", op if $DEBUG - @postproc.call(op, chrs) - return "" else chrs.unshift ch - return nil + 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 $DEBUG - chrs.unshift ch + printf "op3: %s\n", op if CONFIG[:DEBUG] @postproc.call(op, chrs) return "" else - chrs.unshift ch return nil end end @@ -712,14 +748,9 @@ module BC_APPLICATION__ end def def_rule(token, preproc = nil, postproc = nil) - node = search(token, :CREATE) -# print node.inspect, "\n" if $DEBUG - node.preproc(preproc) - if iterator? - node.postproc(proc) - elsif postproc - node.postproc(postproc) - end +# print node.inspect, "\n" if CONFIG[:DEBUG] + postproc = proc if iterator? + node = create(token, preproc, postproc) end def def_rules(*tokens) @@ -731,24 +762,28 @@ module BC_APPLICATION__ end end - def preporc(token) + def preporc(token, proc) node = search(token) - node.preproc proc + node.preproc=proc end def postproc(token) - node = search(token) - node.postproc proc + node = search(token, proc) + node.postproc=proc end - def search(token, opt = nil) - @head.search(token.split(//), opt) + 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 $DEBUG + printf "match end: %s:%s", ret, token.inspect if CONFIG[:DEBUG] ret end @@ -795,25 +830,26 @@ module BC_APPLICATION__ module CONTEXT def _=(value) - @_ = value + CONFIG[:_] = value + eval "_=BC_APPLICATION__::CONFIG[:_]", CONFIG[:BIND] end - def _ - @_ - end +# def _ +# eval "_", CONFIG[:BIND] +# end def quit exit end def trace_load(opt = nil) - if opt - @Trace_require = opt + if !opt.nil? + CONFIG[:TRACE_LOAD] = opt else - @Trace_require = !@Trace_require + CONFIG[:TRACE_LOAD] = !CONFIG[:TRACE_LOAD] end - print "Switch to load/require #{unless @Trace_require; ' non';end} trace mode.\n" - if @Trace_require + 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 @@ -828,7 +864,7 @@ module BC_APPLICATION__ end } end - @Trace_require + CONFIG[:TRACE_LOAD] end alias rbc_load_org load @@ -845,17 +881,18 @@ module BC_APPLICATION__ case file_name when /\.rb$/ if load_sub(file_name) - $:.push file_name + $".push file_name return true end when /\.(so|o|sl)$/ - require_org(file_name) + rbc_require_org(file_name) end if load_sub(f = file_name + ".rb") - $:.push f + $".push f + return true end - require(file_name) + rbc_require_org(file_name) end def load_sub(fn) @@ -874,19 +911,34 @@ module BC_APPLICATION__ return false end - def inspect(opt = nil) + def inspect_mode(opt = nil) if opt CONFIG[:INSPECT] = opt else - CONFIG[:INSPECT] = !$INSPECT + CONFIG[:INSPECT] = !CONFIG[:INSPECT] end - print "Switch to#{unless $INSPECT; ' non';end} inspect mode.\n" - $INSPECT + print "Switch to#{unless CONFIG[:INSPECT]; ' non';end} inspect mode.\n" + CONFIG[:INSPECT] end - def run - CONFIG[:BIND] = proc + def run(bind) + CONFIG[:BIND] = bind + if CONFIG[:RC] + rc = File.expand_path("~/.irbrc") + if File.exists?(rc) + begin + load rc + rescue + 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 @@ -898,7 +950,7 @@ module BC_APPLICATION__ print $@[0], ":", $!.type, ": ", $!, "\n" end end - + if !$0.equal?(CONFIG[0]) io = FileInputMethod.new($0) elsif defined? Readline @@ -959,4 +1011,5 @@ module BC_APPLICATION__ end extend BC_APPLICATION__::CONTEXT -run{} +run(binding) + diff --git a/sample/sieve.rb b/sample/sieve.rb index 03ff8a67f4..5e9f792d81 100644 --- a/sample/sieve.rb +++ b/sample/sieve.rb @@ -1,7 +1,6 @@ # sieve of Eratosthenes sieve = [] -if ! max = ARGV.shift; max = 100; end -max = max.to_i +max = Integer(ARGV.shift || 100) print "1" for i in 2 .. max diff --git a/sample/test.rb b/sample/test.rb index 0a9d41c2ed..f28327659e 100644 --- a/sample/test.rb +++ b/sample/test.rb @@ -24,6 +24,24 @@ end # make sure conditional operators work +check "assignment" + +a=[]; a[0] ||= "bar"; +ok(a[0] == "bar") +h={}; h["foo"] ||= "bar"; +ok(h["foo"] == "bar") + +aa = 5 +aa ||= 25 +ok(aa == 5) +bb ||= 25 +ok(bb == 25) +cc &&=33 +ok(cc == nil) +cc = 5 +cc &&=44 +ok(cc == 44) + check "condition" $x = '0'; @@ -109,8 +127,8 @@ tmp.close $bad = false tmp = open("while_tmp", "r") while tmp.gets() - next if /vt100/; - $bad = 1 if /vt100/; + next if /vt100/; + $bad = 1 if /vt100/; end ok(!(!tmp.eof? || /vt100/ || $bad)) tmp.close @@ -240,6 +258,18 @@ while true end ok(!$bad) +ok(catch(:foo) { + loop do + loop do + throw :foo, true + break + end + break + ok(false) # should no reach here + end + false + }) + check "array" ok([1, 2] + [3, 4] == [1, 2, 3, 4]) ok([1, 2] * 2 == [1, 2, 1, 2]) @@ -265,11 +295,20 @@ ok($x[0] == -1 && $x[1] == 10) $x[-1, 1] = 20 ok($x[-1] == 20 && $x.pop == 20) +# array and/or +ok(([1,2,3]&[2,4,6]) == [2]) +ok(([1,2,3]|[2,4,6]) == [1,2,3,4,6]) + # compact $x = [nil, 1, nil, nil, 5, nil, nil] $x.compact! ok($x == [1, 5]) +# uniq +$x = [1, 1, 4, 2, 5, 4, 5, 1, 2] +$x.uniq! +ok($x == [1, 4, 2, 5]) + # empty? ok(!$x.empty?) $x = [] @@ -287,7 +326,8 @@ ok($x == [7,5,3,2,1]) # split test $x = "The Book of Mormon" -ok($x.split(//).reverse!.join == "nomroM fo kooB ehT") +ok($x.split(//).reverse!.join == $x.reverse) +ok($x.reverse == $x.reverse!) ok("1 byte string".split(//).reverse.join(":") == "g:n:i:r:t:s: :e:t:y:b: :1") $x = "a b c d" ok($x.split == ['a', 'b', 'c', 'd']) @@ -296,7 +336,7 @@ ok(defined? "a".chomp) ok("abc".scan(/./) == ["a", "b", "c"]) ok("1a2b3c".scan(/(\d.)/) == [["1a"], ["2b"], ["3c"]]) # non-greedy match -ok("a=12;b=22".scan(/(.*?)=(\d*?);?/) == [["a", "12"], ["b", "22"]]) +ok("a=12;b=22".scan(/(.*?)=(\d*);?/) == [["a", "12"], ["b", "22"]]) $x = [1] ok(($x * 5).join(":") == '1:1:1:1:1') @@ -374,17 +414,6 @@ tt{|i| break if i == 5} ok(i == 5) # iterator break/redo/next/retry -unless defined? loop - def loop - while true - yield - end - end - ok(false) -else - ok(true) -end - done = true loop{ break @@ -431,6 +460,76 @@ end ok($x.size == 10) ok($x == [1, 2, 3, 1, 2, 3, 4, 5, 6, 7]) +# append method to built-in class +class Array + def iter_test1 + collect{|e| [e, yield(e)]}.sort{|a,b|a[1]<=>b[1]} + end + def iter_test2 + a = collect{|e| [e, yield(e)]} + a.sort{|a,b|a[1]<=>b[1]} + end +end +$x = [[1,2],[3,4],[5,6]] +ok($x.iter_test1{|x|x} == $x.iter_test2{|x|x}) + +class IterTest + def initialize(e); @body = e; end + + def each0(&block); @body.each(&block); end + def each1(&block); @body.each { |*x| block.call(*x) } end + def each2(&block); @body.each { |*x| block.call(x) } end + def each3(&block); @body.each { |x| block.call(*x) } end + def each4(&block); @body.each { |x| block.call(x) } end + def each5; @body.each { |*x| yield(*x) } end + def each6; @body.each { |*x| yield(x) } end + def each7; @body.each { |x| yield(*x) } end + def each8; @body.each { |x| yield(x) } end +end + +IterTest.new([0]).each0 { |x| $x = x } +ok($x == 0) +IterTest.new([1]).each1 { |x| $x = x } +ok($x == 1) +IterTest.new([2]).each2 { |x| $x = x } +ok($x == [2]) +IterTest.new([3]).each3 { |x| $x = x } +ok($x == 3) +IterTest.new([4]).each4 { |x| $x = x } +ok($x == 4) +IterTest.new([5]).each5 { |x| $x = x } +ok($x == 5) +IterTest.new([6]).each6 { |x| $x = x } +ok($x == [6]) +IterTest.new([7]).each7 { |x| $x = x } +ok($x == 7) +IterTest.new([8]).each8 { |x| $x = x } +ok($x == 8) + +IterTest.new([[0]]).each0 { |x| $x = x } +ok($x == [0]) +IterTest.new([[1]]).each1 { |x| $x = x } +ok($x == 1) +IterTest.new([[2]]).each2 { |x| $x = x } +ok($x == [2]) +IterTest.new([[3]]).each3 { |x| $x = x } +ok($x == 3) +IterTest.new([[4]]).each4 { |x| $x = x } +ok($x == [4]) +IterTest.new([[5]]).each5 { |x| $x = x } +ok($x == 5) +IterTest.new([[6]]).each6 { |x| $x = x } +ok($x == [6]) +IterTest.new([[7]]).each7 { |x| $x = x } +ok($x == 7) +IterTest.new([[8]]).each8 { |x| $x = x } +ok($x == [8]) + +IterTest.new([[0,0]]).each0 { |x| $x = x } +ok($x == [0,0]) +IterTest.new([[8,8]]).each8 { |x| $x = x } +ok($x == [8,8]) + check "bignum" def fact(n) return 1 if n == 0 @@ -482,7 +581,9 @@ ok($good) $good = true; for i in 4000..4096 n1 = 1 << i; - $good = false if ((n1**2-1) / (n1+1) != (n1-1)) + if (n1**2-1) / (n1+1) != (n1-1) + $good = false + end end ok($good) @@ -491,9 +592,9 @@ check "string & char" ok("abcd" == "abcd") ok("abcd" =~ "abcd") ok("abcd" === "abcd") -ok(("abc" =~ /^$/) == false) -ok(("abc\n" =~ /^$/) == false) -ok(("abc" =~ /^d*$/) == false) +ok("abc" !~ /^$/) +ok("abc\n" !~ /^$/) +ok("abc" !~ /^d*$/) ok(("abc" =~ /d*$/) == 3) ok("" =~ /^$/) ok("\n" =~ /^$/) @@ -539,6 +640,8 @@ ok(?\M-\C-a == 129) ok("a".upcase![0] == ?A) ok("A".downcase![0] == ?a) ok("abc".tr!("a-z", "A-Z") == "ABC") +ok("aabbcccc".tr_s!("a-z", "A-Z") == "ABC") +ok("abc".tr!("0-9", "A-Z") == nil) ok("abcc".squeeze!("a-z") == "abc") ok("abcd".delete!("bc") == "ad") @@ -571,10 +674,13 @@ ok(a == 1) a, *b = 1, 2, 3 ok(a == 1 && b == [2, 3]) +a, (b, c), d = 1, [2, 3], 4 +ok(a == 1 && b == 2 && c == 3 && d == 4) + *a = 1, 2, 3 ok(a == [1, 2, 3]) -*a = 1..3 +*a = 1..3 # array conversion ok(a == [1, 2, 3]) check "call" @@ -614,14 +720,14 @@ ok($proc.call(2) == 4) ok($proc.call(3) == 6) proc{ - iii=5 # dynamic local variable + iii=5 # nested local variable $proc = proc{|i| iii = i } $proc2 = proc { - $x = iii # dynamic variables shared by procs + $x = iii # nested variables shared by procs } - # scope of dynamic variables + # scope of nested variables ok(defined?(iii)) }.call ok(!defined?(iii)) # out of scope @@ -649,9 +755,7 @@ if defined? Process.kill rescue x = $! end - ok(x && x =~ /Interrupt/) -else - ok(false) + ok(x && /Interrupt/ =~ x) end check "eval" @@ -691,8 +795,8 @@ def test_ev end $x = test_ev -ok(eval("local1", $x) == "local1") # static local var -ok(eval("local2", $x) == "local2") # dynamic local var +ok(eval("local1", $x) == "local1") # normal local var +ok(eval("local2", $x) == "local2") # nested local var $bad = true begin p eval("local1") @@ -716,6 +820,51 @@ rescue NameError # must raise error end ok(!$bad) +x = proc{} +eval "i4 = 1", x +ok(eval("i4", x) == 1) +x = proc{proc{}}.call +eval "i4 = 22", x +ok(eval("i4", x) == 22) +$x = [] +x = proc{proc{}}.call +eval "(0..9).each{|i5| $x[i5] = proc{i5*2}}", x +ok($x[4].call == 8) + +x = binding +eval "i = 1", x +ok(eval("i", x) == 1) +x = proc{binding}.call +eval "i = 22", x +ok(eval("i", x) == 22) +$x = [] +x = proc{binding}.call +eval "(0..9).each{|i5| $x[i5] = proc{i5*2}}", x +ok($x[4].call == 8) + +proc { + p = binding + eval "foo11 = 1", p + proc{foo11=22}.call + ok(eval("foo11", p) == eval("foo11")) + ok(eval("foo11") == 1) +}.call + +p1 = proc{i6 = 0; proc{i6}}.call +ok(p1.call == 0) +eval "i6=5", p1 +ok(p1.call == 5) +ok(!defined?(i6)) + +p1 = proc{i6 = 0; proc{i6}}.call +i6 = nil +ok(p1.call == 0) +eval "i6=1", p1 +ok(p1.call == 1) +eval "i6=5", p1 +ok(p1.call == 5) +ok(i6 == nil) + check "system" ok(`echo foobar` == "foobar\n") ok(`./ruby -e 'print "foobar"'` == 'foobar') @@ -766,6 +915,14 @@ ok(done) File.unlink "script_tmp" or `/bin/rm -f "script_tmp"` File.unlink "script_tmp.bak" or `/bin/rm -f "script_tmp.bak"` +$bad = false +for script in Dir["{lib,sample}/*.rb"] + unless `./ruby -c #{script}`.chomp == "Syntax OK" + $bad = true + end +end +ok(!$bad) + check "const" TEST1 = 1 TEST2 = 2 @@ -809,6 +966,11 @@ rescue ok true end +check "marshal" +$x = [1,2,3,[4,5,"foo"],{1=>"bar"},2.5,fact(30)] +$y = Marshal.dump($x) +ok($x == Marshal.load($y)) + check "pack" $format = "c2x5CCxsdila6"; diff --git a/sample/trojan.rb b/sample/trojan.rb index 2024da0908..edf8ee63ce 100644 --- a/sample/trojan.rb +++ b/sample/trojan.rb @@ -2,10 +2,10 @@ path = ENV['PATH'].split(/:/) for dir in path - if File.d(dir) + if File.directory?(dir) for f in d = Dir.open(dir) fpath = dir+"/"+f - if File.f(fpath) && (File.stat(fpath).mode & 022) != 0 + if File.file?(fpath) && (File.stat(fpath).mode & 022) != 0 printf("file %s is writable from other users\n", fpath) end end diff --git a/sample/tsvr.rb b/sample/tsvr.rb index fbc6545bb5..d6a5620d11 100644 --- a/sample/tsvr.rb +++ b/sample/tsvr.rb @@ -13,7 +13,7 @@ while TRUE ns = gs.accept print(ns, " is accepted\n") Thread.start do - s = ns # save to dynamic variable + s = ns # save to thread-local variable while s.gets s.write($_) end diff --git a/signal.c b/signal.c index e5621b4ec1..d7ce4921b2 100644 --- a/signal.c +++ b/signal.c @@ -9,16 +9,25 @@ ************************************************/ #include "ruby.h" -#include "sig.h" +#include "rubysig.h" #include <signal.h> #include <stdio.h> +#ifdef __BEOS__ +#undef SIGBUS +#endif + #ifndef NSIG -#ifdef DJGPP -#define NSIG SIGMAX -#else -#define NSIG (_SIGMAX + 1) /* For QNX */ +# ifdef DJGPP +# define NSIG SIGMAX +# else +# define NSIG (_SIGMAX + 1) /* For QNX */ +# endif #endif + +#ifdef USE_CWGUSI +# undef NSIG +# define NSIG __signal_max #endif static struct signals { @@ -171,31 +180,33 @@ signm2signo(nm) } VALUE -f_kill(argc, argv) +rb_f_kill(argc, argv) int argc; VALUE *argv; { +#ifdef USE_CWGUSI + rb_notimplement(); +#else + int negative = 0; int sig; int i; char *s; rb_secure(2); if (argc < 2) - ArgError("wrong # of arguments -- kill(sig, pid...)"); + rb_raise(rb_eArgError, "wrong # of arguments -- kill(sig, pid...)"); switch (TYPE(argv[0])) { case T_FIXNUM: sig = FIX2UINT(argv[0]); if (sig >= NSIG) { s = rb_id2name(sig); - if (!s) ArgError("Bad signal"); + if (!s) rb_raise(rb_eArgError, "Bad signal"); goto str_signal; } break; case T_STRING: - { - int negative = 0; - + { s = RSTRING(argv[0])->ptr; if (s[0] == '-') { negative++; @@ -205,7 +216,7 @@ f_kill(argc, argv) if (strncmp("SIG", s, 3) == 0) s += 3; if((sig = signm2signo(s)) == 0) - ArgError("Unrecognized signal name `%s'", s); + rb_raise(rb_eArgError, "Unrecognized signal name `%s'", s); if (negative) sig = -sig; @@ -213,7 +224,8 @@ f_kill(argc, argv) break; default: - ArgError("bad signal type %s", rb_class2name(CLASS_OF(argv[0]))); + rb_raise(rb_eArgError, "bad signal type %s", + rb_class2name(CLASS_OF(argv[0]))); break; } @@ -237,23 +249,26 @@ f_kill(argc, argv) } } return INT2FIX(i-1); +#endif /* USE_CWGUSI */ } static VALUE trap_list[NSIG]; static int trap_pending_list[NSIG]; -int trap_pending; -int trap_immediate; -int prohibit_interrupt; +int rb_trap_pending; +int rb_trap_immediate; +int rb_prohibit_interrupt; void -gc_mark_trap_list() +rb_gc_mark_trap_list() { +#ifndef MACOS_UNUSE_SIGNAL int i; for (i=0; i<NSIG; i++) { if (trap_list[i]) - gc_mark(trap_list[i]); + rb_gc_mark(trap_list[i]); } +#endif /* MACOS_UNUSE_SIGNAL */ } #ifdef POSIX_SIGNAL @@ -271,31 +286,32 @@ posix_signal(signum, handler) } #endif +#ifdef USE_THREAD +# define rb_interrupt rb_thread_interrupt +# define rb_trap_eval rb_thread_trap_eval +#endif + static RETSIGTYPE sighandle(sig) int sig; { if (sig >= NSIG ||(sig != SIGINT && !trap_list[sig])) - Bug("trap_handler: Bad signal %d", sig); + rb_bug("trap_handler: Bad signal %d", sig); #if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL) signal(sig, sighandle); #endif - if (trap_immediate) { - trap_immediate = 0; + if (rb_trap_immediate) { + rb_trap_immediate = 0; if (sig == SIGINT && !trap_list[SIGINT]) { -#ifdef THREAD - thread_interrupt(); -#else rb_interrupt(); -#endif } rb_trap_eval(trap_list[sig], sig); - trap_immediate = 1; + rb_trap_immediate = 1; } else { - trap_pending++; + rb_trap_pending++; trap_pending_list[sig]++; } } @@ -305,7 +321,7 @@ static RETSIGTYPE sigbus(sig) int sig; { - Bug("Bus Error"); + rb_bug("Bus Error"); } #endif @@ -314,41 +330,42 @@ static RETSIGTYPE sigsegv(sig) int sig; { - Bug("Segmentation fault"); + rb_bug("Segmentation fault"); } #endif void rb_trap_exit() { - if (trap_list[0]) - rb_eval_cmd(trap_list[0], ary_new3(1, INT2FIX(0))); +#ifndef MACOS_UNUSE_SIGNAL + if (trap_list[0]) { + rb_eval_cmd(trap_list[0], rb_ary_new3(1, INT2FIX(0))); + } +#endif } void rb_trap_exec() { +#ifndef MACOS_UNUSE_SIGNAL int i; for (i=0; i<NSIG; i++) { if (trap_pending_list[i]) { trap_pending_list[i] = 0; if (i == SIGINT && trap_list[SIGINT] == 0) { -#ifdef THREAD - thread_interrupt(); -#else rb_interrupt(); -#endif return; } rb_trap_eval(trap_list[i], i); } } - trap_pending = 0; +#endif /* MACOS_UNUSE_SIGNAL */ + rb_trap_pending = 0; } struct trap_arg { -#ifndef NT +#if !defined(NT) && !defined(USE_CWGUSI) # ifdef HAVE_SIGPROCMASK sigset_t mask; # else @@ -358,6 +375,12 @@ struct trap_arg { VALUE sig, cmd; }; +# ifdef HAVE_SIGPROCMASK +static sigset_t trap_last_mask; +# else +static int trap_last_mask; +# endif + static RETSIGTYPE sigexit() { @@ -415,17 +438,17 @@ trap(arg) s += 3; sig = signm2signo(s); if (sig == 0 && strcmp(s, "EXIT") != 0) - ArgError("Invalid signal SIG%s", s); + rb_raise(rb_eArgError, "Invalid signal SIG%s", s); } else { sig = NUM2INT(arg->sig); } if (sig < 0 || sig > NSIG) { - ArgError("Invalid signal no %d", sig); + rb_raise(rb_eArgError, "Invalid signal no %d", sig); } -#if defined(THREAD) && defined(HAVE_SETITIMER) && !defined(__BOW__) +#if defined(USE_THREAD) && defined(HAVE_SETITIMER) && !defined(__BOW__) if (sig == SIGVTALRM) { - ArgError("SIGVTALRM reserved for Thread; cannot set handler"); + rb_raise(rb_eArgError, "SIGVTALRM reserved for Thread; cannot set handler"); } #endif if (func == SIG_DFL) { @@ -455,7 +478,7 @@ trap(arg) trap_list[sig] = command; /* enable at least specified signal. */ -#ifndef NT +#if !defined(NT) && !defined(USE_CWGUSI) #ifdef HAVE_SIGPROCMASK sigdelset(&arg->mask, sig); #else @@ -465,8 +488,8 @@ trap(arg) return old; } -#ifndef NT -static void +#if !defined(NT) && !defined(USE_CWGUSI) +static VALUE trap_ensure(arg) struct trap_arg *arg; { @@ -476,11 +499,25 @@ trap_ensure(arg) #else sigsetmask(arg->mask); #endif + trap_last_mask = arg->mask; + return 0; } #endif +void +rb_trap_restore_mask() +{ +#ifndef NT +# ifdef HAVE_SIGPROCMASK + sigprocmask(SIG_SETMASK, &trap_last_mask, NULL); +# else + sigsetmask(trap_last_mask); +# endif +#endif +} + static VALUE -f_trap(argc, argv) +rb_f_trap(argc, argv) int argc; VALUE *argv; { @@ -488,18 +525,18 @@ f_trap(argc, argv) rb_secure(2); if (argc == 0 || argc > 2) { - ArgError("wrong # of arguments -- trap(sig, cmd)/trap(sig){...}"); + rb_raise(rb_eArgError, "wrong # of arguments -- trap(sig, cmd)/trap(sig){...}"); } arg.sig = argv[0]; if (argc == 1) { - arg.cmd = f_lambda(); + arg.cmd = rb_f_lambda(); } else if (argc == 2) { arg.cmd = argv[1]; } -#ifndef NT +#if !defined(NT) && !defined(USE_CWGUSI) /* disable interrupt */ # ifdef HAVE_SIGPROCMASK sigfillset(&arg.mask); @@ -508,7 +545,7 @@ f_trap(argc, argv) arg.mask = sigblock(~0); # endif - return rb_ensure(trap, &arg, trap_ensure, &arg); + return rb_ensure(trap, (VALUE)&arg, trap_ensure, (VALUE)&arg); #else return trap(&arg); #endif @@ -517,9 +554,8 @@ f_trap(argc, argv) void Init_signal() { - extern VALUE mKernel; - - rb_define_global_function("trap", f_trap, -1); +#ifndef MACOS_UNUSE_SIGNAL + rb_define_global_function("trap", rb_f_trap, -1); #ifdef POSIX_SIGNAL posix_signal(SIGINT, sighandle); #else @@ -531,4 +567,5 @@ Init_signal() #ifdef SIGSEGV signal(SIGSEGV, sigsegv); #endif +#endif /* MACOS_UNUSE_SIGNAL */ } diff --git a/sprintf.c b/sprintf.c index 7862a469e8..3c09a8ed2a 100644 --- a/sprintf.c +++ b/sprintf.c @@ -6,14 +6,14 @@ $Date$ created at: Fri Oct 15 10:39:26 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include <ctype.h> -static void fmt_setup(); +static void fmt_setup _((char*,char,int,int,int)); static char* remove_sign_bits(str, base) @@ -23,20 +23,21 @@ remove_sign_bits(str, base) char *s, *t, *end; s = t = str; + end = str + strlen(str); if (base == 16) { x_retry: switch (*t) { - case 'c': - *t = '8'; + case 'c': case 'C': + *t = '4'; break; - case 'd': - *t = '9'; + case 'd': case 'D': + *t = '5'; break; - case 'e': + case 'e': case 'E': *t = '2'; break; - case 'f': + case 'f': case 'F': if (t[1] > '8') { t++; goto x_retry; @@ -99,32 +100,16 @@ remove_sign_bits(str, base) return str; } -double big2dbl(); -#ifndef atof -double atof(); -#endif - -VALUE -f_sprintf(argc, argv) - int argc; - VALUE *argv; -{ - VALUE fmt; - char *buf, *p, *end; - int blen, bsiz; - VALUE result; +double rb_big2dbl _((VALUE)); #define FNONE 0 #define FSHARP 1 #define FMINUS 2 #define FPLUS 4 #define FZERO 8 -#define FWIDTH 16 -#define FPREC 32 - - int width = 0, prec = 0, flags = FNONE; - VALUE str; - +#define FSPACE 16 +#define FWIDTH 32 +#define FPREC 64 #define CHECK(l) {\ while (blen + (l) >= bsiz) {\ @@ -140,17 +125,30 @@ f_sprintf(argc, argv) } #define GETARG() \ - ((argc == 0)?(ArgError("too few argument."),0):(argc--,((argv++)[0]))) + ((argc == 0)?(rb_raise(rb_eArgError, "too few argument."),0):(argc--,((argv++)[0]))) - fmt = GETARG(); - Check_Type(fmt, T_STRING); +VALUE +rb_f_sprintf(argc, argv) + int argc; + VALUE *argv; +{ + VALUE fmt; + char *buf, *p, *end; + int blen, bsiz; + VALUE result; + + int width, prec, flags = FNONE; + VALUE tmp; + VALUE str; + fmt = GETARG(); + p = str2cstr(fmt, &blen); + end = p + blen; blen = 0; bsiz = 120; buf = ALLOC_N(char, bsiz); - end = RSTRING(fmt)->ptr + RSTRING(fmt)->len; - for (p = RSTRING(fmt)->ptr; p < end; p++) { + for (; p < end; p++) { char *t; for (t = p; t < end && *t != '%'; t++) ; @@ -162,16 +160,18 @@ f_sprintf(argc, argv) } p = t + 1; /* skip `%' */ + width = prec = -1; retry: switch (*p) { default: - if (isprint(*p)) - ArgError("malformed format string - %%%c", *p); + if (ISPRINT(*p)) + rb_raise(rb_eArgError, "malformed format string - %%%c", *p); else - ArgError("malformed format string"); + rb_raise(rb_eArgError, "malformed format string"); break; case ' ': + flags |= FSPACE; p++; goto retry; @@ -199,51 +199,50 @@ f_sprintf(argc, argv) case '5': case '6': case '7': case '8': case '9': flags |= FWIDTH; width = 0; - for (; p < end && isdigit(*p); p++) { + for (; p < end && ISDIGIT(*p); p++) { width = 10 * width + (*p - '0'); } if (p >= end) { - ArgError("malformed format string - %%[0-9]"); + rb_raise(rb_eArgError, "malformed format string - %%[0-9]"); } goto retry; case '*': if (flags & FWIDTH) { - ArgError("width given twice"); + rb_raise(rb_eArgError, "width given twice"); } flags |= FWIDTH; - width = GETARG(); - width = NUM2INT(width); + tmp = GETARG(); + width = NUM2INT(tmp); if (width < 0) { flags |= FMINUS; - width = - width; + width = -width; } p++; goto retry; case '.': if (flags & FPREC) { - ArgError("precision given twice"); + rb_raise(rb_eArgError, "precision given twice"); } prec = 0; p++; - if (*p == '0') flags |= FZERO; if (*p == '*') { - prec = GETARG(); - prec = NUM2INT(prec); + tmp = GETARG(); + prec = NUM2INT(tmp); if (prec > 0) flags |= FPREC; p++; goto retry; } - for (; p < end && isdigit(*p); p++) { + for (; p < end && ISDIGIT(*p); p++) { prec = 10 * prec + (*p - '0'); } if (p >= end) { - ArgError("malformed format string - %%.[0-9]"); + rb_raise(rb_eArgError, "malformed format string - %%.[0-9]"); } if (prec > 0) flags |= FPREC; @@ -261,8 +260,13 @@ f_sprintf(argc, argv) VALUE val = GETARG(); char c; + if (!(flags & FMINUS)) + while (--width > 0) + PUSH(" ", 1); c = NUM2INT(val) & 0xff; PUSH(&c, 1); + while (--width > 0) + PUSH(" ", 1); } break; @@ -271,7 +275,7 @@ f_sprintf(argc, argv) VALUE arg = GETARG(); int len; - str = obj_as_string(arg); + str = rb_obj_as_string(arg); len = RSTRING(str)->len; if (flags&FPREC) { if (prec < len) { @@ -283,8 +287,8 @@ f_sprintf(argc, argv) } if (flags&FWIDTH) { if (width > len) { - width -= len; CHECK(width); + width -= len; if (!(flags&FMINUS)) { while (width--) { buf[blen++] = ' '; @@ -306,28 +310,58 @@ f_sprintf(argc, argv) } break; - case 'b': - case 'B': + case 'd': + case 'i': case 'o': case 'x': + case 'X': + case 'b': case 'u': { volatile VALUE val = GETARG(); char fbuf[32], nbuf[64], *s, *t; - int v, base, bignum = 0; - int len, slen, pos; + char *prefix = 0; + int sign = 0; + char sc = 0; + long v; + int base, bignum = 0; + int len, pos; + + switch (*p) { + case 'd': + case 'i': + sign = 1; break; + case 'o': + case 'x': + case 'X': + case 'b': + case 'u': + default: + if (flags&(FPLUS|FSPACE)) sign = 1; + break; + } + if (flags & FSHARP) { + if (*p == 'o') prefix = "0"; + else if (*p == 'x') prefix = "0x"; + else if (*p == 'X') prefix = "0X"; + else if (*p == 'b') prefix = "0b"; + if (prefix) { + width -= strlen(prefix); + } + } bin_retry: switch (TYPE(val)) { case T_FIXNUM: - v = FIX2INT(val); + v = FIX2LONG(val); break; case T_FLOAT: - val = dbl2big(RFLOAT(val)->value); + val = rb_dbl2big(RFLOAT(val)->value); + if (FIXNUM_P(val)) goto bin_retry; bignum = 1; break; case T_STRING: - val = str2inum(RSTRING(val)->ptr, 0); + val = rb_str2inum(RSTRING(val)->ptr, 10); goto bin_retry; case T_BIGNUM: bignum = 1; @@ -337,51 +371,90 @@ f_sprintf(argc, argv) break; } - if (*p == 'x') base = 16; + if (*p == 'u' || *p == 'd' || *p == 'i') base = 10; + else if (*p == 'x' || *p == 'X') base = 16; else if (*p == 'o') base = 8; - else if (*p == 'u') base = 10; - else if (*p == 'b' || *p == 'B') base = 2; + else if (*p == 'b') base = 2; if (!bignum) { - if (*p == 'b' || *p == 'B') { - val = int2big(v); + if (base == 2) { + val = rb_int2big(v); + goto bin_retry; } - else { - s = nbuf; + if (sign) { + char c = *p; + if (c == 'i') c = 'd'; /* %d and %i are identical */ if (v < 0) { - strcpy(s, ".."); - s += 2; - bignum = 2; + v = -v; + sc = '-'; + width--; } - sprintf(fbuf, "%%%c", *p); - sprintf(s, fbuf, v); - if (v < 0) { - char d = 0; - - remove_sign_bits(s, base); - switch (base) { - case 16: - d = 'f'; break; - case 8: - d = '7'; break; - } - if (d && *s != d) { - memmove(s+1, s, strlen(s)+1); - *s = d; - } + else if (flags & FPLUS) { + sc = '+'; + width--; } + else if (flags & FSPACE) { + sc = ' '; + width--; + } + sprintf(fbuf, "%%l%c", c); + sprintf(nbuf, fbuf, v); s = nbuf; - goto unsigned_format; + goto format_integer; + } + s = nbuf; + if (v < 0) { + strcpy(s, ".."); + s += 2; + } + sprintf(fbuf, "%%l%c", *p); + sprintf(s, fbuf, v); + if (v < 0) { + char d = 0; + + remove_sign_bits(s, base); + switch (base) { + case 16: + d = 'f'; + break; + case 8: + d = '7'; break; + } + if (d && *s != d) { + memmove(s+1, s, strlen(s)+1); + *s = d; + } } + s = nbuf; + goto format_integer; } - if (*p != 'B' && !RBIGNUM(val)->sign) { - val = big_clone(val); - big_2comp(val); + + if (sign) { + val = rb_big2str(val, base); + s = RSTRING(val)->ptr; + if (s[0] == '-') { + s++; + sc = '-'; + width--; + } + else if (flags & FPLUS) { + sc = '+'; + width--; + } + else if (flags & FSPACE) { + sc = ' '; + width--; + } + goto format_integer; + } + if (!RBIGNUM(val)->sign) { + val = rb_big_clone(val); + rb_big_2comp(val); } - val = big2str(val, base); + val = rb_big2str(val, base); s = RSTRING(val)->ptr; - if (*s == '-' && *p != 'B') { + if (*s == '-') { remove_sign_bits(++s, base); - val = str_new(0, 3+strlen(s)); + val = rb_str_new(0, 3+strlen(s)); t = RSTRING(val)->ptr; strcpy(t, ".."); t += 2; @@ -396,165 +469,79 @@ f_sprintf(argc, argv) } s = RSTRING(val)->ptr; - unsigned_format: - slen = len = strlen(s); - pos = blen; - if (flags&FWIDTH) { - if (width <= len) flags &= ~FWIDTH; - else { - slen = width; + format_integer: + pos = -1; + len = strlen(s); + + if (*p == 'X') { + char *pp = s; + while (*pp) { + *pp = toupper(*pp); + pp++; } } - if (flags&FPREC) { - if (prec <= len) flags &= ~FPREC; - else { - if (prec >= slen) { - flags &= ~FWIDTH; - slen = prec; - } + if (prec < len) prec = len; + width -= prec; + if (!(flags&(FZERO|FMINUS)) && s[0] != '.') { + CHECK(width); + while (width-->0) { + buf[blen++] = ' '; } } - if (slen > len) { - int n = slen-len; - char d = ' '; - if (flags & FZERO) d = '0'; - CHECK(n); - while (n--) { - buf[blen++] = d; - } + if (sc) PUSH(&sc, 1); + if (prefix) { + int plen = strlen(prefix); + CHECK(plen); + strcpy(&buf[blen], prefix); + blen += plen; + if (pos) pos += plen; } - if ((flags&(FWIDTH|FPREC)) == (FWIDTH|FPREC)) { - if (prec < width) { - pos = width - prec; + if (!(flags & FMINUS)) { + char c = ' '; + + if (s[0] == '.') { + c = '.'; + if ((flags & FPREC) && prec > len) { + pos = blen; + } + else { + pos = blen + 2; + } + } + else if (flags & FZERO) c = '0'; + CHECK(width); + while (width-->0) { + buf[blen++] = c; } } + CHECK(prec - len); + while (len < prec--) { + buf[blen++] = s[0]=='.'?'.':'0'; + } CHECK(len); strcpy(&buf[blen], s); blen += len; - t = &buf[pos]; - if (bignum == 2) { - char d = '.'; + CHECK(width); + while (width-->0) { + buf[blen++] = ' '; + } + if (pos >= 0 && buf[pos] == '.') { + char c = '.'; switch (base) { case 16: - d = 'f'; break; + if (*p == 'X') c = 'F'; + else c = 'f'; + break; case 8: - d = '7'; break; + c = '7'; break; case '2': - d = '1'; break; - } - - if ((flags & FPREC) == 0 || prec <= len-2) { - *t++ = '.'; *t++ = '.'; - } - while (*t == ' ' || *t == '.') { - *t++ = d; - } - } - else if (flags & (FPREC|FZERO)) { - while (*t == ' ') { - *t++ = '0'; - } - } - } - break; - - case 'd': - case 'D': - case 'O': - case 'X': - { - volatile VALUE val = GETARG(); - char fbuf[32], c = *p; - int bignum = 0, base; - int v; - - if (c == 'D') c = 'd'; - int_retry: - switch (TYPE(val)) { - case T_FIXNUM: - v = FIX2INT(val); - break; - case T_FLOAT: - v = RFLOAT(val)->value; - break; - case T_STRING: - val = str2inum(RSTRING(val)->ptr, 0); - goto int_retry; - case T_BIGNUM: - if (c == 'd') base = 10; - else if (c == 'X') base = 16; - else if (c == 'O') base = 8; - val = big2str(val, base); - bignum = 1; - break; - default: - val = num2fix(val); - goto int_retry; - } - - if (bignum) { - char *s = RSTRING(val)->ptr; - int slen, len, pos_b, pos; - - slen = len = strlen(s); - pos = pos_b = blen; - if (flags&FWIDTH) { - if (width <= len) flags &= ~FWIDTH; - else { - slen = width; - } - } - if (flags&FPREC) { - if (prec <= len) flags &= ~FPREC; - else { - if (prec >= slen) { - flags &= ~FWIDTH; - slen = prec; - } - } - } - if (slen > len) { - int n = slen-len; - CHECK(n); - while (n--) { - buf[blen++] = ' '; - } + c = '1'; break; } - if ((flags&(FWIDTH|FPREC)) == (FWIDTH|FPREC)) { - if (prec < width) { - pos = width - prec; - } - } - CHECK(len); - strcpy(&buf[blen], s); - blen += len; - if (flags & (FPREC|FZERO)) { - char *t = &buf[pos]; - char *b = &buf[pos_b]; - - if (s[0] == '-') { - if (slen > len && t != b ) t[-1] = '-'; - else *t++ = '-'; - } - while (*t == ' ' || *t == '-') { - *t++ = '0'; - } - } - } - else { - int max = 11; - - if ((flags & FPREC) && prec > max) max = prec; - if ((flags & FWIDTH) && width > max) max = width; - CHECK(max); - if (v < 0 && (c == 'X' || c == 'O')) { - v = -v; - PUSH("-", 1); + s = &buf[pos]; + while (*s && *s == '.') { + *s++ = c; } - fmt_setup(fbuf, c, flags, width, prec); - sprintf(&buf[blen], fbuf, v); - blen += strlen(&buf[blen]); } } break; @@ -562,6 +549,7 @@ f_sprintf(argc, argv) case 'f': case 'g': case 'e': + case 'E': { VALUE val = GETARG(); double fval; @@ -569,13 +557,13 @@ f_sprintf(argc, argv) switch (TYPE(val)) { case T_FIXNUM: - fval = FIX2INT(val); + fval = (double)FIX2LONG(val); break; case T_FLOAT: fval = RFLOAT(val)->value; break; case T_BIGNUM: - fval = big2dbl(val); + fval = rb_big2dbl(val); break; case T_STRING: fval = atof(RSTRING(val)->ptr); @@ -597,10 +585,10 @@ f_sprintf(argc, argv) } sprint_exit: - if (RTEST(verbose) && argc > 1) { - ArgError("too many argument for format string"); + if (RTEST(rb_verbose) && argc > 1) { + rb_raise(rb_eArgError, "too many argument for format string"); } - result = str_new(buf, blen); + result = rb_str_new(buf, blen); free(buf); return result; @@ -616,6 +604,7 @@ fmt_setup(buf, c, flags, width, prec) if (flags & FPLUS) *buf++ = '+'; if (flags & FMINUS) *buf++ = '-'; if (flags & FZERO) *buf++ = '0'; + if (flags & FSPACE) *buf++ = ' '; if (flags & FWIDTH) { sprintf(buf, "%d", width); diff --git a/st.c b/st.c index 6b25bc854b..8c0a3861f5 100644 --- a/st.c +++ b/st.c @@ -6,6 +6,19 @@ static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; #include <stdio.h> #include "st.h" +#ifdef USE_CWGUSI +#include <stdlib.h> +#endif + +typedef struct st_table_entry st_table_entry; + +struct st_table_entry { + unsigned int hash; + char *key; + char *record; + st_table_entry *next; +}; + #define ST_DEFAULT_MAX_DENSITY 5 #define ST_DEFAULT_INIT_TABLE_SIZE 11 @@ -37,14 +50,70 @@ void *xcalloc(); void *xrealloc(); static void rehash(); -#define max(a,b) ((a) > (b) ? (a) : (b)) -#define nil(type) ((type*)0) #define alloc(type) (type*)xmalloc((unsigned)sizeof(type)) #define Calloc(n,s) (char*)xcalloc((n),(s)) #define EQUAL(table, x, y) ((*table->type->compare)(x, y) == 0) -#define do_hash(key, table) (*(table)->type->hash)((key), (table)->num_bins) +#define do_hash(key, table) (unsigned int)(*(table)->type->hash)((key)) +#define do_hash_bin(key, table) (do_hash(key, table)%(table)->num_bins) + +/* + * MINSIZE is the minimum size of a dictionary. + */ + +#define MINSIZE 8 + +/* +Table of prime numbers 2^n+a, 2<=n<=30. +*/ +static long primes[] = { + 8 + 3, + 16 + 3, + 32 + 5, + 64 + 3, + 128 + 3, + 256 + 29, + 512 + 17, + 1024 + 9, + 2048 + 5, + 4096 + 83, + 8192 + 27, + 16384 + 43, + 32768 + 3, + 65536 + 45, + 131072 + 9, + 262144 + 39, + 524288 + 39, + 1048576 + 9, + 2097152 + 5, + 4194304 + 3, + 8388608 + 33, + 16777216 + 27, + 33554432 + 9, + 67108864 + 71, + 134217728 + 39, + 268435456 + 9, + 536870912 + 5, + 1073741824 + 83, + 0 +}; + +static int +new_size(size) + int size; +{ + int i, newsize; + + for (i = 0, newsize = MINSIZE; + i < sizeof(primes)/sizeof(primes[0]); + i++, newsize <<= 1) + { + if (newsize > size) return primes[i]; + } + /* Ran out of polynomials */ + return -1; /* should raise exception */ +} st_table* st_init_table_with_size(type, size) @@ -53,17 +122,14 @@ st_init_table_with_size(type, size) { st_table *tbl; - if (size == 0) size = ST_DEFAULT_INIT_TABLE_SIZE; - else size /= ST_DEFAULT_MAX_DENSITY*0.87; - - if (size < ST_DEFAULT_INIT_TABLE_SIZE) - size = ST_DEFAULT_INIT_TABLE_SIZE; + size = new_size(size); /* round up to prime number */ tbl = alloc(st_table); tbl->type = type; tbl->num_entries = 0; tbl->num_bins = size; tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*)); + return tbl; } @@ -80,12 +146,26 @@ st_init_numtable() return st_init_table(&type_numhash); } +st_table* +st_init_numtable_with_size(size) + int size; +{ + return st_init_table_with_size(&type_numhash, size); +} + st_table* st_init_strtable() { return st_init_table(&type_strhash); } +st_table* +st_init_strtable_with_size(size) + int size; +{ + return st_init_table_with_size(&type_strhash, size); +} + void st_free_table(table) st_table *table; @@ -95,23 +175,24 @@ st_free_table(table) for(i = 0; i < table->num_bins ; i++) { ptr = table->bins[i]; - while (ptr != nil(st_table_entry)) { + while (ptr != 0) { next = ptr->next; - free((char*)ptr); + free(ptr); ptr = next; } } - free((char*)table->bins); - free((char*)table); + free(table->bins); + free(table); } -#define PTR_NOT_EQUAL(table, ptr, key) \ -(ptr != nil(st_table_entry) && !EQUAL(table, key, (ptr)->key)) +#define PTR_NOT_EQUAL(table, ptr, hash_val, key) \ +((ptr) != 0 && ptr->hash != (hash_val) && !EQUAL((table), (key), (ptr)->key)) -#define FIND_ENTRY(table, ptr, hash_val) \ -ptr = (table)->bins[hash_val];\ -if (PTR_NOT_EQUAL(table, ptr, key)) {\ - while (PTR_NOT_EQUAL(table, ptr->next, key)) {\ +#define FIND_ENTRY(table, ptr, hash_val, bin_pos) \ +bin_pos = hash_val%(table)->num_bins;\ +ptr = (table)->bins[bin_pos];\ +if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\ + while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\ ptr = ptr->next;\ }\ ptr = ptr->next;\ @@ -123,34 +204,35 @@ st_lookup(table, key, value) register char *key; char **value; { - int hash_val; + unsigned int hash_val, bin_pos; register st_table_entry *ptr; hash_val = do_hash(key, table); + FIND_ENTRY(table, ptr, hash_val, bin_pos); - FIND_ENTRY(table, ptr, hash_val); - - if (ptr == nil(st_table_entry)) { + if (ptr == 0) { return 0; } else { - if (value != nil(char*)) *value = ptr->record; + if (value != 0) *value = ptr->record; return 1; } } -#define ADD_DIRECT(table, key, value, hash_val, tbl)\ +#define ADD_DIRECT(table, key, value, hash_val, bin_pos)\ {\ + st_table_entry *tbl;\ if (table->num_entries/table->num_bins > ST_DEFAULT_MAX_DENSITY) {\ rehash(table);\ - hash_val = do_hash(key, table);\ + bin_pos = hash_val % table->num_bins;\ }\ \ tbl = alloc(st_table_entry);\ \ + tbl->hash = hash_val;\ tbl->key = key;\ tbl->record = value;\ - tbl->next = table->bins[hash_val];\ - table->bins[hash_val] = tbl;\ + tbl->next = table->bins[bin_pos];\ + table->bins[bin_pos] = tbl;\ table->num_entries++;\ } @@ -160,16 +242,14 @@ st_insert(table, key, value) register char *key; char *value; { - int hash_val; - st_table_entry *tbl; + unsigned int hash_val, bin_pos; register st_table_entry *ptr; hash_val = do_hash(key, table); + FIND_ENTRY(table, ptr, hash_val, bin_pos); - FIND_ENTRY(table, ptr, hash_val); - - if (ptr == nil(st_table_entry)) { - ADD_DIRECT(table,key,value,hash_val,tbl); + if (ptr == 0) { + ADD_DIRECT(table, key, value, hash_val, bin_pos); return 0; } else { ptr->record = value; @@ -183,65 +263,37 @@ st_add_direct(table, key, value) char *key; char *value; { - int hash_val; - st_table_entry *tbl; - - hash_val = do_hash(key, table); - ADD_DIRECT(table, key, value, hash_val, tbl); -} - -int -st_find_or_add(table, key, slot) - st_table *table; - char *key; - char ***slot; -{ - int hash_val; - st_table_entry *tbl, *ptr; + unsigned int hash_val, bin_pos; hash_val = do_hash(key, table); - - FIND_ENTRY(table, ptr, hash_val); - - if (ptr == nil(st_table_entry)) { - ADD_DIRECT(table, key, (char*)0, hash_val, tbl) - if (slot != nil(char**)) *slot = &tbl->record; - return 0; - } else { - if (slot != nil(char**)) *slot = &ptr->record; - return 1; - } + bin_pos = hash_val % table->num_bins; + ADD_DIRECT(table, key, value, hash_val, bin_pos); } static void rehash(table) register st_table *table; { - register st_table_entry *ptr, *next, **old_bins = table->bins; - int i, old_num_bins = table->num_bins, hash_val; - - table->num_bins = 1.79*old_num_bins; - - if (table->num_bins%2 == 0) { - table->num_bins += 1; - } + register st_table_entry *ptr, *next, **new_bins; + int i, old_num_bins = table->num_bins, new_num_bins; + unsigned int hash_val; - table->num_entries = 0; - table->bins = (st_table_entry **) - Calloc((unsigned)table->num_bins, sizeof(st_table_entry*)); + new_num_bins = new_size(old_num_bins); + new_bins = (st_table_entry**)Calloc(new_num_bins, sizeof(st_table_entry*)); for(i = 0; i < old_num_bins ; i++) { - ptr = old_bins[i]; - while (ptr != nil(st_table_entry)) { + ptr = table->bins[i]; + while (ptr != 0) { next = ptr->next; - hash_val = do_hash(ptr->key, table); - ptr->next = table->bins[hash_val]; - table->bins[hash_val] = ptr; - table->num_entries++; + hash_val = ptr->hash % new_num_bins; + ptr->next = new_bins[hash_val]; + new_bins[hash_val] = ptr; ptr = next; } } - free((char*)old_bins); + free(table->bins); + table->num_bins = new_num_bins; + table->bins = new_bins; } st_table* @@ -253,28 +305,28 @@ st_copy(old_table) int i, num_bins = old_table->num_bins; new_table = alloc(st_table); - if (new_table == nil(st_table)) { - return nil(st_table); + if (new_table == 0) { + return 0; } *new_table = *old_table; new_table->bins = (st_table_entry**) Calloc((unsigned)num_bins, sizeof(st_table_entry*)); - if (new_table->bins == nil(st_table_entry*)) { - free((char*)new_table); - return nil(st_table); + if (new_table->bins == 0) { + free(new_table); + return 0; } for(i = 0; i < num_bins ; i++) { - new_table->bins[i] = nil(st_table_entry); + new_table->bins[i] = 0; ptr = old_table->bins[i]; - while (ptr != nil(st_table_entry)) { + while (ptr != 0) { tbl = alloc(st_table_entry); - if (tbl == nil(st_table_entry)) { - free((char*)new_table->bins); - free((char*)new_table); - return nil(st_table); + if (tbl == 0) { + free(new_table->bins); + free(new_table); + return 0; } *tbl = *ptr; tbl->next = new_table->bins[i]; @@ -291,36 +343,35 @@ st_delete(table, key, value) register char **key; char **value; { - int hash_val; + unsigned int hash_val; st_table_entry *tmp; register st_table_entry *ptr; - hash_val = do_hash(*key, table); - + hash_val = do_hash_bin(*key, table); ptr = table->bins[hash_val]; - if (ptr == nil(st_table_entry)) { - if (value != nil(char*)) *value = nil(char); + if (ptr == 0) { + if (value != 0) *value = 0; return 0; } if (EQUAL(table, *key, ptr->key)) { table->bins[hash_val] = ptr->next; table->num_entries--; - if (value != nil(char*)) *value = ptr->record; + if (value != 0) *value = ptr->record; *key = ptr->key; - free((char*)ptr); + free(ptr); return 1; } - for(; ptr->next != nil(st_table_entry); ptr = ptr->next) { + for(; ptr->next != 0; ptr = ptr->next) { if (EQUAL(table, ptr->next->key, *key)) { tmp = ptr->next; ptr->next = ptr->next->next; table->num_entries--; - if (value != nil(char*)) *value = tmp->record; + if (value != 0) *value = tmp->record; *key = tmp->key; - free((char*)tmp); + free(tmp); return 1; } } @@ -335,31 +386,30 @@ st_delete_safe(table, key, value, never) char **value; char *never; { - int hash_val; + unsigned int hash_val; register st_table_entry *ptr; - hash_val = do_hash(*key, table); - + hash_val = do_hash_bin(*key, table); ptr = table->bins[hash_val]; - if (ptr == nil(st_table_entry)) { - if (value != nil(char*)) *value = nil(char); + if (ptr == 0) { + if (value != 0) *value = 0; return 0; } if (EQUAL(table, *key, ptr->key)) { table->num_entries--; *key = ptr->key; - if (value != nil(char*)) *value = ptr->record; + if (value != 0) *value = ptr->record; ptr->key = ptr->record = never; return 1; } - for(; ptr->next != nil(st_table_entry); ptr = ptr->next) { + for(; ptr->next != 0; ptr = ptr->next) { if (EQUAL(table, ptr->next->key, *key)) { table->num_entries--; *key = ptr->key; - if (value != nil(char*)) *value = ptr->record; + if (value != 0) *value = ptr->record; ptr->key = ptr->record = never; return 1; } @@ -379,8 +429,8 @@ st_foreach(table, func, arg) int i; for(i = 0; i < table->num_bins; i++) { - last = nil(st_table_entry); - for(ptr = table->bins[i]; ptr != nil(st_table_entry);) { + last = 0; + for(ptr = table->bins[i]; ptr != 0;) { retval = (*func)(ptr->key, ptr->record, arg); switch (retval) { case ST_CONTINUE: @@ -391,13 +441,13 @@ st_foreach(table, func, arg) return; case ST_DELETE: tmp = ptr; - if (last == nil(st_table_entry)) { + if (last == 0) { table->bins[i] = ptr->next; } else { last->next = ptr->next; } ptr = ptr->next; - free((char*)tmp); + free(tmp); table->num_entries--; } } @@ -405,9 +455,8 @@ st_foreach(table, func, arg) } static int -strhash(string, modulus) +strhash(string) register char *string; - int modulus; { register int val = 0; register int c; @@ -416,7 +465,7 @@ strhash(string, modulus) val = val*997 + c; } - return ((val < 0) ? -val : val)%modulus; + return val; } static int @@ -427,9 +476,8 @@ numcmp(x, y) } static int -numhash(n, modulus) +numhash(n) int n; - int modulus; { - return n % modulus; + return n; } diff --git a/st.h b/st.h index c27b110ce1..ce87df6011 100644 --- a/st.h +++ b/st.h @@ -6,14 +6,6 @@ #define ST_INCLUDED -typedef struct st_table_entry st_table_entry; - -struct st_table_entry { - char *key; - char *record; - st_table_entry *next; -}; - typedef struct st_table st_table; struct st_hash_type { @@ -25,19 +17,21 @@ struct st_table { struct st_hash_type *type; int num_bins; int num_entries; - st_table_entry **bins; + struct st_table_entry **bins; }; -#define st_is_member(table,key) st_lookup(table,key,(char **) 0) +#define st_is_member(table,key) st_lookup(table,key,(char **)0) enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE}; st_table *st_init_table(); st_table *st_init_table_with_size(); st_table *st_init_numtable(); +st_table *st_init_numtable_with_size(); st_table *st_init_strtable(); -int st_delete(), st_delete_safe(), st_insert(); -int st_lookup(), st_find_or_add(); +st_table *st_init_strtable_with_size(); +int st_delete(), st_delete_safe(); +int st_insert(), st_lookup(); void st_foreach(), st_add_direct(), st_free_table(); st_table *st_copy(); diff --git a/string.c b/string.c index 3c3d24f3cf..e5f0dd2a63 100644 --- a/string.c +++ b/string.c @@ -6,7 +6,7 @@ $Date$ created at: Mon Aug 9 17:12:58 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -16,32 +16,28 @@ #define BEG(no) regs->beg[no] #define END(no) regs->end[no] -#include <stdio.h> #include <ctype.h> + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -VALUE cString; - -#define STRLEN(s) RSTRING(s)->len +VALUE rb_cString; #define STR_FREEZE FL_USER1 -#define STR_TAINT FL_USER2 -void reg_prepare_re _((VALUE)); -void kcode_reset_option _((void)); +#define STR_NO_ORIG FL_USER3 + +extern VALUE rb_rs; VALUE -str_new(ptr, len) - UCHAR *ptr; - UINT len; +rb_str_new(ptr, len) + char *ptr; + size_t len; { NEWOBJ(str, struct RString); - OBJSETUP(str, cString, T_STRING); + OBJSETUP(str, rb_cString, T_STRING); - if (rb_safe_level() >= 3) { - FL_SET(str, STR_TAINT); - } + str->ptr = 0; str->len = len; str->orig = 0; str->ptr = ALLOC_N(char,len+1); @@ -53,57 +49,98 @@ str_new(ptr, len) } VALUE -str_new2(ptr) - UCHAR *ptr; +rb_str_new2(ptr) + char *ptr; +{ + return rb_str_new(ptr, strlen(ptr)); +} + +VALUE +rb_tainted_str_new(ptr, len) + char *ptr; + size_t len; { - return str_new(ptr, strlen(ptr)); + return rb_obj_taint(rb_str_new(ptr, len)); } VALUE -str_new3(str) +rb_tainted_str_new2(ptr) + char *ptr; +{ + return rb_obj_taint(rb_str_new2(ptr)); +} + +VALUE +rb_str_new3(str) VALUE str; { NEWOBJ(str2, struct RString); - OBJSETUP(str2, cString, T_STRING); + OBJSETUP(str2, rb_cString, T_STRING); str2->len = RSTRING(str)->len; str2->ptr = RSTRING(str)->ptr; str2->orig = str; - if (rb_safe_level() >= 3) { - FL_SET(str2, STR_TAINT); - } - return (VALUE)str2; } VALUE -str_new4(orig) +rb_str_new4(orig) VALUE orig; { - NEWOBJ(str, struct RString); - OBJSETUP(str, cString, T_STRING); - - str->len = RSTRING(orig)->len; - str->ptr = RSTRING(orig)->ptr; - if (RSTRING(orig)->orig) { - str->orig = RSTRING(orig)->orig; + if (FL_TEST(orig, STR_FREEZE)) { + return orig; + } + else if (RSTRING(orig)->orig && !FL_TEST(orig, STR_NO_ORIG)) { + return rb_str_freeze(RSTRING(orig)->orig); } else { + NEWOBJ(str, struct RString); + OBJSETUP(str, rb_cString, T_STRING); + + str->len = RSTRING(orig)->len; + str->ptr = RSTRING(orig)->ptr; RSTRING(orig)->orig = (VALUE)str; str->orig = 0; + if (rb_safe_level() >= 3) { + FL_SET(str, FL_TAINT); + } + return (VALUE)str; } - if (rb_safe_level() >= 3) { - FL_SET(str, STR_TAINT); - } +} - return (VALUE)str; +VALUE +rb_str_to_str(str) + VALUE str; +{ + return rb_convert_type(str, T_STRING, "String", "to_str"); +} + +static void +rb_str_assign(str, str2) + VALUE str, str2; +{ + if (str == str2) return; + if (NIL_P(str2)) { + RSTRING(str)->ptr = 0; + RSTRING(str)->len = 0; + RSTRING(str)->orig = 0; + return; + } + if ((!RSTRING(str)->orig||FL_TEST(str, STR_NO_ORIG))&&RSTRING(str)->ptr) + free(RSTRING(str)->ptr); + RSTRING(str)->ptr = RSTRING(str2)->ptr; + RSTRING(str)->len = RSTRING(str2)->len; + RSTRING(str)->orig = RSTRING(str2)->orig; + RSTRING(str2)->ptr = 0; /* abandon str2 */ + RSTRING(str2)->len = 0; + if (OBJ_TAINTED(str2)) OBJ_TAINT(str); } -static ID pr_str; +static ID to_str; VALUE -obj_as_string(obj) +rb_obj_as_string(obj) VALUE obj; { VALUE str; @@ -111,111 +148,130 @@ obj_as_string(obj) if (TYPE(obj) == T_STRING) { return obj; } - str = rb_funcall(obj, pr_str, 0); + str = rb_funcall(obj, to_str, 0); if (TYPE(str) != T_STRING) - return any_to_s(obj); + return rb_any_to_s(obj); + if (OBJ_TAINTED(obj)) OBJ_TAINT(str); return str; } static VALUE -str_clone(orig) +rb_str_clone(orig) VALUE orig; { VALUE str; - if (RSTRING(orig)->orig) - str = str_new3(RSTRING(orig)->orig); + if (RSTRING(orig)->orig && !FL_TEST(orig, STR_NO_ORIG)) + str = rb_str_new3(RSTRING(orig)->orig); else - str = str_new(RSTRING(orig)->ptr, RSTRING(orig)->len); + str = rb_str_new(RSTRING(orig)->ptr, RSTRING(orig)->len); + if (RSTRING(orig)->orig && FL_TEST(orig, STR_NO_ORIG)) + RSTRING(str)->orig = RSTRING(orig)->orig; CLONESETUP(str, orig); return str; } VALUE -str_dup(str) +rb_str_dup(str) VALUE str; { - VALUE s = str_new(RSTRING(str)->ptr, RSTRING(str)->len); - if (str_tainted(str)) s = str_taint(s); + VALUE s; + + if (TYPE(str) != T_STRING) str = rb_str_to_str(str); + s = rb_str_new(RSTRING(str)->ptr, RSTRING(str)->len); + if (OBJ_TAINTED(str)) OBJ_TAINT(s); + return s; } static VALUE -str_s_new(class, orig) - VALUE class; +rb_str_s_new(klass, orig) + VALUE klass; VALUE orig; { NEWOBJ(str, struct RString); - OBJSETUP(str, class, T_STRING); + OBJSETUP(str, klass, T_STRING); - orig = obj_as_string(orig); + str->orig = 0; + orig = rb_obj_as_string(orig); str->len = RSTRING(orig)->len; - str->ptr = ALLOC_N(char, RSTRING(orig)->len+1); - if (str->ptr) { + if (RSTRING(orig)->ptr) { + str->ptr = ALLOC_N(char, RSTRING(orig)->len+1); memcpy(str->ptr, RSTRING(orig)->ptr, RSTRING(orig)->len); + str->ptr[RSTRING(orig)->len] = '\0'; } - str->ptr[RSTRING(orig)->len] = '\0'; - str->orig = 0; if (rb_safe_level() >= 3) { - FL_SET(str, STR_TAINT); + FL_SET(str, FL_TAINT); } + rb_obj_call_init((VALUE)str); return (VALUE)str; } static VALUE -str_length(str) +rb_str_length(str) VALUE str; { return INT2FIX(RSTRING(str)->len); } +static VALUE +rb_str_empty(str) + VALUE str; +{ + if (RSTRING(str)->len == 0) + return Qtrue; + return Qfalse; +} + VALUE -str_plus(str1, str2) +rb_str_plus(str1, str2) VALUE str1, str2; { VALUE str3; - str2 = obj_as_string(str2); - str3 = str_new(0, RSTRING(str1)->len+RSTRING(str2)->len); + if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); + str3 = rb_str_new(0, RSTRING(str1)->len+RSTRING(str2)->len); memcpy(RSTRING(str3)->ptr, RSTRING(str1)->ptr, RSTRING(str1)->len); - memcpy(RSTRING(str3)->ptr+RSTRING(str1)->len, RSTRING(str2)->ptr, RSTRING(str2)->len); + memcpy(RSTRING(str3)->ptr + RSTRING(str1)->len, + RSTRING(str2)->ptr, RSTRING(str2)->len); RSTRING(str3)->ptr[RSTRING(str3)->len] = '\0'; - if (str_tainted(str1) || str_tainted(str2)) - return str_taint(str3); - return (VALUE)str3; + if (OBJ_TAINTED(str1) || OBJ_TAINTED(str2)) + OBJ_TAINT(str3); + return str3; } VALUE -str_times(str, times) +rb_str_times(str, times) VALUE str; VALUE times; { VALUE str2; - int i, len; + size_t i, len; len = NUM2INT(times); if (len < 0) { - ArgError("negative argument"); + rb_raise(rb_eArgError, "negative argument"); } - str2 = str_new(0, RSTRING(str)->len*len); + str2 = rb_str_new(0, RSTRING(str)->len*len); for (i=0; i<len; i++) { - memcpy(RSTRING(str2)->ptr+(i*RSTRING(str)->len), RSTRING(str)->ptr, RSTRING(str)->len); + memcpy(RSTRING(str2)->ptr+(i*RSTRING(str)->len), + RSTRING(str)->ptr, RSTRING(str)->len); } RSTRING(str2)->ptr[RSTRING(str2)->len] = '\0'; - if (str_tainted(str)) { - return str_taint((VALUE)str2); + if (OBJ_TAINTED(str)) { + OBJ_TAINT(str2); } return str2; } -VALUE -str_format(str, arg) +static VALUE +rb_str_format(str, arg) VALUE str, arg; { VALUE *argv; @@ -224,44 +280,47 @@ str_format(str, arg) argv = ALLOCA_N(VALUE, RARRAY(arg)->len + 1); argv[0] = str; MEMCPY(argv+1, RARRAY(arg)->ptr, VALUE, RARRAY(arg)->len); - return f_sprintf(RARRAY(arg)->len+1, argv); + return rb_f_sprintf(RARRAY(arg)->len+1, argv); } argv = ALLOCA_N(VALUE, 2); argv[0] = str; argv[1] = arg; - return f_sprintf(2, argv); + return rb_f_sprintf(2, argv); } VALUE -str_substr(str, start, len) +rb_str_substr(str, start, len) VALUE str; - int start, len; + size_t start, len; { - struct RString *str2; + VALUE str2; if (start < 0) { start = RSTRING(str)->len + start; } if (RSTRING(str)->len <= start || len < 0) { - return str_new(0,0); + return rb_str_new(0,0); } if (RSTRING(str)->len < start + len) { len = RSTRING(str)->len - start; } - return str_new(RSTRING(str)->ptr+start, len); + str2 = rb_str_new(RSTRING(str)->ptr+start, len); + if (OBJ_TAINTED(str)) OBJ_TAINT(str2); + + return str2; } static VALUE -str_subseq(str, beg, end) +rb_str_subseq(str, beg, end) VALUE str; - int beg, end; + size_t beg, end; { - int len; + size_t len; if ((beg > 0 && end > 0 || beg < 0 && end < 0) && beg > end) { - IndexError("end smaller than beg [%d..%d]", beg, end); + rb_raise(rb_eIndexError, "end smaller than beg [%d..%d]", beg, end); } if (beg < 0) { @@ -277,7 +336,7 @@ str_subseq(str, beg, end) } if (beg >= RSTRING(str)->len) { - return str_new(0, 0); + return rb_str_new(0, 0); } len = end - beg + 1; @@ -285,24 +344,20 @@ str_subseq(str, beg, end) len = 0; } - return str_substr(str, beg, len); + return rb_str_substr(str, beg, len); } -extern VALUE ignorecase; - void -str_modify(str) +rb_str_modify(str) VALUE str; { - UCHAR *ptr; + char *ptr; - if (rb_safe_level() >= 5) { - extern VALUE eSecurityError; - Raise(eSecurityError, "cannot change string status"); - } if (FL_TEST(str, STR_FREEZE)) - TypeError("can't modify frozen string"); - if (!RSTRING(str)->orig) return; + rb_raise(rb_eTypeError, "can't modify frozen string"); + if (rb_safe_level() >= 4 && !FL_TEST(str, FL_TAINT)) + rb_raise(rb_eSecurityError, "Insecure: can't modify string"); + if (!RSTRING(str)->orig || FL_TEST(str, STR_NO_ORIG)) return; ptr = RSTRING(str)->ptr; RSTRING(str)->ptr = ALLOC_N(char, RSTRING(str)->len+1); if (RSTRING(str)->ptr) { @@ -313,7 +368,7 @@ str_modify(str) } VALUE -str_freeze(str) +rb_str_freeze(str) VALUE str; { FL_SET(str, STR_FREEZE); @@ -321,48 +376,32 @@ str_freeze(str) } static VALUE -str_frozen_p(str) +rb_str_frozen_p(str) VALUE str; { if (FL_TEST(str, STR_FREEZE)) - return TRUE; - return FALSE; -} - -VALUE -str_dup_freezed(str) - VALUE str; -{ - str = str_dup(str); - str_freeze(str); - return str; + return Qtrue; + return Qfalse; } VALUE -str_taint(str) +rb_str_dup_frozen(str) VALUE str; { - if (TYPE(str) == T_STRING) { - FL_SET(str, STR_TAINT); + if (RSTRING(str)->orig && !FL_TEST(str, STR_NO_ORIG)) { + return rb_str_freeze(RSTRING(str)->orig); } - return str; -} - -VALUE -str_tainted(str) - VALUE str; -{ - if (FL_TEST(str, STR_TAINT)) - return TRUE; - return FALSE; + if (FL_TEST(str, STR_FREEZE)) + return str; + return rb_str_freeze(rb_str_dup(str)); } VALUE -str_resize(str, len) +rb_str_resize(str, len) VALUE str; - int len; + size_t len; { - str_modify(str); + rb_str_modify(str); if (len >= 0) { if (RSTRING(str)->len < len || RSTRING(str)->len - len > 1024) { @@ -371,17 +410,17 @@ str_resize(str, len) RSTRING(str)->len = len; RSTRING(str)->ptr[len] = '\0'; /* sentinel */ } - return (VALUE)str; + return str; } VALUE -str_cat(str, ptr, len) +rb_str_cat(str, ptr, len) VALUE str; - UCHAR *ptr; - UINT len; + char *ptr; + size_t len; { if (len > 0) { - str_modify(str); + rb_str_modify(str); REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len + len + 1); if (ptr) memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); @@ -391,24 +430,30 @@ str_cat(str, ptr, len) return str; } -static VALUE -str_concat(str1, str2) +VALUE +rb_str_concat(str1, str2) VALUE str1, str2; { - str2 = obj_as_string(str2); - str_cat(str1, RSTRING(str2)->ptr, RSTRING(str2)->len); - return str1; + if (FIXNUM_P(str2)) { + int i = FIX2INT(str2); + if (0 <= i && i <= 0xff) { /* byte */ + char c = i; + return rb_str_cat(str1, &c, 1); + } + } + if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); + return rb_str_cat(str1, RSTRING(str2)->ptr, RSTRING(str2)->len); } int -str_hash(str) +rb_str_hash(str) VALUE str; { - register int len = RSTRING(str)->len; - register UCHAR *p = RSTRING(str)->ptr; + register size_t len = RSTRING(str)->len; + register char *p = RSTRING(str)->ptr; register int key = 0; - if (RTEST(ignorecase)) { + if (ruby_ignorecase) { while (len--) { key = key*65599 + toupper(*p); p++; @@ -424,75 +469,79 @@ str_hash(str) } static VALUE -str_hash_method(str) +rb_str_hash_method(str) VALUE str; { - int key = str_hash(str); + int key = rb_str_hash(str); return INT2FIX(key); } -#define min(a,b) (((a)>(b))?(b):(a)) +#define lesser(a,b) (((a)>(b))?(b):(a)) int -str_cmp(str1, str2) +rb_str_cmp(str1, str2) VALUE str1, str2; { - UINT len; + size_t len; int retval; - if (RTEST(ignorecase)) { - return str_cicmp(str1, str2); + if (ruby_ignorecase) { + return rb_str_cicmp(str1, str2); } - len = min(RSTRING(str1)->len, RSTRING(str2)->len); + len = lesser(RSTRING(str1)->len, RSTRING(str2)->len); retval = memcmp(RSTRING(str1)->ptr, RSTRING(str2)->ptr, len); if (retval == 0) { - return RSTRING(str1)->ptr[len] - RSTRING(str2)->ptr[len]; + if (RSTRING(str1)->len == RSTRING(str2)->len) return 0; + if (RSTRING(str1)->len > RSTRING(str2)->len) return 1; + return -1; } - return retval; + if (retval == 0) return 0; + if (retval > 0) return 1; + return -1; } static VALUE -str_equal(str1, str2) +rb_str_equal(str1, str2) VALUE str1, str2; { if (TYPE(str2) != T_STRING) - return FALSE; + return Qfalse; if (RSTRING(str1)->len == RSTRING(str2)->len - && str_cmp(str1, str2) == 0) { - return TRUE; + && rb_str_cmp(str1, str2) == 0) { + return Qtrue; } - return FALSE; + return Qfalse; } static VALUE -str_cmp_method(str1, str2) +rb_str_cmp_method(str1, str2) VALUE str1, str2; { int result; - str2 = obj_as_string(str2); - result = str_cmp(str1, str2); + if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); + result = rb_str_cmp(str1, str2); return INT2FIX(result); } static VALUE -str_match(x, y) +rb_str_match(x, y) VALUE x, y; { VALUE reg; - int start; + size_t start; switch (TYPE(y)) { case T_REGEXP: - return reg_match(y, x); + return rb_reg_match(y, x); case T_STRING: - reg = reg_regcomp(y); - start = reg_search(reg, x, 0, 0); + reg = rb_reg_regcomp(y); + start = rb_reg_search(reg, x, 0, 0); if (start == -1) { - return FALSE; + return Qfalse; } return INT2FIX(start); @@ -502,19 +551,19 @@ str_match(x, y) } static VALUE -str_match2(str) +rb_str_match2(str) VALUE str; { - return reg_match2(reg_regcomp(str)); + return rb_reg_match2(rb_reg_regcomp(str)); } -static int -str_index(str, sub, offset) +static size_t +rb_str_index(str, sub, offset) VALUE str, sub; - int offset; + size_t offset; { - UCHAR *s, *e, *p; - int len; + char *s, *e, *p; + size_t len; if (RSTRING(str)->len - offset < RSTRING(sub)->len) return -1; s = RSTRING(str)->ptr+offset; @@ -527,21 +576,21 @@ str_index(str, sub, offset) } s++; } - return -1; + return (size_t)-1; } static VALUE -str_index_method(argc, argv, str) +rb_str_index_method(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE sub; VALUE initpos; - int pos; + size_t pos; if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) { - pos = NUM2INT(initpos); + pos = NUM2UINT(initpos); } else { pos = 0; @@ -549,17 +598,17 @@ str_index_method(argc, argv, str) switch (TYPE(sub)) { case T_REGEXP: - pos = reg_search(sub, str, pos, (struct re_registers *)-1); + pos = rb_reg_search(sub, str, pos, 0); break; case T_STRING: - pos = str_index(str, sub, pos); + pos = rb_str_index(str, sub, pos); break; case T_FIXNUM: { int c = FIX2INT(sub); - int len = RSTRING(str)->len; + size_t len = RSTRING(str)->len; char *p = RSTRING(str)->ptr; for (;pos<len;pos++) { @@ -569,7 +618,8 @@ str_index_method(argc, argv, str) } default: - TypeError("Type mismatch: %s given", rb_class2name(CLASS_OF(sub))); + rb_raise(rb_eTypeError, "Type mismatch: %s given", + rb_class2name(CLASS_OF(sub))); } if (pos == -1) return Qnil; @@ -577,18 +627,18 @@ str_index_method(argc, argv, str) } static VALUE -str_rindex(argc, argv, str) +rb_str_rindex(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE sub; VALUE initpos; - int pos, len; - UCHAR *s, *sbeg, *t; + size_t pos, len; + char *s, *sbeg, *t; if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) { - pos = NUM2INT(initpos); + pos = NUM2UINT(initpos); if (pos >= RSTRING(str)->len) pos = RSTRING(str)->len; } else { @@ -597,11 +647,7 @@ str_rindex(argc, argv, str) switch (TYPE(sub)) { case T_REGEXP: - reg_prepare_re(sub); - pos = re_search(RREGEXP(sub)->ptr, - RSTRING(str)->ptr, RSTRING(str)->len, - pos, -pos, 0); - kcode_reset_option(); + pos = rb_reg_search(sub, str, pos, 1); if (pos >= 0) return INT2FIX(pos); break; @@ -631,14 +677,15 @@ str_rindex(argc, argv, str) } default: - TypeError("Type mismatch: %s given", rb_class2name(CLASS_OF(sub))); + rb_raise(rb_eTypeError, "Type mismatch: %s given", + rb_class2name(CLASS_OF(sub))); } return Qnil; } -static UCHAR +static char succ_char(s) - UCHAR *s; + char *s; { char c = *s; @@ -662,19 +709,19 @@ succ_char(s) } static VALUE -str_succ(orig) +rb_str_succ(orig) VALUE orig; { VALUE str, str2; - UCHAR *sbeg, *s; + char *sbeg, *s; char c = -1; - str = str_new(RSTRING(orig)->ptr, RSTRING(orig)->len); + str = rb_str_new(RSTRING(orig)->ptr, RSTRING(orig)->len); sbeg = RSTRING(str)->ptr; s = sbeg + RSTRING(str)->len - 1; while (sbeg <= s) { - if (isalnum(*s) && (c = succ_char(s)) == 0) break; + if (ISALNUM(*s) && (c = succ_char(s)) == 0) break; s--; } if (s < sbeg) { @@ -682,35 +729,45 @@ str_succ(orig) RSTRING(str)->ptr[RSTRING(str)->len-1] += 1; } else { - str2 = str_new(0, RSTRING(str)->len+1); + str2 = rb_str_new(0, RSTRING(str)->len+1); RSTRING(str2)->ptr[0] = c; memcpy(RSTRING(str2)->ptr+1, RSTRING(str)->ptr, RSTRING(str)->len); str = str2; } } - if (str_tainted(orig)) { - return str_taint(str); + if (OBJ_TAINTED(orig)) { + OBJ_TAINT(str); } return str; } +static VALUE +rb_str_succ_bang(str) + VALUE str; +{ + rb_str_modify(str); + rb_str_assign(str, rb_str_succ(str)); + + return str; +} + VALUE -str_upto(beg, end) +rb_str_upto(beg, end) VALUE beg, end; { VALUE current; - Check_Type(end, T_STRING); + if (TYPE(end) != T_STRING) end = rb_str_to_str(end); if (RTEST(rb_funcall(beg, '>', 1, end))) return Qnil; current = beg; for (;;) { rb_yield(current); - if (str_equal(current, end)) break; - current = str_succ(current); + if (rb_str_equal(current, end)) break; + current = rb_str_succ(current); if (RSTRING(current)->len > RSTRING(end)->len) break; } @@ -719,11 +776,11 @@ str_upto(beg, end) } static VALUE -str_aref(str, indx) +rb_str_aref(str, indx) VALUE str; VALUE indx; { - int idx; + size_t idx; switch (TYPE(indx)) { case T_FIXNUM: @@ -735,31 +792,32 @@ str_aref(str, indx) if (idx < 0 || RSTRING(str)->len <= idx) { return Qnil; } - return (VALUE)INT2FIX(RSTRING(str)->ptr[idx] & 0xff); + return INT2FIX(RSTRING(str)->ptr[idx] & 0xff); case T_REGEXP: - if (str_match(str, indx)) - return reg_last_match(0); + if (rb_reg_search(indx, str, 0, 0) >= 0) + return rb_reg_last_match(rb_backref_get()); return Qnil; case T_STRING: - if (str_index(str, indx, 0) != -1) return indx; + if (rb_str_index(str, indx, 0) != (size_t)-1) return indx; return Qnil; default: /* check if indx is Range */ { - int beg, end; - if (range_beg_end(indx, &beg, &end)) { - return str_subseq(str, beg, end); + size_t beg, end; + if (rb_range_beg_end(indx, &beg, &end)) { + return rb_str_subseq(str, beg, end); } } - IndexError("Invalid index for string"); + rb_raise(rb_eIndexError, "Invalid index for string"); } + return Qnil; /* not reached */ } static VALUE -str_aref_method(argc, argv, str) +rb_str_aref_method(argc, argv, str) int argc; VALUE *argv; VALUE str; @@ -767,15 +825,15 @@ str_aref_method(argc, argv, str) VALUE arg1, arg2; if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) { - return str_substr(str, NUM2INT(arg1), NUM2INT(arg2)); + return rb_str_substr(str, NUM2INT(arg1), NUM2INT(arg2)); } - return str_aref(str, arg1); + return rb_str_aref(str, arg1); } static void -str_replace(str, beg, len, val) +rb_str_replace(str, beg, len, val) VALUE str, val; - int beg, len; + size_t beg, len; { if (len < RSTRING(val)->len) { /* expand string */ @@ -783,25 +841,28 @@ str_replace(str, beg, len, val) } if (len != RSTRING(val)->len) { - memmove(RSTRING(str)->ptr+beg+RSTRING(val)->len, - RSTRING(str)->ptr+beg+len, - RSTRING(str)->len-(beg+len)); + memmove(RSTRING(str)->ptr + beg + RSTRING(val)->len, + RSTRING(str)->ptr + beg + len, + RSTRING(str)->len - (beg + len)); + } + if (RSTRING(str)->len < beg && len < 0) { + MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, -len); } memcpy(RSTRING(str)->ptr+beg, RSTRING(val)->ptr, RSTRING(val)->len); RSTRING(str)->len += RSTRING(val)->len - len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; } -/* str_replace2() understands negatice offset */ +/* rb_str_replace2() understands negatice offset */ static void -str_replace2(str, beg, end, val) - VALUE str, *val; - int beg, end; +rb_str_replace2(str, beg, end, val) + VALUE str, val; + size_t beg, end; { - int len; + size_t len; if ((beg > 0 && end > 0 || beg < 0 && end < 0) && beg > end) { - IndexError("end smaller than beg [%d..%d]", beg, end); + rb_raise(rb_eIndexError, "end smaller than beg [%d..%d]", beg, end); } if (beg < 0) { @@ -827,307 +888,295 @@ str_replace2(str, beg, end, val) len = 0; } - str_replace(str, beg, len, val); + rb_str_replace(str, beg, len, val); } -static VALUE -str_sub_s(str, pat, val, once) - VALUE str, pat, val; - int once; -{ - VALUE result, repl; - int beg, offset, n; - struct re_registers *regs; - - switch (TYPE(pat)) { - case T_REGEXP: - break; - - case T_STRING: - pat = reg_regcomp(pat); - break; - - default: - /* type failed */ - Check_Type(pat, T_REGEXP); - } - - val = obj_as_string(val); - result = str_new(0,0); - offset=0; n=0; - while ((beg=reg_search(pat, str, offset, 0)) >= 0) { - n++; - - regs = RMATCH(backref_get())->regs; - str_cat(result, RSTRING(str)->ptr+offset, beg-offset); - - repl = reg_regsub(val, str, regs); - str_cat(result, RSTRING(repl)->ptr, RSTRING(repl)->len); - if (END(0) == offset) { - /* - * Always consume at least one character of the input string - * in order to prevent infinite loops. - */ - if (RSTRING(str)->len > 0) { - str_cat(result, RSTRING(str)->ptr+END(0), 1); - } - offset = END(0)+1; - } - else { - offset = END(0); - } - - if (once) break; - if (offset >= STRLEN(str)) break; - } - if (n == 0) return Qnil; - if (RSTRING(str)->len > offset) { - str_cat(result, RSTRING(str)->ptr+offset, RSTRING(str)->len-offset); - } - - if (str_tainted(val)) str_taint(result); - return result; -} +static VALUE rb_str_sub_bang _((int, VALUE*, VALUE)); static VALUE -str_sub_f(str, pat, val, once) - VALUE str; - VALUE pat; - VALUE val; - int once; -{ - VALUE result; - - str_modify(str); - result = str_sub_s(str, pat, val, once); - - if (NIL_P(result)) return Qnil; - str_resize(str, RSTRING(result)->len); - memcpy(RSTRING(str)->ptr, RSTRING(result)->ptr, RSTRING(result)->len); - if (str_tainted(result)) str_taint(str); - - return (VALUE)str; -} - -static VALUE -str_sub_iter_s(str, pat, once) - VALUE str; - VALUE pat; - int once; -{ - VALUE val, result; - int beg, offset, n, null; - struct re_registers *regs; - - if (!iterator_p()) { - ArgError("Wrong # of arguments(1 for 2)"); - } - - switch (TYPE(pat)) { - case T_REGEXP: - break; - - case T_STRING: - pat = reg_regcomp(pat); - break; - - default: - /* type failed */ - Check_Type(pat, T_REGEXP); - } - - result = str_new(0,0); - n = 0; offset = 0; - while ((beg=reg_search(pat, str, offset, 0)) >= 0) { - n++; - - null = 0; - str_cat(result, RSTRING(str)->ptr+offset, beg-offset); - - regs = RMATCH(backref_get())->regs; - if (END(0) == offset) { - null = 1; - offset = END(0)+1; - } - else { - offset = END(0); - } - - val = rb_yield(reg_nth_match(0, backref_get())); - val = obj_as_string(val); - str_cat(result, RSTRING(val)->ptr, RSTRING(val)->len); - if (null && RSTRING(str)->len) { - str_cat(result, RSTRING(str)->ptr+offset-1, 1); - } - - if (once) break; - if (offset >= STRLEN(str)) break; - } - if (n == 0) return Qnil; - if (RSTRING(str)->len > offset) { - str_cat(result, RSTRING(str)->ptr+offset, RSTRING(str)->len-offset); - } - - return result; -} - -static VALUE -str_sub_iter_f(str, pat, once) - VALUE str; - VALUE pat; - int once; -{ - VALUE result; - - str_modify(str); - result = str_sub_iter_s(str, pat, once); - - if (NIL_P(result)) return Qnil; - str_resize(str, RSTRING(result)->len); - memcpy(RSTRING(str)->ptr, RSTRING(result)->ptr, RSTRING(result)->len); - - return (VALUE)str; -} - -static VALUE -str_aset(str, indx, val) +rb_str_aset(str, indx, val) VALUE str; VALUE indx, val; { - int idx, beg, end, offset; + size_t idx, beg, end; switch (TYPE(indx)) { case T_FIXNUM: - idx = NUM2INT(indx); + idx = NUM2UINT(indx); if (idx < 0) { idx = RSTRING(str)->len + idx; } if (idx < 0 || RSTRING(str)->len <= idx) { - IndexError("index %d out of range [0..%d]", idx, RSTRING(str)->len-1); + rb_raise(rb_eIndexError, "index %d out of range [0..%d]", idx, + RSTRING(str)->len - 1); + } + if (TYPE(val) == T_STRING) { + rb_str_replace(str, idx, 1, val); + } + else { + RSTRING(str)->ptr[idx] = NUM2INT(val) & 0xff; } - RSTRING(str)->ptr[idx] = FIX2INT(val) & 0xff; return val; case T_REGEXP: - str_sub_f(str, indx, val, 0); + { + VALUE args[2]; + args[0] = indx; + args[1] = val; + rb_str_sub_bang(2, args, str); + } return val; case T_STRING: - for (offset=0; - (beg=str_index(str, indx, offset)) >= 0; - offset=beg+STRLEN(val)) { - end = beg + STRLEN(indx) - 1; - str_replace2(str, beg, end, val); + beg = rb_str_index(str, indx, 0); + if (beg != (size_t)-1) { + end = beg + RSTRING(indx)->len - 1; + rb_str_replace2(str, beg, end, val); } - if (offset == 0) return Qnil; return val; default: /* check if indx is Range */ { - int beg, end; - if (range_beg_end(indx, &beg, &end)) { - str_replace2(str, beg, end, val); + size_t beg, end; + if (rb_range_beg_end(indx, &beg, &end)) { + if (TYPE(val) != T_STRING) val = rb_str_to_str(val); + rb_str_replace2(str, beg, end, val); return val; } } - IndexError("Invalid index for string"); + rb_raise(rb_eIndexError, "Invalid index for string"); } } static VALUE -str_aset_method(argc, argv, str) +rb_str_aset_method(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE arg1, arg2, arg3; - str_modify(str); + rb_str_modify(str); if (rb_scan_args(argc, argv, "21", &arg1, &arg2, &arg3) == 3) { - int beg, len; - - Check_Type(arg3, T_STRING); + size_t beg, len; - beg = NUM2INT(arg1); + if (TYPE(arg3) != T_STRING) arg3 = rb_str_to_str(arg3); + beg = NUM2UINT(arg1); if (beg < 0) { beg = RSTRING(str)->len + beg; if (beg < 0) beg = 0; } - len = NUM2INT(arg2); - if (len < 0) IndexError("negative length %d", len); + len = NUM2UINT(arg2); + if (len < 0) rb_raise(rb_eIndexError, "negative length %d", len); if (beg + len > RSTRING(str)->len) { len = RSTRING(str)->len - beg; } - str_replace(str, beg, len, arg3); + rb_str_replace(str, beg, len, arg3); return arg3; } - return str_aset(str, arg1, arg2); + return rb_str_aset(str, arg1, arg2); } static VALUE -str_sub_bang(argc, argv, str) - int argc; - VALUE *argv; - VALUE str; +get_pat(pat) + VALUE pat; { - VALUE pat, val; + switch (TYPE(pat)) { + case T_REGEXP: + break; + + case T_STRING: + pat = rb_reg_regcomp(pat); + break; - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - return str_sub_iter_f(str, pat, 1); + default: + /* type failed */ + Check_Type(pat, T_REGEXP); } - return str_sub_f(str, pat, val, 1); + return pat; } static VALUE -str_sub(argc, argv, str) +rb_str_sub_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { - VALUE pat, val, v; + VALUE pat, repl, match; + struct re_registers *regs; + int iter = 0; + size_t plen; - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - v = str_sub_iter_s(str, pat, 1); + if (argc == 1 && rb_iterator_p()) { + iter = 1; + } + else if (argc == 2) { + repl = rb_obj_as_string(argv[1]);; } else { - v = str_sub_s(str, pat, val, 1); + rb_raise(rb_eArgError, "Wrong # of arguments(%d for 2)", argc); } - if (NIL_P(v)) return str_dup(str); - return v; + + pat = get_pat(argv[0]); + if (rb_reg_search(pat, str, 0, 0) >= 0) { + rb_str_modify(str); + match = rb_backref_get(); + regs = RMATCH(match)->regs; + + if (iter) { + repl = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); + } + else { + repl = rb_reg_regsub(repl, str, regs); + } + plen = END(0) - BEG(0); + if (RSTRING(repl)->len > plen) { + REALLOC_N(RSTRING(str)->ptr, char, + RSTRING(str)->len + RSTRING(repl)->len - plen + 1); + } + if (RSTRING(repl)->len != plen) { + memmove(RSTRING(str)->ptr + BEG(0) + RSTRING(repl)->len, + RSTRING(str)->ptr + BEG(0) + plen, + RSTRING(str)->len - BEG(0) - plen); + } + memcpy(RSTRING(str)->ptr + BEG(0), + RSTRING(repl)->ptr, RSTRING(repl)->len); + RSTRING(str)->len += RSTRING(repl)->len - plen; + RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; + return str; + } + return Qnil; } static VALUE -str_gsub_bang(argc, argv, str) +rb_str_sub(argc, argv, str) int argc; VALUE *argv; VALUE str; { - VALUE pat, val; + VALUE val = rb_str_sub_bang(argc, argv, str = rb_str_dup(str)); - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - return str_sub_iter_f(str, pat, 0); - } - return str_sub_f(str, pat, val, 0); + if (NIL_P(val)) return str; + return val; } static VALUE -str_gsub(argc, argv, str) +rb_str_gsub_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { - VALUE pat, val, v; + VALUE pat, val, repl, match; + struct re_registers *regs; + int beg, offset, n; + int iter = 0; + char *buf, *bp, *cp; + size_t blen, len; - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - v = str_sub_iter_s(str, pat, 0); + if (argc == 1 && rb_iterator_p()) { + iter = 1; + } + else if (argc == 2) { + repl = rb_obj_as_string(argv[1]);; } else { - v = str_sub_s(str, pat, val, 0); + rb_raise(rb_eArgError, "Wrong # of arguments(%d for 2)", argc); + } + + pat = get_pat(argv[0]); + offset=0; n=0; + beg = rb_reg_search(pat, str, 0, 0); + if (beg < 0) return Qnil; /* no match, no substitution */ + + blen = RSTRING(str)->len + 30; /* len + margin */ + buf = ALLOC_N(char, blen); + bp = buf; + cp = RSTRING(str)->ptr; + + while (beg >= 0) { + n++; + match = rb_backref_get(); + regs = RMATCH(match)->regs; + if (iter) { + val = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); + } + else { + val = rb_reg_regsub(repl, str, regs); + } + len = (bp - buf) + (beg - offset) + RSTRING(val)->len + 3; + if (blen < len) { + while (blen < len) blen *= 2; + len = bp - buf; + REALLOC_N(buf, char, blen); + bp = buf + len; + } + len = beg - offset; /* copy pre-match substr */ + memcpy(bp, cp, len); + bp += len; + memcpy(bp, RSTRING(val)->ptr, RSTRING(val)->len); + bp += RSTRING(val)->len; + if (BEG(0) == END(0)) { + /* + * Always consume at least one character of the input string + * in order to prevent infinite loops. + */ + len = mbclen(RSTRING(str)->ptr[END(0)]); + if (RSTRING(str)->len > END(0)) { + memcpy(bp, RSTRING(str)->ptr+END(0), len); + bp += len; + } + offset = END(0) + len; + } + else { + offset = END(0); + } + cp = RSTRING(str)->ptr + offset; + if (offset > RSTRING(str)->len) break; + beg = rb_reg_search(pat, str, offset, 0); + } + if (RSTRING(str)->len > offset) { + len = bp - buf; + if (blen - len < RSTRING(str)->len - offset) { + REALLOC_N(buf, char, len + RSTRING(str)->len - offset + 1); + bp = buf + len; + } + memcpy(bp, cp, RSTRING(str)->len - offset); + bp += RSTRING(str)->len - offset; } - if (NIL_P(v)) return str_dup(str); - return v; + rb_str_modify(str); + free(RSTRING(str)->ptr); + RSTRING(str)->ptr = buf; + RSTRING(str)->len = len = bp - buf; + RSTRING(str)->ptr[len] = '\0'; + + return str; +} + +static VALUE +rb_str_gsub(argc, argv, str) + int argc; + VALUE *argv; + VALUE str; +{ + VALUE val = rb_str_gsub_bang(argc, argv, str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; +} + +static VALUE +rb_str_replace_method(str, str2) + VALUE str, str2; +{ + if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); + rb_str_modify(str); + rb_str_resize(str, RSTRING(str2)->len); + memcpy(RSTRING(str)->ptr, RSTRING(str2)->ptr, RSTRING(str2)->len); + if (OBJ_TAINTED(str2)) OBJ_TAINT(str); + + return str; } static VALUE @@ -1135,108 +1184,86 @@ uscore_get() { VALUE line; - line = lastline_get(); + line = rb_lastline_get(); if (TYPE(line) != T_STRING) { - TypeError("$_ value need to be String (%s given)", - rb_class2name(CLASS_OF(line))); + rb_raise(rb_eTypeError, "$_ value need to be String (%s given)", + NIL_P(line)?"nil":rb_class2name(CLASS_OF(line))); } return line; } static VALUE -f_sub_bang(argc, argv) +rb_f_sub_bang(argc, argv) int argc; VALUE *argv; { - VALUE pat, val, line; - - line = uscore_get(); - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - return str_sub_iter_f(line, pat, 1); - } - return str_sub_f(line, pat, val, 1); + return rb_str_sub_bang(argc, argv, uscore_get()); } static VALUE -f_sub(argc, argv) +rb_f_sub(argc, argv) int argc; VALUE *argv; { - VALUE pat, val, line, v; + VALUE line, v; - line = uscore_get(); - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - v = str_sub_iter_s(line, pat, 1); - } - else { - v = str_sub_s(line, pat, val, 1); - } - if (!NIL_P(v)) { - lastline_set(v); - return v; - } - return line; + line = rb_str_dup(uscore_get()); + v = rb_str_sub_bang(argc, argv, line); + if (NIL_P(v)) return line; + rb_lastline_set(v); + return v; } static VALUE -f_gsub_bang(argc, argv) +rb_f_gsub_bang(argc, argv) int argc; VALUE *argv; { - VALUE pat, val, line; - - line = uscore_get(); - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - return str_sub_iter_f(line, pat, 0); - } - return str_sub_f(line, pat, val, 0); + return rb_str_gsub_bang(argc, argv, uscore_get()); } static VALUE -f_gsub(argc, argv) +rb_f_gsub(argc, argv) int argc; VALUE *argv; { - VALUE pat, val, line, v; - - line = uscore_get(); - if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) { - v = str_sub_iter_s(line, pat, 0); - } - else { - v = str_sub_s(line, pat, val, 0); - } - if (NIL_P(v)) v = str_dup(line); - lastline_set(v); + VALUE line, v; + line = rb_str_dup(uscore_get()); + v = rb_str_gsub_bang(argc, argv, line); + if (NIL_P(v)) return line; + rb_lastline_set(v); return v; } static VALUE -str_reverse_bang(str) +rb_str_reverse_bang(str) VALUE str; { - UCHAR *s, *e, *p; + char *s, *e, *p, *q; s = RSTRING(str)->ptr; e = s + RSTRING(str)->len - 1; - p = ALLOCA_N(char, RSTRING(str)->len); + p = q = ALLOCA_N(char, RSTRING(str)->len); while (e >= s) { *p++ = *e--; } - MEMCPY(RSTRING(str)->ptr, p, char, RSTRING(str)->len); + MEMCPY(RSTRING(str)->ptr, q, char, RSTRING(str)->len); - return (VALUE)str; + return str; } static VALUE -str_reverse(str) +rb_str_reverse(str) VALUE str; { - VALUE obj = str_new(0, RSTRING(str)->len); - UCHAR *s, *e, *p; + VALUE obj; + char *s, *e, *p; + + if (RSTRING(str)->len <= 1) return str; + obj = rb_str_new(0, RSTRING(str)->len); s = RSTRING(str)->ptr; e = s + RSTRING(str)->len - 1; p = RSTRING(obj)->ptr; @@ -1248,14 +1275,14 @@ str_reverse(str) } static VALUE -str_include(str, arg) +rb_str_include(str, arg) VALUE str, arg; { - int i; + size_t i; if (FIXNUM_P(arg)) { int c = FIX2INT(arg); - int len = RSTRING(str)->len; + size_t len = RSTRING(str)->len; char *p = RSTRING(str)->ptr; for (i=0; i<len; i++) { @@ -1263,51 +1290,47 @@ str_include(str, arg) return INT2FIX(i); } } - return FALSE; + return Qfalse; } - Check_Type(arg, T_STRING); - i = str_index(str, arg, 0); + if (TYPE(arg) != T_STRING) arg = rb_str_to_str(arg); + i = rb_str_index(str, arg, 0); - if (i == -1) return FALSE; + if (i == (size_t)-1) return Qfalse; return INT2FIX(i); } static VALUE -str_to_i(str) +rb_str_to_i(str) VALUE str; { - return str2inum(RSTRING(str)->ptr, 10); + return rb_str2inum(RSTRING(str)->ptr, 10); } -#ifndef atof -double atof(); -#endif - static VALUE -str_to_f(str) +rb_str_to_f(str) VALUE str; { double f = atof(RSTRING(str)->ptr); - return float_new(f); + return rb_float_new(f); } static VALUE -str_to_s(str) +rb_str_to_s(str) VALUE str; { return str; } VALUE -str_inspect(str) +rb_str_inspect(str) VALUE str; { #define STRMAX 80 - UCHAR buf[STRMAX]; - UCHAR *p, *pend; - UCHAR *b; + char buf[STRMAX]; + char *p, *pend; + char *b; p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; b = buf; @@ -1322,23 +1345,26 @@ str_inspect(str) } while (p < pend) { - UCHAR c = *p++; + char c = *p++; if (ismbchar(c) && p < pend) { - CHECK(2); + int len = mbclen(c)-1; + + CHECK(len); *b++ = c; - *b++ = *p++; + while (len--) { + *b++ = *p++; + } } - else if (c == '"') { - CHECK(2); - *b++ = '\\'; - *b++ = '"'; + else if ((c & 0x80) && rb_kcode() != MBCTYPE_EUC) { + CHECK(1); + *b++ = c; } - else if (c == '\\') { + else if (c == '"'|| c == '\\') { CHECK(2); *b++ = '\\'; - *b++ = '\\'; + *b++ = c; } - else if (isprint(c)) { + else if (ISPRINT(c)) { CHECK(1); *b++ = c; } @@ -1362,7 +1388,7 @@ str_inspect(str) *b++ = '\\'; *b++ = 'f'; } - else if (c == '\13') { + else if (c == '\013') { CHECK(2); *b++ = '\\'; *b++ = 'v'; @@ -1380,123 +1406,248 @@ str_inspect(str) else { CHECK(4); *b++ = '\\'; - sprintf(b, "%03o", c); + sprintf(b, "%03o", c & 0377); b += 3; } } *b++ = '"'; - return str_new(buf, b - buf); + return rb_str_new(buf, b - buf); +} + +static VALUE +rb_str_dump(str) + VALUE str; +{ + size_t len; + char *p, *pend; + char *q, *qend; + VALUE result; + + len = 2; /* "" */ + p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; + while (p < pend) { + char c = *p++; + switch (c) { + case '"': case '\\': + case '\n': case '\r': + case '\t': case '\f': + case '\013': case '\007': case '\033': + len += 2; + break; + + default: + if (ISPRINT(c)) { + len++; + } + else { + len += 4; /* \nnn */ + } + break; + } + } + + result = rb_str_new(0, len); + p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; + q = RSTRING(result)->ptr; qend = q + len; + + *q++ = '"'; + while (p < pend) { + char c = *p++; + + if (c == '"' || c == '\\') { + *q++ = '\\'; + *q++ = c; + } + else if (ISPRINT(c)) { + *q++ = c; + } + else if (c == '\n') { + *q++ = '\\'; + *q++ = 'n'; + } + else if (c == '\r') { + *q++ = '\\'; + *q++ = 'r'; + } + else if (c == '\t') { + *q++ = '\\'; + *q++ = 't'; + } + else if (c == '\f') { + *q++ = '\\'; + *q++ = 'f'; + } + else if (c == '\013') { + *q++ = '\\'; + *q++ = 'v'; + } + else if (c == '\007') { + *q++ = '\\'; + *q++ = 'a'; + } + else if (c == '\033') { + *q++ = '\\'; + *q++ = 'e'; + } + else { + *q++ = '\\'; + sprintf(q, "%03o", c&0xff); + q += 3; + } + } + *q++ = '"'; + + return result; } static VALUE -str_upcase_bang(str) +rb_str_upcase_bang(str) VALUE str; { - UCHAR *s, *send; + char *s, *send; + int modify = 0; - str_modify(str); + rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; while (s < send) { - if (islower(*s)) { + if (ismbchar(*s)) { + s+=mbclen(*s); + } + else if (islower(*s)) { *s = toupper(*s); + modify = 1; } s++; } - return (VALUE)str; + if (modify) return str; + return Qnil; } static VALUE -str_upcase(str) +rb_str_upcase(str) VALUE str; { - return str_upcase_bang(str_dup(str)); + VALUE val = rb_str_upcase_bang(str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE -str_downcase_bang(str) +rb_str_downcase_bang(str) VALUE str; { - UCHAR *s, *send; + char *s, *send; + int modify = 0; - str_modify(str); + rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; while (s < send) { - if (isupper(*s)) { + if (ismbchar(*s)) { + s+=mbclen(*s); + } + else if (ISUPPER(*s)) { *s = tolower(*s); + modify = 1; } s++; } - return (VALUE)str; + if (modify) return str; + return Qnil; } static VALUE -str_downcase(str) +rb_str_downcase(str) VALUE str; { - return str_downcase_bang(str_dup(str)); + VALUE val = rb_str_downcase_bang(str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE -str_capitalize_bang(str) +rb_str_capitalize_bang(str) VALUE str; { - UCHAR *s, *send; + char *s, *send; + int modify = 0; - str_modify(str); + rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; - if (islower(*s)) + if (ISLOWER(*s)) { *s = toupper(*s); + modify = 1; + } while (++s < send) { - if (isupper(*s)) { + if (ismbchar(*s)) { + s+=mbclen(*s); + } + else if (ISUPPER(*s)) { *s = tolower(*s); + modify = 1; } } - return (VALUE)str; + if (modify) return str; + return Qnil; } static VALUE -str_capitalize(str) +rb_str_capitalize(str) VALUE str; { - return str_capitalize_bang(str_dup(str)); + VALUE val = rb_str_capitalize_bang(str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE -str_swapcase_bang(str) +rb_str_swapcase_bang(str) VALUE str; { - UCHAR *s, *send; + char *s, *send; + int modify = 0; - str_modify(str); + rb_str_modify(str); s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; while (s < send) { - if (isupper(*s)) { + if (ismbchar(*s)) { + s+=mbclen(*s); + } + else if (ISUPPER(*s)) { *s = tolower(*s); + modify = 1; } - else if (islower(*s)) { + else if (ISLOWER(*s)) { *s = toupper(*s); + modify = 1; } s++; } - return (VALUE)str; + if (modify) return str; + return Qnil; } static VALUE -str_swapcase(str) +rb_str_swapcase(str) VALUE str; { - return str_swapcase_bang(str_dup(str)); + VALUE val = rb_str_swapcase_bang(str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } -typedef UCHAR *USTR; +typedef unsigned char *USTR; -static struct tr { +struct tr { int gen, now, max; - UCHAR *p, *pend; -} trsrc, trrepl; + char *p, *pend; +}; static int trnext(t) @@ -1505,7 +1656,7 @@ trnext(t) for (;;) { if (!t->gen) { if (t->p == t->pend) return -1; - t->now = *t->p++; + t->now = *(USTR)t->p++; if (t->p < t->pend && *t->p == '-') { t->p++; if (t->p < t->pend) { @@ -1529,7 +1680,7 @@ trnext(t) } } -static VALUE str_delete_bang(); +static VALUE rb_str_delete_bang _((VALUE,VALUE)); static VALUE tr_trans(str, src, repl, sflag) @@ -1538,19 +1689,21 @@ tr_trans(str, src, repl, sflag) { struct tr trsrc, trrepl; int cflag = 0; - UCHAR trans[256]; - int i, c, c0; - UCHAR *s, *send, *t; + char trans[256]; + int i, c, c0, modify = 0; + char *s, *send; - Check_Type(src, T_STRING); + rb_str_modify(str); + if (TYPE(src) != T_STRING) src = rb_str_to_str(src); trsrc.p = RSTRING(src)->ptr; trsrc.pend = trsrc.p + RSTRING(src)->len; if (RSTRING(src)->len > 2 && RSTRING(src)->ptr[0] == '^') { cflag++; trsrc.p++; } - Check_Type(repl, T_STRING); - if (RSTRING(repl)->len == 0) return str_delete_bang(str, src); - trrepl.p = RSTRING(repl)->ptr; trrepl.pend = trrepl.p + RSTRING(repl)->len; + if (TYPE(repl) != T_STRING) repl = rb_str_to_str(repl); + if (RSTRING(repl)->len == 0) return rb_str_delete_bang(str, src); + trrepl.p = RSTRING(repl)->ptr; + trrepl.pend = trrepl.p + RSTRING(repl)->len; trsrc.gen = trrepl.gen = 0; trsrc.now = trrepl.now = 0; trsrc.max = trrepl.max = 0; @@ -1590,48 +1743,64 @@ tr_trans(str, src, repl, sflag) } } - str_modify(str); - t = s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; + s = RSTRING(str)->ptr; send = s + RSTRING(str)->len; c0 = -1; if (sflag) { + char *t = s; + while (s < send) { c = trans[*s++ & 0xff] & 0xff; if (s[-1] == c || c != c0) { c0 = (s[-1] == c)?-1:c; + if (*t != c) { + *t = c; + modify = 1; + } *t++ = c; } } + if (RSTRING(str)->len > (t - RSTRING(str)->ptr)) { + RSTRING(str)->len = (t - RSTRING(str)->ptr); + modify = 1; + *t = '\0'; + } } else { while (s < send) { - c = trans[*s++ & 0xff] & 0xff; - *t++ = c; + c = trans[*s & 0xff] & 0xff; + if (*s != c) { + *s = c; + modify = 1; + } + s++; } } - *t = '\0'; - if (sflag) RSTRING(str)->len = (t - RSTRING(str)->ptr); - return (VALUE)str; + if (modify) return str; + return Qnil; } static VALUE -str_tr_bang(str, src, repl) +rb_str_tr_bang(str, src, repl) VALUE str, src, repl; { return tr_trans(str, src, repl, 0); } static VALUE -str_tr(str, src, repl) +rb_str_tr(str, src, repl) VALUE str, src, repl; { - return tr_trans(str_dup(str), src, repl, 0); + VALUE val = tr_trans(str = rb_str_dup(str), src, repl, 0); + + if (NIL_P(val)) return str; + return val; } static void tr_setup_table(str, table) VALUE str; - UCHAR table[256]; + char table[256]; { struct tr tr; int i, cflag = 0; @@ -1653,45 +1822,51 @@ tr_setup_table(str, table) } static VALUE -str_delete_bang(str1, str2) - VALUE str1, *str2; +rb_str_delete_bang(str1, str2) + VALUE str1, str2; { - UCHAR *s, *send, *t; - UCHAR squeez[256]; + char *s, *send, *t; + char squeez[256]; + int modify = 0; - Check_Type(str2, T_STRING); + if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); tr_setup_table(str2, squeez); - str_modify(str1); + rb_str_modify(str1); s = t = RSTRING(str1)->ptr; send = s + RSTRING(str1)->len; while (s < send) { - if (!squeez[*s & 0xff]) { + if (squeez[*s & 0xff]) + modify = 1; + else *t++ = *s; - } s++; } *t = '\0'; RSTRING(str1)->len = t - RSTRING(str1)->ptr; - return (VALUE)str1; + if (modify) return str1; + return Qnil; } static VALUE -str_delete(str1, str2) - VALUE str1, *str2; +rb_str_delete(str1, str2) + VALUE str1, str2; { - return str_delete_bang(str_dup(str1), str2); + VALUE val = rb_str_delete_bang(str1 = rb_str_dup(str1), str2); + + if (NIL_P(val)) return str1; + return val; } static VALUE tr_squeeze(str1, str2) VALUE str1, str2; { - UCHAR squeez[256]; - UCHAR *s, *send, *t; - char c, save; + char squeez[256]; + char *s, *send, *t; + char c, save, modify = 0; if (!NIL_P(str2)) { tr_setup_table(str2, squeez); @@ -1704,7 +1879,7 @@ tr_squeeze(str1, str2) } } - str_modify(str1); + rb_str_modify(str1); s = t = RSTRING(str1)->ptr; send = s + RSTRING(str1)->len; @@ -1713,78 +1888,82 @@ tr_squeeze(str1, str2) c = *s++ & 0xff; if (c != save || !squeez[c & 0xff]) { *t++ = save = c; + modify = 1; } } *t = '\0'; RSTRING(str1)->len = t - RSTRING(str1)->ptr; - return (VALUE)str1; + if (modify) return str1; + return Qnil; } static VALUE -str_squeeze_bang(argc, argv, str1) +rb_str_squeeze_bang(argc, argv, str1) int argc; VALUE *argv; VALUE str1; { VALUE str2; - if (rb_scan_args(argc, argv, "01", &str2) == 1) { - Check_Type(str2, T_STRING); + if (rb_scan_args(argc, argv, "01", &str2) == 1 && TYPE(str2) != T_STRING) { + str2 = rb_str_to_str(str2); } return tr_squeeze(str1, str2); } static VALUE -str_squeeze(argc, argv, str) +rb_str_squeeze(argc, argv, str) int argc; VALUE *argv; VALUE str; { - return str_squeeze_bang(argc, argv, str_dup(str)); + VALUE val = rb_str_squeeze_bang(argc, argv, str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE -str_tr_s_bang(str, src, repl) +rb_str_tr_s_bang(str, src, repl) VALUE str, src, repl; { - Check_Type(src, T_STRING); - Check_Type(repl, T_STRING); - return tr_trans(str, src, repl, 1); } static VALUE -str_tr_s(str, src, repl) +rb_str_tr_s(str, src, repl) VALUE str, src, repl; { - return str_tr_s_bang(str_dup(str), src, repl); + VALUE val = tr_trans(str = rb_str_dup(str), src, repl, 1); + + if (NIL_P(val)) return str; + return val; } static VALUE -str_split_method(argc, argv, str) +rb_str_split_method(argc, argv, str) int argc; VALUE *argv; VALUE str; { - extern VALUE FS; VALUE spat; VALUE limit; - char char_sep = 0; - int beg, end, lim, i; + int char_sep = -1; + int beg, end, i; + int lim = 0; VALUE result, tmp; - rb_scan_args(argc, argv, "02", &spat, &limit); - if (!NIL_P(limit)) { + if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) { lim = NUM2INT(limit); - if (lim == 0) limit = Qnil; - else if (lim == 1) return ary_new3(1, str); + if (lim <= 0) limit = Qnil; + else if (lim == 1) return rb_ary_new3(1, str); i = 1; } - if (NIL_P(spat)) { - if (!NIL_P(FS)) { - spat = FS; + if (argc == 0) { + if (!NIL_P(rb_fs)) { + spat = rb_fs; goto fs_set; } char_sep = ' '; @@ -1793,33 +1972,33 @@ str_split_method(argc, argv, str) switch (TYPE(spat)) { case T_STRING: fs_set: - if (STRLEN(spat) == 1) { - char_sep = RSTRING(spat)->ptr[0]; + if (RSTRING(spat)->len == 1) { + char_sep = (unsigned char)RSTRING(spat)->ptr[0]; } else { - spat = reg_regcomp(spat); + spat = rb_reg_regcomp(spat); } break; case T_REGEXP: break; default: - ArgError("split(): bad separator"); + rb_raise(rb_eArgError, "bad separator"); } } - result = ary_new(); + result = rb_ary_new(); beg = 0; - if (char_sep != 0) { - UCHAR *ptr = RSTRING(str)->ptr; - int len = RSTRING(str)->len; - UCHAR *eptr = ptr + len; + if (char_sep >= 0) { + char *ptr = RSTRING(str)->ptr; + size_t len = RSTRING(str)->len; + char *eptr = ptr + len; if (char_sep == ' ') { /* AWK emulation */ int skip = 1; for (end = beg = 0; ptr<eptr; ptr++) { if (skip) { - if (isspace(*ptr)) { + if (ISSPACE(*ptr)) { beg++; } else { @@ -1828,8 +2007,8 @@ str_split_method(argc, argv, str) } } else { - if (isspace(*ptr)) { - ary_push(result, str_substr(str, beg, end-beg)); + if (ISSPACE(*ptr)) { + rb_ary_push(result, rb_str_substr(str, beg, end-beg)); skip = 1; beg = end + 1; if (!NIL_P(limit) && lim <= ++i) break; @@ -1842,8 +2021,8 @@ str_split_method(argc, argv, str) } else { for (end = beg = 0; ptr<eptr; ptr++) { - if (*ptr == char_sep) { - ary_push(result, str_substr(str, beg, end-beg)); + if (*ptr == (char)char_sep) { + rb_ary_push(result, rb_str_substr(str, beg, end-beg)); beg = end + 1; if (!NIL_P(limit) && lim <= ++i) break; } @@ -1852,29 +2031,26 @@ str_split_method(argc, argv, str) } } else { - int start = beg; + size_t start = beg; int last_null = 0; - int idx; + size_t idx; struct re_registers *regs; - while ((end = reg_search(spat, str, start, 0)) >= 0) { - regs = RMATCH(backref_get())->regs; + while ((end = rb_reg_search(spat, str, start, 0)) >= 0) { + regs = RMATCH(rb_backref_get())->regs; if (start == end && BEG(0) == END(0)) { if (last_null == 1) { - if (ismbchar(RSTRING(str)->ptr[beg])) - ary_push(result, str_substr(str, beg, 2)); - else - ary_push(result, str_substr(str, beg, 1)); + rb_ary_push(result, rb_str_substr(str, beg, mbclen(RSTRING(str)->ptr[beg]))); beg = start; } else { - start += ismbchar(RSTRING(str)->ptr[start])?2:1; + start += mbclen(RSTRING(str)->ptr[start]); last_null = 1; continue; } } else { - ary_push(result, str_substr(str, beg, end-beg)); + rb_ary_push(result, rb_str_substr(str, beg, end-beg)); beg = start = END(0); } last_null = 0; @@ -1882,67 +2058,69 @@ str_split_method(argc, argv, str) for (idx=1; idx < regs->num_regs; idx++) { if (BEG(idx) == -1) continue; if (BEG(idx) == END(idx)) - tmp = str_new(0, 0); + tmp = rb_str_new(0, 0); else - tmp = str_subseq(str, BEG(idx), END(idx)-1); - ary_push(result, tmp); + tmp = rb_str_subseq(str, BEG(idx), END(idx)-1); + rb_ary_push(result, tmp); } if (!NIL_P(limit) && lim <= ++i) break; } } - if (RSTRING(str)->len > beg) { - ary_push(result, str_subseq(str, beg, -1)); + if (!NIL_P(limit) || RSTRING(str)->len > beg || lim < 0) { + rb_ary_push(result, rb_str_subseq(str, beg, -1)); + } + if (NIL_P(limit) && lim == 0) { + while (RARRAY(result)->len > 0 && + RSTRING(RARRAY(result)->ptr[RARRAY(result)->len-1])->len == 0) + rb_ary_pop(result); } return result; } VALUE -str_split(str, sep0) +rb_str_split(str, sep0) VALUE str; char *sep0; { VALUE sep; - Check_Type(str, T_STRING); - sep = str_new2(sep0); - return str_split_method(1, &sep, str); + if (TYPE(str) != T_STRING) str = rb_str_to_str(str); + sep = rb_str_new2(sep0); + return rb_str_split_method(1, &sep, str); } static VALUE -f_split(argc, argv) +rb_f_split(argc, argv) int argc; VALUE *argv; { - return str_split_method(argc, argv, uscore_get()); + return rb_str_split_method(argc, argv, uscore_get()); } static VALUE -str_each_line(argc, argv, str) +rb_str_each_line(argc, argv, str) int argc; VALUE *argv; VALUE str; { - extern VALUE RS; VALUE rs; int newline; int rslen; - UCHAR *p = RSTRING(str)->ptr, *pend = p + RSTRING(str)->len, *s; - UCHAR *ptr = p; - int len = RSTRING(str)->len; + char *p = RSTRING(str)->ptr, *pend = p + RSTRING(str)->len, *s; + char *ptr = p; + size_t len = RSTRING(str)->len; VALUE line; - if (rb_scan_args(argc, argv, "01", &rs) == 1) { - if (!NIL_P(rs)) Check_Type(rs, T_STRING); - } - else { - rs = RS; + if (rb_scan_args(argc, argv, "01", &rs) == 0) { + rs = rb_rs; } if (NIL_P(rs)) { rb_yield(str); return Qnil; } + if (TYPE(rs) != T_STRING) rs = rb_str_to_str(rs); rslen = RSTRING(rs)->len; if (rslen == 0) { @@ -1954,25 +2132,22 @@ str_each_line(argc, argv, str) for (s = p, p += rslen; p < pend; p++) { if (rslen == 0 && *p == '\n') { - if (*(p+1) != '\n') continue; + if (p[1] != '\n') continue; while (*p == '\n') p++; - p--; } - if (*p == newline && + if (p[-1] == newline && (rslen <= 1 || - memcmp(RSTRING(rs)->ptr, p-rslen+1, rslen) == 0)) { - line = str_new(s, p - s + 1); - lastline_set(line); + memcmp(RSTRING(rs)->ptr, p-rslen, rslen) == 0)) { + line = rb_str_new(s, p - s); rb_yield(line); if (RSTRING(str)->ptr != ptr || RSTRING(str)->len != len) - Fail("string modified"); - s = p + 1; + rb_raise(rb_eArgError, "string modified"); + s = p; } } if (s != pend) { - line = str_new(s, p - s); - lastline_set(line); + line = rb_str_new(s, p - s); rb_yield(line); } @@ -1980,10 +2155,10 @@ str_each_line(argc, argv, str) } static VALUE -str_each_byte(str) +rb_str_each_byte(str) struct RString* str; { - int i; + size_t i; for (i=0; i<RSTRING(str)->len; i++) { rb_yield(INT2FIX(RSTRING(str)->ptr[i] & 0xff)); @@ -1992,12 +2167,11 @@ str_each_byte(str) } static VALUE -str_chop_bang(str) +rb_str_chop_bang(str) VALUE str; { - str_modify(str); - if (RSTRING(str)->len > 0) { + rb_str_modify(str); RSTRING(str)->len--; if (RSTRING(str)->ptr[RSTRING(str)->len] == '\n') { if (RSTRING(str)->len > 0 && @@ -2006,90 +2180,132 @@ str_chop_bang(str) } } RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; + return str; } - - return str; + return Qnil; } static VALUE -str_chop(str) +rb_str_chop(str) VALUE str; { - return str_chop_bang(str_dup(str)); + VALUE val = rb_str_chop_bang(str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE -f_chop_bang(str) +rb_f_chop_bang(str) VALUE str; { - return str_chop_bang(uscore_get()); + return rb_str_chop_bang(uscore_get()); } static VALUE -f_chop() +rb_f_chop() { - return str_chop_bang(str_dup(uscore_get())); + VALUE str = rb_str_dup(uscore_get()); + VALUE val = rb_str_chop_bang(str); + + if (NIL_P(str)) return str; + rb_lastline_set(val); + return val; } static VALUE -str_chomp_bang(str) +rb_str_chomp_bang(argc, argv, str) + int argc; + VALUE *argv; VALUE str; { - str_modify(str); + VALUE rs; + int newline; + int rslen; + char *p = RSTRING(str)->ptr; + size_t len = RSTRING(str)->len; - if (RSTRING(str)->len > 0 && - RSTRING(str)->ptr[RSTRING(str)->len-1] == '\n') { - RSTRING(str)->len--; - if (RSTRING(str)->len > 0 && - RSTRING(str)->ptr[RSTRING(str)->len] == '\r') { - RSTRING(str)->len--; + if (rb_scan_args(argc, argv, "01", &rs) == 0) { + rs = rb_rs; + } + if (NIL_P(rs)) return Qnil; + + if (TYPE(rs) != T_STRING) rs = rb_str_to_str(rs); + rslen = RSTRING(rs)->len; + if (rslen == 0) { + while (len>0 && p[len-1] == '\n') { + len--; + } + if (len < RSTRING(str)->len) { + RSTRING(str)->len = len; + RSTRING(str)->ptr[len] = '\0'; + return str; } + return Qnil; + } + if (rslen > len) return Qnil; + newline = RSTRING(rs)->ptr[rslen-1]; + + if (p[len-1] == newline && + (rslen <= 1 || + memcmp(RSTRING(rs)->ptr, p+len-rslen, rslen) == 0)) { + RSTRING(str)->len -= rslen; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; + return str; } - return str; + return Qnil; } static VALUE -str_chomp(str) +rb_str_chomp(argc, argv, str) + int argc; + VALUE *argv; VALUE str; { - return str_chomp_bang(str_dup(str)); + VALUE val = rb_str_chomp_bang(argc, argv, str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE -f_chomp_bang(str) - VALUE str; +rb_f_chomp_bang(argc, argv) + int argc; + VALUE *argv; { - return str_chomp_bang(uscore_get()); + return rb_str_chomp_bang(argc, argv, uscore_get()); } static VALUE -f_chomp() +rb_f_chomp(argc, argv) + int argc; + VALUE *argv; { - return str_chomp_bang(str_dup(uscore_get())); + VALUE str = rb_str_dup(uscore_get()); + VALUE val = rb_str_chomp_bang(argc, argv, str); + return val; } static VALUE -str_strip_bang(str) +rb_str_strip_bang(str) VALUE str; { - UCHAR *s, *t, *e; - - str_modify(str); + char *s, *t, *e; + rb_str_modify(str); s = RSTRING(str)->ptr; e = t = s + RSTRING(str)->len; /* remove spaces at head */ - while (s < t && isspace(*s)) s++; + while (s < t && ISSPACE(*s)) s++; /* remove trailing spaces */ t--; - while (s <= t && isspace(*t)) t--; + while (s <= t && ISSPACE(*t)) t--; t++; RSTRING(str)->len = t-s; if (s > RSTRING(str)->ptr) { - UCHAR *p = RSTRING(str)->ptr; + char *p = RSTRING(str)->ptr; RSTRING(str)->ptr = ALLOC_N(char, RSTRING(str)->len+1); memcpy(RSTRING(str)->ptr, s, RSTRING(str)->len); @@ -2099,38 +2315,50 @@ str_strip_bang(str) else if (t < e) { RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; } + else { + return Qnil; + } - return (VALUE)str; + return str; +} + +static VALUE +rb_str_strip(str) + VALUE str; +{ + VALUE val = rb_str_strip_bang(str = rb_str_dup(str)); + + if (NIL_P(val)) return str; + return val; } static VALUE scan_once(str, pat, start) VALUE str, pat; - int *start; + size_t *start; { - VALUE result; + VALUE result, match; struct re_registers *regs; - int i; + size_t i; - if (reg_search(pat, str, *start, 0) >= 0) { - regs = RMATCH(backref_get())->regs; - if (END(0) == *start) { - *start = END(0)+1; + if (rb_reg_search(pat, str, *start, 0) >= 0) { + match = rb_backref_get(); + regs = RMATCH(match)->regs; + if (BEG(0) == END(0)) { + /* + * Always consume at least one character of the input string + */ + *start = END(0)+mbclen(RSTRING(str)->ptr[END(0)]); } else { *start = END(0); } if (regs->num_regs == 1) { - return str_substr(str, BEG(0), END(0)-BEG(0)); + return rb_reg_nth_match(0, match); } - result = ary_new2(regs->num_regs); + result = rb_ary_new2(regs->num_regs); for (i=1; i < regs->num_regs; i++) { - if (BEG(i) == -1) { - ary_push(result, Qnil); - } - else { - ary_push(result, str_substr(str, BEG(i), END(i)-BEG(i))); - } + rb_ary_push(result, rb_reg_nth_match(i, match)); } return result; @@ -2139,27 +2367,18 @@ scan_once(str, pat, start) } static VALUE -str_scan(str, pat) +rb_str_scan(str, pat) VALUE str, pat; { VALUE result; - int start = 0; - - switch (TYPE(pat)) { - case T_STRING: - pat = reg_regcomp(pat); - break; - case T_REGEXP: - break; - default: - Check_Type(pat, T_REGEXP); - } + size_t start = 0; - if (!iterator_p()) { - VALUE ary = ary_new(); + pat = get_pat(pat); + if (!rb_iterator_p()) { + VALUE ary = rb_ary_new(); while (!NIL_P(result = scan_once(str, pat, &start))) { - ary_push(ary, result); + rb_ary_push(ary, result); } return ary; } @@ -2171,65 +2390,66 @@ str_scan(str, pat) } static VALUE -str_strip(str) +rb_str_hex(str) VALUE str; { - return str_strip_bang(str_dup(str)); + return rb_str2inum(RSTRING(str)->ptr, 16); } static VALUE -str_hex(str) +rb_str_oct(str) VALUE str; { - return str2inum(RSTRING(str)->ptr, 16); -} + int base = 8; -static VALUE -str_oct(str) - VALUE str; -{ - return str2inum(RSTRING(str)->ptr, 8); + if (RSTRING(str)->len > 2 && RSTRING(str)->ptr[0] == '0' && + (RSTRING(str)->ptr[1] == 'x' || RSTRING(str)->ptr[1] == 'X')) { + base = 16; + } + return rb_str2inum(RSTRING(str)->ptr, base); } static VALUE -str_crypt(str, salt) +rb_str_crypt(str, salt) VALUE str, salt; { extern char *crypt(); - salt = obj_as_string(salt); + + if (TYPE(salt) != T_STRING) salt = rb_str_to_str(salt); if (RSTRING(salt)->len < 2) - ArgError("salt too short(need >2 bytes)"); - return str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr)); + rb_raise(rb_eArgError, "salt too short(need >2 bytes)"); + return rb_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr)); } static VALUE -str_intern(str) +rb_str_intern(str) VALUE str; { ID id; if (strlen(RSTRING(str)->ptr) != RSTRING(str)->len) - ArgError("string contains `\0'"); + rb_raise(rb_eArgError, "string contains `\\0'"); id = rb_intern(RSTRING(str)->ptr); return INT2FIX(id); } static VALUE -str_sum(argc, argv, str) +rb_str_sum(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE vbits; int bits; - UCHAR *p, *pend; + char *p, *pend; - rb_scan_args(argc, argv, "01", &vbits); - if (NIL_P(vbits)) bits = 16; + if (rb_scan_args(argc, argv, "01", &vbits) == 0) { + bits = 16; + } else bits = NUM2INT(vbits); p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; - if (bits > 32) { + if (bits > sizeof(long)*CHAR_BIT) { VALUE res = INT2FIX(0); VALUE mod; @@ -2237,36 +2457,39 @@ str_sum(argc, argv, str) mod = rb_funcall(mod, '-', 1, INT2FIX(1)); while (p < pend) { - res = rb_funcall(res, '+', 1, INT2FIX((UINT)*p)); - res = rb_funcall(res, '%', 1, mod); + res = rb_funcall(res, '+', 1, INT2FIX((unsigned int)*p)); p++; } + res = rb_funcall(res, '&', 1, mod); return res; } else { - UINT res = 0; - UINT mod = (1<<bits)-1; + unsigned int res = 0; + unsigned int mod = (1<<bits)-1; + if (mod == 0) { + mod = -1; + } while (p < pend) { - res += (UINT)*p; - res %= mod; + res += (unsigned int)*p; p++; } - return int2inum(res); + res &= mod; + return rb_int2inum(res); } } static VALUE -str_ljust(str, w) +rb_str_ljust(str, w) VALUE str; VALUE w; { - int width = NUM2INT(w); + size_t width = NUM2UINT(w); VALUE res; - UCHAR *p, *pend; + char *p, *pend; - if (RSTRING(str)->len >= width) return (VALUE)str; - res = str_new(0, width); + if (width < 0 || RSTRING(str)->len >= width) return str; + res = rb_str_new(0, width); memcpy(RSTRING(res)->ptr, RSTRING(str)->ptr, RSTRING(str)->len); p = RSTRING(res)->ptr + RSTRING(str)->len; pend = RSTRING(res)->ptr + width; while (p < pend) { @@ -2276,16 +2499,16 @@ str_ljust(str, w) } static VALUE -str_rjust(str, w) +rb_str_rjust(str, w) VALUE str; VALUE w; { - int width = NUM2INT(w); + size_t width = NUM2UINT(w); VALUE res; - UCHAR *p, *pend; + char *p, *pend; - if (RSTRING(str)->len >= width) return (VALUE)str; - res = str_new(0, width); + if (width < 0 || RSTRING(str)->len >= width) return str; + res = rb_str_new(0, width); p = RSTRING(res)->ptr; pend = p + width - RSTRING(str)->len; while (p < pend) { *p++ = ' '; @@ -2295,17 +2518,17 @@ str_rjust(str, w) } static VALUE -str_center(str, w) +rb_str_center(str, w) VALUE str; VALUE w; { - int width = NUM2INT(w); + size_t width = NUM2UINT(w); VALUE res; - UCHAR *p, *pend; - int n; + char *p, *pend; + size_t n; - if (RSTRING(str)->len >= width) return (VALUE)str; - res = str_new(0, width); + if (width < 0 || RSTRING(str)->len >= width) return str; + res = rb_str_new(0, width); n = (width - RSTRING(str)->len)/2; p = RSTRING(res)->ptr; pend = p + n; while (p < pend) { @@ -2319,122 +2542,118 @@ str_center(str, w) return res; } -extern VALUE mKernel; -extern VALUE mComparable; -extern VALUE mEnumerable; -extern VALUE eGlobalExit; - void Init_String() { - cString = rb_define_class("String", cObject); - rb_include_module(cString, mComparable); - rb_include_module(cString, mEnumerable); - rb_define_singleton_method(cString, "new", str_s_new, 1); - rb_define_method(cString, "clone", str_clone, 0); - rb_define_method(cString, "dup", str_dup, 0); - rb_define_method(cString, "<=>", str_cmp_method, 1); - rb_define_method(cString, "==", str_equal, 1); - rb_define_method(cString, "===", str_equal, 1); - rb_define_method(cString, "eql?", str_equal, 1); - rb_define_method(cString, "hash", str_hash_method, 0); - rb_define_method(cString, "+", str_plus, 1); - rb_define_method(cString, "*", str_times, 1); - rb_define_method(cString, "%", str_format, 1); - rb_define_method(cString, "[]", str_aref_method, -1); - rb_define_method(cString, "[]=", str_aset_method, -1); - rb_define_method(cString, "length", str_length, 0); - rb_define_alias(cString, "size", "length"); - rb_define_method(cString, "=~", str_match, 1); - rb_define_method(cString, "~", str_match2, 0); - rb_define_method(cString, "succ", str_succ, 0); - rb_define_method(cString, "upto", str_upto, 1); - rb_define_method(cString, "index", str_index_method, -1); - rb_define_method(cString, "rindex", str_rindex, -1); - - rb_define_method(cString, "freeze", str_freeze, 0); - rb_define_method(cString, "frozen?", str_frozen_p, 0); - - rb_define_method(cString, "taint", str_taint, 0); - rb_define_method(cString, "tainted?", str_tainted, 0); - - rb_define_method(cString, "to_i", str_to_i, 0); - rb_define_method(cString, "to_f", str_to_f, 0); - rb_define_method(cString, "to_s", str_to_s, 0); - rb_define_method(cString, "inspect", str_inspect, 0); - - rb_define_method(cString, "upcase", str_upcase, 0); - rb_define_method(cString, "downcase", str_downcase, 0); - rb_define_method(cString, "capitalize", str_capitalize, 0); - rb_define_method(cString, "swapcase", str_swapcase, 0); - - rb_define_method(cString, "upcase!", str_upcase_bang, 0); - rb_define_method(cString, "downcase!", str_downcase_bang, 0); - rb_define_method(cString, "capitalize!", str_capitalize_bang, 0); - rb_define_method(cString, "swapcase!", str_swapcase_bang, 0); - - rb_define_method(cString, "hex", str_hex, 0); - rb_define_method(cString, "oct", str_oct, 0); - rb_define_method(cString, "split", str_split_method, -1); - rb_define_method(cString, "reverse", str_reverse, 0); - rb_define_method(cString, "reverse!", str_reverse_bang, 0); - rb_define_method(cString, "concat", str_concat, 1); - rb_define_method(cString, "<<", str_concat, 1); - rb_define_method(cString, "crypt", str_crypt, 1); - rb_define_method(cString, "intern", str_intern, 0); - - rb_define_method(cString, "include?", str_include, 1); - - rb_define_method(cString, "scan", str_scan, 1); - - rb_define_method(cString, "ljust", str_ljust, 1); - rb_define_method(cString, "rjust", str_rjust, 1); - rb_define_method(cString, "center", str_center, 1); - - rb_define_method(cString, "sub", str_sub, -1); - rb_define_method(cString, "gsub", str_gsub, -1); - rb_define_method(cString, "chop", str_chop, 0); - rb_define_method(cString, "chomp", str_chomp, 0); - rb_define_method(cString, "strip", str_strip, 0); - - rb_define_method(cString, "sub!", str_sub_bang, -1); - rb_define_method(cString, "gsub!", str_gsub_bang, -1); - rb_define_method(cString, "strip!", str_strip_bang, 0); - rb_define_method(cString, "chop!", str_chop_bang, 0); - rb_define_method(cString, "chomp!", str_chomp_bang, 0); - - rb_define_method(cString, "tr", str_tr, 2); - rb_define_method(cString, "tr_s", str_tr_s, 2); - rb_define_method(cString, "delete", str_delete, 1); - rb_define_method(cString, "squeeze", str_squeeze, -1); - - rb_define_method(cString, "tr!", str_tr_bang, 2); - rb_define_method(cString, "tr_s!", str_tr_s_bang, 2); - rb_define_method(cString, "delete!", str_delete_bang, 1); - rb_define_method(cString, "squeeze!", str_squeeze_bang, -1); - - rb_define_method(cString, "each_line", str_each_line, -1); - rb_define_method(cString, "each", str_each_line, -1); - rb_define_method(cString, "each_byte", str_each_byte, 0); - - rb_define_method(cString, "sum", str_sum, -1); - - rb_define_global_function("sub", f_sub, -1); - rb_define_global_function("gsub", f_gsub, -1); - - rb_define_global_function("sub!", f_sub_bang, -1); - rb_define_global_function("gsub!", f_gsub_bang, -1); - - rb_define_global_function("chop", f_chop, 0); - rb_define_global_function("chop!", f_chop_bang, 0); - - rb_define_global_function("chomp", f_chomp, 0); - rb_define_global_function("chomp!", f_chomp_bang, 0); - - rb_define_global_function("split", f_split, -1); - - pr_str = rb_intern("to_s"); - - /* Fix-up initialize ordering */ - RCLASS(eGlobalExit)->super = cString; + rb_cString = rb_define_class("String", rb_cObject); + rb_include_module(rb_cString, rb_mComparable); + rb_include_module(rb_cString, rb_mEnumerable); + rb_define_singleton_method(rb_cString, "new", rb_str_s_new, 1); + rb_define_method(rb_cString, "clone", rb_str_clone, 0); + rb_define_method(rb_cString, "dup", rb_str_dup, 0); + rb_define_method(rb_cString, "<=>", rb_str_cmp_method, 1); + rb_define_method(rb_cString, "==", rb_str_equal, 1); + rb_define_method(rb_cString, "===", rb_str_equal, 1); + rb_define_method(rb_cString, "eql?", rb_str_equal, 1); + rb_define_method(rb_cString, "hash", rb_str_hash_method, 0); + rb_define_method(rb_cString, "+", rb_str_plus, 1); + rb_define_method(rb_cString, "*", rb_str_times, 1); + rb_define_method(rb_cString, "%", rb_str_format, 1); + rb_define_method(rb_cString, "[]", rb_str_aref_method, -1); + rb_define_method(rb_cString, "[]=", rb_str_aset_method, -1); + rb_define_method(rb_cString, "length", rb_str_length, 0); + rb_define_alias(rb_cString, "size", "length"); + rb_define_method(rb_cString, "empty?", rb_str_empty, 0); + rb_define_method(rb_cString, "=~", rb_str_match, 1); + rb_define_method(rb_cString, "~", rb_str_match2, 0); + rb_define_method(rb_cString, "succ", rb_str_succ, 0); + rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0); + rb_define_method(rb_cString, "next", rb_str_succ, 0); + rb_define_method(rb_cString, "next!", rb_str_succ_bang, 0); + rb_define_method(rb_cString, "upto", rb_str_upto, 1); + rb_define_method(rb_cString, "index", rb_str_index_method, -1); + rb_define_method(rb_cString, "rindex", rb_str_rindex, -1); + rb_define_method(rb_cString, "replace", rb_str_replace_method, 1); + + rb_define_method(rb_cString, "freeze", rb_str_freeze, 0); + rb_define_method(rb_cString, "frozen?", rb_str_frozen_p, 0); + + rb_define_method(rb_cString, "to_i", rb_str_to_i, 0); + rb_define_method(rb_cString, "to_f", rb_str_to_f, 0); + rb_define_method(rb_cString, "to_s", rb_str_to_s, 0); + rb_define_method(rb_cString, "to_str", rb_str_to_s, 0); + rb_define_method(rb_cString, "inspect", rb_str_inspect, 0); + rb_define_method(rb_cString, "dump", rb_str_dump, 0); + + rb_define_method(rb_cString, "upcase", rb_str_upcase, 0); + rb_define_method(rb_cString, "downcase", rb_str_downcase, 0); + rb_define_method(rb_cString, "capitalize", rb_str_capitalize, 0); + rb_define_method(rb_cString, "swapcase", rb_str_swapcase, 0); + + rb_define_method(rb_cString, "upcase!", rb_str_upcase_bang, 0); + rb_define_method(rb_cString, "downcase!", rb_str_downcase_bang, 0); + rb_define_method(rb_cString, "capitalize!", rb_str_capitalize_bang, 0); + rb_define_method(rb_cString, "swapcase!", rb_str_swapcase_bang, 0); + + rb_define_method(rb_cString, "hex", rb_str_hex, 0); + rb_define_method(rb_cString, "oct", rb_str_oct, 0); + rb_define_method(rb_cString, "split", rb_str_split_method, -1); + rb_define_method(rb_cString, "reverse", rb_str_reverse, 0); + rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0); + rb_define_method(rb_cString, "concat", rb_str_concat, 1); + rb_define_method(rb_cString, "<<", rb_str_concat, 1); + rb_define_method(rb_cString, "crypt", rb_str_crypt, 1); + rb_define_method(rb_cString, "intern", rb_str_intern, 0); + + rb_define_method(rb_cString, "include?", rb_str_include, 1); + + rb_define_method(rb_cString, "scan", rb_str_scan, 1); + + rb_define_method(rb_cString, "ljust", rb_str_ljust, 1); + rb_define_method(rb_cString, "rjust", rb_str_rjust, 1); + rb_define_method(rb_cString, "center", rb_str_center, 1); + + rb_define_method(rb_cString, "sub", rb_str_sub, -1); + rb_define_method(rb_cString, "gsub", rb_str_gsub, -1); + rb_define_method(rb_cString, "chop", rb_str_chop, 0); + rb_define_method(rb_cString, "chomp", rb_str_chomp, -1); + rb_define_method(rb_cString, "strip", rb_str_strip, 0); + + rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1); + rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1); + rb_define_method(rb_cString, "strip!", rb_str_strip_bang, 0); + rb_define_method(rb_cString, "chop!", rb_str_chop_bang, 0); + rb_define_method(rb_cString, "chomp!", rb_str_chomp_bang, -1); + + rb_define_method(rb_cString, "tr", rb_str_tr, 2); + rb_define_method(rb_cString, "tr_s", rb_str_tr_s, 2); + rb_define_method(rb_cString, "delete", rb_str_delete, 1); + rb_define_method(rb_cString, "squeeze", rb_str_squeeze, -1); + + rb_define_method(rb_cString, "tr!", rb_str_tr_bang, 2); + rb_define_method(rb_cString, "tr_s!", rb_str_tr_s_bang, 2); + rb_define_method(rb_cString, "delete!", rb_str_delete_bang, 1); + rb_define_method(rb_cString, "squeeze!", rb_str_squeeze_bang, -1); + + rb_define_method(rb_cString, "each_line", rb_str_each_line, -1); + rb_define_method(rb_cString, "each", rb_str_each_line, -1); + rb_define_method(rb_cString, "each_byte", rb_str_each_byte, 0); + + rb_define_method(rb_cString, "sum", rb_str_sum, -1); + + rb_define_global_function("sub", rb_f_sub, -1); + rb_define_global_function("gsub", rb_f_gsub, -1); + + rb_define_global_function("sub!", rb_f_sub_bang, -1); + rb_define_global_function("gsub!", rb_f_gsub_bang, -1); + + rb_define_global_function("chop", rb_f_chop, 0); + rb_define_global_function("chop!", rb_f_chop_bang, 0); + + rb_define_global_function("chomp", rb_f_chomp, -1); + rb_define_global_function("chomp!", rb_f_chomp_bang, -1); + + rb_define_global_function("split", rb_f_split, -1); + + to_str = rb_intern("to_s"); } diff --git a/struct.c b/struct.c index 7234d1e5d2..7aaf4e8d25 100644 --- a/struct.c +++ b/struct.c @@ -10,25 +10,37 @@ #include "ruby.h" -ID rb_frame_last_func(); -VALUE cStruct; -extern VALUE mEnumerable; +#ifdef USE_CWGUSI +#include <stdio.h> +#endif + +VALUE rb_cStruct; static VALUE -struct_s_members(obj) +class_of(obj) VALUE obj; { - struct RArray *member; - VALUE ary, *p, *pend; + obj = CLASS_OF(obj); + if (FL_TEST(obj, FL_SINGLETON)) + return RCLASS(obj)->super; + return obj; +} - member = RARRAY(rb_iv_get(obj, "__member__")); +static VALUE +rb_struct_s_members(obj) + VALUE obj; +{ + VALUE member, ary; + VALUE *p, *pend; + + member = rb_iv_get(obj, "__member__"); if (NIL_P(member)) { - Fatal("non-initialized struct"); + rb_bug("non-initialized struct"); } - ary = ary_new2(member->len); - p = member->ptr; pend = p + member->len; + ary = rb_ary_new2(RARRAY(member)->len); + p = RARRAY(member)->ptr; pend = p + RARRAY(member)->len; while (p < pend) { - ary_push(ary, str_new2(rb_id2name(FIX2INT(*p)))); + rb_ary_push(ary, rb_str_new2(rb_id2name(FIX2INT(*p)))); p++; } @@ -36,24 +48,23 @@ struct_s_members(obj) } static VALUE -struct_members(obj) +rb_struct_members(obj) VALUE obj; { - return struct_s_members(CLASS_OF(obj)); + return rb_struct_s_members(class_of(obj)); } VALUE -struct_getmember(obj, id) +rb_struct_getmember(obj, id) VALUE obj; ID id; { - VALUE nstr, member, slot; + VALUE member, slot; int i; - nstr = CLASS_OF(obj); - member = rb_iv_get(nstr, "__member__"); + member = rb_iv_get(class_of(obj), "__member__"); if (NIL_P(member)) { - Bug("non-initialized struct"); + rb_bug("non-initialized struct"); } slot = INT2FIX(id); for (i=0; i<RARRAY(member)->len; i++) { @@ -61,190 +72,209 @@ struct_getmember(obj, id) return RSTRUCT(obj)->ptr[i]; } } - NameError("%s is not struct member", rb_id2name(id)); - /* not reached */ + rb_raise(rb_eNameError, "%s is not struct member", rb_id2name(id)); + return Qnil; /* not reached */ } static VALUE -struct_ref(obj) +rb_struct_ref(obj) VALUE obj; { - return struct_getmember(obj, rb_frame_last_func()); + return rb_struct_getmember(obj, rb_frame_last_func()); } -static VALUE struct_ref0(obj) VALUE obj; {return RSTRUCT(obj)->ptr[0];} -static VALUE struct_ref1(obj) VALUE obj; {return RSTRUCT(obj)->ptr[1];} -static VALUE struct_ref2(obj) VALUE obj; {return RSTRUCT(obj)->ptr[2];} -static VALUE struct_ref3(obj) VALUE obj; {return RSTRUCT(obj)->ptr[3];} -static VALUE struct_ref4(obj) VALUE obj; {return RSTRUCT(obj)->ptr[4];} -static VALUE struct_ref5(obj) VALUE obj; {return RSTRUCT(obj)->ptr[5];} -static VALUE struct_ref6(obj) VALUE obj; {return RSTRUCT(obj)->ptr[6];} -static VALUE struct_ref7(obj) VALUE obj; {return RSTRUCT(obj)->ptr[7];} -static VALUE struct_ref8(obj) VALUE obj; {return RSTRUCT(obj)->ptr[8];} -static VALUE struct_ref9(obj) VALUE obj; {return RSTRUCT(obj)->ptr[9];} +static VALUE rb_struct_ref0(obj) VALUE obj; {return RSTRUCT(obj)->ptr[0];} +static VALUE rb_struct_ref1(obj) VALUE obj; {return RSTRUCT(obj)->ptr[1];} +static VALUE rb_struct_ref2(obj) VALUE obj; {return RSTRUCT(obj)->ptr[2];} +static VALUE rb_struct_ref3(obj) VALUE obj; {return RSTRUCT(obj)->ptr[3];} +static VALUE rb_struct_ref4(obj) VALUE obj; {return RSTRUCT(obj)->ptr[4];} +static VALUE rb_struct_ref5(obj) VALUE obj; {return RSTRUCT(obj)->ptr[5];} +static VALUE rb_struct_ref6(obj) VALUE obj; {return RSTRUCT(obj)->ptr[6];} +static VALUE rb_struct_ref7(obj) VALUE obj; {return RSTRUCT(obj)->ptr[7];} +static VALUE rb_struct_ref8(obj) VALUE obj; {return RSTRUCT(obj)->ptr[8];} +static VALUE rb_struct_ref9(obj) VALUE obj; {return RSTRUCT(obj)->ptr[9];} VALUE (*ref_func[10])() = { - struct_ref0, - struct_ref1, - struct_ref2, - struct_ref3, - struct_ref4, - struct_ref5, - struct_ref6, - struct_ref7, - struct_ref8, - struct_ref9, + rb_struct_ref0, + rb_struct_ref1, + rb_struct_ref2, + rb_struct_ref3, + rb_struct_ref4, + rb_struct_ref5, + rb_struct_ref6, + rb_struct_ref7, + rb_struct_ref8, + rb_struct_ref9, }; static VALUE -struct_set(obj, val) +rb_struct_set(obj, val) VALUE obj, val; { - VALUE nstr, member, slot; + VALUE member, slot; int i; - nstr = CLASS_OF(obj); - member = rb_iv_get(nstr, "__member__"); + member = rb_iv_get(class_of(obj), "__member__"); if (NIL_P(member)) { - Fatal("non-initialized struct"); + rb_bug("non-initialized struct"); } for (i=0; i<RARRAY(member)->len; i++) { slot = RARRAY(member)->ptr[i]; - if (id_attrset(FIX2INT(slot)) == rb_frame_last_func()) { + if (rb_id_attrset(FIX2INT(slot)) == rb_frame_last_func()) { return RSTRUCT(obj)->ptr[i] = val; } } - NameError("not struct member"); - /* not reached */ + rb_raise(rb_eNameError, "not struct member"); + return Qnil; /* not reached */ } -VALUE struct_alloc(); - static VALUE -make_struct(name, member) - VALUE name, member; +make_struct(name, member, klass) + VALUE name, member, klass; { VALUE nstr; ID id; int i; - id = rb_intern(RSTRING(name)->ptr); - if (!rb_is_const_id(id)) { - NameError("identifier %s needs to be constant", RSTRING(name)->ptr); + if (NIL_P(name)) { + nstr = rb_class_new(klass); + } + else { + char *cname = STR2CSTR(name); + id = rb_intern(cname); + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "identifier %s needs to be constant", cname); + } + nstr = rb_define_class_under(klass, cname, klass); } - nstr = rb_define_class_under(cStruct, RSTRING(name)->ptr, cStruct); rb_iv_set(nstr, "__size__", INT2FIX(RARRAY(member)->len)); rb_iv_set(nstr, "__member__", member); - rb_define_singleton_method(nstr, "new", struct_alloc, -2); - rb_define_singleton_method(nstr, "[]", struct_alloc, -2); - rb_define_singleton_method(nstr, "members", struct_s_members, 0); + rb_define_singleton_method(nstr, "new", rb_struct_alloc, -2); + rb_define_singleton_method(nstr, "[]", rb_struct_alloc, -2); + rb_define_singleton_method(nstr, "members", rb_struct_s_members, 0); for (i=0; i< RARRAY(member)->len; i++) { ID id = FIX2INT(RARRAY(member)->ptr[i]); if (i<10) { rb_define_method_id(nstr, id, ref_func[i], 0); } else { - rb_define_method_id(nstr, id, struct_ref, 0); + rb_define_method_id(nstr, id, rb_struct_ref, 0); } - rb_define_method_id(nstr, id_attrset(id), struct_set, 1); + rb_define_method_id(nstr, rb_id_attrset(id), rb_struct_set, 1); } return nstr; } +#ifdef HAVE_STDARG_PROTOTYPES +#include <stdarg.h> +#define va_init_list(a,b) va_start(a,b) +#else #include <varargs.h> +#define va_init_list(a,b) va_start(a) +#endif VALUE -struct_define(name, va_alist) +#ifdef HAVE_STDARG_PROTOTYPES +rb_struct_define(char *name, ...) +#else +rb_struct_define(name, va_alist) char *name; va_dcl +#endif { va_list ar; VALUE nm, ary; char *mem; - nm = str_new2(name); - ary = ary_new(); + nm = rb_str_new2(name); + ary = rb_ary_new(); - va_start(ar); + va_init_list(ar, name); while (mem = va_arg(ar, char*)) { ID slot = rb_intern(mem); - ary_push(ary, INT2FIX(slot)); + rb_ary_push(ary, INT2FIX(slot)); } va_end(ar); - return make_struct(nm, ary); + return make_struct(nm, ary, rb_cStruct); } static VALUE -struct_s_def(argc, argv) +rb_struct_s_def(argc, argv, klass) int argc; VALUE *argv; { - struct RString *name; - struct RArray *rest; + VALUE name, rest; int i; + VALUE st; rb_scan_args(argc, argv, "1*", &name, &rest); - Check_Type(name, T_STRING); - for (i=0; i<rest->len; i++) { - ID id = rb_to_id(rest->ptr[i]); - rest->ptr[i] = INT2FIX(id); + for (i=0; i<RARRAY(rest)->len; i++) { + ID id = rb_to_id(RARRAY(rest)->ptr[i]); + RARRAY(rest)->ptr[i] = INT2FIX(id); } - return make_struct(name, rest); + st = make_struct(name, rest, klass); + rb_obj_call_init(st); + + return st; } VALUE -struct_alloc(class, values) - VALUE class, values; +rb_struct_alloc(klass, values) + VALUE klass, values; { VALUE size; int n; - size = rb_iv_get(class, "__size__"); + size = rb_iv_get(klass, "__size__"); n = FIX2INT(size); - if (n < RARRAY(values)->len) { - ArgError("struct size differs"); + if (n != RARRAY(values)->len) { + rb_raise(rb_eArgError, "struct size differs"); } else { NEWOBJ(st, struct RStruct); - OBJSETUP(st, class, T_STRUCT); - st->len = n; - st->ptr = 0; /* avoid GC crashing */ + OBJSETUP(st, klass, T_STRUCT); + st->len = 0; /* avoid GC crashing */ st->ptr = ALLOC_N(VALUE, n); + st->len = n; MEMCPY(st->ptr, RARRAY(values)->ptr, VALUE, RARRAY(values)->len); - memclear(st->ptr+RARRAY(values)->len, n - RARRAY(values)->len); + rb_obj_call_init((VALUE)st); return (VALUE)st; } - /* not reached */ + return Qnil; /* not reached */ } VALUE -struct_new(class, va_alist) - VALUE class; +#ifdef HAVE_STDARG_PROTOTYPES +rb_struct_new(VALUE klass, ...) +#else +rb_struct_new(klass, va_alist) + VALUE klass; va_dcl +#endif { VALUE val, mem; - int size; + int size, i; va_list args; - val = rb_iv_get(class, "__size__"); + val = rb_iv_get(klass, "__size__"); size = FIX2INT(val); - mem = ary_new(); - va_start(args); - while (size--) { + mem = rb_ary_new2(size); + va_init_list(args, klass); + for (i=0; i<size; i++) { val = va_arg(args, VALUE); - ary_push(mem, val); + rb_ary_store(mem, i, val); } va_end(args); - return struct_alloc(class, mem); + return rb_struct_alloc(klass, mem); } static VALUE -struct_each(s) +rb_struct_each(s) VALUE s; { int i; @@ -255,145 +285,213 @@ struct_each(s) return Qnil; } -char *rb_class2name(); - static VALUE -struct_to_s(s) +rb_struct_to_s(s) VALUE s; { - char *name, *buf; + char *cname = rb_class2name(CLASS_OF(s)); + char *buf = ALLOCA_N(char, strlen(cname) + 4); - name = rb_class2name(CLASS_OF(s)); - buf = ALLOCA_N(char, strlen(name)+1); - sprintf(buf, "%s", name); - return str_new2(buf); + sprintf(buf, "#<%s>", cname); + return rb_str_new2(buf); } static VALUE -struct_inspect(s) +inspect_struct(s) VALUE s; { - char *name = rb_class2name(CLASS_OF(s)); + char *cname = rb_class2name(CLASS_OF(s)); VALUE str, member; - char buf[256]; int i; member = rb_iv_get(CLASS_OF(s), "__member__"); if (NIL_P(member)) { - Fatal("non-initialized struct"); + rb_bug("non-initialized struct"); } - sprintf(buf, "#<%s ", name); - str = str_new2(buf); + str = rb_str_new2("#<"); + rb_str_cat(str, cname, strlen(cname)); + rb_str_cat(str, " ", 1); for (i=0; i<RSTRUCT(s)->len; i++) { VALUE str2, slot; char *p; if (i > 0) { - str_cat(str, ", ", 2); + rb_str_cat(str, ", ", 2); } slot = RARRAY(member)->ptr[i]; p = rb_id2name(FIX2INT(slot)); - str_cat(str, p, strlen(p)); - str_cat(str, "=", 1); + rb_str_cat(str, p, strlen(p)); + rb_str_cat(str, "=", 1); str2 = rb_inspect(RSTRUCT(s)->ptr[i]); - str2 = obj_as_string(str2); - str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + rb_str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); } - str_cat(str, ">", 1); + rb_str_cat(str, ">", 1); return str; } static VALUE -struct_to_a(s) +rb_struct_inspect(s) VALUE s; { - return ary_new4(RSTRUCT(s)->len, RSTRUCT(s)->ptr); + if (rb_inspecting_p(s)) { + char *cname = rb_class2name(CLASS_OF(s)); + char *buf = ALLOCA_N(char, strlen(cname) + 8); + + sprintf(buf, "#<%s:...>", cname); + return rb_str_new2(buf); + } + return rb_protect_inspect(inspect_struct, s, 0); } static VALUE -struct_clone(s) +rb_struct_to_a(s) + VALUE s; +{ + return rb_ary_new4(RSTRUCT(s)->len, RSTRUCT(s)->ptr); +} + +static VALUE +rb_struct_clone(s) VALUE s; { NEWOBJ(st, struct RStruct); CLONESETUP(st, s); - st->len = RSTRUCT(s)->len; - st->ptr = 0; /* avoid GC crashing */ + st->len = 0; /* avoid GC crashing */ st->ptr = ALLOC_N(VALUE, RSTRUCT(s)->len); + st->len = RSTRUCT(s)->len; MEMCPY(st->ptr, RSTRUCT(s)->ptr, VALUE, st->len); return (VALUE)st; } +static VALUE +rb_struct_aref_id(s, id) + VALUE s; + ID id; +{ + VALUE member; + int i, len; + + member = rb_iv_get(CLASS_OF(s), "__member__"); + if (NIL_P(member)) { + rb_bug("non-initialized struct"); + } + + len = RARRAY(member)->len; + for (i=0; i<len; i++) { + if (FIX2UINT(RARRAY(member)->ptr[i]) == id) { + return RSTRUCT(s)->ptr[i]; + } + } + rb_raise(rb_eNameError, "no member '%s' in struct", rb_id2name(id)); + return Qnil; /* not reached */ +} + VALUE -struct_aref(s, idx) +rb_struct_aref(s, idx) VALUE s, idx; { int i; + if (TYPE(idx) == T_STRING) { + return rb_struct_aref_id(s, rb_to_id(idx)); + } + i = NUM2INT(idx); - if (i < 0) i = RSTRUCT(s)->len - i; + if (i < 0) i = RSTRUCT(s)->len + i; if (i < 0) - IndexError("offset %d too small for struct(size:%d)", i, RSTRUCT(s)->len); + rb_raise(rb_eIndexError, "offset %d too small for struct(size:%d)", + i, RSTRUCT(s)->len); if (RSTRUCT(s)->len <= i) - IndexError("offset %d too large for struct(size:%d)", i, RSTRUCT(s)->len); + rb_raise(rb_eIndexError, "offset %d too large for struct(size:%d)", + i, RSTRUCT(s)->len); return RSTRUCT(s)->ptr[i]; } +static VALUE +rb_struct_aset_id(s, id, val) + VALUE s, val; + ID id; +{ + VALUE member; + int i, len; + + member = rb_iv_get(CLASS_OF(s), "__member__"); + if (NIL_P(member)) { + rb_bug("non-initialized struct"); + } + + len = RARRAY(member)->len; + for (i=0; i<len; i++) { + if (FIX2UINT(RARRAY(member)->ptr[i]) == id) { + RSTRUCT(s)->ptr[i] = val; + return val; + } + } + rb_raise(rb_eNameError, "no member '%s' in struct", rb_id2name(id)); +} + VALUE -struct_aset(s, idx, val) +rb_struct_aset(s, idx, val) VALUE s, idx, val; { int i; + if (TYPE(idx) == T_STRING) { + return rb_struct_aset_id(s, rb_to_id(idx), val); + } + i = NUM2INT(idx); - if (i < 0) i = RSTRUCT(s)->len - i; + if (i < 0) i = RSTRUCT(s)->len + i; if (i < 0) - IndexError("offset %d too small for struct(size:%d)", i, RSTRUCT(s)->len); + rb_raise(rb_eIndexError, "offset %d too small for struct(size:%d)", + i, RSTRUCT(s)->len); if (RSTRUCT(s)->len <= i) - IndexError("offset %d too large for struct(size:%d)", i, RSTRUCT(s)->len); + rb_raise(rb_eIndexError, "offset %d too large for struct(size:%d)", + i, RSTRUCT(s)->len); return RSTRUCT(s)->ptr[i] = val; } static VALUE -struct_equal(s, s2) +rb_struct_equal(s, s2) VALUE s, s2; { int i; - if (TYPE(s2) != T_STRUCT) return FALSE; - if (CLASS_OF(s) != CLASS_OF(s2)) return FALSE; + if (TYPE(s2) != T_STRUCT) return Qfalse; + if (CLASS_OF(s) != CLASS_OF(s2)) return Qfalse; if (RSTRUCT(s)->len != RSTRUCT(s2)->len) { - Bug("inconsistent struct"); /* should never happen */ + rb_bug("inconsistent struct"); /* should never happen */ } for (i=0; i<RSTRUCT(s)->len; i++) { - if (!rb_equal(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return FALSE; + if (!rb_equal(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return Qfalse; } - return TRUE; + return Qtrue; } static VALUE -struct_eql(s, s2) +rb_struct_eql(s, s2) VALUE s, s2; { int i; - if (TYPE(s2) != T_STRUCT) return FALSE; - if (CLASS_OF(s) != CLASS_OF(s2)) return FALSE; + if (TYPE(s2) != T_STRUCT) return Qfalse; + if (CLASS_OF(s) != CLASS_OF(s2)) return Qfalse; if (RSTRUCT(s)->len != RSTRUCT(s2)->len) { - Bug("inconsistent struct"); /* should never happen */ + rb_bug("inconsistent struct"); /* should never happen */ } for (i=0; i<RSTRUCT(s)->len; i++) { - if (!rb_eql(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return FALSE; + if (!rb_eql(RSTRUCT(s)->ptr[i], RSTRUCT(s2)->ptr[i])) return Qfalse; } - return TRUE; + return Qtrue; } static VALUE -struct_hash(s) +rb_struct_hash(s) VALUE s; { int i, h; @@ -408,25 +506,25 @@ struct_hash(s) void Init_Struct() { - cStruct = rb_define_class("Struct", cObject); - rb_include_module(cStruct, mEnumerable); + rb_cStruct = rb_define_class("Struct", rb_cObject); + rb_include_module(rb_cStruct, rb_mEnumerable); - rb_define_singleton_method(cStruct, "new", struct_s_def, -1); + rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1); - rb_define_method(cStruct, "clone", struct_clone, 0); + rb_define_method(rb_cStruct, "clone", rb_struct_clone, 0); - rb_define_method(cStruct, "==", struct_equal, 1); - rb_define_method(cStruct, "eql?", struct_eql, 1); - rb_define_method(cStruct, "hash", struct_hash, 0); + rb_define_method(rb_cStruct, "==", rb_struct_equal, 1); + rb_define_method(rb_cStruct, "eql?", rb_struct_eql, 1); + rb_define_method(rb_cStruct, "hash", rb_struct_hash, 0); - rb_define_method(cStruct, "to_s", struct_to_s, 0); - rb_define_method(cStruct, "inspect", struct_inspect, 0); - rb_define_method(cStruct, "to_a", struct_to_a, 0); - rb_define_method(cStruct, "values", struct_to_a, 0); + rb_define_method(rb_cStruct, "to_s", rb_struct_to_s, 0); + rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0); + rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0); + rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0); - rb_define_method(cStruct, "each", struct_each, 0); - rb_define_method(cStruct, "[]", struct_aref, 1); - rb_define_method(cStruct, "[]=", struct_aset, 2); + rb_define_method(rb_cStruct, "each", rb_struct_each, 0); + rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1); + rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2); - rb_define_method(cStruct, "members", struct_members, 0); + rb_define_method(rb_cStruct, "members", rb_struct_members, 0); } diff --git a/time.c b/time.c index 1749c32319..fc14d8e5b6 100644 --- a/time.c +++ b/time.c @@ -6,13 +6,18 @@ $Date$ created at: Tue Dec 28 14:31:59 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include <sys/types.h> +#ifdef USE_CWGUSI +int gettimeofday(struct timeval*, struct timezone*); +int strcasecmp(char*, char*); +#endif + #include <time.h> #ifndef NT #ifdef HAVE_SYS_TIME_H @@ -30,11 +35,10 @@ struct timeval { #endif #include <math.h> -static VALUE cTime; +VALUE rb_cTime; #if defined(HAVE_TIMES) || defined(NT) static VALUE S_Tms; #endif -extern VALUE mComparable; struct time_object { struct timeval tv; @@ -50,31 +54,34 @@ struct time_object { } static VALUE -time_s_now(class) - VALUE class; +time_s_now(klass) + VALUE klass; { VALUE obj; struct time_object *tobj; - obj = Data_Make_Struct(class, struct time_object, 0, 0, tobj); + obj = Data_Make_Struct(klass, struct time_object, 0, free, tobj); tobj->tm_got=0; if (gettimeofday(&(tobj->tv), 0) == -1) { rb_sys_fail("gettimeofday"); } + rb_obj_call_init(obj); return obj; } static VALUE -time_new_internal(class, sec, usec) - VALUE class; +time_new_internal(klass, sec, usec) + VALUE klass; int sec, usec; { VALUE obj; struct time_object *tobj; - obj = Data_Make_Struct(class, struct time_object, 0, 0, tobj); + if (sec < 0 || (sec == 0 && usec < 0)) + rb_raise(rb_eArgError, "time must be positive"); + obj = Data_Make_Struct(klass, struct time_object, 0, free, tobj); tobj->tm_got = 0; tobj->tv.tv_sec = sec; tobj->tv.tv_usec = usec; @@ -83,14 +90,14 @@ time_new_internal(class, sec, usec) } VALUE -time_new(sec, usec) +rb_time_new(sec, usec) int sec, usec; { - return time_new_internal(cTime, sec, usec); + return time_new_internal(rb_cTime, sec, usec); } struct timeval -time_timeval(time) +rb_time_timeval(time) VALUE time; { struct time_object *tobj; @@ -98,34 +105,30 @@ time_timeval(time) switch (TYPE(time)) { case T_FIXNUM: - t.tv_sec = FIX2UINT(time); + t.tv_sec = FIX2INT(time); if (t.tv_sec < 0) - ArgError("time must be positive"); + rb_raise(rb_eArgError, "time must be positive"); t.tv_usec = 0; break; case T_FLOAT: - { - double seconds, microseconds; - - if (RFLOAT(time)->value < 0.0) - ArgError("time must be positive"); - seconds = floor(RFLOAT(time)->value); - microseconds = (RFLOAT(time)->value - seconds) * 1000000.0; - t.tv_sec = seconds; - t.tv_usec = microseconds; - } + if (RFLOAT(time)->value < 0.0) + rb_raise(rb_eArgError, "time must be positive"); + t.tv_sec = (long)floor(RFLOAT(time)->value); + t.tv_usec = (long)((RFLOAT(time)->value - t.tv_sec) * 1000000.0); break; case T_BIGNUM: t.tv_sec = NUM2INT(time); + if (t.tv_sec < 0) + rb_raise(rb_eArgError, "time must be positive"); t.tv_usec = 0; break; default: - if (!obj_is_kind_of(time, cTime)) { - TypeError("Can't convert %s into Time", - rb_class2name(CLASS_OF(time))); + if (!rb_obj_is_kind_of(time, rb_cTime)) { + rb_raise(rb_eTypeError, "Can't convert %s into Time", + rb_class2name(CLASS_OF(time))); } GetTimeval(time, tobj); t = tobj->tv; @@ -135,13 +138,13 @@ time_timeval(time) } static VALUE -time_s_at(class, time) - VALUE class, time; +time_s_at(klass, time) + VALUE klass, time; { struct timeval tv; - tv = time_timeval(time); - return time_new_internal(class, tv.tv_sec, tv.tv_usec); + tv = rb_time_timeval(time); + return time_new_internal(klass, tv.tv_sec, tv.tv_usec); } static char *months [12] = { @@ -149,6 +152,17 @@ static char *months [12] = { "jul", "aug", "sep", "oct", "nov", "dec", }; +static int +obj2int(obj) + VALUE obj; +{ + if (TYPE(obj) == T_STRING) { + obj = rb_str2inum(RSTRING(obj)->ptr, 10); + } + + return NUM2INT(obj); +} + static void time_arg(argc, argv, args) int argc; @@ -158,12 +172,22 @@ time_arg(argc, argv, args) VALUE v[6]; int i; - rb_scan_args(argc, argv, "15", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]); + if (argc == 10) { + v[0] = argv[5]; + v[1] = argv[4]; + v[2] = argv[3]; + v[3] = argv[2]; + v[4] = argv[1]; + v[5] = argv[0]; + } + else { + rb_scan_args(argc, argv, "15", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5]); + } - args[0] = NUM2INT(v[0]); + args[0] = obj2int(v[0]); if (args[0] < 70) args[0] += 100; if (args[0] > 1900) args[0] -= 1900; - if (v[1] == Qnil) { + if (NIL_P(v[1])) { args[1] = 0; } else if (TYPE(v[1]) == T_STRING) { @@ -178,44 +202,46 @@ time_arg(argc, argv, args) char c = RSTRING(v[1])->ptr[0]; if ('0' <= c && c <= '9') { - args[1] = NUM2INT(v[1])-1; + args[1] = obj2int(v[1])-1; } } } else { - args[1] = NUM2INT(v[1]); + args[1] = obj2int(v[1]) - 1; } - if (v[2] == Qnil) { + if (NIL_P(v[2])) { args[2] = 1; } else { - args[2] = NUM2INT(v[2]); + args[2] = obj2int(v[2]); } for (i=3;i<6;i++) { - if (v[i] == Qnil) { + if (NIL_P(v[i])) { args[i] = 0; } else { - args[i] = NUM2INT(v[i]); + args[i] = obj2int(v[i]); } } /* value validation */ - if ( args[0] < 70|| args[1] > 137 + if ( args[0] < 70|| args[0] > 137 || args[1] < 0 || args[1] > 11 || args[2] < 1 || args[2] > 31 || args[3] < 0 || args[3] > 23 - || args[4] < 0 || args[4] > 60 - || args[5] < 0 || args[5] > 61) - ArgError("argument out of range"); + || args[4] < 0 || args[4] > 59 + || args[5] < 0 || args[5] > 60) + rb_raise(rb_eArgError, "argument out of range"); } +static VALUE time_gmtime _((VALUE)); +static VALUE time_localtime _((VALUE)); static VALUE -time_gm_or_local(argc, argv, gm_or_local, class) +time_gm_or_local(argc, argv, gm_or_local, klass) int argc; VALUE *argv; int gm_or_local; - VALUE class; + VALUE klass; { int args[6]; struct timeval tv; @@ -223,6 +249,7 @@ time_gm_or_local(argc, argv, gm_or_local, class) time_t guess, t; int diff; struct tm *(*fn)(); + VALUE time; fn = (gm_or_local) ? gmtime : localtime; time_arg(argc, argv, args); @@ -233,9 +260,9 @@ time_gm_or_local(argc, argv, gm_or_local, class) tm = (*fn)(&guess); if (!tm) goto error; t = args[0]; - while (diff = t - tm->tm_year) { + while (diff = t - (tm->tm_year)) { guess += diff * 364 * 24 * 3600; - if (guess < 0) ArgError("too far future"); + if (guess < 0) rb_raise(rb_eArgError, "too far future"); tm = (*fn)(&guess); if (!tm) goto error; } @@ -250,28 +277,31 @@ time_gm_or_local(argc, argv, gm_or_local, class) guess += (args[4] - tm->tm_min) * 60; guess += args[5] - tm->tm_sec; - return time_new_internal(class, guess, 0); + time = time_new_internal(klass, guess, 0); + if (gm_or_local) return time_gmtime(time); + return time_localtime(time); error: - ArgError("gmtime error"); + rb_raise(rb_eArgError, "gmtime/localtime error"); + return Qnil; /* not reached */ } static VALUE -time_s_timegm(argc, argv, class) +time_s_timegm(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { - return time_gm_or_local(argc, argv, 1, class); + return time_gm_or_local(argc, argv, 1, klass); } static VALUE -time_s_timelocal(argc, argv, class) +time_s_timelocal(argc, argv, klass) int argc; VALUE *argv; - VALUE class; + VALUE klass; { - return time_gm_or_local(argc, argv, 0, class); + return time_gm_or_local(argc, argv, 0, klass); } static VALUE @@ -281,7 +311,7 @@ time_to_i(time) struct time_object *tobj; GetTimeval(time, tobj); - return int2inum(tobj->tv.tv_sec); + return rb_int2inum(tobj->tv.tv_sec); } static VALUE @@ -291,7 +321,7 @@ time_to_f(time) struct time_object *tobj; GetTimeval(time, tobj); - return float_new((double)tobj->tv.tv_sec+(double)tobj->tv.tv_usec/1000000); + return rb_float_new((double)tobj->tv.tv_sec+(double)tobj->tv.tv_usec/1000000); } static VALUE @@ -331,7 +361,7 @@ time_cmp(time1, time2) } } - if (obj_is_instance_of(time2, cTime)) { + if (rb_obj_is_instance_of(time2, rb_cTime)) { GetTimeval(time2, tobj2); if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) { if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return INT2FIX(0); @@ -354,13 +384,13 @@ time_eql(time1, time2) struct time_object *tobj1, *tobj2; GetTimeval(time1, tobj1); - if (obj_is_instance_of(time2, cTime)) { + if (rb_obj_is_instance_of(time2, rb_cTime)) { GetTimeval(time2, tobj2); if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) { - if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return TRUE; + if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return Qtrue; } } - return FALSE; + return Qfalse; } static VALUE @@ -412,6 +442,23 @@ time_gmtime(time) static VALUE time_asctime(time) VALUE time; +{ + struct time_object *tobj; + char *s; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + time_localtime(time); + } + s = asctime(&(tobj->tm)); + if (s[24] == '\n') s[24] = '\0'; + + return rb_str_new2(s); +} + +static VALUE +time_to_s(time) + VALUE time; { struct time_object *tobj; char buf[64]; @@ -430,7 +477,7 @@ time_asctime(time) { len = strftime(buf, 64, "%a %b %d %H:%M:%S %Z %Y", &(tobj->tm)); } - return str_new(buf, len); + return rb_str_new(buf, len); } static VALUE @@ -438,15 +485,15 @@ time_plus(time1, time2) VALUE time1, time2; { struct time_object *tobj1, *tobj2; - int sec, usec; + long sec, usec; GetTimeval(time1, tobj1); if (TYPE(time2) == T_FLOAT) { unsigned int nsec = (unsigned int)RFLOAT(time2)->value; sec = tobj1->tv.tv_sec + nsec; - usec = tobj1->tv.tv_usec + (RFLOAT(time2)->value - (double)nsec)*1e6; + usec = tobj1->tv.tv_usec + (long)(RFLOAT(time2)->value-(double)nsec)*1e6; } - else if (obj_is_instance_of(time2, cTime)) { + else if (rb_obj_is_instance_of(time2, rb_cTime)) { GetTimeval(time2, tobj2); sec = tobj1->tv.tv_sec + tobj2->tv.tv_sec; usec = tobj1->tv.tv_usec + tobj2->tv.tv_usec; @@ -460,7 +507,7 @@ time_plus(time1, time2) sec++; usec -= 1000000; } - return time_new(sec, usec); + return rb_time_new(sec, usec); } static VALUE @@ -471,7 +518,7 @@ time_minus(time1, time2) int sec, usec; GetTimeval(time1, tobj1); - if (obj_is_instance_of(time2, cTime)) { + if (rb_obj_is_instance_of(time2, rb_cTime)) { double f; GetTimeval(time2, tobj2); @@ -479,7 +526,7 @@ time_minus(time1, time2) f += (tobj1->tv.tv_usec - tobj2->tv.tv_usec)*1e-6; - return float_new(f); + return rb_float_new(f); } else if (TYPE(time2) == T_FLOAT) { sec = tobj1->tv.tv_sec - (int)RFLOAT(time2)->value; @@ -494,7 +541,7 @@ time_minus(time1, time2) sec--; usec += 1000000; } - return time_new(sec, usec); + return rb_time_new(sec, usec); } static VALUE @@ -559,7 +606,7 @@ time_mon(time) if (tobj->tm_got == 0) { time_localtime(time); } - return INT2FIX(tobj->tm.tm_mon); + return INT2FIX(tobj->tm.tm_mon+1); } static VALUE @@ -572,7 +619,7 @@ time_year(time) if (tobj->tm_got == 0) { time_localtime(time); } - return INT2FIX(tobj->tm.tm_year); + return INT2FIX(tobj->tm.tm_year+1900); } static VALUE @@ -611,7 +658,7 @@ time_isdst(time) if (tobj->tm_got == 0) { time_localtime(time); } - return INT2FIX(tobj->tm.tm_isdst); + return tobj->tm.tm_isdst?Qtrue:Qfalse; } static VALUE @@ -628,7 +675,7 @@ time_zone(time) } len = strftime(buf, 10, "%Z", &(tobj->tm)); - return str_new(buf, len); + return rb_str_new(buf, len); } static VALUE @@ -636,23 +683,22 @@ time_to_a(time) VALUE time; { struct time_object *tobj; - VALUE ary; GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_localtime(time); } - ary = ary_new3(9, - INT2FIX(tobj->tm.tm_sec), - INT2FIX(tobj->tm.tm_min), - INT2FIX(tobj->tm.tm_hour), - INT2FIX(tobj->tm.tm_mday), - INT2FIX(tobj->tm.tm_mon), - INT2FIX(tobj->tm.tm_year), - INT2FIX(tobj->tm.tm_wday), - INT2FIX(tobj->tm.tm_yday), - INT2FIX(tobj->tm.tm_isdst)); - return ary; + return rb_ary_new3(10, + INT2FIX(tobj->tm.tm_sec), + INT2FIX(tobj->tm.tm_min), + INT2FIX(tobj->tm.tm_hour), + INT2FIX(tobj->tm.tm_mday), + INT2FIX(tobj->tm.tm_mon+1), + INT2FIX(tobj->tm.tm_year+1900), + INT2FIX(tobj->tm.tm_wday), + INT2FIX(tobj->tm.tm_yday), + tobj->tm.tm_isdst?Qtrue:Qfalse, + time_zone(time)); } #define SMALLBUF 100 @@ -677,7 +723,8 @@ rb_strftime(buf, format, time) return len; } - ArgError("bad strftime format or result too long"); + rb_raise(rb_eArgError, "bad strftime format or result too long"); + return Qnil; /* not reached */ } static VALUE @@ -686,32 +733,32 @@ time_strftime(time, format) { struct time_object *tobj; char buffer[SMALLBUF]; + char *fmt; char *buf = buffer; int len; VALUE str; - Check_Type(format, T_STRING); GetTimeval(time, tobj); if (tobj->tm_got == 0) { time_localtime(time); } - if (strlen(RSTRING(format)->ptr) < RSTRING(format)->len) { + fmt = str2cstr(format, &len); + if (strlen(fmt) < len) { /* Ruby string may contain \0's. */ - int l; - char *p = RSTRING(format)->ptr, *pe = p + RSTRING(format)->len; + char *p = fmt, *pe = fmt + len; - str = str_new(0, 0); + str = rb_str_new(0, 0); while (p < pe) { len = rb_strftime(&buf, p, &(tobj->tm)); - str_cat(str, buf, len); + rb_str_cat(str, buf, len); p += strlen(p) + 1; if (len > SMALLBUF) free(buf); } return str; } len = rb_strftime(&buf, RSTRING(format)->ptr, &(tobj->tm)); - str = str_new(buf, len); - if (len > SMALLBUF) free(buf); + str = rb_str_new(buf, len); + if (buf != buffer) free(buf); return str; } @@ -726,11 +773,11 @@ time_s_times(obj) struct tms buf; if (times(&buf) == -1) rb_sys_fail(0); - return struct_new(S_Tms, - float_new((double)buf.tms_utime / HZ), - float_new((double)buf.tms_stime / HZ), - float_new((double)buf.tms_cutime / HZ), - float_new((double)buf.tms_cstime / HZ)); + return rb_struct_new(S_Tms, + rb_float_new((double)buf.tms_utime / HZ), + rb_float_new((double)buf.tms_stime / HZ), + rb_float_new((double)buf.tms_cutime / HZ), + rb_float_new((double)buf.tms_cstime / HZ)); #else #ifdef NT FILETIME create, exit, kernel, user; @@ -738,69 +785,121 @@ time_s_times(obj) hProc = GetCurrentProcess(); GetProcessTimes(hProc,&create, &exit, &kernel, &user); - return struct_new(S_Tms, - float_new((double)(kernel.dwHighDateTime*2e32+kernel.dwLowDateTime)/2e6), - float_new((double)(user.dwHighDateTime*2e32+user.dwLowDateTime)/2e6), - float_new((double)0), - float_new((double)0)); + return rb_struct_new(S_Tms, + rb_float_new((double)(kernel.dwHighDateTime*2e32+kernel.dwLowDateTime)/2e6), + rb_float_new((double)(user.dwHighDateTime*2e32+user.dwLowDateTime)/2e6), + rb_float_new((double)0), + rb_float_new((double)0)); #else rb_notimplement(); #endif #endif } +static VALUE +time_dump(time, limit) + VALUE time, limit; +{ + struct time_object *tobj; + int sec, usec; + unsigned char buf[8]; + int i; + + GetTimeval(time, tobj); + sec = tobj->tv.tv_sec; + usec = tobj->tv.tv_usec; + + for (i=0; i<4; i++) { + buf[i] = sec & 0xff; + sec = RSHIFT(sec, 8); + } + for (i=4; i<8; i++) { + buf[i] = usec & 0xff; + usec = RSHIFT(usec, 8); + } + return rb_str_new(buf, 8); +} + +static VALUE +time_load(klass, str) + VALUE klass, str; +{ + int sec, usec; + unsigned char *buf; + int i; + + buf = str2cstr(str, &i); + if (i != 8) { + rb_raise(rb_eTypeError, "marshaled time format differ"); + } + + sec = usec = 0; + for (i=0; i<4; i++) { + sec |= buf[i]<<(8*i); + } + for (i=4; i<8; i++) { + usec |= buf[i]<<(8*(i-4)); + } + + return time_new_internal(klass, sec, usec); +} + void Init_Time() { - cTime = rb_define_class("Time", cObject); - rb_include_module(cTime, mComparable); - - rb_define_singleton_method(cTime, "now", time_s_now, 0); - rb_define_singleton_method(cTime, "new", time_s_now, 0); - rb_define_singleton_method(cTime, "at", time_s_at, 1); - rb_define_singleton_method(cTime, "gm", time_s_timegm, -1); - rb_define_singleton_method(cTime, "local", time_s_timelocal, -1); - rb_define_singleton_method(cTime, "mktime", time_s_timelocal, -1); - - rb_define_singleton_method(cTime, "times", time_s_times, 0); - - rb_define_method(cTime, "to_i", time_to_i, 0); - rb_define_method(cTime, "to_f", time_to_f, 0); - rb_define_method(cTime, "<=>", time_cmp, 1); - rb_define_method(cTime, "eql?", time_eql, 0); - rb_define_method(cTime, "hash", time_hash, 0); - - rb_define_method(cTime, "localtime", time_localtime, 0); - rb_define_method(cTime, "gmtime", time_gmtime, 0); - rb_define_method(cTime, "ctime", time_asctime, 0); - rb_define_method(cTime, "asctime", time_asctime, 0); - rb_define_method(cTime, "to_s", time_asctime, 0); - rb_define_method(cTime, "inspect", time_asctime, 0); - rb_define_method(cTime, "to_a", time_to_a, 0); - - rb_define_method(cTime, "+", time_plus, 1); - rb_define_method(cTime, "-", time_minus, 1); - - rb_define_method(cTime, "sec", time_sec, 0); - rb_define_method(cTime, "min", time_min, 0); - rb_define_method(cTime, "hour", time_hour, 0); - rb_define_method(cTime, "mday", time_mday, 0); - rb_define_method(cTime, "day", time_mday, 0); - rb_define_method(cTime, "mon", time_mon, 0); - rb_define_method(cTime, "month", time_mon, 0); - rb_define_method(cTime, "year", time_year, 0); - rb_define_method(cTime, "wday", time_wday, 0); - rb_define_method(cTime, "yday", time_yday, 0); - rb_define_method(cTime, "isdst", time_isdst, 0); - rb_define_method(cTime, "zone", time_zone, 0); - - rb_define_method(cTime, "tv_sec", time_to_i, 0); - rb_define_method(cTime, "tv_usec", time_usec, 0); - rb_define_method(cTime, "usec", time_usec, 0); - - rb_define_method(cTime, "strftime", time_strftime, 1); + rb_cTime = rb_define_class("Time", rb_cObject); + rb_include_module(rb_cTime, rb_mComparable); + + rb_define_singleton_method(rb_cTime, "now", time_s_now, 0); + rb_define_singleton_method(rb_cTime, "new", time_s_now, 0); + rb_define_singleton_method(rb_cTime, "at", time_s_at, 1); + rb_define_singleton_method(rb_cTime, "gm", time_s_timegm, -1); + rb_define_singleton_method(rb_cTime, "local", time_s_timelocal, -1); + rb_define_singleton_method(rb_cTime, "mktime", time_s_timelocal, -1); + + rb_define_singleton_method(rb_cTime, "times", time_s_times, 0); + + rb_define_method(rb_cTime, "to_i", time_to_i, 0); + rb_define_method(rb_cTime, "to_f", time_to_f, 0); + rb_define_method(rb_cTime, "<=>", time_cmp, 1); + rb_define_method(rb_cTime, "eql?", time_eql, 1); + rb_define_method(rb_cTime, "hash", time_hash, 0); + + rb_define_method(rb_cTime, "localtime", time_localtime, 0); + rb_define_method(rb_cTime, "gmtime", time_gmtime, 0); + rb_define_method(rb_cTime, "ctime", time_asctime, 0); + rb_define_method(rb_cTime, "asctime", time_asctime, 0); + rb_define_method(rb_cTime, "to_s", time_to_s, 0); + rb_define_method(rb_cTime, "inspect", time_to_s, 0); + rb_define_method(rb_cTime, "to_a", time_to_a, 0); + + rb_define_method(rb_cTime, "+", time_plus, 1); + rb_define_method(rb_cTime, "-", time_minus, 1); + + rb_define_method(rb_cTime, "sec", time_sec, 0); + rb_define_method(rb_cTime, "min", time_min, 0); + rb_define_method(rb_cTime, "hour", time_hour, 0); + rb_define_method(rb_cTime, "mday", time_mday, 0); + rb_define_method(rb_cTime, "day", time_mday, 0); + rb_define_method(rb_cTime, "mon", time_mon, 0); + rb_define_method(rb_cTime, "month", time_mon, 0); + rb_define_method(rb_cTime, "year", time_year, 0); + rb_define_method(rb_cTime, "wday", time_wday, 0); + rb_define_method(rb_cTime, "yday", time_yday, 0); + rb_define_method(rb_cTime, "isdst", time_isdst, 0); + rb_define_method(rb_cTime, "zone", time_zone, 0); + + rb_define_method(rb_cTime, "tv_sec", time_to_i, 0); + rb_define_method(rb_cTime, "tv_usec", time_usec, 0); + rb_define_method(rb_cTime, "usec", time_usec, 0); + + rb_define_method(rb_cTime, "strftime", time_strftime, 1); #if defined(HAVE_TIMES) || defined(NT) - S_Tms = struct_define("Tms", "utime", "stime", "cutime", "cstime", 0); + S_Tms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", 0); #endif + + /* methods for marshaling */ + rb_define_singleton_method(rb_cTime, "_load", time_load, 1); + rb_define_method(rb_cTime, "_dump", time_dump, 1); } diff --git a/top.sed b/top.sed index 934f60142d..a9ec12f7b6 100644 --- a/top.sed +++ b/top.sed @@ -1,52 +1,58 @@ /^SHELL/s,/bin/sh,$(COMPSEC), s/@srcdir@/./g s/@top_srcdir@/../ -s/@CC@/gcc/ -s/@CPP@/gcc -E/ -s/@CPPFLAGS@// -s/@AR@/ar/ -s/@RANLIB@/ranlib/ -s/@YACC@/bison -y/ -s/@INSTALL@/ginstall -c/ -s/@INSTALL_PROGRAM@/${INSTALL}/ -s/@INSTALL_DATA@/${INSTALL} -m 644/ -s/@SET_MAKE@// -s/@CFLAGS@/-g -O2 -I./ -s/@STATIC@// -s/@LDFLAGS@// -s/@LIBS@// -s/@LIBOBJS@/crypt.o flock.o/ -s/@ALLOCA@// -s!@prefix@!/usr/local! -s/@exec_prefix@/${prefix}/ -s!@bindir@!${exec_prefix}/bin! -s!@libdir@!${exec_prefix}/lib! -s/@STRIP@/strip/ -s!/bin/rm!rm! -s/@DLEXT@/o/ -s/@CCDLFLAGS@/-fpic/ -s/@DLDFLAGS@// -s/@LDSHARED@// -s/@binsuffix@/.exe/g -s/@setup@/Setup/g -s/|| true// -s!@archlib@!/usr/local/lib/ruby/i386-djgpp! +s%@CFLAGS@%-g -O2%g +s%@CPPFLAGS@%%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-djgpp%g +s%@host_alias@%i386-djgpp%g +s%@host_cpu@%i386%g +s%@host_vendor@%pc%g +s%@host_os@%djgpp%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%@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%@LIBRUBYARG@%libruby.a%g +s%@SOLIBS@%%g +s%@arch@%i386-djgpp%g +s%/bin/rm%rm% +s%|| true%% +s%@archlib@%/usr/local/lib/ruby/i386-djgpp% /\/dev\/null/ { s,/dev/null 2>&1, nul, s,2> /dev/null,, } -s/y\.tab\.c/y_tab.c/ -#/if older/s/"ruby"/"ruby.exe"/g -#/`rm -f ruby`/s//`rm -f ruby.exe`/ -#/`cp miniruby ruby`/s//`cp miniruby.exe ruby.exe`/ -/^all:.*miniruby/ { - n;c\ - cd ext\ - ../miniruby ./extmk.rb\ - cd .. -} -/^clean:;/ { - n;n;s!cd.*!cd ext\ - ../miniruby ./extmk.rb clean\ - cd ..! -} +s%y\.tab\.c%y_tab.c% diff --git a/util.c b/util.c index 21e0a55639..ae0914d217 100644 --- a/util.c +++ b/util.c @@ -6,21 +6,39 @@ $Date$ created at: Fri Mar 10 17:22:34 JST 1995 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ +#include <stdio.h> + +#ifdef NT +#include "missing/file.h" +#endif + #define RUBY_NO_INLINE #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; + + 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 == FALSE) return T_FALSE; - if (obj == TRUE) return T_TRUE; + if (obj == Qfalse) return T_FALSE; + if (obj == Qtrue) return T_TRUE; return BUILTIN_TYPE(obj); } @@ -29,24 +47,24 @@ int rb_special_const_p(obj) VALUE obj; { - if (FIXNUM_P(obj)) return TRUE; - if (obj == Qnil) return TRUE; - if (obj == FALSE) return TRUE; - if (obj == TRUE) return TRUE; + if (FIXNUM_P(obj)) return Qtrue; + if (obj == Qnil) return Qtrue; + if (obj == Qfalse) return Qtrue; + if (obj == Qtrue) return Qtrue; - return FALSE; + return Qfalse; } int rb_test_false_or_nil(v) VALUE v; { - return (v != Qnil) && (v != FALSE); + return (v != Qnil) && (v != Qfalse); } #include "util.h" #ifndef HAVE_STRING_H -char *strchr(); +char *strchr _((char*,char)); #endif unsigned long @@ -86,8 +104,55 @@ int *retlen; return retval; } -#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT) +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if defined(HAVE_FCNTL) #include <fcntl.h> +#endif + +#ifndef S_ISDIR +# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#endif + +#ifdef NT +#include "missing/file.h" +#endif + +static char * +check_dir(dir) + char *dir; +{ + struct stat st; + + if (dir == NULL) return NULL; + if (stat(dir, &st) < 0) return NULL; + if (!S_ISDIR(st.st_mode)) return NULL; + if (eaccess(dir, W_OK) < 0) return NULL; + return dir; +} + +char * +ruby_mktemp() +{ + char *dir; + char *buf; + + dir = check_dir(getenv("TMP")); + if (!dir) dir = check_dir(getenv("TMPDIR")); + if (!dir) dir = "/tmp"; + + buf = ALLOC_N(char,strlen(dir)+10); + sprintf(buf, "%s/rbXXXXXX", dir); + dir = mktemp(buf); + if (dir == NULL) free(buf); + + return dir; +} + +#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT) /* * Copyright (c) 1993, Intergraph Corporation * @@ -167,7 +232,9 @@ static char suffix2[] = ".~~~"; #define strEQ(s1,s2) (strcmp(s1,s2) == 0) void -add_suffix(VALUE str, char *suffix) +ruby_add_suffix(str, suffix) + VALUE str; + char *suffix; { int baselen; int extlen = strlen(suffix); @@ -176,12 +243,13 @@ add_suffix(VALUE str, char *suffix) char buf[1024]; if (RSTRING(str)->len > 1000) - Fatal("Cannot do inplace edit on long filename (%d characters)", RSTRING(str)->len); + rb_fatal("Cannot do inplace edit on long filename (%d characters)", + RSTRING(str)->len); #if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) /* Style 0 */ slen = RSTRING(str)->len; - str_cat(str, suffix, extlen); + rb_str_cat(str, suffix, extlen); #if defined(DJGPP) if (_USE_LFN) return; #else @@ -224,7 +292,7 @@ add_suffix(VALUE str, char *suffix) fallback: (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5); } - str_resize(str, strlen(buf)); + rb_str_resize(str, strlen(buf)); memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len); } @@ -262,12 +330,10 @@ valid_filename(char *s) #include <libc/stubs.h> #include <stdio.h> /* For FILENAME_MAX */ #include <errno.h> /* For errno */ -#include <ctype.h> /* For tolower */ #include <fcntl.h> /* For LFN stuff */ #include <go32.h> #include <dpmi.h> /* For dpmisim */ #include <crt0.h> /* For crt0 flags */ -#include <sys/stat.h> #include <libc/dosio.h> static unsigned use_lfn; @@ -486,3 +552,256 @@ int main (int argc, char *argv[]) #endif #endif + +/* mm.c */ + +static int mmkind, mmsize, high, low; + +#define A ((int*)a) +#define B ((int*)b) +#define C ((int*)c) +#define D ((int*)d) + +static void mmprepare(base, size) void *base; int size; +{ +#ifdef DEBUG + if (sizeof(int) != 4) die("sizeof(int) != 4"); + if (size <= 0) die("mmsize <= 0"); +#endif + + if ( ((int)base & (4-1)) == 0 && (size & (4-1)) == 0 ) + if (size >= 16) mmkind = 1; + else mmkind = 0; + else mmkind = -1; + + mmsize = size; + high = (size & (-16)); + low = (size & 0x0C ); +} + +static void mmswap(a, b) register char *a, *b; +{ + register int s; + if (a == b) return; + if (mmkind >= 0) { + if (mmkind > 0) { + register char *t = a + high; + do { + s = A[0]; A[0] = B[0]; B[0] = s; + s = A[1]; A[1] = B[1]; B[1] = s; + s = A[2]; A[2] = B[2]; B[2] = s; + s = A[3]; A[3] = B[3]; B[3] = s; a += 16; b += 16; + }while (a < t); + } + if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = s; + if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = s; + if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} + }else{ + register char *t = a + mmsize; + do {s = *a; *a++ = *b; *b++ = s;} while (a < t); + } +} + +static void mmswapblock(a, b, size) register char *a, *b; int size; +{ + register int s; + if (mmkind >= 0) { + register char *t = a + (size & (-16)); register int lo = (size & 0x0C); + if (size >= 16) { + do { + s = A[0]; A[0] = B[0]; B[0] = s; + s = A[1]; A[1] = B[1]; B[1] = s; + s = A[2]; A[2] = B[2]; B[2] = s; + s = A[3]; A[3] = B[3]; B[3] = s; a += 16; b += 16; + }while (a < t); + } + if (lo != 0) { s = A[0]; A[0] = B[0]; B[0] = s; + if (lo >= 8) { s = A[1]; A[1] = B[1]; B[1] = s; + if (lo == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} + }else{ + register char *t = a + size; + do {s = *a; *a++ = *b; *b++ = s;} while (a < t); + } +} + +static void mmrot3(a, b, c) register char *a, *b, *c; +{ + register int s; + if (mmkind >= 0) { + if (mmkind > 0) { + register char *t = a + high; + do { + s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s; + s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; + s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s; + s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s; a += 16; b += 16; c += 16; + }while (a < t); + } + if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s; + if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; + if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}} + }else{ + register char *t = a + mmsize; + do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t); + } +} + +/* qs6.c */ +/*****************************************************/ +/* */ +/* qs6 (Quick sort function) */ +/* */ +/* by Tomoyuki Kawamura 1995.4.21 */ +/* kawamura@tokuyama.ac.jp */ +/*****************************************************/ + +typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */ +#define PUSH(ll,rr) {top->LL = (ll); top->RR = (rr); ++top;} /* Push L,l,R,r */ +#define POP(ll,rr) {--top; ll = top->LL; rr = top->RR;} /* Pop L,l,R,r */ + +#define med3(a,b,c) ((*cmp)(a,b)<0 ? \ + ((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \ + ((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<0 ? a : c)) ) + +void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)(); +{ + register char *l, *r, *m; /* l,r:left,right group m:median point */ + register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ + char *L = base; /* left end of curren region */ + char *R = (char*)base + size*(nel-1); /* right end of current region */ + int chklim = 63; /* threshold of ordering element check */ + stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */ + + if (nel <= 1) return; /* need not to sort */ + mmprepare( base, size ); + goto start; + + nxt: + if (stack == top) return; /* return if stack is empty */ + POP(L,R); + + for (;;) { + start: + if (L + size == R) {if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt;}/* 2 elements */ + + l = L; r = R; + t = (r - l + size) / size; /* number of elements */ + m = l + size * (t >> 1); /* calculate median value */ + + if (t >= 60) { + register char *m1; + register char *m3; + if (t >= 200) { + t = size*(t>>3); /* number of bytes in splitting 8 */ + { + register char *p1 = l + t; + register char *p2 = p1 + t; + register char *p3 = p2 + t; + m1 = med3( p1, p2, p3 ); + p1 = m + t; + p2 = p1 + t; + p3 = p2 + t; + m3 = med3( p1, p2, p3 ); + } + }else{ + t = size*(t>>2); /* number of bytes in splitting 4 */ + m1 = l + t; + m3 = m + t; + } + m = med3( m1, m, m3 ); + } + + if ((t = (*cmp)(l,m)) < 0) { /*3-5-?*/ + if ((t = (*cmp)(m,r)) < 0) { /*3-5-7*/ + if (chklim && nel >= chklim) { /* check if already ascending order */ + char *p; + chklim = 0; + for (p=l; p<r; p+=size) if ((*cmp)(p,p+size) > 0) goto fail; + goto nxt; + } + fail: goto loopA; /*3-5-7*/ + } + if (t > 0) { + if ((*cmp)(l,r) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/ + mmrot3(r,m,l); goto loopA; /*3-5-2*/ + } + goto loopB; /*3-5-5*/ + } + + if (t > 0) { /*7-5-?*/ + if ((t = (*cmp)(m,r)) > 0) { /*7-5-3*/ + if (chklim && nel >= chklim) { /* check if already ascending order */ + char *p; + chklim = 0; + for (p=l; p<r; p+=size) if ((*cmp)(p,p+size) < 0) goto fail2; + while (l<r) {mmswap(l,r); l+=size; r-=size;} /* reverse region */ + goto nxt; + } + fail2: mmswap(l,r); goto loopA; /*7-5-3*/ + } + if (t < 0) { + if ((*cmp)(l,r) <= 0) {mmswap(l,m); goto loopB;} /*7-5-8*/ + mmrot3(l,m,r); goto loopA; /*7-5-6*/ + } + mmswap(l,r); goto loopA; /*7-5-5*/ + } + + if ((t = (*cmp)(m,r)) < 0) {goto loopA;} /*5-5-7*/ + if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/ + + /* deteming splitting type in case 5-5-5 */ /*5-5-5*/ + for (;;) { + if ((l += size) == r) goto nxt; /*5-5-5*/ + if (l == m) continue; + if ((t = (*cmp)(l,m)) > 0) {mmswap(l,r); l = L; goto loopA;} /*575-5*/ + if (t < 0) {mmswap(L,l); l = L; goto loopB;} /*535-5*/ + } + + loopA: eq_l = 1; eq_r = 1; /* splitting type A */ /* left <= median < right±¦*/ + for (;;) { + for (;;) { + if ((l += size) == r) + {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} + if (l == m) continue; + if ((t = (*cmp)(l,m)) > 0) {eq_r = 0; break;} + if (t < 0) eq_l = 0; + } + for (;;) { + if (l == (r -= size)) + {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} + if (r == m) {m = l; break;} + if ((t = (*cmp)(r,m)) < 0) {eq_l = 0; break;} + if (t == 0) break; + } + mmswap(l,r); /* swap left and right */ + } + + loopB: eq_l = 1; eq_r = 1; /* splitting type B */ /* left < median <= right */ + for (;;) { + for (;;) { + if (l == (r -= size)) + {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} + if (r == m) continue; + if ((t = (*cmp)(r,m)) < 0) {eq_l = 0; break;} + if (t > 0) eq_r = 0; + } + for (;;) { + if ((l += size) == r) + {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} + if (l == m) {m = r; break;} + if ((t = (*cmp)(l,m)) > 0) {eq_r = 0; break;} + if (t == 0) break; + } + mmswap(l,r); /* swap left and right */ + } + + fin: + if (eq_l == 0) /* need to sort left side */ + if (eq_r == 0) /* need to sort right side */ + if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */ + else {PUSH(L,l); L = r;} /* sort right side first */ + else R = l; /* need to sort left side only */ + else if (eq_r == 0) L = r; /* need to sort right side only */ + else goto nxt; /* need not to sort both sides */ + } +} diff --git a/util.h b/util.h index 570d894ccb..756daeeac6 100644 --- a/util.h +++ b/util.h @@ -6,13 +6,33 @@ $Date$ created at: Thu Mar 9 11:55:53 JST 1995 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ #ifndef UTIL_H #define UTIL_H -unsigned long scan_hex(); -unsigned long scan_oct(); +#ifndef _ +# ifdef __STDC__ +# define _(args) args +# else +# define _(args) () +# endif +#endif + +#define scan_oct ruby_scan_oct +unsigned long scan_oct _((char*, int, int*)); +#define scan_hex ruby_scan_hex +unsigned long scan_hex _((char*, int, int*)); + +#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT) +#define add_suffix ruby_add_suffix +void add_suffix(); +#endif + +char *ruby_mktemp _((void)); + +void ruby_qsort _((void*, int, int, int (*)())); +#define qsort(b,n,s,c) ruby_qsort(b,n,s,c) #endif /* UTIL_H */ diff --git a/variable.c b/variable.c index 0115b87d68..03262c5d83 100644 --- a/variable.c +++ b/variable.c @@ -13,24 +13,18 @@ #include "node.h" #include "st.h" +#ifdef USE_CWGUSI +char* strdup(char*); +#endif + static st_table *rb_global_tbl; st_table *rb_class_tbl; -#define global_tbl rb_global_tbl -#define class_tbl rb_class_tbl - -int rb_const_defined(); - -st_table* -new_idhash() -{ - return st_init_numtable(); -} void Init_var_tables() { - global_tbl = new_idhash(); - class_tbl = new_idhash(); + rb_global_tbl = st_init_numtable(); + rb_class_tbl = st_init_numtable(); } struct fc_result { @@ -41,8 +35,6 @@ struct fc_result { struct fc_result *prev; }; -extern VALUE cModule; - static int fc_i(key, value, res) ID key; @@ -56,19 +48,19 @@ fc_i(key, value, res) name = rb_id2name(key); if (res->path) { - path = str_dup(res->path); - str_cat(path, "::", 2); - str_cat(path, name, strlen(name)); + path = rb_str_dup(res->path); + rb_str_cat(path, "::", 2); + rb_str_cat(path, name, strlen(name)); } else { - path = str_new2(name); + path = rb_str_new2(name); } if (value == res->klass) { res->name = key; res->path = path; return ST_STOP; } - if (obj_is_kind_of(value, cModule)) { + if (rb_obj_is_kind_of(value, rb_cModule)) { struct fc_result arg; struct fc_result *list; @@ -97,99 +89,108 @@ fc_i(key, value, res) } static VALUE -find_class_path(cls) - VALUE cls; +find_class_path(klass) + VALUE klass; { struct fc_result arg; arg.name = 0; arg.path = 0; - arg.klass = cls; - arg.track = cObject; + arg.klass = klass; + arg.track = rb_cObject; arg.prev = 0; - if (RCLASS(cObject)->iv_tbl) { - st_foreach(RCLASS(cObject)->iv_tbl, fc_i, &arg); + if (RCLASS(rb_cObject)->iv_tbl) { + st_foreach(RCLASS(rb_cObject)->iv_tbl, fc_i, &arg); } if (arg.name == 0) { - st_foreach(class_tbl, fc_i, &arg); + st_foreach(rb_class_tbl, fc_i, &arg); } if (arg.name) { - rb_iv_set(cls, "__classpath__", arg.path); + rb_iv_set(klass, "__classpath__", arg.path); return arg.path; } return Qnil; } static VALUE -classname(cls) - VALUE cls; +classname(klass) + VALUE klass; { VALUE path; + ID classpath = rb_intern("__classpath__"); - while (TYPE(cls) == T_ICLASS || FL_TEST(cls, FL_SINGLETON)) { - cls = (VALUE)RCLASS(cls)->super; + while (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) { + klass = (VALUE)RCLASS(klass)->super; } - path = rb_iv_get(cls, "__classpath__"); - if (NIL_P(path)) { - path = rb_iv_get(cls, "__classid__"); + if (!klass) klass = rb_cObject; + if (!ROBJECT(klass)->iv_tbl || + !st_lookup(ROBJECT(klass)->iv_tbl, classpath, &path)) { + ID classid = rb_intern("__classid__"); + + path = rb_ivar_get(klass, classid); if (!NIL_P(path)) { - path = str_new2(rb_id2name(FIX2INT(path))); + path = rb_str_new2(rb_id2name(FIX2INT(path))); + if (!ROBJECT(klass)->iv_tbl) + ROBJECT(klass)->iv_tbl = st_init_numtable(); + st_insert(ROBJECT(klass)->iv_tbl, classpath, path); + st_delete(RCLASS(klass)->iv_tbl, &classid, 0); } } if (NIL_P(path)) { - path = find_class_path(cls); + path = find_class_path(klass); if (NIL_P(path)) { return 0; } return path; } - if (TYPE(path) != T_STRING) Bug("class path is not set properly"); + if (TYPE(path) != T_STRING) + rb_bug("class path is not set properly"); return path; } VALUE -mod_name(mod) +rb_mod_name(mod) VALUE mod; { VALUE path = classname(mod); - if (path) return path; - return str_new(0,0); + if (path) return rb_str_dup(path); + return rb_str_new(0,0); } VALUE -rb_class_path(cls) - VALUE cls; +rb_class_path(klass) + VALUE klass; { - VALUE path = classname(cls); + VALUE path = classname(klass); if (path) return path; else { char buf[256]; char *s = "Class"; - if (TYPE(cls) == T_MODULE) s = "Module"; - sprintf(buf, "#<%s 0x%x>", s, cls); - return str_new2(buf); + if (TYPE(klass) == T_MODULE) s = "Module"; + sprintf(buf, "#<%s 0x%x>", s, klass); + return rb_str_new2(buf); } } void -rb_set_class_path(cls, under, name) - VALUE cls, under; +rb_set_class_path(klass, under, name) + VALUE klass, under; char *name; { VALUE str; - if (under == cObject) { - str = str_new2(name); + if (under == rb_cObject) { + str = rb_str_new2(name); } else { - str = str_dup(rb_class_path(under)); - str_cat(str, "::", 2); - str_cat(str, name, strlen(name)); + str = rb_str_dup(rb_class_path(under)); + rb_str_cat(str, "::", 2); + rb_str_cat(str, name, strlen(name)); } - rb_iv_set(cls, "__classpath__", str); + rb_iv_set(klass, "__classpath__", str); } VALUE @@ -197,24 +198,17 @@ rb_path2class(path) char *path; { if (path[0] == '#') { - ArgError("can't retrieve anonymous class %s", path); + rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path); } return rb_eval_string(path); } void -rb_name_class(cls, id) - VALUE cls; +rb_name_class(klass, id) + VALUE klass; ID id; { - extern VALUE cString; - - if (cString) { - rb_iv_set(cls, "__classpath__", str_new2(rb_id2name(id))); - } - else { - rb_iv_set(cls, "__classid__", INT2FIX(id)); - } + rb_iv_set(klass, "__classid__", INT2FIX(id)); } static st_table *autoload_tbl = 0; @@ -225,38 +219,36 @@ rb_autoload_id(id, filename) char *filename; { if (!rb_is_const_id(id)) { - NameError("autoload must be constant name", rb_id2name(id)); + rb_raise(rb_eNameError, "autoload must be constant name", + rb_id2name(id)); } if (!autoload_tbl) { - autoload_tbl = new_idhash(); + autoload_tbl = st_init_numtable(); } st_insert(autoload_tbl, id, strdup(filename)); } void -rb_autoload(cls, filename) - char *cls, *filename; +rb_autoload(klass, filename) + char *klass, *filename; { - rb_autoload_id(rb_intern(cls), filename); + rb_autoload_id(rb_intern(klass), filename); } VALUE -f_autoload(obj, cls, file) - VALUE obj, cls, file; +rb_f_autoload(obj, klass, file) + VALUE obj, klass, file; { - ID id = rb_to_id(cls); - - Check_Type(file, T_STRING); - rb_autoload_id(id, RSTRING(file)->ptr); + rb_autoload_id(rb_to_id(klass), STR2CSTR(file)); return Qnil; } char * -rb_class2name(cls) - VALUE cls; +rb_class2name(klass) + VALUE klass; { - return RSTRING(rb_class_path(cls))->ptr; + return RSTRING(rb_class_path(klass))->ptr; } struct trace_var { @@ -294,9 +286,9 @@ rb_global_entry(id) { struct global_entry *entry; - if (!st_lookup(global_tbl, id, &entry)) { + if (!st_lookup(rb_global_tbl, id, &entry)) { entry = ALLOC(struct global_entry); - st_insert(global_tbl, id, entry); + st_add_direct(rb_global_tbl, id, entry); entry->id = id; entry->data = 0; entry->getter = undef_getter; @@ -313,7 +305,9 @@ static VALUE undef_getter(id) ID id; { - Warning("global variable `%s' not initialized", rb_id2name(id)); + if (rb_verbose) { + rb_warning("global variable `%s' not initialized", rb_id2name(id)); + } return Qnil; } @@ -358,7 +352,7 @@ static void val_marker(data) void *data; { - if (data) gc_mark_maybe(data); + if (data) rb_gc_mark_maybe(data); } static VALUE @@ -383,7 +377,7 @@ static void var_marker(var) VALUE **var; { - if (var) gc_mark_maybe(*var); + if (var) rb_gc_mark_maybe(*var); } static void @@ -392,7 +386,7 @@ readonly_setter(val, id, var) ID id; void *var; { - NameError("Can't set variable %s", rb_id2name(id)); + rb_raise(rb_eNameError, "Can't set variable %s", rb_id2name(id)); } static int @@ -405,16 +399,16 @@ mark_global_entry(key, entry) (*entry->marker)(entry->data); trace = entry->trace; while (trace) { - if (trace->data) gc_mark_maybe(trace->data); + if (trace->data) rb_gc_mark_maybe(trace->data); trace = trace->next; } return ST_CONTINUE; } void -gc_mark_global_tbl() +rb_gc_mark_global_tbl() { - st_foreach(global_tbl, mark_global_entry, 0); + st_foreach(rb_global_tbl, mark_global_entry, 0); } static ID @@ -481,11 +475,11 @@ static void rb_trace_eval(cmd, val) VALUE cmd, val; { - rb_eval_cmd(cmd, ary_new3(1, val)); + rb_eval_cmd(cmd, rb_ary_new3(1, val)); } VALUE -f_trace_var(argc, argv) +rb_f_trace_var(argc, argv) int argc; VALUE *argv; { @@ -495,14 +489,15 @@ f_trace_var(argc, argv) struct trace_var *trace; if (rb_scan_args(argc, argv, "11", &var, &cmd) == 1) { - cmd = f_lambda(); + cmd = rb_f_lambda(); } if (NIL_P(cmd)) { - return f_untrace_var(argc, argv); + return rb_f_untrace_var(argc, argv); } id = rb_to_id(var); - if (!st_lookup(global_tbl, id, &entry)) { - NameError("undefined global variable %s", rb_id2name(id)); + if (!st_lookup(rb_global_tbl, id, &entry)) { + rb_raise(rb_eNameError, "undefined global variable %s", + rb_id2name(id)); } trace = ALLOC(struct trace_var); trace->next = entry->trace; @@ -536,7 +531,7 @@ remove_trace(entry) } VALUE -f_untrace_var(argc, argv) +rb_f_untrace_var(argc, argv) int argc; VALUE *argv; { @@ -547,16 +542,18 @@ f_untrace_var(argc, argv) rb_scan_args(argc, argv, "11", &var, &cmd); id = rb_to_id(var); - if (!st_lookup(global_tbl, id, &entry)) { - NameError("undefined global variable %s", rb_id2name(id)); + if (!st_lookup(rb_global_tbl, id, &entry)) { + rb_raise(rb_eNameError, "undefined global variable %s", + rb_id2name(id)); } + + trace = entry->trace; if (NIL_P(cmd)) { - VALUE ary = ary_new(); + VALUE ary = rb_ary_new(); - trace = entry->trace; while (trace) { struct trace_var *next = trace->next; - ary_push(ary, (VALUE)trace->data); + rb_ary_push(ary, (VALUE)trace->data); trace->removed = 1; trace = next; } @@ -570,7 +567,7 @@ f_untrace_var(argc, argv) if (trace->data == (void*)cmd) { trace->removed = 1; if (!entry->block_trace) remove_trace(entry); - return ary_new3(1, cmd); + return rb_ary_new3(1, cmd); } trace = trace->next; } @@ -589,7 +586,7 @@ struct trace_data { VALUE val; }; -static void +static VALUE trace_ev(data) struct trace_data *data; { @@ -599,14 +596,16 @@ trace_ev(data) (*trace->func)(trace->data, data->val); trace = trace->next; } + return Qnil; /* not reached */ } -static void +static VALUE trace_en(entry) struct global_entry *entry; { entry->block_trace = 0; remove_trace(entry); + return Qnil; /* not reached */ } VALUE @@ -616,17 +615,15 @@ rb_gvar_set(entry, val) { struct trace_data trace; - if (rb_safe_level() >= 4) { - extern VALUE eSecurityError; - Raise(eSecurityError, "cannot change global variable value"); - } + if (rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: can't change global variable value"); (*entry->setter)(val, entry->id, entry->data, entry); if (entry->trace && !entry->block_trace) { entry->block_trace = 1; trace.trace = entry->trace; trace.val = val; - rb_ensure(trace_ev, &trace, trace_en, entry); + rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)entry); } return val; } @@ -646,8 +643,8 @@ VALUE rb_gvar_defined(entry) struct global_entry *entry; { - if (entry->getter == undef_getter) return FALSE; - return TRUE; + if (entry->getter == undef_getter) return Qfalse; + return Qtrue; } static int @@ -656,21 +653,23 @@ gvar_i(key, entry, ary) struct global_entry *entry; VALUE ary; { - ary_push(ary, str_new2(rb_id2name(entry->id))); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); return ST_CONTINUE; } VALUE -f_global_variables() +rb_f_global_variables() { - VALUE ary = ary_new(); - char buf[3]; - char *s = "^&`'+123456789"; + VALUE ary = rb_ary_new(); + char buf[4]; + char *s = "&`'+123456789"; - st_foreach(global_tbl, gvar_i, ary); - while (*s) { - sprintf(buf, "$%c", *s++); - ary_push(ary, str_new2(buf)); + st_foreach(rb_global_tbl, gvar_i, ary); + if (!NIL_P(rb_backref_get())) { + while (*s) { + sprintf(buf, "$%c", *s++); + rb_ary_push(ary, rb_str_new2(buf)); + } } return ary; } @@ -691,6 +690,133 @@ rb_alias_variable(name1, name2) entry1->marker = entry2->marker; } +static int special_generic_ivar = 0; +static st_table *generic_iv_tbl; + +static VALUE +generic_ivar_get(obj, id) + VALUE obj; + ID id; +{ + st_table *tbl; + VALUE val; + + if (!generic_iv_tbl) return Qnil; + if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qnil; + if (st_lookup(tbl, id, &val)) { + return val; + } + return Qnil; +} + +static void +generic_ivar_set(obj, id, val) + VALUE obj; + ID id; + VALUE val; +{ + st_table *tbl; + + if (rb_special_const_p(obj)) { + special_generic_ivar = 1; + } + if (!generic_iv_tbl) { + generic_iv_tbl = st_init_numtable(); + } + + if (!st_lookup(generic_iv_tbl, obj, &tbl)) { + FL_SET(obj, FL_EXIVAR); + tbl = st_init_numtable(); + st_add_direct(generic_iv_tbl, obj, tbl); + st_add_direct(tbl, id, val); + return; + } + st_insert(tbl, id, val); +} + +static VALUE +generic_ivar_defined(obj, id) + VALUE obj; + ID id; +{ + st_table *tbl; + VALUE val; + + if (!generic_iv_tbl) return Qfalse; + if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qfalse; + if (st_lookup(tbl, id, &val)) { + return Qtrue; + } + return Qfalse; +} + +static VALUE +generic_ivar_remove(obj, id) + VALUE obj; + ID id; +{ + st_table *tbl; + VALUE val; + + if (!generic_iv_tbl) return Qnil; + if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qnil; + st_delete(tbl, &id, &val); + if (tbl->num_entries == 0) { + st_delete(generic_iv_tbl, &obj, &tbl); + st_free_table(tbl); + } + return val; +} + +static int +givar_mark_i(key, value) + ID key; + VALUE value; +{ + rb_gc_mark(value); + return ST_CONTINUE; +} + +void +rb_mark_generic_ivar(obj) + VALUE obj; +{ + st_table *tbl; + + if (st_lookup(generic_iv_tbl, obj, &tbl)) { + rb_mark_tbl(tbl); + } +} + +static int +givar_i(obj, tbl) + VALUE obj; + st_table *tbl; +{ + if (rb_special_const_p(obj)) { + st_foreach(tbl, givar_mark_i, 0); + } + return ST_CONTINUE; +} + +void +rb_mark_generic_ivar_tbl() +{ + if (special_generic_ivar == 0) return; + if (!generic_iv_tbl) return; + st_foreach(generic_iv_tbl, givar_i, 0); +} + +void +rb_free_generic_ivar(obj) + VALUE obj; +{ + st_table *tbl; + + if (st_delete(generic_iv_tbl, &obj, &tbl)) + st_free_table(tbl); +} + VALUE rb_ivar_get(obj, id) VALUE obj; @@ -702,15 +828,18 @@ rb_ivar_get(obj, id) case T_OBJECT: case T_CLASS: case T_MODULE: + case T_FILE: if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, &val)) return val; - return Qnil; + break; default: - TypeError("class %s can not have instance variables", - rb_class2name(CLASS_OF(obj))); + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) + return generic_ivar_get(obj, id); break; } - Warning("instance var %s not initialized", rb_id2name(id)); + if (rb_verbose) { + rb_warning("instance var %s not initialized", rb_id2name(id)); + } return Qnil; } @@ -720,20 +849,18 @@ rb_ivar_set(obj, id, val) ID id; VALUE val; { - if (rb_safe_level() >= 5) { - extern VALUE eSecurityError; - Raise(eSecurityError, "cannot change object status"); - } switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: - if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = new_idhash(); + case T_FILE: + if (rb_safe_level() >= 4 && !FL_TEST(obj, FL_TAINT)) + rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); + if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable(); st_insert(ROBJECT(obj)->iv_tbl, id, val); break; default: - TypeError("class %s can not have instance variables", - rb_class2name(CLASS_OF(obj))); + generic_ivar_set(obj, id, val); break; } return val; @@ -744,119 +871,136 @@ rb_ivar_defined(obj, id) VALUE obj; ID id; { - if (!rb_is_instance_id(id)) return FALSE; + if (!rb_is_instance_id(id)) return Qfalse; switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: + case T_FILE: if (ROBJECT(obj)->iv_tbl && st_lookup(ROBJECT(obj)->iv_tbl, id, 0)) - return TRUE; + return Qtrue; + break; + default: + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) + return generic_ivar_defined(obj, id); break; } - return FALSE; + return Qfalse; } static int -ivar_i(key, value, hash) +ivar_i(key, entry, ary) ID key; - VALUE value; - VALUE hash; + struct global_entry *entry; + VALUE ary; { if (rb_is_instance_id(key)) { - hash_aset(hash, str_new2(rb_id2name(key)), value); + rb_ary_push(ary, rb_str_new2(rb_id2name(key))); } return ST_CONTINUE; } VALUE -obj_instance_variables(obj) +rb_obj_instance_variables(obj) VALUE obj; { - VALUE hash = hash_new(); + VALUE ary; switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: + case T_FILE: + ary = rb_ary_new(); if (ROBJECT(obj)->iv_tbl) { - st_foreach(ROBJECT(obj)->iv_tbl, ivar_i, hash); + st_foreach(ROBJECT(obj)->iv_tbl, ivar_i, ary); } - break; + return ary; default: - break; + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { + st_table *tbl; + + if (st_lookup(generic_iv_tbl, obj, &tbl)) { + ary = rb_ary_new(); + st_foreach(tbl, ivar_i, ary); + return ary; + } + } } - return hash; + return Qnil; } VALUE -obj_remove_instance_variable(obj, name) +rb_obj_remove_instance_variable(obj, name) VALUE obj, name; { - VALUE val; + VALUE val = Qnil; ID id = rb_to_id(name); - if (rb_ivar_defined(obj, id)) { - NameError("`%s' is not an instance variable", rb_id2name(id)); + if (!rb_is_instance_id(id)) { + rb_raise(rb_eNameError, "`%s' is not an instance variable", + rb_id2name(id)); } switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: case T_MODULE: + case T_FILE: if (ROBJECT(obj)->iv_tbl) { st_delete(ROBJECT(obj)->iv_tbl, &id, &val); } break; default: - TypeError("object %s can not have instance variables", - rb_class2name(CLASS_OF(obj))); + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) + return generic_ivar_remove(obj, id); break; } - return obj; + return val; } VALUE -rb_const_get_at(cls, id) - VALUE cls; +rb_const_get_at(klass, id) + VALUE klass; ID id; { VALUE value; - if (RCLASS(cls)->iv_tbl && st_lookup(RCLASS(cls)->iv_tbl, id, &value)) { + if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { return value; } - if (cls == cObject) { - return rb_const_get(cls, id); + if (klass == rb_cObject) { + return rb_const_get(klass, id); } - NameError("Uninitialized constant %s::%s", - RSTRING(rb_class_path(cls))->ptr, - rb_id2name(id)); - /* not reached */ + rb_raise(rb_eNameError, "Uninitialized constant %s::%s", + RSTRING(rb_class_path(klass))->ptr, + rb_id2name(id)); + return Qnil; /* not reached */ } VALUE -rb_const_get(cls, id) - VALUE cls; +rb_const_get(klass, id) + VALUE klass; ID id; { VALUE value; VALUE tmp; - tmp = cls; + tmp = klass; while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { return value; } tmp = RCLASS(tmp)->super; } - if (BUILTIN_TYPE(cls) == T_MODULE) { - return rb_const_get(cObject, id); + if (BUILTIN_TYPE(klass) == T_MODULE) { + return rb_const_get(rb_cObject, id); } /* pre-defined class */ - if (st_lookup(class_tbl, id, &value)) return value; + if (st_lookup(rb_class_tbl, id, &value)) return value; /* autoload */ if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) { @@ -864,21 +1008,21 @@ rb_const_get(cls, id) VALUE module; st_delete(autoload_tbl, &id, &modname); - module = str_new2(modname); + module = rb_str_new2(modname); free(modname); - f_require(0, module); - return rb_const_get(cls, id); + rb_f_require(Qnil, module); + return rb_const_get(klass, id); } /* Uninitialized constant */ - if (cls && cls != cObject) - NameError("Uninitialized constant %s::%s", - RSTRING(rb_class_path(cls))->ptr, - rb_id2name(id)); + if (klass && klass != rb_cObject) + rb_raise(rb_eNameError, "Uninitialized constant %s::%s", + RSTRING(rb_class_path(klass))->ptr, + rb_id2name(id)); else { - NameError("Uninitialized constant %s",rb_id2name(id)); + rb_raise(rb_eNameError, "Uninitialized constant %s",rb_id2name(id)); } - /* not reached */ + return Qnil; /* not reached */ } static int @@ -888,36 +1032,59 @@ const_i(key, value, ary) VALUE ary; { if (rb_is_const_id(key)) { - VALUE kval = str_new2(rb_id2name(key)); - if (!ary_includes(ary, kval)) { - ary_push(ary, kval); + VALUE kval = rb_str_new2(rb_id2name(key)); + if (!rb_ary_includes(ary, kval)) { + rb_ary_push(ary, kval); } } return ST_CONTINUE; } +VALUE +rb_mod_remove_const(mod, name) + VALUE mod, name; +{ + ID id = rb_to_id(name); + VALUE val; + + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "`%s' is not constant", rb_id2name(id)); + } + + if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) { + return val; + } + if (rb_const_defined_at(mod, id)) { + rb_raise(rb_eNameError, "cannot remove %s::%s", + rb_class2name(mod), rb_id2name(id)); + } + rb_raise(rb_eNameError, "constant %s::%s not defined", + rb_class2name(mod), rb_id2name(id)); + return Qnil; /* not reached */ +} + static int autoload_i(key, name, ary) ID key; char *name; VALUE ary; { - VALUE kval = str_new2(rb_id2name(key)); - if (!ary_includes(ary, kval)) { - ary_push(ary, kval); + VALUE kval = rb_str_new2(rb_id2name(key)); + if (!rb_ary_includes(ary, kval)) { + rb_ary_push(ary, kval); } return ST_CONTINUE; } VALUE -mod_const_at(mod, ary) +rb_mod_const_at(mod, ary) VALUE mod, ary; { if (RCLASS(mod)->iv_tbl) { st_foreach(RCLASS(mod)->iv_tbl, const_i, ary); } - if ((VALUE)mod == cObject) { - st_foreach(class_tbl, const_i, ary); + if ((VALUE)mod == rb_cObject) { + st_foreach(rb_class_tbl, const_i, ary); if (autoload_tbl) { st_foreach(autoload_tbl, autoload_i, ary); } @@ -926,38 +1093,38 @@ mod_const_at(mod, ary) } VALUE -mod_constants(mod) +rb_mod_constants(mod) VALUE mod; { - return mod_const_at(mod, ary_new()); + return rb_mod_const_at(mod, rb_ary_new()); } VALUE -mod_const_of(mod, ary) +rb_mod_const_of(mod, ary) VALUE mod; VALUE ary; { - mod_const_at(mod, ary); + rb_mod_const_at(mod, ary); for (;;) { mod = RCLASS(mod)->super; if (!mod) break; - mod_const_at(mod, ary); + rb_mod_const_at(mod, ary); } return ary; } int -rb_const_defined_at(cls, id) - VALUE cls; +rb_const_defined_at(klass, id) + VALUE klass; ID id; { - if (RCLASS(cls)->iv_tbl && st_lookup(RCLASS(cls)->iv_tbl, id, 0)) { - return TRUE; + if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, 0)) { + return Qtrue; } - if (cls == cObject) { - return rb_const_defined(cls, id); + if (klass == rb_cObject) { + return rb_const_defined(klass, id); } - return FALSE; + return Qfalse; } int @@ -965,53 +1132,65 @@ rb_autoload_defined(id) ID id; { if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) - return TRUE; - return FALSE; + return Qtrue; + return Qfalse; } int -rb_const_defined(cls, id) - VALUE cls; +rb_const_defined(klass, id) + VALUE klass; ID id; { - while (cls) { - if (RCLASS(cls)->iv_tbl && st_lookup(RCLASS(cls)->iv_tbl, id, 0)) { - return TRUE; + VALUE tmp = klass; + + while (tmp) { + if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { + return Qtrue; } - cls = RCLASS(cls)->super; + tmp = RCLASS(tmp)->super; + } + if (BUILTIN_TYPE(klass) == T_MODULE) { + return rb_const_defined(rb_cObject, id); } - if (st_lookup(class_tbl, id, 0)) - return TRUE; + if (st_lookup(rb_class_tbl, id, 0)) + return Qtrue; return rb_autoload_defined(id); } void -rb_const_set(cls, id, val) - VALUE cls; +rb_const_set(klass, id, val) + VALUE klass; ID id; VALUE val; { - if (!RCLASS(cls)->iv_tbl) { - RCLASS(cls)->iv_tbl = new_idhash(); + if (rb_safe_level() >= 4 && !FL_TEST(klass, FL_TAINT)) + rb_raise(rb_eSecurityError, "Insecure: can't set constant"); + if (!RCLASS(klass)->iv_tbl) { + RCLASS(klass)->iv_tbl = st_init_numtable(); } - else if (st_lookup(RCLASS(cls)->iv_tbl, id, 0)) { - NameError("already initialized constant %s", rb_id2name(id)); + else if (st_lookup(RCLASS(klass)->iv_tbl, id, 0)) { + rb_raise(rb_eNameError, "already initialized constant %s", + rb_id2name(id)); } - st_insert(RCLASS(cls)->iv_tbl, id, val); + st_add_direct(RCLASS(klass)->iv_tbl, id, val); } void -rb_define_const(cls, name, val) - VALUE cls; +rb_define_const(klass, name, val) + VALUE klass; char *name; VALUE val; { ID id = rb_intern(name); + + if (klass == rb_cObject) { + rb_secure(4); + } if (!rb_is_const_id(id)) { - NameError("wrong constant name %s", name); + rb_raise(rb_eNameError, "wrong constant name %s", name); } - rb_const_set(cls, id, val); + rb_const_set(klass, id, val); } void @@ -1019,7 +1198,7 @@ rb_define_global_const(name, val) char *name; VALUE val; { - rb_define_const(cObject, name, val); + rb_define_const(rb_cObject, name, val); } VALUE diff --git a/version.c b/version.c index 71f531c963..22393f0f4a 100644 --- a/version.c +++ b/version.c @@ -7,7 +7,7 @@ $Date$ created at: Thu Sep 30 20:08:01 JST 1993 - Copyright (C) 1993-1996 Yukihiro Matsumoto + Copyright (C) 1993-1998 Yukihiro Matsumoto ************************************************/ @@ -18,19 +18,19 @@ void Init_version() { - rb_define_global_const("VERSION", str_new2(RUBY_VERSION)); - rb_define_global_const("PLATFORM", str_new2(RUBY_PLATFORM)); + rb_define_global_const("VERSION", rb_str_new2(RUBY_VERSION)); + rb_define_global_const("PLATFORM", rb_str_new2(RUBY_PLATFORM)); } void -show_version() +ruby_show_version() { fprintf(stderr, "ruby %s(%s) [%s]\n", RUBY_VERSION, VERSION_DATE, RUBY_PLATFORM); } void -show_copyright() +ruby_show_copyright() { - fprintf(stderr, "ruby - Copyright (C) 1993-1997 Yukihiro Matsumoto\n"); + fprintf(stderr, "ruby - Copyright (C) 1993-1998 Yukihiro Matsumoto\n"); exit(0); } diff --git a/version.h b/version.h index b737876434..3b291392b3 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ -#define RUBY_VERSION "1.1b5" -#define VERSION_DATE "98/01/16" +#define RUBY_VERSION "1.3.1" +#define VERSION_DATE "99/01/20" diff --git a/win32/Makefile b/win32/Makefile index c7e8b8dbec..152bdc88ea 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -15,12 +15,12 @@ INSTALL_DATA = $(INSTALL) -m 644 PURIFY = -CFLAGS = -nologo -DNT=1 -Ox +CFLAGS = -nologo -DNT=1 -Ox -I. -I./missing LDFLAGS = $(CFLAGS) -Fm #CFLAGS = -nologo -DNT=1 -Zi -MD #LDFLAGS = $(CFLAGS) -Fm -MD LIBS = $(EXTLIBS) advapi32.lib wsock32.lib -MISSING = crypt.obj setenv.obj alloca.obj nt.obj +MISSING = crypt.obj alloca.obj win32.obj prefix = binprefix = @@ -30,7 +30,6 @@ libdir = STACK = 0x200000 ORGLIBPATH = $(LIB) -#MISCLIBS = win32\sdbm.lib #### End of system configuration section. #### @@ -157,9 +156,6 @@ memmove.obj: missing/memmove.c mkdir.obj: missing/mkdir.c $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/mkdir.c -setenv.obj: missing/setenv.c - $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/setenv.c - strerror.obj: missing/strerror.c $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strerror.c @@ -180,22 +176,15 @@ strtoul.obj: missing/strtoul.c # when I use -I., there is confliction at "OpenFile" # so, set . into environment varible "include" -nt.obj: missing/nt.c +win32.obj: win32/win32.c @set include=$(INCLUDE);. - $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/nt.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c win32/win32.c parse.c: parse.y $(YACC) $(YFLAGS) parse.y sed -e "s!^extern char \*getenv();!/* & */!" y.tab.c > parse.c @rm y.tab.c -win32\sdbm.lib : win32\sdbm.c win32\sdbm.h - cd win32 - $(CC) $(CFLAGS) $(CPPFLAGS) -DMSDOS -c sdbm.c - lib /OUT:sdbm.lib sdbm.obj - copy sdbm.h ndbm.h - cd .. - # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: ### @@ -210,26 +199,26 @@ dln.obj: dln.c config.h defines.h dln.h st.h dmyext.obj: dmyext.c enum.obj: enum.c ruby.h config.h defines.h error.obj: error.c ruby.h config.h defines.h env.h -eval.obj: eval.c ruby.h config.h defines.h env.h node.h sig.h st.h dln.h -file.obj: file.c ruby.h config.h defines.h io.h sig.h +eval.obj: eval.c ruby.h config.h defines.h env.h node.h rubysig.h st.h dln.h +file.obj: file.c ruby.h config.h defines.h rubyio.h rubysig.h fnmatch.obj: fnmatch.c config.h fnmatch.h -gc.obj: gc.c ruby.h config.h defines.h env.h sig.h st.h node.h re.h regex.h +gc.obj: gc.c ruby.h config.h defines.h env.h rubysig.h st.h node.h re.h regex.h glob.obj: glob.c config.h fnmatch.h hash.obj: hash.c ruby.h config.h defines.h st.h inits.obj: inits.c ruby.h config.h defines.h -io.obj: io.c ruby.h config.h defines.h io.h sig.h +io.obj: io.c ruby.h config.h defines.h rubyio.h rubysig.h main.obj: main.c math.obj: math.c ruby.h config.h defines.h numeric.obj: numeric.c ruby.h config.h defines.h object.obj: object.c ruby.h config.h defines.h st.h pack.obj: pack.c ruby.h config.h defines.h -process.obj: process.c ruby.h config.h defines.h sig.h st.h +process.obj: process.c ruby.h config.h defines.h rubysig.h st.h random.obj: random.c ruby.h config.h defines.h range.obj: range.c ruby.h config.h defines.h re.obj: re.c ruby.h config.h defines.h re.h regex.h regex.obj: regex.c config.h defines.h regex.h util.h ruby.obj: ruby.c ruby.h config.h defines.h re.h regex.h dln.h -signal.obj: signal.c ruby.h config.h defines.h sig.h +signal.obj: signal.c ruby.h config.h defines.h rubysig.h sprintf.obj: sprintf.c ruby.h config.h defines.h st.obj: st.c config.h st.h string.obj: string.c ruby.h config.h defines.h re.h regex.h diff --git a/win32/config.h b/win32/config.h index cf5cb332bf..8385154cd5 100644 --- a/win32/config.h +++ b/win32/config.h @@ -1,4 +1,10 @@ -#define THREAD 1 +#define USE_THREAD 1 +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 +#define SIZEOF_VOIDP 4 +#define HAVE_PROTOTYPES 1 +#define HAVE_STDARG_PROTOTYPES 1 +/* #define HAVE_ATTR_NORETURN 1 */ /* #define HAVE_DIRENT_H 1 */ /* #define HAVE_UNISTD_H 1 */ #define HAVE_STDLIB_H 1 @@ -31,6 +37,7 @@ /* #define HAVE_SETITIMER 1 */ #define HAVE_GETGROUPS 1 /* #define HAVE_SIGPROCMASK 1 */ +#define RSHIFT(x,y) ((x)>>y) #define FILE_COUNT _cnt #define DLEXT ".dll" #define RUBY_LIB ";/usr/local/lib/ruby;." @@ -43,6 +50,9 @@ #define pclose _pclose #define pipe _pipe #define bzero(x, y) memset(x, 0, y) +#define snprintf _snprintf +#define vsnprintf _vsnprintf + #define S_IFMT _S_IFMT #define S_IFDIR _S_IFDIR diff --git a/win32/ruby.def b/win32/ruby.def index e8ece2ae50..dfe63e5ba6 100644 --- a/win32/ruby.def +++ b/win32/ruby.def @@ -1,37 +1,58 @@ LIBRARY rubymw.dll -CODE LOADONCALL -DATA LOADONCALL DESCRIPTION 'win32 rubymw.dll' EXPORTS -;global objects +;;global objects ;array.c: - cArray + rb_cArray ;bignum.c: - cBignum + rb_cBignum +;enum.c + rb_mEnumerable +;error.c + rb_eException; + rb_eSystemExit + rb_eInterrupt + rb_eFatal; + rb_eStandardError; + rb_eRuntimeError; + rb_eSyntaxError; + rb_eTypeError; + rb_eArgError; + rb_eNameError; + rb_eIndexError; + rb_eLoadError; + rb_eSecurityError; + rb_eNotImpError; + rb_eSystemCallError; + rb_mErrno; ;eval.c: - cProc + rb_cProc ;file.c: - cFile + rb_cFile ;hash.c: - cHash + rb_cHash ;io.c: - cIO + rb_cIO ;numeric.c: - cNumeric - cFloat - cInteger - cFixnum + rb_cNumeric + rb_cFloat + rb_cInteger + rb_cFixnum ;object.c - cObject - cModule - cClass - cFixnum - cData + rb_mKernel + rb_cObject + rb_cModule + rb_cClass + rb_cData + + rb_cNilClass + rb_cTrueClass + rb_cFalseClass ;re.c: - cRegexp + rb_cRegexp ;string.c: - cString - cStruct + rb_cString + rb_cStruct ; procedures/methods ;missing/nt.c @@ -60,64 +81,63 @@ EXPORTS mygetservbyname mygetservbyport ;array.c - memclear - ary_freeze - ary_new2 - ary_new - ary_new3 - ary_new4 - assoc_new - ary_store - ary_push - ary_pop - ary_shift - ary_unshift - ary_entry - ary_each - ary_join - ary_to_s - ary_reverse - ary_sort_bang - ary_sort - ary_delete - ary_delete_at - ary_plus - ary_concat - ary_assoc - ary_rassoc - ary_includes + rb_ary_freeze + rb_ary_new2 + rb_ary_new + rb_ary_new3 + rb_ary_new4 + rb_assoc_new + rb_ary_store + rb_ary_push + rb_ary_pop + rb_ary_shift + rb_ary_unshift + rb_ary_entry + rb_ary_aref + rb_ary_each + rb_ary_join + rb_ary_to_s + rb_ary_reverse + rb_ary_sort_bang + rb_ary_sort + rb_ary_delete + rb_ary_delete_at + rb_ary_plus + rb_ary_concat + rb_ary_assoc + rb_ary_rassoc + rb_ary_includes ;bignum.c - big_clone - big_2comp - big_norm - uint2big - int2big - uint2inum - int2inum - str2inum - big2str - big2int - big_to_i - dbl2big - big2dbl - big_to_f - big_plus - big_minus - big_mul - big_pow - big_and - big_or - big_xor - big_lshift - big_rand + rb_big_clone + rb_big_2comp + rb_big_norm + rb_uint2big + rb_int2big + rb_uint2inum + rb_int2inum + rb_str2inum + rb_big2str + rb_big2ulong + rb_big2long + rb_dbl2big + rb_big2dbl + rb_big_plus + rb_big_minus + rb_big_mul + rb_big_pow + rb_big_and + rb_big_or + rb_big_xor + rb_big_lshift + rb_big_rand ;class.c - class_new - singleton_class_new - singleton_class_clone + rb_class_new + rb_singleton_class_new + rb_singleton_class_clone rb_define_class_id rb_define_class rb_define_class_under - module_new + rb_module_new rb_define_module_id rb_define_module rb_define_module_under @@ -126,6 +146,7 @@ EXPORTS rb_define_method rb_undef_method rb_define_private_method + rb_define_protected_method rb_singleton_class rb_define_singleton_method rb_define_module_function @@ -134,39 +155,37 @@ EXPORTS rb_define_attr rb_scan_args ; dln.c + dln_find_exe + dln_find_file dln_load dln_find_exe dln_find_file ; enum.c rb_each - enum_length + rb_enum_length ; error.c - Error - Error_Append - Warning - Bug + rb_compile_error + rb_compile_error_append + rb_warn + rb_warning + rb_bug rb_check_type - exc_new - exc_new2 - exc_new3 - Raise - TypeError - ArgError - NameError - IndexError - Fail + rb_exc_new + rb_exc_new2 + rb_exc_new3 + rb_raise + rb_loaderror rb_notimplement - LoadError - Fatal + rb_fatal rb_sys_fail ;eval.c rb_clear_cache - rb_add_method rb_alias + rb_add_method + rb_remove_method + rb_disable_super + rb_enable_super rb_method_boundp - dyna_var_defined - dyna_var_ref - dyna_var_asgn rb_safe_level rb_set_safe_level rb_check_safe_str @@ -183,9 +202,7 @@ EXPORTS rb_raise rb_fatal rb_interrupt - iterator_p - rb_yield_0 - rb_yield + rb_iterator_p rb_iterate rb_rescue rb_ensure @@ -194,88 +211,89 @@ EXPORTS rb_funcall2 rb_backtrace rb_frame_last_func - f_load + rb_load rb_provide - f_require - class_new_instance + rb_f_require + rb_obj_instance_eval + rb_obj_call_init + rb_class_new_instance rb_extend_object - f_lambda - gc_mark_threads - thread_schedule - thread_wait_fd - thread_fd_writable - thread_wait_for - thread_alone - thread_select - thread_sleep - thread_sleep_forever - thread_create - thread_interrupt + rb_f_global_variables + rb_set_end_proc + rb_f_autoload + rb_f_lambda + rb_gc_mark_threads + rb_thread_schedule + rb_thread_wait_fd + rb_thread_fd_writable + rb_thread_wait_for + rb_thread_alone + rb_thread_select + rb_thread_sleep + rb_thread_sleep_forever + rb_thread_create + rb_thread_scope_shared_p + rb_thread_interrupt + rb_thread_trap_eval + rb_catch + rb_throw + rb_yield ; file.c - file_open + rb_file_open eaccess - file_s_expand_path + rb_file_s_expand_path ; gc.c xmalloc xcalloc xrealloc - gc_s_enable - gc_s_disable rb_global_variable rb_newobj - data_object_alloc - gc_mark_locations - gc_mark_maybe - gc_mark - gc_force_recycle - gc_mark_frame - gc_gc + rb_data_object_alloc + rb_gc_mark_locations + rb_gc_mark_maybe + rb_gc_mark + rb_gc_force_recycle + rb_gc_mark_frame + rb_gc ; hash.c + rb_hash_freeze rb_hash - hash_new - hash_aref - hash_aset + rb_hash_new + rb_hash_aref + rb_hash_aset ; inits.c rb_call_inits ; io.c - eof_error - io_writable - io_readable - io_write - io_gets_method - io_gets - io_getc - io_ungetc - io_fptr_finalize - io_close - io_binmode - io_mode_flags + rb_eof_error + rb_io_write + rb_io_gets + rb_io_getc + rb_io_ungetc + rb_io_fptr_finalize + rb_io_close + rb_io_binmode + rb_io_mode_flags rb_fopen rb_fdopen - io_unbuffered - io_reopen - f_gets + rb_io_unbuffered + rb_io_reopen rb_str_setter ; numeric.c - num_zerodiv - num_coerce_bin - float_new - flo_pow - num2int - num2fix - fix2str - fix_to_s - num_upto - fix_upto + rb_num_zerodiv + rb_num_coerce_bin + rb_float_new + rb_num2long + rb_num2ulong + rb_num2fix + rb_fix2str ; object.c rb_equal rb_eql - obj_equal - any_to_s + rb_any_to_s rb_inspect - obj_is_instance_of - obj_is_kind_of - obj_alloc + rb_obj_is_instance_of + rb_obj_is_kind_of + rb_obj_alloc rb_to_id rb_class_of rb_type @@ -285,54 +303,51 @@ EXPORTS rb_String rb_Array ; parse.c - ;;compile_string - ;;compile_file - ;;node_newnode - nodetype - nodeline - id_attrset + rb_node_newnode + rb_id_attrset rb_intern rb_id2name rb_is_const_id rb_is_instance_id - local_var_append - backref_get - backref_set - lastline_get - lastline_set + rb_backref_get + rb_backref_set + rb_lastline_get + rb_lastline_set ; process.c rb_proc_exec rb_syswait ; range.c - range_new - range_beg_end + rb_range_new + rb_range_beg_end ; re.c - str_cicmp - reg_search - reg_nth_defined - reg_nth_match - reg_last_match - reg_match_pre - reg_match_post - reg_match_last - reg_free - reg_new - reg_regcomp - reg_match - reg_match2 - reg_regsub + rb_str_cicmp + rb_reg_search + rb_reg_nth_defined + rb_reg_nth_match + rb_reg_last_match + rb_reg_match_pre + rb_reg_match_post + rb_reg_match_last + rb_reg_new + rb_reg_regcomp + rb_reg_match + rb_reg_match2 + rb_reg_regsub + rb_get_kcode rb_set_kcode ; ruby.c - rb_require_modules + ruby_require_modules rb_load_file ruby_script ruby_prog_init ruby_set_argv ruby_process_options ; signal.c - gc_mark_trap_list + rb_gc_mark_trap_list rb_trap_exit rb_trap_exec +; sprintf.c + rb_f_sprintf ; st.c st_init_table_with_size st_init_table @@ -342,58 +357,61 @@ EXPORTS st_lookup st_insert st_add_direct - st_find_or_add st_copy st_delete st_delete_safe st_foreach ; string.c - str_new - str_new2 - str_new3 - str_new4 - obj_as_string - str_dup - str_plus - str_times - str_substr - str_modify - str_freeze - str_dup_freezed - str_taint - str_tainted - str_resize - str_cat - str_hash - str_cmp - str_upto - str_inspect - str_split + rb_str_new + rb_str_new2 + rb_tainted_str_new + rb_tainted_str_new2 + rb_str_new3 + rb_str_new4 + rb_str_to_str + rb_obj_as_string + rb_str_dup + rb_str_plus + rb_str_times + rb_str_substr + rb_str_modify + rb_str_freeze + rb_str_dup_frozen + rb_str_resize + rb_str_cat + rb_str_hash + rb_str_cmp + rb_str_upto + rb_str_inspect + rb_str_split ; struct.c - struct_getmember - struct_define - struct_alloc - struct_new - struct_aref - struct_aset + rb_struct_getmember + rb_struct_define + rb_struct_alloc + rb_struct_new + rb_struct_aref + rb_struct_aset ; time.c - time_new - time_timeval + rb_time_new + rb_time_timeval ; util.c - scan_oct - scan_hex - add_suffix + rb_class_of + rb_type + rb_special_const_p + rb_test_false_or_nil + ruby_scan_oct + ruby_scan_hex + rb_add_suffix ;variable.c - new_idhash rb_class_path rb_set_class_path rb_path2class rb_name_class rb_autoload - f_autoload + rb_f_autoload rb_class2name rb_global_entry - gc_mark_global_tbl + rb_gc_mark_global_tbl rb_define_hooked_variable rb_define_variable rb_define_readonly_variable @@ -408,7 +426,9 @@ EXPORTS rb_ivar_defined rb_const_get_at rb_const_get - mod_constants + rb_mod_const_at + rb_mod_constants + rb_mod_const_of rb_const_defined_at rb_autoload_defined rb_const_defined @@ -418,7 +438,6 @@ EXPORTS rb_iv_get rb_iv_set ; version.c - show_version - show_copyright - + ruby_show_version + ruby_show_copyright diff --git a/win32/sdbm.c b/win32/sdbm.c index 0e4673bbb5..d2d2171875 100644 --- a/win32/sdbm.c +++ b/win32/sdbm.c @@ -634,7 +634,7 @@ register DBM *db; */ #ifndef lint -/*char pair_rcsid[] = "$Id: pair.c,v 1.10 90/12/13 13:00:35 oz Exp $";*/ +/*char pair_rcsid[] = "$Id: sdbm.c,v 1.1.1.1.2.1 1998/01/16 12:36:12 matz Exp $";*/ #endif #ifndef BSD42 -- cgit v1.2.3