diff options
-rw-r--r-- | C-IF | 135 | ||||
-rw-r--r-- | CVS/Entries | 51 | ||||
-rw-r--r-- | CVS/Repository | 1 | ||||
-rw-r--r-- | ChangeLog | 788 | ||||
-rw-r--r-- | FAQ | 65 | ||||
-rw-r--r-- | Makefile | 202 | ||||
-rw-r--r-- | Makefile.in | 186 | ||||
-rw-r--r-- | ToDo | 6 | ||||
-rw-r--r-- | array.c | 805 | ||||
-rw-r--r-- | bignum.c | 1121 | ||||
-rw-r--r-- | bring | 57 | ||||
-rw-r--r-- | class.c | 387 | ||||
-rw-r--r-- | compar.c | 99 | ||||
-rwxr-xr-x | config.status | 72 | ||||
-rw-r--r-- | configure.in | 63 | ||||
-rw-r--r-- | dbm.c | 401 | ||||
-rw-r--r-- | defines.h | 36 | ||||
-rw-r--r-- | dict.c | 517 | ||||
-rw-r--r-- | dir.c | 257 | ||||
-rw-r--r-- | dln.c | 1088 | ||||
-rw-r--r-- | dln.h | 33 | ||||
-rw-r--r-- | enum.c | 332 | ||||
-rw-r--r-- | env.h | 40 | ||||
-rw-r--r-- | error.c | 165 | ||||
-rw-r--r-- | etc.c | 220 | ||||
-rw-r--r-- | eval.c | 1858 | ||||
-rw-r--r-- | file.c | 1059 | ||||
-rw-r--r-- | gc.c | 490 | ||||
-rw-r--r-- | ident.h | 25 | ||||
-rw-r--r-- | inits.c | 50 | ||||
-rw-r--r-- | io.c | 1221 | ||||
-rw-r--r-- | io.h | 47 | ||||
-rw-r--r-- | math.c | 125 | ||||
-rw-r--r-- | methods.c | 145 | ||||
-rw-r--r-- | missing.c | 67 | ||||
-rw-r--r-- | missing/CVS/Entries | 9 | ||||
-rw-r--r-- | missing/CVS/Repository | 1 | ||||
-rw-r--r-- | missing/getopt.c | 662 | ||||
-rw-r--r-- | missing/getopt.h | 128 | ||||
-rw-r--r-- | missing/getopt1.c | 162 | ||||
-rw-r--r-- | missing/memmove.c | 24 | ||||
-rw-r--r-- | missing/mkdir.c | 103 | ||||
-rw-r--r-- | missing/strerror.c | 19 | ||||
-rw-r--r-- | missing/strftime.c | 781 | ||||
-rw-r--r-- | missing/strstr.c | 73 | ||||
-rw-r--r-- | missing/strtol.c | 84 | ||||
-rw-r--r-- | missing/strtoul.c | 184 | ||||
-rwxr-xr-x | newver.rb | 14 | ||||
-rw-r--r-- | node.h | 216 | ||||
-rw-r--r-- | numeric.c | 962 | ||||
-rw-r--r-- | object.c | 458 | ||||
-rw-r--r-- | pack.c | 849 | ||||
-rw-r--r-- | parse.y | 2585 | ||||
-rw-r--r-- | process.c | 849 | ||||
-rw-r--r-- | random.c | 80 | ||||
-rw-r--r-- | range.c | 149 | ||||
-rw-r--r-- | re.c | 442 | ||||
-rw-r--r-- | re.h | 28 | ||||
-rw-r--r-- | regex.c | 3237 | ||||
-rw-r--r-- | regex.h | 276 | ||||
-rw-r--r-- | ruby.1 | 212 | ||||
-rw-r--r-- | ruby.c | 374 | ||||
-rw-r--r-- | ruby.h | 298 | ||||
-rw-r--r-- | sample/Artistic | 117 | ||||
-rw-r--r-- | sample/aset.rb | 3 | ||||
-rw-r--r-- | sample/attr.rb | 9 | ||||
-rw-r--r-- | sample/biorhythm.rb | 201 | ||||
-rw-r--r-- | sample/caller.rb | 15 | ||||
-rw-r--r-- | sample/case.rb | 12 | ||||
-rw-r--r-- | sample/cat.rb | 4 | ||||
-rw-r--r-- | sample/cbreak.rb | 34 | ||||
-rw-r--r-- | sample/clnt.rb | 12 | ||||
-rw-r--r-- | sample/clone.rb | 12 | ||||
-rw-r--r-- | sample/const.rb | 20 | ||||
-rw-r--r-- | sample/dbm.rb | 6 | ||||
-rw-r--r-- | sample/dir.rb | 9 | ||||
-rw-r--r-- | sample/evaldef.rb | 21 | ||||
-rw-r--r-- | sample/fib.awk | 5 | ||||
-rw-r--r-- | sample/fib.pl | 10 | ||||
-rw-r--r-- | sample/fib.rb | 8 | ||||
-rw-r--r-- | sample/freq.rb | 13 | ||||
-rw-r--r-- | sample/fullpath.pl | 22 | ||||
-rw-r--r-- | sample/fullpath.rb | 24 | ||||
-rw-r--r-- | sample/gctest.rb | 69 | ||||
-rw-r--r-- | sample/getopts.rb | 111 | ||||
-rwxr-xr-x | sample/getopts.test | 31 | ||||
-rw-r--r-- | sample/hash.rb | 4 | ||||
-rw-r--r-- | sample/io.rb | 40 | ||||
-rwxr-xr-x | sample/less.rb | 30 | ||||
-rw-r--r-- | sample/list.rb | 81 | ||||
-rw-r--r-- | sample/list2.rb | 20 | ||||
-rw-r--r-- | sample/math.rb | 4 | ||||
-rwxr-xr-x | sample/mpart.rb | 42 | ||||
-rw-r--r-- | sample/newver.rb | 13 | ||||
-rw-r--r-- | sample/occur.pl | 9 | ||||
-rw-r--r-- | sample/occur.rb | 10 | ||||
-rw-r--r-- | sample/occur2.rb | 14 | ||||
-rw-r--r-- | sample/opt_s.rb | 8 | ||||
-rw-r--r-- | sample/opt_x.rb | 8 | ||||
-rw-r--r-- | sample/parsearg.rb | 69 | ||||
-rw-r--r-- | sample/perror.rb | 7 | ||||
-rw-r--r-- | sample/rcs.awk | 33 | ||||
-rw-r--r-- | sample/rcs.dat | 17 | ||||
-rw-r--r-- | sample/rcs.rb | 42 | ||||
-rw-r--r-- | sample/reach.rb | 5 | ||||
-rw-r--r-- | sample/resp.rb | 2 | ||||
-rw-r--r-- | sample/samp.rb | 12 | ||||
-rw-r--r-- | sample/split.rb | 12 | ||||
-rw-r--r-- | sample/struct.rb | 4 | ||||
-rw-r--r-- | sample/svr.rb | 23 | ||||
-rw-r--r-- | sample/system.rb | 1 | ||||
-rw-r--r-- | sample/t1.rb | 20 | ||||
-rw-r--r-- | sample/t2.rb | 24 | ||||
-rw-r--r-- | sample/test.rb | 5 | ||||
-rw-r--r-- | sample/trap.pl | 6 | ||||
-rw-r--r-- | sample/trap.rb | 3 | ||||
-rw-r--r-- | sample/tt.rb | 103 | ||||
-rw-r--r-- | socket.c | 738 | ||||
-rw-r--r-- | spec | 3244 | ||||
-rw-r--r-- | sprintf.c | 431 | ||||
-rw-r--r-- | st.c | 365 | ||||
-rw-r--r-- | st.h | 57 | ||||
-rw-r--r-- | string.c | 1552 | ||||
-rw-r--r-- | struct.c | 274 | ||||
-rw-r--r-- | time.c | 562 | ||||
-rw-r--r-- | variable.c | 416 | ||||
-rw-r--r-- | version.c | 31 | ||||
-rw-r--r-- | version.h | 2 |
128 files changed, 34584 insertions, 0 deletions
@@ -0,0 +1,135 @@ +.\" C-IF - -*- Text -*- created at: Tue Oct 12 14:15:00 JST 1993 + +Ruby-C �����ե����� + +VALUE + + Ruby���֥������Ȥ�ɽ�����뷿. ɬ�פ˱����ƥ��㥹�Ȥ����Ѥ���. + +Qnil + + ���: nil���֥������� + +Qself + + �ѿ�: ���ߤ�self���֥������Ȥ���. �����ѿ����ͤ��ѹ�������ϰʸ�� + self���ͤ��Τ�Τ��Ѥ�äƤ��ޤ��Τ�, ���Ť˹Ԥʤ�����. + +VALUE rb_define_class(char *name, VALUE super) + + Ruby���饹���������. + +VALUE rb_define_module(char *name) + + Ruby�⥸�塼����������. + +rb_include_module(VALUE class, VALUE module) + + �⥸�塼��롼�ɤ���. class�����Ǥ�module�롼�ɤ��Ƥ� + ����ˤϲ��⤷�ʤ�(¿�ť��롼�ɤζػ�). + +void rb_define_variable(char *name, VALUE *var, + VALUE (*get_hook), VALUE (*set+hook)()) + + Ruby��C�ȤǶ�ͭ���륰�����Х��ѿ����������. Ruby���֥������Ȥ�ؤ��� + ���ѿ������Ƥ��δؿ��ˤ�ä��������ʤ���Фʤ�ʤ�(GC�����ݸ�뤿 + ��). get_hook��Qnil�Ǥʤ���, �ѿ����Ȥκݤ�get_hook�˥��åȤ��줿�ؿ� + ���ƤФ��. set_hook��Qnil�Ǥʤ����ˤ������λ���set_hook���ƤФ��. + + �ѿ�̾��`$'�ǻϤޤ�ʤ����ˤϼ�ưŪ���ɲä����. �ѿ�̾�Ȥ���ruby�μ� + �̻ҤȤ��Ƶ�����ʤ�ʸ��(�㤨��` ')��ޤ���ˤ�ruby�ץ�����फ�饢 + �������Ǥ��ʤ��ʤ�. + +void rb_global_variable(VALUE *var) + + GC��Ruby����ϥ�����������ʤ���, Ruby���֥������Ȥ�ޤ�����ѿ���ޡ� + ��������. + +void rb_read_only_hook() + + �ɤ߽Ф����Ѥ��ѿ��Τ����set_hook�ؿ�. + +rb_define_method(VALUE class, char *name, VALUE (*func)(), int argc) + + ��åɤ��������. argc��-1�λ�, ������argc, argv������Ϳ������. + +rb_define_single_method(VALUE class, char *name, VALUE (*func)(), int argc) + + �ðۥ�åɤ��������. ������rb_define_method()��Ʊ��. + +ID rb_intern(char *name) + + ʸ������б�����ID���֤�. + +char *rb_id2name(ID id) + + ID���б�����ʸ������֤�(�ǥХå���). + +VALUE rb_funcall(VALUE recv, ID mid, int narg, ...) + + ��åɸƤӽФ�. ʸ����mid�����뤿��ˤ�rb_intern()��Ȥ�. + +rb_iv_get(VALUE obj, char *name) + + obj�Υ������ѿ�������. @����Ϥޤ�ʤ��������ѿ���Ruby�� + ������फ�饢�������Ǥ��ʤ�. + +rb_iv_set(VALUE obj, char *name, VALUE val) + + obj�Υ������ѿ���val�˥��åȤ���. + +rb_call_super(VALUE args) + + �����ѡ����饹�Υ�åɤ�ƤӽФ�. args�ϰ����ꥹ�ȤȤʤ�����. args + ��Qnil�λ��ϰ����Τޤް����Ѥ�. + +rb_iterate(VALUE (*func1)(), char *arg1, VALUE (*func2)(), char *arg2) + + func2��֥��å��Ȥ������ꤷ, func1�ƥ졼���Ȥ��ƸƤ�. func1�ˤ� + arg1�������Ȥ����Ϥ���, func2�ˤ���1�����˥��ƥ졼���Ȥ���Ϳ����줿 + ��, ��2������arg2���Ϥ����. + +rb_yield(VALUE val) + + val���ͤȤ��ƥ��ƥ졼���֥��å���ƤӽФ�. + +rb_resque(VALUE (*func1)(), char *arg1, VALUE (*func2)(), char *arg2) + + �ؿ�func1��arg1������˸ƤӽФ�. func1�μ¹�����㳰��ȯ���������ˤ� + func2��arg2������Ȥ��ƸƤ�. ����ͤ��㳰��ȯ�����ʤ��ä�����func1�� + �����, �㳰��ȯ���������ˤ�func2������ͤǤ���. + +rb_ensure(VALUE (*func1)(), char *arg1, VALUE (*func2)(), char *arg2) + + �ؿ�func1��arg1������Ȥ��Ƽ¹Ԥ�, �¹Խ�λ��(���Ȥ��㳰��ȯ�����Ƥ�) + func2��arg2������Ȥ��Ƽ¹Ԥ���. ����ͤ�func1������ͤǤ���(�㳰��ȯ + ����������nil). + +GC_LINK + + ���������ѿ���GC�ݸ��Ԥʤ����. + +GC_PRO(var) + + ���������ѿ���GC�����ݸ��. ���������ѿ����ݸ��Ƥ��ʤ���ǽ���� + ����Ruby���֥������Ȥ�ؤ��Ƥ�����ˤ�GC_PRO()��Ȥä��ݸ��ɬ�פ� + ����. GC_PRO()���ݸ����ѿ���ɬ�����������Ƥ���ɬ�פ�����(̤��� + ���Υ��ߤ����äƤ��GC�������). + +GC_PRO2(var) + + GC�ݸ�, var��nil�ǽ�������뤳�Ȱʳ���GC_PRO(var)��Ʊ��. + +GC_PRO2(var, init) + + GC�ݸ�, var��init�˽�������뤳�Ȱʳ���GC_PRO(var)��Ʊ��. + +GC_UNLINK + + GC�ݸλ�����. + +/* + * Local variables: + * fill-column: 70 + * end: + */ diff --git a/CVS/Entries b/CVS/Entries new file mode 100644 index 0000000000..067e16dd65 --- /dev/null +++ b/CVS/Entries @@ -0,0 +1,51 @@ +/autoexec.c/0.15/Wed Jun 1 23:40:54 1994 Thu Mar 17 18:49:43 1994// +/class.c/0.22/Wed Jun 1 23:40:54 1994 Fri Mar 25 13:12:36 1994// +/compar.c/0.15/Wed Jun 1 23:40:54 1994 Thu Mar 17 18:49:43 1994// +/dln.h/0.14/Wed Jun 1 23:40:57 1994 Thu Mar 17 15:55:00 1994// +/error.c/0.15/Wed Jun 1 23:40:57 1994 Thu Mar 17 18:49:43 1994// +/etc.c/0.22/Wed Jun 1 23:40:58 1994 Fri Mar 25 13:12:36 1994// +/ident.h/0.17/Wed Jun 1 23:41:00 1994 Wed May 25 00:56:16 1994// +/inits.c/0.27/Wed Jun 1 23:41:00 1994 Mon Apr 25 23:30:29 1994// +/io.h/0.14/Wed Jun 1 23:41:01 1994 Thu Mar 17 15:55:00 1994// +/methods.c/0.20/Wed Jun 1 23:41:01 1994 Tue Mar 22 16:58:31 1994// +/missing.c/0.29/Wed Jun 1 23:41:01 1994 Wed Jun 1 23:36:26 1994// +/parse.y/0.35/Wed Jun 1 23:41:08 1994 Wed Jun 1 23:36:30 1994// +/random.c/0.15/Wed Jun 1 23:41:09 1994 Thu Mar 17 18:49:43 1994// +/range.c/0.15/Wed Jun 1 23:41:09 1994 Thu Mar 17 18:49:43 1994// +/re.h/0.15/Wed Jun 1 23:41:10 1994 Thu May 26 00:41:30 1994// +/regex.c/0.15/Wed Jun 1 23:41:12 1994 Wed Jun 1 23:36:35 1994// +/regex.h/0.14/Wed Jun 1 23:41:12 1994 Thu Mar 17 15:55:00 1994// +/st.h/0.14/Wed Jun 1 23:41:14 1994 Thu Mar 17 15:55:00 1994// +/variable.c/0.29/Wed Jun 1 23:41:16 1994 Wed May 25 00:56:35 1994// +/version.c/0.27/Wed Jun 1 23:41:16 1994 Mon Apr 25 23:30:35 1994// +/Makefile/0.32/Fri Jun 3 00:15:00 1994 Fri Jun 3 00:15:00 1994// +/Makefile.in/1.3/Fri Jun 3 00:15:01 1994 Fri Jun 3 00:15:01 1994// +/array.c/0.29/Fri Jun 3 00:15:02 1994 Fri Jun 3 00:15:02 1994// +/configure/1.3/Fri Jun 3 00:15:04 1994 Fri Jun 3 00:15:03 1994// +/configure.in/1.3/Fri Jun 3 00:15:04 1994 Fri Jun 3 00:15:04 1994// +/dbm.c/0.28/Fri Jun 3 00:15:05 1994 Fri Jun 3 00:15:05 1994// +/defines.h/1.4/Fri Jun 3 00:15:06 1994 Fri Jun 3 00:15:06 1994// +/dict.c/0.28/Fri Jun 3 00:15:06 1994 Fri Jun 3 00:15:06 1994// +/dir.c/0.18/Fri Jun 3 00:15:07 1994 Fri Jun 3 00:15:07 1994// +/dln.c/0.29/Fri Jun 3 00:15:08 1994 Fri Jun 3 00:15:08 1994// +/enum.c/0.16/Fri Jun 3 00:15:09 1994 Fri Jun 3 00:15:08 1994// +/eval.c/0.35/Fri Jun 3 00:15:10 1994 Fri Jun 3 00:15:09 1994// +/file.c/0.29/Fri Jun 3 00:15:11 1994 Fri Jun 3 00:15:11 1994// +/gc.c/0.30/Fri Jun 3 00:15:12 1994 Fri Jun 3 00:15:12 1994// +/io.c/0.29/Fri Jun 3 00:15:13 1994 Fri Jun 3 00:15:13 1994// +/math.c/0.28/Fri Jun 3 00:15:14 1994 Fri Jun 3 00:15:14 1994// +/node.h/0.32/Fri Jun 3 00:15:15 1994 Fri Jun 3 00:15:14 1994// +/numeric.c/0.19/Fri Jun 3 00:15:15 1994 Fri Jun 3 00:15:15 1994// +/object.c/0.32/Fri Jun 3 00:15:16 1994 Fri Jun 3 00:15:16 1994// +/pack.c/0.18/Fri Jun 3 00:15:17 1994 Fri Jun 3 00:15:17 1994// +/process.c/0.30/Fri Jun 3 00:15:18 1994 Fri Jun 3 00:15:17 1994// +/re.c/0.32/Fri Jun 3 00:15:19 1994 Fri Jun 3 00:15:18 1994// +/ruby.c/0.34/Fri Jun 3 00:15:19 1994 Fri Jun 3 00:15:19 1994// +/ruby.h/0.30/Fri Jun 3 00:15:20 1994 Fri Jun 3 00:15:20 1994// +/socket.c/0.27/Fri Jun 3 00:15:21 1994 Fri Jun 3 00:15:21 1994// +/sprintf.c/0.23/Fri Jun 3 00:15:22 1994 Fri Jun 3 00:15:21 1994// +/st.c/0.15/Fri Jun 3 00:15:22 1994 Fri Jun 3 00:15:22 1994// +/string.c/0.29/Fri Jun 3 00:15:23 1994 Fri Jun 3 00:15:23 1994// +/struct.c/0.26/Fri Jun 3 00:15:25 1994 Fri Jun 3 00:15:24 1994// +/time.c/0.29/Fri Jun 3 00:15:26 1994 Fri Jun 3 00:15:26 1994// +/version.h/1.7/Fri Jun 3 00:15:27 1994 Fri Jun 3 00:15:27 1994// diff --git a/CVS/Repository b/CVS/Repository new file mode 100644 index 0000000000..b98482fac9 --- /dev/null +++ b/CVS/Repository @@ -0,0 +1 @@ +/work/cvsroot/ruby diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..c54fa3085c --- /dev/null +++ b/ChangeLog @@ -0,0 +1,788 @@ +Mon Jul 18 10:19:15 1994 Yukihiro Matsumoto (matz@ix-02) + + * parse.y: ¿���������������롼��˥Х������ä�, 3���ǰʾ��¿�� + �����˼��Ԥ��Ƥ���. + + * eval.c(rb_eval): ¿��������, ���դ�����Ǥʤ����ˤ�`to_a'��� + �ɤ�������Ѵ�������������褦�ˤ���. ���ޤǤλ��ͤ��ȱ����ͤ��� + 1���Ǥˤ��Τޤ���������Ƥ�����, struct�ʤ�������Ѵ��Ǥ����� + ���Ѵ�������������������. + + * dbm.c,dict.c(delete_if): ��å��ɲ�. + + * process.c(wait,waitpid): �����ƥॳ����waitpid�ޤ���wait4������ + ���Ϥ������Ȥ��褦��. configure�⤽��������å�����褦���ѹ�. + + * dbm.c, dict.c(clear): ��å��ɲ�. + +Fri Jul 15 10:54:45 1994 Yukihiro Matsumoto (matz@ix-02) + + * array.c(Fary_fill,Fary_clear): ��åɤ��ɲ�. + + * string.c(Fstr_split): $;���ͤ�Ĺ��1��ʸ����Ǥ����, ��������� + ɽ�������ʤ���, ñ�ʤ�ʸ���Ȥ���ʬ�䤹��. + + * string.c(Fstr_aset/Fstr_aref): ����ǥå�����ʸ������ϰϳ����� + ������ư���Array�ͤ˽�������. + + * array.c(astore,Fary_aset): �ΰ��realloc������, �����ǥ��ꥢ���� + �褦��. ���ޤ�����˥��ߤ����äƤ���. + + * array.c: []/[]=�ǤΥ���ǥå����ط�������. ����Ū����Υ���ǥ� + �������������ʤ��¤��㳰�ϵ����ʤ��褦���ѹ�����. ɬ�פ˱�����Ŭ + ���˲�ᤷ��, ɬ�פʤ���ΰ���ĥ����褦��. + +Thu Jul 14 11:18:07 1994 Yukihiro Matsumoto (matz@ix-02) + + * autoexec.c: ���. autoload�ط��ε�ǽ�Ϻ��帡Ƥ���褦. + + * dict.c: ���饹������̾�Τ�Dict���ѹ�����. ��̾�Ȥ���Hash���� + �դ���. ���ޤ�Dictionary�ʤɤ�Ĺ��̾���ˤ��Ƥ�����ï��ȤäƤ��� + ���ä�����. *BACKWARD INCOMPATIBILITY* + + * parse.y: Dict���������빽ʸ���ɲ�. �������{..}�ˤ���. + + * parse.y: ������������빽ʸ��[..]���ѹ�����. ����Ruby������� + �ȤȤθߴ������ݤƤʤ���, Dict���������빽ʸ��Ƴ�������������, + perl5�˹�碌��(�ռ�����), �ѹ���������Ϻ������ʤ��ȹͤ���. + *BACKWARD INCOMPATIBILITY* + + * eval.c(Feval): eval()�ǥ�åɤ���������, �������륯�饹�� + ��åɤν�°���륯�饹�ˤ���. ���ޤǤ�Object���饹���������� + ����. + + * parse.y: ��������������ʤ�����eval()������Ƥ���. + +Thu Jul 14 11:18:07 1994 Yukihiro Matsumoto (matz@ix-02) + + * eval.c: ��åɤ�¸�ߤ��ʤ����ˤ�Kernel:_undefined(id)���ƤФ� + ��褦��. ������, ruby�Ǥϸġ��Υ�å���ν�������, ���饹 + ñ�̤ν�����ɬ�פʵ��⤹��ʤ�. + + * autoexec.c: ���. autoload�ط��ε�ǽ�Ϻ��帡Ƥ���褦. + + * dict.c: ���饹������̾�Τ�Dict���ѹ�����. ��̾�Ȥ���Hash���� + �դ���. ���ޤ�Dictionary�ʤɤ�Ĺ��̾���ˤ��Ƥ�����ï��ȤäƤ��� + ���ä�����. *BACKWARD INCOMPATIBILITY* + + * parse.y: Dict���������빽ʸ���ɲ�. �������{..}�ˤ���. + + * parse.y: ������������빽ʸ��[..]���ѹ�����. ����Ruby������� + �ȤȤθߴ������ݤƤʤ���, Dict���������빽ʸ��Ƴ�������������, + perl5�˹�碌��(�ռ�����), �ѹ���������Ϻ������ʤ��ȹͤ���. + *BACKWARD INCOMPATIBILITY* + + * eval.c(Feval): eval()�ǥ�åɤ���������, �������륯�饹�� + ��åɤν�°���륯�饹�ˤ���. ���ޤǤ�Object���饹���������� + ����. + + * parse.y: ��������������ʤ�����eval()������Ƥ���. + +Tue Jul 12 09:41:28 1994 Yukihiro Matsumoto (matz@ix-02) + + * pack.c: uuencode�����Υ��ݡ���. + + * `-0'��`-R'��. ���ϥ쥳���ɥ��ѥ졼���ޥ�ɥ饤����ꤹ�� + ��ˡ�Ϥʤ��ʤä�. �ɤ���, ���ͤ�����ʤ�. + +Mon Jul 11 09:51:24 1994 Yukihiro Matsumoto (matz@ix-02) + + * ruby.c: `-r'���ץ�����`-0'���ץ����ˤʤä�. ���̤�`-r'��ͭ�� + �����ѹ�������ǽ��������. `-R'�����̤Ϥ��Τޤ�. + + * version.c: versionɽ�������դ�ޤ. + + * parse.y: private method������. Ruby��private��åɤ�C++�ˤ��� + ��protected method�˳��������Τ�, `@'�ǻϤޤ�̾�������. + + * env.h: struct ENVIRON�������ʬΥ. + + * parse.y: `\$var', `\@var', `%var'������褦��. + + * variable.c(Fdefined): id������Ȥ��Ƽ����դ���褦��. + + * parse.y: ifʸ/unlessʸ�˥������then���ɲ�. then�ʤ��Ȥ����Τ�, + �ճ��ȴְ㤤��¿���Τ�. ��������ά�Ǥ���. + +Sat Jul 9 02:16:04 1994 Yukihiro Matsumoto (matz@dyna) + + * eval.c(rb_eval): class/module��ɾ���ǿ������������פ������Ƥ� + ���ʤ��ä�. �������׳��������ʬ��rb_call()����rb_eval()�˰ܤ���. + + * eval.c(rb_call): realloc()���Ϥ������Τ���, ���������ѿ��Ѥ��� + ���alloca()���Ƥ���. ���ޤ������櫓��. + + * string.c(Fstr_times): ������Ƥ��ΰ��ۤ�����ʬ���ѹ����Ƥ���. + +Wed Jul 6 15:52:42 1994 Yukihiro Matsumoto (matz@ix-02) + + * socket.c: Socket -> BasicSocket, RawSocket -> Socket �˲�̾. + + * string.c(ucfirst,lcfirst): �ǽ��1ʸ����������ʸ��/��ʸ���Ѵ�. + + * numeric.c(chr): ������ʸ����å�. + + * inits.c, dbm.c: DBM���Ȥ��ʤ����ϥ��饹���Τ�Τ�������ʤ��褦 + �ˤ���. ���ѤǤ��ʤ����饹��nil�Ȥ��뤳�Ȥ�Υݥꥷ���Ȥ��� + ��(���ޤޤǤϥ����������������ǥ��顼��ȯ�����Ƥ���). autoexec() + �Τ������⸡Ƥ��ɬ�פˤʤꤽ����. + + * bignum.c(bigadd): �Х�����. + +Thu Jul 7 11:12:18 1994 Yukihiro Matsumoto (matz@ix-02) + + * eval.c(Fload,Feval): eval_tree�ꥢ��˺��Ƥ���. + + * _inspect: ���֥������Ȥ���ɷ�����ʸ������Ѵ�����(��˥ǥХå� + ������). + +Wed Jul 6 00:57:18 1994 Yukihiro Matsumoto (matz@dyna) + + * numeric.c, bignum.c: �������Ф���`[]'�黻��. n�ӥå��ܤ����åȤ� + ��Ƥ��뤫�ɤ������֤�. + +Tue Jul 5 12:48:39 1994 Yukihiro Matsumoto (matz@ix-02) + + * io.c(Feof): �ɲ�. ���ޥ�ɥ饤��ʤ벾�ۥե�����ˤĤ��Ƥ� + EOF�����ФǤ���褦��. + + * ruby.c: -l/-r/-R/-X���ץ������ɲ�. + + * ruby.c: -n/-p���ץ�����loop���ղäʤɤ�ᥤ��롼����˰�ư�� + ��. �����, ���ץ����β��������(`-c'���ץ����Τ�����)��λ�� + �ɤȤ��ä����ȤϤʤ�. + + * io.c(Fgets): ��®��. �Ťä����Ȥʤ�����®���ä�. ������. + +Mon Jul 4 15:55:48 1994 Yukihiro Matsumoto (matz@ix-02) + + * Socket:getsockname/getpeername - �褦�䤯���ͤ����ꤷ��. + + * io.c(Fgets): each��gets�Ҥ���ΤǤϤʤ�, gets��each�Ҥ� + ��褦�ˤ���. + +Fri Jul 1 10:35:49 1994 Yukihiro Matsumoto (matz@ix-02) + + * $ENV[env] = nil/$ENV.delete(env)�ǴĶ��ѿ������Ǥ���褦�ˤʤ� + ��. $ENV.delete�ϴĶ��ѿ��ΰ������ͤ��֤�. + + * !~��������ְ�äƤ���. + + * Dict,DBM:[]= - nil�������ˤ�ä����Ǥ����Ǥ���褦�ˤʤä�. �� + ��ˤȤ�ʤ�nil��Dict�����Ǥˤʤ�ʤ��ʤä�. + + * ������������. ��IJ�Τ褦�ʻȤ��Ƥ��ʤ������ɤ�ʤ�������, �ѿ� + ̾���դ��Ѥ����ꤷ��. + +Fri Jul 1 00:21:29 1994 Yukihiro Matsumoto (matz@dyna) + + * Array:join() - ���ǿ�0��������Ф��ƶ�ʸ������֤�. + + * RawSocket:open(),socketpair() - ʸ����ǻ���Ǥ���ɥᥤ��ȥ��� + �פ��Ĥ��ɲä���. + +Thu Jun 30 13:51:29 1994 Yukihiro Matsumoto (matz@ix-02) + + * -f���ץ�����ʤ�����. ��(load�Τʤ��ä���)��̾�ĤʤΤ�, ���Ȥʤ� + �Ƥ�ɬ�פʤ�������. + + * -s���ץ������ɲ�. perl��-s���ץ�����Ʊ��ư����. + + * RawSocket���饹������. Socket���Ф��륷���ƥॳ�����٥�� + ������������ǽ�ˤʤä�. + +Thu Jun 30 00:27:19 1994 Yukihiro Matsumoto (matz@dyna) + + * Socket - bug fixes. + + * linux�Ǥ�syscall(SYS_select)�������ư��ʤ�. + + * Socket:addr,peeraddr - ����Ȥ���sockaddr�ξ�����֤�. + +Wed Jun 29 00:14:20 1994 Yukihiro Matsumoto (matz@dyna) + + * Socket:setopt,getopt - setsockopt(2), getsockopt(2)�ؤΥ������� + ��¸�. + + * sprintf() - ruby�ˤ�unsigned��̵���Τ�, %u���������. + + * sprintf() - %b, %x, %o�Ǥ�2�����ɽ��, %B, %X, %O�Ǥ�����դ�ɽ + ���ǽ��Ϥ���褦��. ����������sprintf()�λ��ͤ���餤�Ǥ�����, + ���������夭������. + +Tue Jun 28 14:42:03 1994 Yukihiro Matsumoto (matz@ix-02) + + * Bignum:<<,>> - 2�������Ȥ�����������. ���եȱ黻�ˤϴط��ʤ� + �������ä�. + + * Bignum:^ - bug fix. ��礬ȿ�Ф��ä�. + + * sprintf() - 2�ʽ��ϻ�"%b"���ɲ�. + + * sprintf() - %x, %o��Fixnum����Ϥ����, 2�����ɽ����Ԥʤ�ʤ�. + + * sprintf() - %x, %o�Ϥ�Ϥ���ο��λ���`-'����Ϥ���褦��. + +Mon Jun 27 14:56:13 1994 Yukihiro Matsumoto (matz@ix-02) + + * sprintf() - Bignum�ˤĤ��Ƥ�%d, %o��(2�����ɽ�����Ѵ�����)���� + ������ɽ������褦�ˤ���. + + * Bignum���Ф��������黻�������������. ��ο���2�����ɽ���Ǥ� + ��Ȥߤʤ�, ���IJ���Ū�˺�¦��̵�¤�1��Ϣ³���Ƥ���褦�ʱ黻�� + �̤�����. + + * Fixnum:<<,>> - ����ե��եȤ��ѹ�. + + * Bignum:>> - ��������Υ��եȤ��б�����. + + * __END__, ^D, ^Z�ǥ�����ץȤ�λ�Ǥ���. + + * -x���ץ������ɲ�. #! ..ruby�ʤ�Ԥޤ��ɤ����Ф�. + + * -c���ץ������ɲ�. ����ѥ���Τߤ�Ԥ�. + +Sat Jun 25 01:37:21 1994 Yukihiro Matsumoto (matz@dyna) + + * Fixnum:<< - ɬ�פ˱�����Bignum�˳�ĥ���ƺ����եȤ���褦��. ��� + ��, ���ե�����32��ۤ����C��Perl�Ȥϰ�ä��ͤ��֤�. + +Fri Jun 24 10:01:28 1994 Yukihiro Matsumoto (matz@ix-02) + + * ioctl()/fcntl() - �����ƥॳ�����ƤӽФ����˥Хåե����礭���� + Ĵ�᤹��褦�ˤ���. + + * String:toupper/tolower - ʸ������֤����������ԡ�����ΤǤϤ� + ��, ����ʸ��������Ƥ��ѹ�����褦�ˤ���. + + * inplace edit��¸�����. perl��Ʊ���褦��`-i'���ץ����ǻ��ꤹ��. + ��äȤ�, �������MS-DOS�Τ��ȤȤ��ͤ��Ƥʤ�����. + + * �ǥե���Ȥν�������ɲä���. ���ޤǤ�$stdout���������뤷����ˡ + �Ϥʤ��ä�. + +Fri Jun 17 10:55:08 1994 Yukihiro Matsumoto (matz@ix-02) + + * �Ķ��ѿ��˥�������������ˡ�Ȥ���getenv()/setenv()�ʳ���$ENV���� + �դ���. $ENV��ʸ����-ʸ����μ���Ǥ��뤫�Τ褦��ư���EnvDict + ���֥������Ȥ���������Ƥ���(each��assoc��Ϳ����). + + * nil�����������core dump����. ����ѥ�����Υ����å���. + + * Struct: struct_new()�ΰ�����GC�ץ��ƥ��Ȥ���ɬ�פ�����. ����ƥ� + ���å��ΰ�����Ǥ⥹�����Ǥ���褦�ˤ��ʤ���Ф����ʤ�������� + ��? �Ǥ�, �ܿ������ʤ�. + +Fri Jun 17 01:01:46 1994 Yukihiro Matsumoto (matz@dyna) + + * Time::asctime() - ���դΥե����ޥåȤ���������Ƥ���. + + * Stat: Stat��Etc�ʤɤ�Ʊ�ͤ�Struct�Ǽ¸������Τ�, Stat���饹��̵ + ���ʤä�. + +Thu Jun 16 10:32:23 1994 Yukihiro Matsumoto (matz@ix-02) + + * bignum.c: �����Ĥ��ΥХ���������. Fixnum���Ϥ��٤��Ȥ��������� + ��int���Ϥ��Ƥ���. ����. + + * big2str() - 1�夺��base�dz�������, 4�夺�ij任��Ԥʤ��褦�� + ����. �����¿��Ĺ�任�β����1/4�ˤʤ�. ���������->��(ʸ��)�� + ���Ѵ���ơ��֥���Ѥ���褦�ˤ���. + + * rb_ivar_get_1() - ���Ǥ˲��餫�Υ������ѿ�����ĥ��֥����� + �ȤǤ�, ̤����Υ������ѿ����ͤ������ͤˤʤäƤ���. + + * yylex() - �������ѿ���ǧ���˼��Ԥ��Ƥ���. attr()��������ư + ��Ƥ����Τ�, ���Ѥ����ư��ʤ��ä�. ������äƤ�������ư�� + �Ƥ����Τ�. + + * Object:attr() - ���Ǥ˥���������åɤ��������Ƥ�����ˤϥǥե� + ��ȤΥ���������åɤ�������ʤ��褦�ˤ���. ��äȤ⥢�������� + ���åɤ�Ʊ̾�Υ�åɤζ��̤�Ruby�ˤ�¸�ߤ��ʤ�����, ����ϻ��� + ���ʤ����. + + * pack.c: ����ǥ������autoconf��Ƚ�ꤹ��褦�ˤ����Τ�, v/V���� + ����褦�ˤʤä�. �ޤ�ntoh?()/hton?()�⼫�����Ѱդ���. + + * Stat: st_rdev�����������åɤ��ɲ�. ����˥����ƥबstat + ��¤�Τ�st_blksize, st_block����äƤ��뤫��autoconf�ǥ����å��� + ��褦�ˤ���. + + * �ɥ�����Ȥ���������. + + * INT2FIX()�Τ���, 31bit�����ݾڤǤ��ʤ���Τ�, int2inum()���֤��� + ����. + +Wed Jun 15 10:18:27 1994 Yukihiro Matsumoto (matz@ix-02) + + * sprintf() - bignum�ν��Ϥλ�, ��������������������褦�ˤ���. + + * str2inum() - base��0�λ�, base��ưȽ�ꤹ��褦��(0x�ǻϤޤ�� + 16 ��, 0�ǻϤޤ��8��). + +Tue Jun 14 16:08:42 1994 Yukihiro Matsumoto (matz@ix-02) + + * gc.c: Bignum���ɲä���Τ�˺��Ƥ���. �Ȥ߹��߷����ɲä������ˤ� + ɬ��mark()��sweep()�ˤ��η��˴ؤ���������ɲä���ɬ�פ�����. + + * bignum: �任��ư�����褦�ʵ�������. ���르�ꥺ������Ƥ��ʤ� + �Τ�, �������ʤ�. + +Mon Jun 13 14:36:55 1994 Yukihiro Matsumoto (matz@ix-02) + + * �ޤ����ݡ��Ȥ��Ƥ��ʤ���åɤʤɤ����뤬, �ʤ���ʤ�ˤ�Bignum + ���Ȥ���褦�ˤʤ�. �����ioctl��Ȥ���. + +Fri Jun 10 17:26:42 1994 Yukihiro Matsumoto (matz@ix-02) + + * Comparable: ���äȤʤ��åɤ�`=='��`>'����`<=>'���ѹ�����. �� + ��Comparable�Υ��֥��饹��`<=>'�������������ɬ�פ�����. + +Wed Jun 8 13:12:18 1994 Yukihiro Matsumoto (matz@ix-02) + + * Need_Fixnum()��ۤȤ�ɤʤ�����, NUM2INT()��ľ��int���Ѵ����뤳 + �Ȥˤ���. �����31bit�˴ݤ�Ʒ�����������꤬�ʤ��ʤ�. + +Tue Jun 7 09:45:31 1994 Yukihiro Matsumoto (matz@ix-02) + + * ruby.h: �ޥ���FIXABLE(n)���ɲ�. �Ĥ��Ǥ�FIXNUM�����������ѹ��� + ��, �ܿ������(�Ĥ��). + + * C++��ͽ���Ǥ���new��������. ������, �⤦�ҤȤĤ�ͽ���Ǥ��� + class�˴ؤ��Ƥ�, �֤�������ñ�줬�פ��Ĥ��ʤ����Ȥ⤢�äƤ��Τ� + �ޤˤʤäƤ���. + + * 31bit��ۤ�������INT2FIX()��ؿ��ƤӽФ����Ѥ���. ����bignum��Ƴ + �����줿���ˤϼ�ưŪ��bignum���֤��褦�ˤ���. + + * readline() - ������`-'��ɸ�����Ϥ��̣����褦�ˤʤä�. + + * ruby.h: �����եȤ��������եȤ����ѥ��եȤ��Ͻ����ϰ�¸�Τ褦�ʤ� + ��, ruby.h��cpp��Ȥäƥ����å�����褦�ˤ���. ����Ǥ��ޤ����� + �Ȼפ��Τ���, �긵�������int���������եȤ�������Ϥ��ʤ��Τdz� + ǧ�Ǥ��ʤ�. NEWS-OS��CC�ϳΤ������եȤϤ��Ĥ��������եȤ��ä��� + ���ʵ������������ɡ�. + +Mon Jun 6 10:10:22 1994 Yukihiro Matsumoto (matz@ix-02) + + * FIX2INT()��������ѹ�����. �ɤ������ΤϤ��ޤ�ư���ʤ��ä������ + ����? �⤷������, �����եȤ�����ĥ�Ͻ����ϰ�¸? + + * FIX2INT()��FIX2UINT()��Ȥ�ʬ����褦�ˤ���. ��äȤ�fixnum��31 + �ӥåȤ����ʤ��Τ�, �ܼ�Ū�ʲ��ˤϤʤ�ʤ��Τ���(ioctl���Ȥ߹� + �ߤ����ä�). + + * print��ؿ�Ū��åɤ����̾��åɤ��ѹ�. ������Ϳ�����ʤ� + ���ˤϥ쥷���Ф�ץ��Ȥ���褦�ˤ���. �����print���å����� + �����Ǥ�¹ԤǤ���褦�ˤʤä�. ��: + + ruby -e 'readlines().sort.print' + + ��Υ�����ץȤ�, �����Ȥ���Ϳ����줿(���뤤��ɸ�����Ϥ����ɤ� + ���ޤ줿)ʸ�����ƹ���˥����Ȥ���ɽ������. + + * eval.c: argc,argv�ѥ�����ǰ�����������åɤ˰�������Ĥ�Ϳ + �����ʤ���, argv��nil�ˤʤäƤ���(argv[0]�˥��������������� + �Ƥ��ޤ�). + + * _exit()���ɲ�. ��������㳰�����ʤɹԤʤ�ʤ�. + + * dbm���饹: ���饹̾�Τ�DBM(��ʸ��)�����줷��. + +Sat Jun 4 00:51:04 1994 Yukihiro Matsumoto (matz@dyna) + + * �롼���ѿ��ˤ�°�����������Ǥ����Ǥ���褦�ˤ���. + +Fri Jun 3 09:49:48 1994 Yukihiro Matsumoto (matz@ix-02) + + * ¿�������ˤ�����, °������, �������Ǥؤ�������Ԥʤ���褦�ˤ���. + + * Need_Fixnum(): nil��0���Ѵ�����褦��. + + * Enumerable:min, max, index, includes - �ɲ�. min, max�����Ǥ� + `<=>'��åɤ���Ĥ��Ȥ��ꤷ�Ƥ���. + + * Dict/Dbm:length - ���ǿ����֤���å�. + + * Dbm���饹��to_a��åɤ��ɲ�. + + * Sun�ˤ�����sort�θ�ư��η�, �����ν�����fix���줿. ������, ���� + �Ǥʤ�ư���ʤ��ä��Τ������餫�ǤϤʤ�����. ��Ӵؿ����ɤ���ͤ� + �֤��Ƥ���ꤷ���ΰ賰����������ΤϥХ��ǤϤʤ���. + + * �ե�����������Ƥ��ɤ��, �ƹԤ�����Ȥ����֤���åɤ�python�� + ���ͤˤ���`readlines'�Ȥ���̾���ˤ���. ����ˤȤ�ʤ�gets���Ф� + ��readline�Ȥ�����̾���Ѱդ���. + +Fri Jun 3 00:08:38 1994 Yukihiro Matsumoto (matz@dyna) + + * Array:sort - Ƚ�̴ؿ�������ͤ�Fixnum�ǤϤʤ�, Int�Ǥ���٤����� + ��. �ְ㤤. Sun��ư����������ä��ΤϤ��Τ��������Τ�ʤ�. + +Thu Jun 2 11:48:37 1994 Yukihiro Matsumoto (matz@ix-02) + + * IO:read_all() - ���ȥ��κǸ�ޤ����Ϥ���, �ƹԤ����ǤȤ����� + ����֤���åɤ��ɲ�. �ޤ��ؿ���å� read_all()���ɲä���. + ����ϰ����Υե����뤫���ɤ߹���dzƹԤ����ǤȤ���������֤�. �� + ̣Ū�ˤ� + + def read_all() + ary = {} + while gets() + ary.push($_) + end + end + + �Ȥۤ������Ǥ���. + + * String:atoi��åɤ���. to_a��åɤ���a������Ǥ���Ȥ�Ϣ�� + ��Ƥ��, ������ʤ�����. �����to_i��åɤ�Ȥ�����. + + * ����ؤ��Ѵ���å�to_a��Ƴ������. �̾�Υ��֥������Ȥϼ�ʬ���� + ��ͣ������ǤȤ���Ĺ��1��������֤�. ����ϼ�ʬ���Ȥ�, ����ϥ��� + ���ͤΥڥ���������֤�. Enumerated��include�������饹��, each�� + �֤������Ǥ�ޤ�������֤�. + + * file.c: ����Ĥΰ���������Ȥ��å�(chmod,chown,utimes)��� + ������, ��������. �����ȼ��, �ǽ�����Ƥΰ����η������å���Ԥ� + ���褦�ˤ���. �������å��˼��Ԥ���Ƚ�����Ԥʤ鷺���㳰��ȯ���� + ����. + + * configure.in: ��ɬ�פʥƥ��Ȥ�Ԥʤ�ʤ��褦�˽�������. + +Tue May 31 10:41:08 1994 Yukihiro Matsumoto (matz@ix-02) + + * String:pack(): 2�ʿ���ʸ�����Ѵ�(B,b)��0��1���դ��ä�. + + * Math.c: �¿��ϤΥ�åɤ˰����Ȥ����������Ϥ��줿���˼�ưŪ���� + ������褦�ˤ���. + + * toupper(), tolower(): ʸ�����Ƚ��ߥ����Ѵ�����Ƥ��ʤ��ä�. + + * getopt_long()�λ��ͤˤ�ä�, ������ץȤؤΰ��������ץ�� + �������Ȳ�ᤵ��Ƥ���. �����ѥ�����ʸ�������Ƭ��`+'���ɲ�. + + * config.h��������. DEFINE��Makefile��Ϳ������. + + * sprintf(): "%d"��ʸ����Ϳ����줿���ˤϥ��ɥ쥹�ǤϤʤ����Ƥ� + �������Ѵ�����褦�ˤ���. �Ĥ��Ǥ���ư�����������Ѵ�����褦���� + ������. + + * regexp.c: ruby�γ�ĥ����ɽ��(\d, \D, \s, \S)�ν����dz�����Ƥ��� + ���ۤ��ƥХåե��˽���Ǥ���. �������˥Хåե�����ȳ� + ĥ����褦�ˤ���. ����Ǻ�������ˤ��Ƥ������������ϲ��Ǥ� + ���Ȼפ�. + + * yylex(): ���֥륯������ʸ������ǥ��֥륯�����Ȥ�ɽ�����뤿�� + �ΥХå�����å���ɽ�����Ǥ��ʤ��ä�. + +Mon May 30 10:07:42 1994 Yukihiro Matsumoto (matz@ix-02) + + * �黻��`!'�α��դ��P�Ǥ���Ȥ���. ����ˤ�ä�, ���α黻�Ҥ� + ���������ͤϺ��𤹤뤫���Τ�ʤ���, ��¿���Τ��α黻�Ҥ�Ȥ��� + �Ϻ�����뤳�Ȥ��Ǥ���Ȼפ�. + + * autoconf��Ȥä�, ��ưŪ��Makefile, config.h����������褦�ˤ���. + �����, ����Υޥ���Ǥ�`configure'��¹Ԥ�����, `make'��ȯ�ǥ� + ��ѥ���Ǥ���Ȼפ�. + + * clone: ���֥��饹���Ф����Ѥ���줿���, ���Υ��֥������Ȥ�Ʊ�� + ���饹�Υ������֤��褦��(�����ϥӥ�ȥ��饹�ξ��� + �ͤ��Ƥʤ��ä�). + + * �ӥ�ȥ��饹�Υ��֥��饹�����褦��, ��ƥ��Τ��륯�饹 + �ˤ�new��åɤ��ɲä���. + + * malloc()�������. purify��ɬ�פ����Τ�ʤ�. + + * re.c: rb_global_variable()�θƤӤ��������δְ㤤. �ѿ��ؤΥݥ��� + �����Ϥ��ʤ���Ф����ʤ�. + + * parse.y: ���������ѿ��ΰ����˰�����ɾ����˰�¸����ܿ����Τʤ� + ��ʬ�����ä�. + + * attr(): °������ΥХ���ľ����. �����������ͤ��Ѥ�ä����������? + +Sat May 28 23:08:18 1994 Yukihiro Matsumoto (matz@dyna) + + * ����ɽ������å����ʸ�������Ƚ���ݥ����פ������ư��פ��� + ������. ����������ʸ�����ƥ��ϰ����˿��������֥������Ȥ��� + �������Τ��ä�. + +Fri May 27 11:42:00 1994 Yukihiro Matsumoto (matz@ix-02) + + * ����ɽ����ʸ�������ɤΥǥե���Ȥ�������б��ˤ���. ����ˤ�ä� + �㴳�ι�®�����ޤ��. + + * tr����ʸ�����(delete), ʸ������(squeeze)��ʬΥ����. ����ˤȤ� + �ʤ�tr�Υ��ץ��������Ϥʤ��ʤä�. + +Thu May 26 10:32:55 1994 Yukihiro Matsumoto (matz@ix-02) + + * ������ץ��ɤ߹��ߥ롼������ľ����, �̾�ե�����ʳ��Υե��� + ��̾���ʸ��������ץȤȤ���Ϳ����줿�����б�����. �ޤ�, + ɸ�����Ϥ��饹����ץȤ��ɤ߹������, ����ե����뤬/tmp�˻Ĥ�� + ���褦�ˤ���. + + * Fixnum:id2name - ID����ʸ������᤹�ؿ�. String:intern�ε�. + + * Array: ������ϰϳ������Ǥ��������������㳰��ȯ����������, + nil���֤��褦�ˤ���. ����ϼ�ưŪ�˳�ĥ�����. + + * string:strip���ɲ�. + + * -n���ץ����-e���ץ�����ʣ�����ꤷ������ư���褦��. + + * parse.y��<sys/types.h>�⥤�롼�ɤ���褦�ˤ���. + + * fname����κ٤���bug����. + +Wed May 26 11:45:10 1994 Yukihiro Matsumoto (matz@dyna) + + * �����å��夹��褦�ˤ���. �����֤���¿�����ˤ�ͭ���ΤϤ� + ����, ���٤��������������ʤ������٤��ʤ�ʤ�. + +Wed May 25 00:42:24 1994 Yukihiro Matsumoto (matz@dyna) + + * ¿������ʸ(foo, bar = 1, 2)�κ���. + + * ��P����ʸ���뤤������ɽ����ƥ�����`=~'�黻�Ҥˤ�� + ��`$_'����Ӥ����. ����`...'��ξ�դǤ�������ƥ�뤬`$.'����� + �����. + +Mon May 23 23:27:03 1994 Yukihiro Matsumoto (matz@dyna) + + * &�� �����Ϥʤ��ʤä�. �����kernel:apply(id, args..)��Ƴ��. + + * def op () ..������Ƴ��. op�Ϻ������ǽ�ʱ黻��. + + * constant�������������å�. ���˽��������Ƥ������������������� + ���㳰��ȯ������. + + * ¿������ʸ. + +Thu May 19 22:57:07 1994 Yukihiro Matsumoto (matz@dyna) + + * ʣ��ʸ�Ǥ�void value�Υ����å���Ԥ��褦�ˤ���. + + * until��ư��ν���(do..until�����ä�). + +Wed May 18 01:06:25 1994 Yukihiro Matsumoto (matz@dyna) + + * �ܿ��˴ؤ���㴳���������. + + * ��̾�ι�ʸ���def a b�פˤ���. + + * until/unless: �黻�Ҥ�������ʸ��. �㳰����ª���뵡ǽ�Ϥ��Τޤ�. + + * �����ǽ�ʵ�ǽ��config.h����defines.h�˰�ư. + +Fri May 13 23:20:21 1994 Yukihiro Matsumoto (matz@dyna) + + * -y���ץ�������. -d���ץ���饳��ѥ���ΥǥХå���ʬ��ʬ + Υ����. + +Tue Apr 25 20:17:33 1994 Yukihiro Matsumoto (matz@dyna) + + * �ޥ���Х���ʸ������̻Ҥ˻Ȥ���褦��. �Ŀ�Ū�ˤϻȤ�������̵ + �����ɤʤ�. + + * `-v'�ե饰�ξ��֤�$verbose�ǥ��������Ǥ���褦��. + + * CVS��Ƴ����ȼ��, �С�������������ˡ���ѹ�. + + * �����ܤ�ChangeLog��Ĥ�����ˤ���. + +Tue Mar 8 10:09:25 1994 Yukihiro Matsumoto (matz at nws119) + + * %�ѿ�̾ �ˤ�륯�饹�����Ƴ��. + + * undef ��å� �ˤ���å�����μ��ä���Ƴ��. + + * rb_get_method_body�Ǥ�the_env���ѹ�����, rb_call()������Ū���ѹ� + ����褦��. �����responds_to�ʤɤǴĶ����˲�����ʤ�. + +Mon Mar 7 17:46:15 1994 Yukihiro Matsumoto (matz at nws119) + + * ��&ʸ�������. �ּ�.ʸ������Υ�å���������ɤϤʤ��ʤä�. + + * ������������(+=. -=, ...) + + * obj.attr = expr�����κ���. + +Thu Feb 24 16:23:28 1994 Yukihiro Matsumoto (matz at nws119) + + * toint, tofloat, print_string�줾��to_i, to_f, to_s���ѹ�. + + * String:clone - Copy on Write�μ¸�. + +Tue Feb 22 11:11:44 1994 Yukihiro Matsumoto (matz at nws119) + + * re.c: �ޥå�����ʸ�������¸�˼��Ԥ��Ƥ���. + + * trap: ��ǽ�ʤ�н����˻��֤Τ����륷���ƥॳ����(read, wait, + sigpause, select)��եå����Ƴ����߽�����¨���������(DOS�� + �ɤǤ�̵�����ʤ�). + + * trap: �����ߤξ�ǽ������뤫(��®��������), �����ʥ����ߥ� + ���ǽ������뤫������Ǥ���褦��. + +Tue Feb 17 11:11:12 1994 Yukihiro Matsumoto (matz at nws119) + + * trap: �����ߥϥ�ɥ�. + +Wed Feb 16 12:29:12 1994 Yukihiro Matsumoto (matz at nws119) + + * String:crypt: �Ź沽�롼���� + + * "::"�黻�Ҥ��ɲ�. a::b �� {a, b}��Ʊ��. a::b::c �� {a, {b, c}}�� + Ʊ��(�����). Ʊ���ȤϤ�����Τ�, "::"�黻�Ҥ�Ȥä������������� + �����Ψ���ɤ�. + + * Dir.rmdir(), File.unlink(), File.utime() -- �ƥ����ƥॳ����ؤ� + ���ե�����. + + * kill -- kill(2) I/F + + * select(): read�Υ����å��Ǥ�stdio�˥Хåե������Ƥ��뤫�� + ����������å�����褦��. + +Tue Feb 15 15:08:31 1994 Yukihiro Matsumoto (matz at nws119) + + * file.c: stat��å��夹��褦��. + + * File:utime()���ɲ�. + + * unliteralize(): �ե饰���˲����Ƥ���. + + * Bug(): core���Ǥ��褦��. + + * String:tr -- tr(1)�ߴ�. �����ѥ�������äȰ㤦���ɡ�. + +Mon Feb 14 18:24:13 1994 Yukihiro Matsumoto (matz at nws119) + + * unless, until���㳰��ȸ��ʤ��褦��. + + * select() -- select(2) I/F + + * Array:pack, String:unpack: perl��pack/unpack��Ʊ���� + +Tue Feb 8 17:11:10 1994 Yukihiro Matsumoto (matz at nws119) + + * setenv()�Τʤ������ƥ�Τ����putenv()��Ȥä������ɤ��Ѱդ���. + +Mon Feb 7 09:52:44 1994 Yukihiro Matsumoto (matz at nws119) + + * �����ΰ��ֺǸ��`*'���֤���褦�ˤ���. �����rest�����Υꥹ�Ȥ� + ����ɬ�פ����ʤ��ʤ�. + +Fri Feb 4 18:23:26 1994 Yukihiro Matsumoto (matz at nws119) + + * ruby-mode.el���ľ��. �����֤�ޤ��ˤʤä��Ȼפ�. + + * ʸ�����ƥ���Copy on Write��¸�. �����ʸ����ƥ��Ǥ� + �뤫��Ȥ��äƤ�������clone���ʤ��Ƥ�Ѥ�. + +Tue Feb 1 09:21:09 1994 Yukihiro Matsumoto (matz at nws119) + + * sub(), gsub()��, �ޥå�����ʸ�����$&, $1..$9�ǥ��������Ǥ���� + ���ˤ���. Ʊ���˥ޥå�������ʬʸ����ԡ����Ƥ����褦��(���� + ʸ�����ѹ�����Ƥ���֤���¸���뤿��). + +Mon Jan 31 15:16:58 1994 Yukihiro Matsumoto (matz at nws119) + + * �ץ饤�١��ȥ�åɤλ��ͤ��ѹ�. ���ޤǤ�Ʊ�����饹�Υ�åɤ� + �餷�����������Ǥ��ʤ��ä���, ���֥��饹�Υ�åɤ���⥢������ + �Ǥ���褦�ˤ���(C++�ˤ�����protected ���дؿ�). + + * ��åɥ������Υ��르�ꥺ��������, 10%���٤ι�®����Ԥʤä�. + + * ��®��. C�ǵ��Ҥ��줿��åɤ�ƤӽФ����ˤ�setjmp��ƤФʤ��� + ���ˤ���. �����C��åɤ�¿�Ѥ�����ˤ�3�����ٹ�®�ˤʤä�. + +Fri Jan 28 15:44:04 1994 Yukihiro Matsumoto (matz at nws119) + + * sh-mode��ruby-mode.el����. �黻�Ҥǽ���, 2�Ԥ��Ϥ�ʸ�ˤ��� + �����Ƥ��ʤ����ɡ�. + +Thu Jan 27 11:35:19 1994 Yukihiro Matsumoto (matz at nws119) + + * freenode(): NODE_NIL�β���˺��. + + * ����������ΥХ�����(�����Ȥθ�ξ��֤��ᤷ˺��). + + * protect .. end�ΥХ�����. GC_LINK�Υͥ��Ȥ��������ä�. + + * join�ΥХ�����(�ȤäƤ��륪�֥������Ȥ�free���Ƥ���). + + * split�ΥХ�����(���르�ꥺ�ब���������ä�). + + * fork()���ɲ�. + +Wed Jan 26 17:09:56 1994 Yukihiro Matsumoto (matz at nws119) + + * �ե�����ƥ��ȥ�åɤ��ɲ�. + + * rb_autoexec(): ���饹����ƥ��������������ε�ư������Ǥ���� + ���ˤ���. �����autoload��¸��Ǥ���. ����ˤȤ�ʤ���å� + unknown�Ϥʤ��ʤä�. + +Tue Jan 25 15:51:36 1994 Yukihiro Matsumoto (matz at nws119) + + * Dbm���饹, Math�⥸�塼������. + + * -I���ץ����ǥ������ѥ����ɲäǤ���褦��. + + * �������ѥ����ѿ�$load_path������Ǥ���褦��. + + * load(): �����ʥߥå������ɤ�Ȥ���褦�ˤ���. + +Tue Jan 18 14:14:01 1994 Yukihiro Matsumoto (matz at nws119) + + * Comparable:"<=>" + + * Float,Fixnum:"**" + + * Array:sort + +Fri Jan 14 16:53:37 1994 Yukihiro Matsumoto (matz at nws119) + + * version 0.07 + + * ��åɤ˴ؤ���ɥ�����Ȥ¤�����. + + * String:index(): ����position�����䤷��. + +Thu Jan 13 15:13:52 1994 Yukihiro Matsumoto (matz at nws119) + + * ̤��������ѿ�����������ʤ�����. + + * ̵�̤�hash table�Υ���������������. + + * Purify'd(on Sun) + + * ~RE �� ~STR�Υ���ѥ����Ÿ��������. + + * Sun�ذܿ�. signal()�������. RData��bug����. + + * parse.y: nls�롼�����. + + * yylex(): ���Ԥ����β�����ʬ���ѹ�. + + * missing/strftime.c: �ܿ���. + + * Time:strftime: ����¾�Υ�åɤ�strftime�����Ѥ���褦��. + + * ��åɺ�������˥�åɥ���å���ꥢ����. + +Fri Jan 7 15:23:20 1994 Yukihiro Matsumoto (matz at nws119) + + * Float:coerce(): Fixnum��Float�ʳ��ΰ�����Ϳ�����뤿���ˤ��㳰 + ��ȯ������褦��. + + * Stat: stat��¤�Τ����ƤΥ��Ф��Ф��륢��������åɤ��Ѱ�. + + * ̤����Υ��饹/�⥸�塼��ؤλ��Ȥ�unknown��åɤ�ƤӽФ��褦 + �ˤ���. + + * baseline - version 0.06. @@ -0,0 +1,65 @@ +.\" FAQ - -*- Indented-Text -*- created at: Tue Jan 4 12:48:12 JST 1994 +�����Ruby�˴ؤ���FAQ(Frequently Asked Question)��ޤȤ��ΤǤ�. +Emacs�Ǥ��Υե�����Ƥ�����ˤ�M-2 C-x $�Ǽ������ʬ�������ɤळ +�Ȥ��Ǥ��ޤ�. C-x $�����Ƥ��ɤ���֤��᤻�ޤ�. +------------------------------ +1) Ruby��̾�Τ�ͳ��� + + Ruby�ϲ�����ά�ΤǤϤʤ�, �֤����Ф�̾����Ȥä�̾�դ����ޤ���. + perl(pearl��6���������)�μ����ܻؤ�(Ruby��7���������)�Ȥ�����̣ + ������ޤ�. �������������ͤ����ΤǤ��ä��ߤ����Ȥ����ꤤ��ޤޤ� + �Ƥ��ޤ�. +------------------------------ +2) Ruby���ƶ�������������? + + Ruby�θ�����ͤ�C, Perl, Eiffel�γƸ���ˤ��ν�˱ƶ�������Ƥ��� + ��. ����¾�˱ƶ������������Ȥ��Ƥ�tcl, AWK, bourne shell, CLU, + Icon, Sather, Smalltalk, Emacs Lisp�ʤɤ�����ޤ�. +------------------------------ +3) Ruby����ħ��? + + �ʲ��˲վ��ˤ��ޤ�. + + + ���ץ�Ǥ���, ��ڤ˥ץ������Ǥ���. + + �ѿ�������פ�ʤ�. + + �ե�����䥹�ȥ��ʤɤؤ�UNIXŪ������ñ�ˤǤ���. + + �Х��ʥ�ե�����ⰷ����. + + ������Ȥ������֥������Ȼظ�����Ǥ���. + + �ðۥ�åɤε�ǽ������Ƥ���. + + �⥸�塼��ˤ�뵡ǽ�ζ�ͭ���Ǥ���. + + �㳰������ǽ������. + + GC������Τǥ�������ˤ��ʤ��ƺѤ�. + + ������Τ���������. + + ʣ���ʥǡ�����¤�ⰷ����. + + �����ʥߥå������ɤݡ��Ȥ���(�����ƥ�ˤ��). + + �դ˷����� + + - ȯŸ�Ӿ�ǵ�ǽ�����ʤ�. + - �ǥХå���(�ޤ�)�ʤ�. + - �٤�. + + ���ȤǤ��礦��. +------------------------------ +4) Ruby���ѿ�������ʤ����ȤΥ��åȤ�? + + �����ѿ����ɤΥ������פ�°���뤫�����ܤ�ʬ����Τ�, �ץ��������ɤ� + �פ�, ���פ����������Ȥ�����Υ��åȤǤ�. �ޤ��ȡ�����Υ����� + �̤�����Τǽפ�, ��ڤ��ˤ�����ޤ�. +------------------------------ +5) Ruby��Perl�ΰ㤤��? + + Ruby��Perl�ϥƥ���������ͥ�줿������ץȸ���Ǥ���Ȥ�������, �� + �С������ϰϤ��, �츫����ȥ饤�Х�˸����ޤ�. �Τ���Ruby���߷� + �ˤ����ơ�Perl�ˤǤ��뤳�ȤϤǤ���褦�ˡפȤ������Ȥ�, ��Ĥν��� + ����ɸ�Ǥ���. ������, Ruby�ο�����Ū�Ϥ����ޤǤ�ּ�ڤʥ��֥����� + �Ȼظ�����פǤ���, �ޤ�, Ruby�߷פ�3����ɸ�Ǥ���, ��ǽ����������� + ��ĥ���η�̤Ȥ���, Ruby��Perl�Ȥϰۤʤ����ˤʤ�ޤ���. + + Ruby��Perl�ۤɡֲ��Ǥ⤢��פǤϤ���ޤ���, �ۤȤ�ɤξ��Perl�� + �����®�٤��٤��Ǥ�. ������, Ruby�Υ��֥������Ȼظ���ǽ��Perl�Ǥ� + ���Ǥ��ʤ��ͤ����˥��ԡ��뤹��Ȼפ��ޤ�. +------------------------------ +Local variables: +fill-column: 70 +end: diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..a5d9bab730 --- /dev/null +++ b/Makefile @@ -0,0 +1,202 @@ +# Generated automatically from Makefile.in by configure. +# Main Makefile for GNU m4. +# Copyright (C) 1992 Free Software Foundation, Inc. + +# 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 2, 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 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# 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. + +SHELL = /bin/sh + +#### Start of system configuration section. #### + +srcdir = . +VPATH = . + +CC = gcc -traditional +DBM = -fpcc-struct-return +YACC = bison -y +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = $(INSTALL) +INSTALL_DATA = $(INSTALL) -m 644 +MAKEINFO = makeinfo + +CFLAGS = -g +LDFLAGS = -static $(CFLAGS) +LIBS = -lm -ldbm +DEFS = -DHAVE_UNISTD_H=1 -DHAVE_SYSCALL_H=1 -DHAVE_A_OUT_H=1 -DDIRENT=1 -DGETGROUPS_T=int -DRETSIGTYPE=void -DHAVE_STRTOL=1 -DHAVE_STRDUP=1 -DHAVE_KILLPG=1 -DHAVE_MKDIR=1 -DHAVE_STRFTIME=1 -DHAVE_PUTENV=1 -DHAVE_ALLOCA_H=1 -DPW_AGE=1 -DPW_COMMENT=1 + +prefix = /usr/local +binprefix = +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +infodir = $(prefix)/info + +#### End of system configuration section. #### + +.c.o: + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I$(srcdir)/lib $< + +HDRS = defines.h \ + dln.h \ + ident.h \ + io.h \ + node.h \ + re.h \ + regex.h \ + ruby.h \ + st.h \ + version.h + +SRCS = array.c \ + autoexec.c \ + class.c \ + compar.c \ + dbm.c \ + dict.c \ + dir.c \ + dln.c \ + enum.c \ + error.c \ + etc.c \ + eval.c \ + file.c \ + gc.c \ + inits.c \ + io.c \ + math.c \ + methods.c \ + missing.c \ + numeric.c \ + object.c \ + pack.c \ + parse.y \ + process.c \ + random.c \ + range.c \ + re.c \ + regex.c \ + ruby.c \ + socket.c \ + sprintf.c \ + st.c \ + string.c \ + struct.c \ + time.c \ + variable.c \ + version.c + +OBJS = array.o \ + autoexec.o \ + class.o \ + compar.o \ + dbm.o \ + dict.o \ + dir.o \ + dln.o \ + enum.o \ + error.o \ + etc.o \ + eval.o \ + file.o \ + gc.o \ + inits.o \ + io.o \ + math.o \ + methods.o \ + missing.o \ + numeric.o \ + object.o \ + pack.o \ + parse.o \ + process.o \ + random.o \ + range.o \ + re.o \ + regex.o \ + ruby.o \ + socket.o \ + sprintf.o \ + st.o \ + string.o \ + struct.o \ + time.o \ + variable.o \ + version.o + +DISTFILES = README NEWS TODO THANKS COPYING INSTALL \ +ChangeLog Makefile.in configure.in \ +$(HDRS) $(SRCS) configure + +PROGRAM = ruby + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) + @echo -n "Loading $(PROGRAM) ... " + @rm -f $(PROGRAM) + @$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) + @echo "done" + +install: $(PROGMAM) + $(INSTALL_PROGRAM) $(PROGRAM) $(bindir)/$(PROGRAM) + +clean:; @rm -f $(OBJS) + +realclean:; @rm -f $(OBJS) + @rm -f core ruby *~ + +dbm.o:dbm.c + $(CC) -c $(DBM) $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I$(srcdir)/lib dbm.c + +# Prevent GNU make v3 from overflowing arg limit on SysV. +.NOEXPORT: +### +array.o : array.c ruby.h defines.h +autoexec.o : autoexec.c ruby.h defines.h +class.o : class.c ruby.h defines.h node.h st.h +compar.o : compar.c ruby.h defines.h +dbm.o : dbm.c ruby.h defines.h +dict.o : dict.c ruby.h defines.h st.h +dir.o : dir.c ruby.h defines.h +dln.o : dln.c defines.h dln.h +enum.o : enum.c ruby.h defines.h +error.o : error.c ruby.h defines.h +etc.o : etc.c ruby.h defines.h +eval.o : eval.c ruby.h defines.h node.h ident.h st.h +file.o : file.c ruby.h defines.h io.h +gc.o : gc.c ruby.h defines.h st.h +inits.o : inits.c +io.o : io.c ruby.h defines.h io.h +math.o : math.c ruby.h defines.h +methods.o : methods.c ruby.h defines.h node.h +missing.o : missing.c ruby.h defines.h missing/memmove.c missing/strerror.c \ + missing/strtoul.c missing/strftime.c missing/getopt.h missing/getopt.c missing/getopt1.c +numeric.o : numeric.c ruby.h defines.h +object.o : object.c ruby.h defines.h +pack.o : pack.c ruby.h defines.h +process.o : process.c ruby.h defines.h st.h +random.o : random.c ruby.h defines.h +range.o : range.c ruby.h defines.h +re.o : re.c ruby.h defines.h re.h regex.h +regex.o : regex.c regex.h +ruby.o : ruby.c ruby.h defines.h re.h regex.h missing/getopt.h +socket.o : socket.c ruby.h defines.h io.h +sprintf.o : sprintf.c ruby.h defines.h +st.o : st.c st.h +string.o : string.c ruby.h defines.h re.h regex.h +struct.o : struct.c ruby.h defines.h +time.o : time.c ruby.h defines.h +variable.o : variable.c ruby.h defines.h st.h ident.h +version.o : version.c ruby.h defines.h \ + version.h diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000000..33338c9e61 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,186 @@ +SHELL = /bin/sh + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +DBM = @DBM@ +YACC = @YACC@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +MAKEINFO = makeinfo + +CFLAGS = -g +LDFLAGS = @STATIC@ $(CFLAGS) +LIBS = @LIBS@ +DEFS = @DEFS@ + +prefix = /usr/local +binprefix = +exec_prefix = $(prefix) +bindir = $(exec_prefix)/bin +infodir = $(prefix)/info + +#### End of system configuration section. #### + +.c.o: + $(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I$(srcdir)/lib $< + +HDRS = defines.h \ + dln.h \ + ident.h \ + io.h \ + node.h \ + re.h \ + regex.h \ + ruby.h \ + st.h \ + version.h + +SRCS = array.c \ + bignum.c \ + class.c \ + compar.c \ + dbm.c \ + dict.c \ + dir.c \ + dln.c \ + enum.c \ + error.c \ + etc.c \ + eval.c \ + file.c \ + gc.c \ + inits.c \ + io.c \ + math.c \ + methods.c \ + missing.c \ + numeric.c \ + object.c \ + pack.c \ + parse.y \ + process.c \ + random.c \ + range.c \ + re.c \ + regex.c \ + ruby.c \ + socket.c \ + sprintf.c \ + st.c \ + string.c \ + struct.c \ + time.c \ + variable.c \ + version.c + +OBJS = array.o \ + bignum.o \ + class.o \ + compar.o \ + dbm.o \ + dict.o \ + dir.o \ + dln.o \ + enum.o \ + error.o \ + etc.o \ + eval.o \ + file.o \ + gc.o \ + inits.o \ + io.o \ + math.o \ + methods.o \ + missing.o \ + numeric.o \ + object.o \ + pack.o \ + parse.o \ + process.o \ + random.o \ + range.o \ + re.o \ + regex.o \ + ruby.o \ + socket.o \ + sprintf.o \ + st.o \ + string.o \ + struct.o \ + time.o \ + variable.o \ + version.o + +DISTFILES = README NEWS TODO THANKS COPYING INSTALL \ +ChangeLog Makefile.in configure.in \ +$(HDRS) $(SRCS) configure + +PROGRAM = ruby + +all: $(PROGRAM) + +$(PROGRAM): $(OBJS) + @echo -n "Loading $(PROGRAM) ... " + @rm -f $(PROGRAM) + @$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM) + @echo "done" + +install: $(PROGMAM) + $(INSTALL_PROGRAM) $(PROGRAM) $(bindir)/$(PROGRAM) + +clean:; @rm -f $(OBJS) + +realclean:; @rm -f $(OBJS) + @rm -f core ruby *~ + +dbm.o:dbm.c + $(CC) -c $(DBM) $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I$(srcdir)/lib dbm.c + +# Prevent GNU make v3 from overflowing arg limit on SysV. +.NOEXPORT: +### +parse.o : parse.y ruby.h defines.h env.h ident.h node.h st.h regex.h +### +array.o : array.c ruby.h defines.h +bignum.o : bignum.c ruby.h defines.h +class.o : class.c ruby.h defines.h env.h node.h st.h +compar.o : compar.c ruby.h defines.h +dbm.o : dbm.c ruby.h defines.h +dict.o : dict.c ruby.h defines.h st.h +dir.o : dir.c ruby.h defines.h +dln.o : dln.c defines.h dln.h +enum.o : enum.c ruby.h defines.h +error.o : error.c ruby.h defines.h env.h +etc.o : etc.c ruby.h defines.h +eval.o : eval.c ruby.h defines.h env.h node.h ident.h st.h +file.o : file.c ruby.h defines.h io.h +gc.o : gc.c ruby.h defines.h env.h st.h +inits.o : inits.c +io.o : io.c ruby.h defines.h io.h +math.o : math.c ruby.h defines.h +methods.o : methods.c ruby.h defines.h env.h node.h +missing.o : missing.c ruby.h defines.h missing/memmove.c missing/strerror.c \ + missing/strtoul.c missing/strftime.c missing/strstr.c missing/getopt.h missing/getopt.c \ + missing/getopt1.c missing/mkdir.c +numeric.o : numeric.c ruby.h defines.h env.h +object.o : object.c ruby.h defines.h env.h node.h st.h +pack.o : pack.c ruby.h defines.h +process.o : process.c ruby.h defines.h st.h +random.o : random.c ruby.h defines.h +range.o : range.c ruby.h defines.h +re.o : re.c ruby.h defines.h re.h regex.h +regex.o : regex.c regex.h +ruby.o : ruby.c ruby.h defines.h re.h regex.h missing/getopt.h +socket.o : socket.c ruby.h defines.h +sprintf.o : sprintf.c ruby.h defines.h +st.o : st.c st.h +string.o : string.c ruby.h defines.h re.h regex.h +struct.o : struct.c ruby.h defines.h env.h +time.o : time.c ruby.h defines.h +variable.o : variable.c ruby.h defines.h env.h node.h ident.h st.h +version.o : version.c ruby.h defines.h version.h @@ -0,0 +1,6 @@ +* $0�ؤ�������ps�ν��Ϥ��Ѳ�������褦�� +* ruby����������ѿ�hook�μ¸� +* FUNC�����Υ�åɤ�������ɬ�פ� +* write debugger for ruby +* re-write regex code for speeding +* byte code interpretor diff --git a/array.c b/array.c new file mode 100644 index 0000000000..91c06a3f6f --- /dev/null +++ b/array.c @@ -0,0 +1,805 @@ +/************************************************ + + array.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:20 $ + created at: Fri Aug 6 09:46:12 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +VALUE C_Array; + +static ID eq; + +#define ARY_DEFAULT_SIZE 16 + +VALUE +ary_new2(len) +{ + NEWOBJ(ary, struct RArray); + OBJSETUP(ary, C_Array, T_ARRAY); + + GC_LINK; + GC_PRO(ary); + ary->len = 0; + ary->capa = len; + ary->ptr = ALLOC_N(VALUE, len); + GC_UNLINK; + + return (VALUE)ary; +} + +VALUE +ary_new() +{ + return ary_new2(ARY_DEFAULT_SIZE); +} + +#include <varargs.h> + +VALUE +ary_new3(n, va_alist) + int n; + va_dcl +{ + va_list ar; + struct RArray* ary; + int len, i; + + if (n < 0) { + Fail("Negative number of items(%d)", n); + } + ary = (struct RArray*)ary_new2(n<ARY_DEFAULT_SIZE?ARY_DEFAULT_SIZE:n); + + va_start(ar); + for (i=0; i<n; i++) { + ary->ptr[i] = va_arg(ar, VALUE); + } + va_end(ar); + + ary->len = n; + return (VALUE)ary; +} + +VALUE +ary_new4(n, elts) + int n; + VALUE *elts; +{ + struct RArray* ary; + + GC_LINK; + GC_PRO4(elts, n); + ary = (struct RArray*)ary_new2(n); + memcpy(ary->ptr, elts, sizeof(VALUE)*n); + ary->len = n; + GC_UNLINK; + + return (VALUE)ary; +} + +VALUE +assoc_new(elm1, elm2) + VALUE elm1, elm2; +{ + struct RArray *ary; + + GC_LINK; + GC_PRO(elm1); GC_PRO(elm2); + ary = (struct RArray*)ary_new2(2); + ary->ptr[0] = elm1; + ary->ptr[1] = elm2; + ary->len = 2; + GC_UNLINK; + + return (VALUE)ary; +} + +static VALUE +Fary_new(class) + VALUE class; +{ + NEWOBJ(ary, struct RArray); + OBJSETUP(ary, class, T_ARRAY); + + GC_LINK; + GC_PRO(ary); + ary->len = 0; + ary->capa = ARY_DEFAULT_SIZE; + ary->ptr = ALLOC_N(VALUE, ARY_DEFAULT_SIZE); + GC_UNLINK; + + return (VALUE)ary; +} + +static void +astore(ary, idx, val) + struct RArray *ary; + int idx; + VALUE val; +{ + int max; + + if (idx < 0) { + Fail("negative index for array"); + } + + max = idx + 1; + if (idx >= ary->capa) { + GC_LINK; GC_PRO(val); + ary->capa = max; + REALLOC_N(ary->ptr, VALUE, max); + GC_UNLINK; + } + if (idx >= ary->len) { + bzero(ary->ptr+ary->len, sizeof(VALUE)*(max-ary->len)); + } + + if (idx >= ary->len) { + ary->len = idx + 1; + } + ary->ptr[idx] = val; +} + +VALUE +Fary_push(ary, item) + struct RArray *ary; + VALUE item; +{ + astore(ary, ary->len, item); + return item; +} + +static VALUE +Fary_append(ary, item) + struct RArray *ary; + VALUE item; +{ + astore(ary, ary->len, item); + return (VALUE)ary; +} + +VALUE +Fary_pop(ary) + struct RArray *ary; +{ + if (ary->len == 0) return Qnil; + return ary->ptr[--ary->len]; +} + +VALUE +Fary_shift(ary) + struct RArray *ary; +{ + VALUE top; + + if (ary->len == 0) return Qnil; + + top = ary->ptr[0]; + ary->len--; + + /* sliding items */ + memmove(ary->ptr, ary->ptr+1, sizeof(VALUE)*(ary->len)); + + return top; +} + +VALUE +Fary_unshift(ary, item) + struct RArray *ary; +{ + VALUE top; + + if (ary->len >= ary->capa) { + ary->capa+=ARY_DEFAULT_SIZE; + REALLOC_N(ary->ptr, VALUE, ary->capa); + } + + /* sliding items */ + memmove(ary->ptr+1, ary->ptr, sizeof(VALUE)*(ary->len)); + + ary->len++; + return ary->ptr[0] = item; +} + +VALUE +ary_entry(ary, offset) + struct RArray *ary; + int offset; +{ + if (ary->len == 0) return Qnil; + + if (offset < 0) { + offset = ary->len + offset; + } + if (offset < 0 || ary->len <= offset) { + return Qnil; + } + + return ary->ptr[offset]; +} + +static VALUE +ary_subseq(ary, beg, len) + struct RArray *ary; + int beg, len; +{ + struct RArray *ary2; + VALUE *ptr; + + if (beg < 0) { + beg = ary->len + beg; + if (beg < 0) beg = 0; + } + if (len < 0) { + Fail("negative length for sub-array(size: %d)", ary->len); + } + if (len == 0) { + return ary_new(); + } + if (beg + len > ary->len) { + len = ary->len - beg; + } + + ary2 = (struct RArray*)ary_new2(len); + memmove(ary2->ptr, ary->ptr+beg, sizeof(VALUE)*len); + ary2->len = len; + + return (VALUE)ary2; +} + +extern VALUE C_Range; + +static void +range_beg_end(range, begp, lenp, len) + VALUE range; + int *begp, *lenp; + int len; +{ + int beg, end; + + beg = rb_iv_get(range, "start"); beg = NUM2INT(beg); + end = rb_iv_get(range, "end"); end = NUM2INT(end); + if (beg < 0) { + beg = len + beg; + if (beg < 0) beg = 0; + } + if (end < 0) { + end = len + end; + if (end < 0) end = 0; + } + if (beg > end) { + int tmp; + + if (verbose) { + Warning("start %d is bigger than end %d", beg, end); + } + tmp = beg; beg = end; end = tmp; + } + *begp = beg; *lenp = end - beg + 1; +} + +static VALUE +Fary_aref(ary, args) + struct RArray *ary; + VALUE args; +{ + VALUE arg1, arg2; + + if (rb_scan_args(args, "11", &arg1, &arg2) == 2) { + int beg, len; + + beg = NUM2INT(arg1); + len = NUM2INT(arg2); + if (len <= 0) { + return ary_new(); + } + return ary_subseq(ary, beg, len); + } + + /* check if idx is Range */ + if (obj_is_kind_of(arg1, C_Range)) { + int beg, len; + + range_beg_end(arg1, &beg, &len, ary->len); + return ary_subseq(ary, beg, len); + } + + return ary_entry(ary, NUM2INT(arg1)); +} + +static VALUE +Fary_aset(ary, args) + struct RArray *ary; + VALUE args; +{ + VALUE arg1, arg2; + struct RArray *arg3; + int offset; + + if (rb_scan_args(args, "21", &arg1, &arg2, &arg3) == 3) { + int beg, len; + + beg = NUM2INT(arg1); + Check_Type(arg3, T_ARRAY); + if (beg < 0) { + beg = ary->len + beg; + if (beg < 0) { + Fail("negative index for array(size: %d)", ary->len); + } + } + if (beg >= ary->len) { + len = beg + arg3->len; + if (len >= ary->capa) { + ary->capa=len; + REALLOC_N(ary->ptr, VALUE, ary->capa); + } + bzero(ary->ptr+ary->len, sizeof(VALUE)*(beg-ary->len)); + memcpy(ary->ptr+beg, arg3->ptr, sizeof(VALUE)*arg3->len); + ary->len = len; + } + else { + int alen; + + len = NUM2INT(arg2); + if (beg + len > ary->len) { + len = ary->len - beg; + } + if (len < 0) { + Fail("negative length for sub-array(size: %d)", ary->len); + } + + alen = ary->len + arg3->len - len; + if (alen >= ary->capa) { + ary->capa=alen; + REALLOC_N(ary->ptr, VALUE, ary->capa); + } + + memmove(ary->ptr+beg+arg3->len, ary->ptr+beg+len, + sizeof(VALUE)*(ary->len-(beg+len))); + memmove(ary->ptr+beg, arg3->ptr, sizeof(VALUE)*arg3->len); + ary->len = alen; + } + return (VALUE)arg3; + } + + /* check if idx is Range */ + if (obj_is_kind_of(arg1, C_Range)) { + int beg, len; + + Check_Type(arg2, T_ARRAY); + range_beg_end(arg1, &beg, &len, ary->len); + if (ary->len < beg) { + len = beg + RARRAY(arg2)->len; + if (len >= ary->capa) { + ary->capa=len; + REALLOC_N(ary->ptr, VALUE, ary->capa); + } + bzero(ary->ptr+ary->len, sizeof(VALUE)*(beg-ary->len)); + memcpy(ary->ptr+beg, RARRAY(arg2)->ptr, + sizeof(VALUE)*RARRAY(arg2)->len); + ary->len = len; + } + else { + int alen; + + alen = ary->len + RARRAY(arg2)->len - len; + if (alen >= ary->capa) { + ary->capa=alen; + REALLOC_N(ary->ptr, VALUE, ary->capa); + } + + memmove(ary->ptr+beg+RARRAY(arg2)->len, ary->ptr+beg+len, + sizeof(VALUE)*(ary->len-(beg+len))); + memmove(ary->ptr+beg, RARRAY(arg2)->ptr, + sizeof(VALUE)*RARRAY(arg2)->len); + ary->len = alen; + } + return arg2; + } + + offset = NUM2INT(arg1); + if (offset < 0) { + offset = ary->len + offset; + } + astore(ary, offset, arg2); + return arg2; +} + +static VALUE +Fary_each(ary) + struct RArray *ary; +{ + int i; + + if (iterator_p()) { + for (i=0; i<ary->len; i++) { + rb_yield(ary->ptr[i]); + } + } + else { + return (VALUE)ary; + } +} + +static VALUE +Fary_length(ary) + struct RArray *ary; +{ + return INT2FIX(ary->len); +} + +static VALUE +Fary_clone(ary) + struct RArray *ary; +{ + VALUE ary2 = ary_new2(ary->len); + + CLONESETUP(ary2, ary); + memcpy(RARRAY(ary2)->ptr, ary->ptr, sizeof(VALUE)*ary->len); + RARRAY(ary2)->len = ary->len; + return ary2; +} + +extern VALUE OFS; + +VALUE +ary_join(ary, sep) + struct RArray *ary; + struct RString *sep; +{ + int i; + VALUE result, tmp; + if (ary->len == 0) return str_new(0, 0); + + if (TYPE(ary->ptr[0]) == T_STRING) + result = Fstr_clone(ary->ptr[0]); + else + result = obj_as_string(ary->ptr[0]); + + GC_LINK; + GC_PRO(result); + GC_PRO2(tmp); + + for (i=1; i<ary->len; i++) { + int need_free = 1; + tmp = ary->ptr[i]; + switch (TYPE(tmp)) { + case T_STRING: + need_free = 0; + break; + case T_ARRAY: + tmp = ary_join(tmp, sep); + break; + default: + tmp = obj_as_string(tmp); + } + if (sep) str_cat(result, sep->ptr, sep->len); + str_cat(result, RSTRING(tmp)->ptr, RSTRING(tmp)->len); + if (need_free == 1) obj_free(tmp); + } + + GC_UNLINK; + + return result; +} + +static VALUE +Fary_join(ary, args) + struct RArray *ary; + VALUE args; +{ + VALUE sep; + + rb_scan_args(args, "01", &sep); + if (sep == Qnil) sep = OFS; + + if (sep != Qnil) + Check_Type(sep, T_STRING); + + return ary_join(ary, sep); +} + +VALUE +Fary_to_s(ary) + VALUE ary; +{ + VALUE str = ary_join(ary, OFS); + if (str == Qnil) return str_new(0, 0); + return str; +} + +static VALUE +Fary_inspect(ary) + struct RArray *ary; +{ + int i, len; + VALUE str; + char *p; + + ary = (struct RArray*)Fary_clone(ary); + GC_LINK; + GC_PRO(ary); + + len = ary->len; + for (i=0; i<len; i++) { + ary->ptr[i] = rb_funcall(ary->ptr[i], rb_intern("_inspect"), 0, Qnil); + } + + GC_PRO3(str, str_new2(", ")); + str = ary_join(ary, str); + if (str == Qnil) return str_new2("[]"); + len = RSTRING(str)->len; + str_grow(str, len+2); + p = RSTRING(str)->ptr; + memmove(p+1, p, len); + p[0] = '['; + p[len+1] = ']'; + + GC_UNLINK; + + return str; +} + +static VALUE +Fary_to_a(ary) + VALUE ary; +{ + return ary; +} + +static VALUE +Fary_reverse(ary) + struct RArray *ary; +{ + VALUE ary2 = ary_new2(ary->len); + int i, j; + + for (i=ary->len-1, j=0; i >=0; i--, j++) { + RARRAY(ary2)->ptr[j] = ary->ptr[i]; + } + RARRAY(ary2)->len = ary->len; + + return ary2; +} + +static ID cmp; + +static int +sort_1(a, b) + VALUE *a, *b; +{ + VALUE retval = rb_yield(assoc_new(*a, *b)); + return NUM2INT(retval); +} + +static int +sort_2(a, b) + VALUE *a, *b; +{ + VALUE retval = rb_funcall(*a, cmp, 1, *b); + return NUM2INT(retval); +} + +VALUE +Fary_sort(ary) + struct RArray *ary; +{ + qsort(ary->ptr, ary->len, sizeof(VALUE), iterator_p()?sort_1:sort_2); + return (VALUE)ary; +} + +static VALUE +Fary_delete(ary, item) + struct RArray *ary; + VALUE item; +{ + int i1, i2; + + for (i1 = i2 = 0; i1 < ary->len; i1++) { + if (rb_funcall(ary->ptr[i1], eq, 1, item)) continue; + if (i1 != i2) { + ary->ptr[i2] = ary->ptr[i1]; + } + i2++; + } + ary->len = i2; + + return (VALUE)ary; +} + +static VALUE +Fary_delete_if(ary) + struct RArray *ary; +{ + int i1, i2; + + for (i1 = i2 = 0; i1 < ary->len; i1++) { + if (rb_yield(ary->ptr[i1])) continue; + if (i1 != i2) { + ary->ptr[i2] = ary->ptr[i1]; + } + i2++; + } + ary->len = i2; + + return (VALUE)ary; +} + +static VALUE +Fary_clear(ary) + struct RArray *ary; +{ + ary->len = 0; + return (VALUE)ary; +} + +static VALUE +Fary_fill(ary, args) + struct RArray *ary; + VALUE args; +{ + VALUE item, arg1, arg2; + int beg, len, end; + VALUE *p, *pend; + + rb_scan_args(args, "12", &item, &arg1, &arg2); + if (arg2 == Qnil && obj_is_kind_of(arg1, C_Range)) { + range_beg_end(arg1, &beg, &len, ary->len); + } + else { + beg = NUM2INT(arg1); + if (beg < 0) { + beg = ary->len + beg; + if (beg < 0) beg = 0; + } + if (arg2) { + len = NUM2INT(arg2); + } + else { + len = ary->len - beg; + } + } + end = beg + len; + if (end > ary->len) { + if (end >= ary->capa) { + ary->capa=end; + REALLOC_N(ary->ptr, VALUE, ary->capa); + } + if (beg > ary->len) { + bzero(ary->ptr+ary->len, sizeof(VALUE)*(end-ary->len)); + } + ary->len = end; + } + p = ary->ptr + beg; pend = p + len; + + while (p < pend) { + *p++ = item; + } + return (VALUE)ary; +} + +static VALUE +Fary_plus(x, y) + struct RArray *x, *y; +{ + struct RArray *z; + + switch (TYPE(y)) { + case T_ARRAY: + z = (struct RArray*)ary_new2(x->len + y->len); + memcpy(z->ptr, x->ptr, x->len*sizeof(VALUE)); + memcpy(z->ptr+x->len, y->ptr, y->len*sizeof(VALUE)); + z->len = x->len + RARRAY(y)->len; + break; + + default: + GC_LINK; + GC_PRO3(z, (struct RArray*)Fary_clone(x)); + Fary_push(z, y); + GC_UNLINK; + break; + } + return (VALUE)z; +} + +static VALUE +Fary_times(ary, times) + struct RArray *ary; + VALUE times; +{ + struct RArray *ary2; + int i, len; + + len = NUM2INT(times) * ary->len; + ary2 = (struct RArray*)ary_new2(len); + ary2->len = len; + + for (i=0; i<len; i+=ary->len) { + memcpy(ary2->ptr+i, ary->ptr, ary->len*sizeof(VALUE)); + } + + return (VALUE)ary2; +} + +VALUE +Fary_assoc(ary, key) + struct RArray *ary; + VALUE key; +{ + VALUE *p, *pend; + + p = ary->ptr; pend = p + ary->len; + while (p < pend) { + if (TYPE(*p) == T_ARRAY + && RARRAY(*p)->len == 2 + && rb_funcall(RARRAY(*p)->ptr[0], eq, 1, key)) + return *p; + } + return Qnil; +} + +VALUE +Fary_rassoc(ary, value) + struct RArray *ary; + VALUE value; +{ + VALUE *p, *pend; + + p = ary->ptr; pend = p + ary->len; + while (p < pend) { + if (TYPE(*p) == T_ARRAY + && RARRAY(*p)->len == 2 + && rb_funcall(RARRAY(*p)->ptr[1], eq, 1, value)) + return *p; + } + return Qnil; +} + +extern VALUE C_Kernel; +extern VALUE M_Enumerable; + +Init_Array() +{ + C_Array = rb_define_class("Array", C_Object); + rb_include_module(C_Array, M_Enumerable); + + rb_define_single_method(C_Array, "new", Fary_new, 0); + rb_define_method(C_Array, "to_s", Fary_to_s, 0); + rb_define_method(C_Array, "_inspect", Fary_inspect, 0); + rb_define_method(C_Array, "to_a", Fary_to_a, 0); + + rb_define_method(C_Array, "[]", Fary_aref, -2); + rb_define_method(C_Array, "[]=", Fary_aset, -2); + rb_define_method(C_Array, "<<", Fary_append, 1); + rb_define_method(C_Array, "push", Fary_push, 1); + rb_define_method(C_Array, "pop", Fary_pop, 0); + rb_define_method(C_Array, "shift", Fary_shift, 0); + rb_define_method(C_Array, "unshift", Fary_unshift, 1); + rb_define_method(C_Array, "each", Fary_each, 0); + rb_define_method(C_Array, "length", Fary_length, 0); + rb_define_method(C_Array, "clone", Fary_clone, 0); + rb_define_method(C_Array, "join", Fary_join, -2); + rb_define_method(C_Array, "reverse", Fary_reverse, 0); + rb_define_method(C_Array, "sort", Fary_sort, 0); + rb_define_method(C_Array, "delete", Fary_delete, 1); + rb_define_method(C_Array, "delete_if", Fary_delete_if, 0); + rb_define_method(C_Array, "clear", Fary_clear, 0); + rb_define_method(C_Array, "fill", Fary_fill, -2); + + rb_define_method(C_Array, "assoc", Fary_assoc, 1); + rb_define_method(C_Array, "rassoc", Fary_rassoc, 1); + + rb_define_method(C_Array, "+", Fary_plus, 1); + rb_define_method(C_Array, "*", Fary_times, 1); + + cmp = rb_intern("<=>"); + eq = rb_intern("=="); + + rb_define_method(C_Kernel, "::", assoc_new, 1); +} diff --git a/bignum.c b/bignum.c new file mode 100644 index 0000000000..ce124a6362 --- /dev/null +++ b/bignum.c @@ -0,0 +1,1121 @@ +/************************************************ + + bignum.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:21 $ + created at: Fri Jun 10 00:48:55 JST 1994 + +************************************************/ + +#include "ruby.h" +#include <ctype.h> + +extern VALUE C_Integer; +VALUE C_Bignum; + +#define BDIGITS(x) RBIGNUM(x)->digits +#define BITSPERDIG (sizeof(USHORT)*CHAR_BIT) +#define BIGRAD (1L << BITSPERDIG) +#define DIGSPERLONG ((UINT)(sizeof(long)/sizeof(USHORT))) +#define BIGUP(x) ((unsigned long)(x) << BITSPERDIG) +#define BIGDN(x) ((x) >> BITSPERDIG) +#define BIGLO(x) ((x) & (BIGRAD-1)) + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static VALUE +bignew_1(class, len, sign) + VALUE class; + UINT len; + char sign; +{ + NEWOBJ(big, struct RBignum); + OBJSETUP(big, C_Bignum, T_BIGNUM); + big->sign = sign; + big->len = len; + BDIGITS(big) = ALLOC_N(USHORT, len); + + return (VALUE)big; +} + +#define bignew(len,sign) bignew_1(C_Bignum,len,sign) + +static VALUE +Fbig_new(class, y) + VALUE class; + struct RBignum *y; +{ + Check_Type(y, T_BIGNUM); + return bignew_1(class, y->len, y->sign); +} + +VALUE +Fbig_clone(x) + struct RBignum *x; +{ + VALUE z = bignew_1(CLASS_OF(x), x->len, x->sign); + + bcopy(BDIGITS(x), BDIGITS(z), x->len*sizeof(USHORT)); + return (VALUE)z; +} + +void +big_2comp(x) /* get 2's complement */ + struct RBignum *x; +{ + UINT i = x->len; + USHORT *ds = BDIGITS(x); + long num; + + while (i--) ds[i] = ~ds[i]; + i = 0; num = 1; + do { + num += (long)ds[i]; + ds[i++] = BIGLO(num); + num = BIGDN(num); + } while (i < x->len); +} + +VALUE +bignorm(x) + struct RBignum *x; +{ + UINT len = x->len; + USHORT *ds = BDIGITS(x); + + while (len-- && !ds[len]) ; + x->len = ++len; + if (len*sizeof(USHORT) <= sizeof(VALUE)) { + long num = 0; + while (len--) { + num = BIGUP(num) + ds[len]; + } + if (x->sign) { + if (POSFIXABLE(num)) return INT2FIX(num); + } + else if (NEGFIXABLE(-num)) return INT2FIX(-num); + } + return (VALUE)x; +} + +VALUE +uint2big(n) + UINT n; +{ + UINT i = 0; + USHORT *digits; + struct RBignum *big; + + i = 0; + big = (struct RBignum*)bignew(DIGSPERLONG, 1); + digits = BDIGITS(big); + while (i < DIGSPERLONG) { + digits[i++] = BIGLO(n); + n = BIGDN(n); + } + + i = DIGSPERLONG; + while (i-- && !digits[i]) ; + big->len = i+1; + return (VALUE)big; +} + +VALUE +int2big(n) + int n; +{ + int neg = 0; + struct RBignum *big; + + if (n < 0) { + n = -n; + neg = 1; + } + big = (struct RBignum*)uint2big(n); + if (neg) { + big->sign = FALSE; + } + return (VALUE)big; +} + +VALUE +uint2inum(n) + UINT n; +{ + if (POSFIXABLE(n)) return INT2FIX(n); + return uint2big(n); +} + +VALUE +int2inum(n) + int n; +{ + if (FIXABLE(n)) return INT2FIX(n); + return int2big(n); +} + +VALUE +str2inum(str, base) + char *str; + int base; +{ + char sign = 1, c; + unsigned long num; + UINT len, blen = 1, i; + VALUE z; + USHORT *zds; + + while (isspace(*str)) str++; + if (*str == '-') { + str++; + sign = 0; + } + if (base == 0) { + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') { + str++; + base = 16; + } + else { + base = 8; + } + if (*str == '\0') return INT2FIX(0); + } + else { + base = 10; + } + } + len = strlen(str); + if (base == 8) { + len = 3*len*sizeof(char); + } + else { /* base == 10 or 16 */ + len = 4*len*sizeof(char); + } + + if (len <= (sizeof(VALUE)*CHAR_BIT)) { + int result = strtoul(str, Qnil, base); + + if (!sign) result = -result; + if (FIXABLE(result)) return INT2FIX(result); + return int2big(result); + } + len = (len/(sizeof(USHORT)*CHAR_BIT))+1; + + z = bignew(len, sign); + zds = BDIGITS(z); + for (i=len;i--;) zds[i]=0; + while (c = *str++) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + c = c - '0'; + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + c = c - 'a' + 10; + break; + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + c = c - 'A' + 10; + break; + default: + c = base; + break; + } + if (c >= base) break; + i = 0; + num = c; + for (;;) { + while (i<blen) { + num += zds[i]*base; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } + if (num) { + blen++; + continue; + } + break; + } + } + return bignorm(z); +} + +static char hexmap[] = "0123456789abcdef"; +VALUE +big2str(x, base) + struct RBignum *x; + int base; +{ + VALUE t; + USHORT *ds; + UINT i, j, hbase; + VALUE ss; + char *s, c; + + if (FIXNUM_P(x)) { + return fix2str(x, base); + } + i = x->len; + if (x->len == 0) return str_new2("0"); + if (base == 10) { + j = (sizeof(USHORT)/sizeof(char)*CHAR_BIT*i*241L)/800+2; + hbase = 10000; + } + else if (base == 16) { + j = (sizeof(USHORT)/sizeof(char)*CHAR_BIT*i)/4+2; + hbase = 0x10000; + } + else if (base == 8) { + j = (sizeof(USHORT)/sizeof(char)*CHAR_BIT*i)+2; + hbase = 010000; + } + else if (base == 2) { + j = (sizeof(USHORT)*CHAR_BIT*i)+2; + hbase = 020; + } + else { + Fail("bignum cannot treat base %d", base); + } + + GC_LINK; + GC_PRO3(t, Fbig_clone(x)); + ds = BDIGITS(t); + GC_PRO3(ss, str_new(0, j)); + s = RSTRING(ss)->ptr; + + s[0] = x->sign ? '+' : '-'; + while (i && j) { + int k = i; + unsigned long num = 0; + while (k--) { + num = BIGUP(num) + ds[k]; + ds[k] = num / hbase; + num %= hbase; + } + if (ds[i-1] == 0) i--; + k = 4; + while (k--) { + c = num % base; + s[--j] = hexmap[(int)c]; + num /= base; + if (i == 0 && num == 0) break; + } + } + while (s[j] == '0') j++; + RSTRING(ss)->len -= x->sign?j:j-1; + memmove(x->sign?s:s+1, s+j, RSTRING(ss)->len); + s[RSTRING(ss)->len] = '\0'; + GC_UNLINK; + return ss; +} + +static VALUE +Fbig_to_s(x) + struct RBignum *x; +{ + return big2str(x, 10); +} + +int +big2int(x) + struct RBignum *x; +{ + unsigned long num; + UINT len = x->len; + USHORT *ds; + + if (len > sizeof(long)/sizeof(USHORT)) + Fail("Bignum too big to convert into fixnum"); + ds = BDIGITS(x); + num = 0; + while (len--) { + num = BIGUP(num); + num += ds[len]; + } + if (!x->sign) return -num; + return num; +} + +VALUE +Fbig_to_i(x) + VALUE x; +{ + int v = big2int(x); + + if (FIXABLE(v)) { + return INT2FIX(v); + } + return x; +} + +VALUE +dbl2big(d) + double d; +{ + UINT i = 0; + long c; + USHORT *digits; + VALUE z; + double u = (d < 0)?-d:d; + + while (0 != floor(u)) { + u /= BIGRAD; + i++; + } + GC_LINK; + GC_PRO3(z, bignew(i, d>=0)); + digits = BDIGITS(z); + while (i--) { + u *= BIGRAD; + c = floor(u); + u -= c; + digits[i] = c; + } + GC_UNLINK; + return bignorm(z); +} + +double +big2dbl(x) + struct RBignum *x; +{ + double d = 0.0; + UINT i = x->len; + USHORT *ds = BDIGITS(x); + + while (i--) d = ds[i] + BIGRAD*d; + if (!x->sign) d = -d; + return d; +} + +VALUE +Fbig_to_f(x) + VALUE x; +{ + return float_new(big2dbl(x)); +} + +static VALUE +Fbig_uminus(x) + struct RBignum *x; +{ + VALUE z = Fbig_clone(x); + + RBIGNUM(z)->sign = !x->sign; + + return bignorm(z); +} + +static VALUE +bigadd(x, y, sign) + struct RBignum *x, *y; + char sign; +{ + struct RBignum *z; + USHORT *zds; + long num; + UINT i, len; + + len = MAX(x->len, y->len) + 1; + z = (struct RBignum*)bignew(len, sign==y->sign); + zds = BDIGITS(z); + + i = len; + while (i--) zds[i] = 0; + i = y->len; + while (i--) zds[i] = BDIGITS(y)[i]; + + GC_LINK; + GC_PRO(z); + i = 0; num = 0; + if (x->sign == z->sign) { + do { + num += (long)zds[i] + BDIGITS(x)[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } while (i < x->len); + if (num) { + while (i < y->len) { + num += zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } + BDIGITS(z)[i] = num; + } + } + else { + do { + num += (long)zds[i] - BDIGITS(x)[i]; + if (num < 0) { + zds[i] = num + BIGRAD; + num = -1; + } + else { + zds[i] = BIGLO(num); + num = 0; + } + } while (++i < x->len); + if (num && x->len == y->len) { + num = 1; i = 0; + z->sign = 1; + do { + num += (BIGRAD-1) - zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } while (i < y->len); + } + else while (i < y->len) { + num += zds[i]; + if (num < 0) { + zds[i++] = num + BIGRAD; + num = -1; + } + else { + zds[i++] = BIGLO(num); + num = 0; + } + } + } + GC_UNLINK; + return bignorm(z); +} + +VALUE +Fbig_plus(x, y) + VALUE x, y; +{ + VALUE z; + + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = int2big(FIX2INT(y)); + else { + Check_Type(x, T_BIGNUM); + } + z = bigadd(x, y, 1); + GC_UNLINK; + return z; +} + +VALUE +Fbig_minus(x, y) + VALUE x, y; +{ + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = int2big(FIX2INT(y)); + else { + Check_Type(y, T_BIGNUM); + } + x = bigadd(x, y, 0); + GC_UNLINK; + + return x; +} + +VALUE +Fbig_mul(x, y) + struct RBignum *x, *y; +{ + UINT i = 0, j; + unsigned long n = 0; + VALUE z; + USHORT *zds; + + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = (struct RBignum*)int2big(FIX2INT(y)); + else { + Check_Type(y, T_BIGNUM); + } + + j = x->len + y->len + 1; + z = bignew(j, x->sign==y->sign); + zds = BDIGITS(z); + while (j--) zds[j] = 0; + do { + j = 0; + if (BDIGITS(x)[i]) { + do { + n += zds[i + j] + ((unsigned long)BDIGITS(x)[i]*BDIGITS(y)[j]); + zds[i + j++] = BIGLO(n); + n = BIGDN(n); + } while (j < y->len); + if (n) { + zds[i + j] = n; + n = 0; + } + } + } while (++i < x->len); + GC_UNLINK; + + return bignorm(z); +} + +static void +bigdivmod(x, y, div, mod) + struct RBignum *x, *y; + VALUE *div, *mod; +{ + UINT nx = x->len, ny = y->len, i, j; + VALUE z; + USHORT *xds, *yds, *zds, *tds; + unsigned long t2; + long num; + USHORT dd, q; + + yds = BDIGITS(y); + if (ny == 0 && yds[0] == 0) Fail("divided by 0"); + if (nx < ny) { + if (div) *div = INT2FIX(0); + if (mod) *mod = bignorm(x); + return; + } + xds = BDIGITS(x); + if (ny == 1) { + dd = yds[0]; + GC_LINK; + GC_PRO3(z, Fbig_clone(x)); + zds = BDIGITS(z); + t2 = 0; i = nx; + while(i--) { + t2 = BIGUP(t2) + zds[i]; + zds[i] = t2 / dd; + t2 %= dd; + } + if (div) *div = bignorm(z); + if (mod) { + if (!y->sign) t2 = -t2; + *mod = FIX2INT(t2); + } + GC_UNLINK; + return; + } + GC_LINK; + GC_PRO3(z, bignew(nx==ny?nx+2:nx+1, x->sign==y->sign)); + zds = BDIGITS(z); + if (nx==ny) zds[nx+1] = 0; + while (!yds[ny-1]) ny--; + if ((dd = BIGRAD/(yds[ny-1]+1)) != 1) { + GC_PRO3(y, (struct RBignum*)Fbig_clone(y)); + tds = BDIGITS(y); + j = 0; + num = 0; + while (j<ny) { + num += (unsigned long)yds[j]*dd; + tds[j++] = BIGLO(num); + num = BIGDN(num); + } + yds = tds; + j = 0; + num = 0; + while (j<nx) { + num += (unsigned long)xds[j]*dd; + zds[j++] = BIGLO(num); + num = BIGDN(num); + } + zds[j] = num; + } + else { + zds[nx] = 0; + j = nx; + while (j--) zds[j] = xds[j]; + } + j = nx==ny?nx+1:nx; + do { + if (zds[j] == yds[ny-1]) q = BIGRAD-1; + else q = (BIGUP(zds[j]) + zds[j-1])/yds[ny-1]; + if (q) { + i = 0; num = 0; t2 = 0; + do { /* multiply and subtract */ + t2 += (unsigned long)yds[i] * q; + num += zds[j - ny + i] - BIGLO(t2); + if (num < 0) { + zds[j - ny + i] = num + BIGRAD; + num = -1; + } + else { + zds[j - ny + i] = num; + num = 0; + } + t2 = BIGDN(t2); + } while (++i < ny); + num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */ + while (num) { /* "add back" required */ + i = 0; num = 0; q--; + do { + num += (long) zds[j - ny + i] + yds[i]; + zds[j - ny + i] = BIGLO(num); + num = BIGDN(num); + } while (++i < ny); + num--; + } + } + zds[j] = q; + } while (--j >= ny); + if (div) { /* move quotient down in z */ + *div = Fbig_clone(z); + zds = BDIGITS(*div); + j = (nx==ny ? nx+2 : nx+1) - ny; + for (i = 0;i < j;i++) zds[i] = zds[i+ny]; + RBIGNUM(*div)->len = i; + *div = bignorm(*div); + } + if (mod) { /* just normalize remainder */ + *mod = Fbig_clone(z); + if (dd) { + zds = BDIGITS(*mod); + t2 = 0; i = ny; + while(i--) { + t2 = BIGUP(t2) + zds[i]; + zds[i] = t2 / dd; + t2 %= dd; + } + } + RBIGNUM(*mod)->len = ny; + RBIGNUM(*mod)->sign = y->sign; + *mod = bignorm(*mod); + } + GC_UNLINK; +} + +static VALUE +Fbig_div(x, y) + VALUE x, y; +{ + VALUE z; + + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = int2big(FIX2INT(y)); + else { + Check_Type(y, T_BIGNUM); + } + bigdivmod(x, y, &z, Qnil); + GC_UNLINK; + return z; +} + +static VALUE +Fbig_mod(x, y) + VALUE x, y; +{ + VALUE z; + + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = int2big(FIX2INT(y)); + else { + Check_Type(y, T_BIGNUM); + } + bigdivmod(x, y, Qnil, &z); + GC_UNLINK; + return z; +} + +static VALUE +Fbig_divmod(x, y) + VALUE x, y; +{ + VALUE div, mod; + + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = int2big(FIX2INT(y)); + else { + Check_Type(y, T_BIGNUM); + } + bigdivmod(x, y, &div, &mod); + GC_UNLINK; + + return assoc_new(div, mod);; +} + +static VALUE +Fbig_pow(x, y) + VALUE x, y; +{ + extern double pow(); + double d1, d2; + + GC_LINK; + GC_PRO(y); + if (FIXNUM_P(y)) y = int2big(FIX2INT(y)); + else { + Check_Type(y, T_BIGNUM); + } + + d1 = big2dbl(x); + d2 = big2dbl(y); + d1 = pow(d1, d2); + GC_UNLINK; + + return dbl2big(d1); +} + +VALUE +Fbig_and(x, y) + struct RBignum *x, *y; +{ + VALUE z; + USHORT *ds1, *ds2, *zds; + UINT i, l1, l2; + char sign; + + if (FIXNUM_P(y)) { + y = (struct RBignum*)int2big(FIX2INT(y)); + } + else { + Check_Type(y, T_BIGNUM); + } + + GC_LINK; + GC_PRO(y); + if (!y->sign) { + y = (struct RBignum*)Fbig_clone(y); + big_2comp(y); + } + if (!x->sign) { + GC_PRO3(x, (struct RBignum*)Fbig_clone(x)); + big_2comp(x); + } + if (x->len > y->len) { + l1 = y->len; + l2 = x->len; + ds1 = BDIGITS(y); + ds2 = BDIGITS(x); + sign = y->sign; + } + else { + l1 = x->len; + l2 = y->len; + ds1 = BDIGITS(x); + ds2 = BDIGITS(y); + sign = x->sign; + } + z = bignew(l2, x->sign && y->sign); + zds = BDIGITS(z); + + for (i=0; i<l1; i++) { + zds[i] = ds1[i] & ds2[i]; + } + for (; i<l2; i++) { + zds[i] = sign?0:ds2[i]; + } + if (!RBIGNUM(z)->sign) big_2comp(z); + GC_UNLINK; + return bignorm(z); +} + +VALUE +Fbig_or(x, y) + struct RBignum *x, *y; +{ + VALUE z; + USHORT *ds1, *ds2, *zds; + UINT i, l1, l2; + char sign; + + if (FIXNUM_P(y)) { + y = (struct RBignum*)int2big(FIX2INT(y)); + } + else { + Check_Type(y, T_BIGNUM); + } + + GC_LINK; + GC_PRO(y); + if (!y->sign) { + y = (struct RBignum*)Fbig_clone(y); + big_2comp(y); + } + if (!x->sign) { + GC_PRO3(x, (struct RBignum*)Fbig_clone(x)); + big_2comp(x); + } + if (x->len > y->len) { + l1 = y->len; + l2 = x->len; + ds1 = BDIGITS(y); + ds2 = BDIGITS(x); + sign = y->sign; + } + else { + l1 = x->len; + l2 = y->len; + ds1 = BDIGITS(x); + ds2 = BDIGITS(y); + sign = x->sign; + } + z = bignew(l2, x->sign || y->sign); + zds = BDIGITS(z); + + for (i=0; i<l1; i++) { + zds[i] = ds1[i] | ds2[i]; + } + for (; i<l2; i++) { + zds[i] = sign?ds2[i]:(BIGRAD-1); + } + if (!RBIGNUM(z)->sign) big_2comp(z); + GC_UNLINK; + return bignorm(z); +} + +VALUE +Fbig_xor(x, y) + struct RBignum *x, *y; +{ + VALUE z; + USHORT *ds1, *ds2, *zds; + UINT i, l1, l2; + char sign; + + if (FIXNUM_P(y)) { + y = (struct RBignum*)int2big(FIX2INT(y)); + } + else { + Check_Type(y, T_BIGNUM); + } + + GC_LINK; + GC_PRO(y); + if (!y->sign) { + y = (struct RBignum*)Fbig_clone(y); + big_2comp(y); + } + if (!x->sign) { + GC_PRO3(x, (struct RBignum*)Fbig_clone(x)); + big_2comp(x); + } + if (x->len > y->len) { + l1 = y->len; + l2 = x->len; + ds1 = BDIGITS(y); + ds2 = BDIGITS(x); + sign = y->sign; + } + else { + l1 = x->len; + l2 = y->len; + ds1 = BDIGITS(x); + ds2 = BDIGITS(y); + sign = x->sign; + } + x->sign = x->sign?1:0; + y->sign = y->sign?1:0; + z = bignew(l2, !(x->sign ^ y->sign)); + zds = BDIGITS(z); + + for (i=0; i<l1; i++) { + zds[i] = ds1[i] ^ ds2[i]; + } + for (; i<l2; i++) { + zds[i] = sign?ds2[i]:~ds2[i]; + } + if (!RBIGNUM(z)->sign) big_2comp(z); + GC_UNLINK; + return bignorm(z); +} + +static VALUE +Fbig_neg(x) + struct RBignum *x; +{ + VALUE z = Fbig_clone(x); + UINT i = x->len; + USHORT *ds = BDIGITS(z); + + if (!x->sign) big_2comp(z); + while (i--) ds[i] = ~ds[i]; + if (x->sign) big_2comp(z); + RBIGNUM(z)->sign = !RBIGNUM(z)->sign; + + return bignorm(z); +} + +static VALUE Fbig_rshift(); + +VALUE +Fbig_lshift(x, y) + struct RBignum *x; + VALUE y; +{ + USHORT *xds, *zds; + UINT shift = NUM2INT(y); + UINT s1 = shift/(sizeof(USHORT)*CHAR_BIT); + UINT s2 = shift%(sizeof(USHORT)*CHAR_BIT); + VALUE z; + unsigned long num = 0; + UINT len, i; + + if (shift < 0) return Fbig_rshift(x, INT2FIX(-shift)); + xds = BDIGITS(x); + len = x->len; + z = bignew(len+s1+1, x->sign); + zds = BDIGITS(z); + for (i=0; i<s1; i++) { + *zds++ = 0; + } + for (i=0; i<len; i++) { + num = num | *xds++<<s2; + *zds++ = BIGLO(num); + num = BIGDN(num); + } + *zds = BIGLO(num); + return bignorm(z); +} + +static VALUE +Fbig_rshift(x, y) + struct RBignum *x; + VALUE y; +{ + USHORT *xds, *zds; + UINT shift = NUM2INT(y); + UINT s1 = shift/(sizeof(USHORT)*CHAR_BIT); + UINT s2 = shift%(sizeof(USHORT)*CHAR_BIT); + VALUE z; + unsigned long num = 0; + UINT i = x->len, j; + + if (shift < 0) return Fbig_lshift(x, INT2FIX(-shift)); + if (s1 > x->len) { + if (x->sign) + return INT2FIX(0); + else + return INT2FIX(-1); + } + xds = BDIGITS(x); + i = x->len; j = i - s1; + z = bignew(j, x->sign); + zds = BDIGITS(z); + while (i--, j--) { + num = (num | xds[i]) >> s2; + zds[j] = BIGLO(num); + num = BIGUP(xds[i]); + } + return bignorm(z); +} + +static VALUE +Fbig_aref(x, y) + struct RBignum *x; + VALUE y; +{ + USHORT *xds; + int shift = NUM2INT(y); + UINT s1, s2; + + if (shift < 0) return INT2FIX(0); + s1 = shift/(sizeof(USHORT)*CHAR_BIT); + s2 = shift%(sizeof(USHORT)*CHAR_BIT); + + if (!x->sign) { + if (s1 >= x->len) return INT2FIX(1); + x = (struct RBignum*)Fbig_clone(x); + big_2comp(x); + } + else { + if (s1 >= x->len) return INT2FIX(0); + } + xds = BDIGITS(x); + if (xds[s1] & (1<<s2)) + return INT2FIX(1); + return INT2FIX(0); +} + +static VALUE +Fbig_cmp(x, y) + struct RBignum *x, *y; +{ + int xlen = x->len; + + Check_Type(x, T_BIGNUM); + if (x->sign > y->sign) return INT2FIX(1); + if (x->sign < y->sign) return INT2FIX(-1); + if (xlen < y->len) + return (x->sign) ? INT2FIX(-1) : INT2FIX(1); + if (xlen > y->len) + return (x->sign) ? INT2FIX(1) : INT2FIX(-1); + + while(xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen])); + if (-1 == xlen) return INT2FIX(0); + return (BDIGITS(x)[xlen] < BDIGITS(y)[xlen]) ? + (x->sign ? INT2FIX(1) : INT2FIX(-1)) : + (x->sign ? INT2FIX(-1) : INT2FIX(1)); +} + +static VALUE +Fbig_hash(x) + struct RBignum *x; +{ + int i, len, key; + USHORT *digits; + + key = 0; digits = BDIGITS(x); + for (i=0,len=x->len; i<x->len; i++) { + key ^= *digits++; + } + return INT2FIX(key); +} + +static VALUE +Fbig_coerce(x, y) + struct RBignum *x; + VALUE y; +{ + if (FIXNUM_P(y)) { + return int2big(FIX2INT(y)); + } + else { + Fail("can't coerce %s to Bignum", rb_class2name(CLASS_OF(y))); + } + /* not reached */ + return Qnil; +} + +static VALUE +Fbig_abs(x) + struct RBignum *x; +{ + if (!x->sign) { + x = (struct RBignum*)Fbig_clone(x); + x->sign = 1; + } + return (VALUE)x; +} + +Init_Bignum() +{ + C_Bignum = rb_define_class("Bignum", C_Integer); + rb_define_single_method(C_Bignum, "new", Fbig_new, 1); + rb_define_method(C_Bignum, "clone", Fbig_clone, 0); + rb_define_method(C_Bignum, "to_s", Fbig_to_s, 0); + rb_define_method(C_Bignum, "coerce", Fbig_coerce, 1); + rb_define_method(C_Bignum, "-@", Fbig_uminus, 0); + rb_define_method(C_Bignum, "+", Fbig_plus, 1); + rb_define_method(C_Bignum, "-", Fbig_minus, 1); + rb_define_method(C_Bignum, "*", Fbig_mul, 1); + rb_define_method(C_Bignum, "/", Fbig_div, 1); + rb_define_method(C_Bignum, "%", Fbig_mod, 1); + rb_define_method(C_Bignum, "divmod", Fbig_divmod, 1); + rb_define_method(C_Bignum, "**", Fbig_pow, 1); + rb_define_method(C_Bignum, "&", Fbig_and, 1); + rb_define_method(C_Bignum, "|", Fbig_or, 1); + rb_define_method(C_Bignum, "^", Fbig_xor, 1); + rb_define_method(C_Bignum, "~", Fbig_neg, 0); + rb_define_method(C_Bignum, "<<", Fbig_lshift, 1); + rb_define_method(C_Bignum, ">>", Fbig_rshift, 1); + rb_define_method(C_Bignum, "[]", Fbig_aref, 1); + + rb_define_method(C_Bignum, "<=>", Fbig_cmp, 1); + rb_define_method(C_Bignum, "hash", Fbig_hash, 0); + rb_define_method(C_Bignum, "to_i", Fbig_to_i, 0); + rb_define_method(C_Bignum, "to_f", Fbig_to_f, 0); + rb_define_method(C_Bignum, "abs_f", Fbig_abs, 0); +} @@ -0,0 +1,57 @@ +#! /usr/bin/bash + +function fdeject() { + if type eject > /dev/null 2>&1; then + eject + fi +} + +function copyfiles() { + for d in . missing sample; do + if [ ! -d $1/$d ];then mkdir $1/$d; fi + for i in $d/*;do + case $i in + */ruby|*.o|*~|*.sav|*.bak|*.orig|*/core|"#"*);; + */Change*|*/config.status|*/Makefile);; + *) + if [ -f $i ]; then + if [ $i -nt $1/$i -o ! -f $1/$i ];then + echo copying $i + cp -p $i $1/$i + fi + fi;; + esac + done + done +} + +if [ ! -d exchange ]; then mkdir exchange; fi + +if [ "$1" = "in" ]; then + + cd exchange + + mread ruby.tgz ruby.tgz + fdeject + tar zxf ruby.tgz + rm -f ruby.tgz + cd ruby + + cp ChangeLog ../../Changes + copyfiles ../.. + +else +# bring out + if [ ! -d exchange/ruby ]; then mkdir exchange/ruby; fi + + cp -p ChangeLog exchange/ruby + copyfiles exchange/ruby + + cd exchange + (cd ruby; make realclean) + + tar zcf ruby.tgz ruby + mwrite ruby.tgz ruby.tgz + fdeject + rm -f ruby.tgz +fi diff --git a/class.c b/class.c new file mode 100644 index 0000000000..406c0f139d --- /dev/null +++ b/class.c @@ -0,0 +1,387 @@ +/************************************************ + + class.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Tue Aug 10 15:05:44 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include "node.h" +#include "st.h" + +struct st_table *new_idhash(); + +extern VALUE C_Class; +extern VALUE C_Module; +extern VALUE C_Method; + +VALUE +class_new(super) + struct RClass *super; +{ + NEWOBJ(cls, struct RClass); + OBJSETUP(cls, C_Class, T_CLASS); + + cls->super = super; + cls->m_tbl = new_idhash(); + cls->c_tbl = Qnil; + + return (VALUE)cls; +} + +VALUE +single_class_new(super) + struct RClass *super; +{ + struct RClass *cls = (struct RClass*)class_new(super); + + FL_SET(cls, FL_SINGLE); + + return (VALUE)cls; +} + +VALUE +single_class_clone(class) + struct RClass *class; +{ + if (!FL_TEST(class, FL_SINGLE)) + return (VALUE)class; + else { + /* copy single(unnamed) class */ + NEWOBJ(cls, struct RClass); + CLONESETUP(cls, class); + + cls->super = class->super; + cls->m_tbl = st_copy(class->m_tbl); + cls->c_tbl = Qnil; + FL_SET(cls, FL_SINGLE); + return (VALUE)cls; + } +} + +VALUE +rb_define_class_id(id, super) + ID id; + struct RBasic *super; +{ + struct RClass *cls = (struct RClass*)class_new(super); + + rb_name_class(cls, id); + + /* make metaclass */ + RBASIC(cls)->class = single_class_new(super?super->class:C_Class); + literalize(RBASIC(cls)->class); + + return (VALUE)cls; +} + +VALUE +rb_define_class(name, super) + char *name; + VALUE super; +{ + return rb_define_class_id(rb_intern(name), super); +} + +VALUE +module_new() +{ + NEWOBJ(mdl, struct RClass); + OBJSETUP(mdl, C_Module, T_MODULE); + + mdl->super = Qnil; + mdl->m_tbl = new_idhash(); + mdl->c_tbl = Qnil; + + return (VALUE)mdl; +} + +VALUE +rb_define_module_id(id) + ID id; +{ + struct RClass *mdl = (struct RClass*)module_new(); + + rb_name_class(mdl, id); + return (VALUE)mdl; +} + +VALUE +rb_define_module(name) + char *name; +{ + return rb_define_module_id(rb_intern(name)); +} + +static struct RClass * +include_class_new(module, super) + struct RClass *module, *super; +{ + struct RClass *p; + + NEWOBJ(cls, struct RClass); + OBJSETUP(cls, C_Class, T_ICLASS); + + cls->m_tbl = module->m_tbl; + cls->c_tbl = module->c_tbl; + cls->super = super; + + return cls; +} + +void +rb_include_module(class, module) + struct RClass *class, *module; +{ + struct RClass *p; + + Check_Type(module, T_MODULE); + + while (module) { + /* ignore if module included already in superclasses */ + for (p = class->super; p; p = p->super) { + if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == module->m_tbl) + goto ignore_module; + } + + class->super = include_class_new(module, class->super); + class = class->super; + ignore_module: + module = module->super; + } + rb_clear_cache2(class); +} + +void +rb_add_method(class, mid, node, scope) + struct RClass *class; + ID mid; + NODE *node; + enum mth_scope scope; +{ + struct RMethod *body; + NEWOBJ(mth, struct RMethod); + OBJSETUP(mth, C_Method, T_METHOD); + + if (class == Qnil) class = (struct RClass*)C_Object; + if (st_lookup(class->m_tbl, mid, &body)) { + if (verbose) { + Warning("redefine %s", rb_id2name(mid)); + } + unliteralize(body); + rb_clear_cache(body); + } + mth->node = node; + if (BUILTIN_TYPE(class) == T_MODULE) + mth->origin = Qnil; + else + mth->origin = class; + mth->id = mid; + mth->scope = scope; + literalize(mth); + st_insert(class->m_tbl, mid, mth); +} + +void +rb_define_method(class, name, func, argc) + struct RClass *class; + char *name; + VALUE (*func)(); + int argc; +{ + NODE *temp = NEW_CFUNC(func, argc); + + rb_add_method(class, rb_intern(name), temp, MTH_METHOD); +} + +void +rb_define_func(class, name, func, argc) + struct RClass *class; + char *name; + VALUE (*func)(); + int argc; +{ + NODE *temp = NEW_CFUNC(func, argc); + + rb_add_method(class, rb_intern(name), temp, MTH_FUNC); +} + +void +rb_undef_method(class, name) + struct RClass *class; + char *name; +{ + rb_add_method(class, rb_intern(name), Qnil, MTH_UNDEF); +} + +VALUE +rb_single_class(obj) + struct RBasic *obj; +{ + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + case T_STRUCT: + break; + default: + Fail("can't define single method for built-in classes"); + break; + } + + if (FL_TEST(obj->class, FL_SINGLE)) { + return (VALUE)obj->class; + } + return obj->class = single_class_new(obj->class); +} + +void +rb_define_single_method(obj, name, func, argc) + VALUE obj; + char *name; + VALUE (*func)(); + int argc; +{ + rb_define_method(rb_single_class(obj), name, func, argc, MTH_METHOD); +} + +void +rb_define_mfunc(class, name, func, argc) + struct RClass *class; + char *name; + VALUE (*func)(); + int argc; +{ + rb_define_func(class, name, func, argc); + rb_define_single_method(class, name, func, argc); +} + +void +rb_define_alias(class, name1, name2) + struct RClass *class; + char *name1, *name2; +{ + rb_alias(class, rb_intern(name1), rb_intern(name2)); +} + +void +rb_define_attr(class, name, pub) + struct RClass *class; + char *name; + int pub; +{ + char *buf; + ID attr, attreq, attriv; + + attr = rb_intern(name); + buf = (char*)alloca(strlen(name) + 2); + sprintf(buf, "%s=", name); + attreq = rb_intern(buf); + sprintf(buf, "@%s", name); + attriv = rb_intern(buf); + if (rb_get_method_body(class, attr, 0, MTH_METHOD) == Qnil) { + rb_add_method(class, attr, NEW_IVAR(attriv), MTH_METHOD); + } + if (pub && rb_get_method_body(class, attreq, 0, MTH_METHOD) == Qnil) { + rb_add_method(class, attreq, NEW_ATTRSET(attriv), MTH_METHOD); + } +} + +void +rb_define_single_attr(obj, name, pub) + VALUE obj; + char *name; + int pub; +{ + rb_define_attr(rb_single_class(obj), name, pub); +} + +#include <varargs.h> +#include <ctype.h> + +int +rb_scan_args(args, fmt, va_alist) + VALUE args; + char *fmt; + va_dcl +{ + int n, i, len; + char *p = fmt; + VALUE *var; + va_list vargs; + + if (NIL_P(args)) { + len = 0; + } + else { + Check_Type(args, T_ARRAY); + len = RARRAY(args)->len; + } + + va_start(vargs); + + if (*p == '*') { + var = va_arg(vargs, VALUE*); + *var = args; + return len; + } + + if (isdigit(*p)) { + n = *p - '0'; + if (n > len) + Fail("Wrong number of arguments for %s", + rb_id2name(the_env->last_func)); + for (i=0; i<n; i++) { + var = va_arg(vargs, VALUE*); + *var = ary_entry(args, i); + } + p++; + } + else { + goto error; + } + + if (isdigit(*p)) { + n = i + *p - '0'; + for (; i<n; i++) { + var = va_arg(vargs, VALUE*); + if (len > i) { + *var = ary_entry(args, i); + } + else { + *var = Qnil; + } + } + p++; + } + + if(*p == '*') { + var = va_arg(vargs, VALUE*); + if (len > i) { + *var = ary_new4(RARRAY(args)->len-i, RARRAY(args)->ptr+i); + } + else { + *var = ary_new(); + } + } + else if (*p == '\0') { + if (len > i) { + Fail("Wrong # of arguments(%d for %d)", len, i); + } + } + else { + goto error; + } + + va_end(vargs); + return len; + + error: + Fail("bad scan arg format: %s", fmt); +} diff --git a/compar.c b/compar.c new file mode 100644 index 0000000000..84b2583ce5 --- /dev/null +++ b/compar.c @@ -0,0 +1,99 @@ +/************************************************ + + compar.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Thu Aug 26 14:39:48 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +VALUE M_Comparable; + +static ID cmp; + +static VALUE +Fcmp_eq(this, other) + VALUE this, other; +{ + VALUE c = rb_funcall(this, cmp, 1, other); + int t = NUM2INT(c); + + if (t == 0) return TRUE; + return FALSE; +} + +static VALUE +Fcmp_gt(this, other) + VALUE this, other; +{ + VALUE c = rb_funcall(this, cmp, 1, other); + int t = NUM2INT(c); + + if (t > 0) return other; + return FALSE; +} + +static VALUE +Fcmp_ge(this, other) + VALUE this, other; +{ + VALUE c = rb_funcall(this, cmp, 1, other); + int t = NUM2INT(c); + + if (t >= 0) return other; + return FALSE; +} + +static VALUE +Fcmp_lt(this, other) + VALUE this, other; +{ + VALUE c = rb_funcall(this, cmp, 1, other); + int t = NUM2INT(c); + + if (t < 0) return other; + return FALSE; +} + +static VALUE +Fcmp_le(this, other) + VALUE this, other; +{ + VALUE c = rb_funcall(this, cmp, 1, other); + int t = NUM2INT(c); + + if (t <= 0) return other; + return FALSE; +} + +static VALUE +Fcmp_between(this, min, max) + VALUE this, min, max; +{ + VALUE c = rb_funcall(this, cmp, 1, min); + int t = NUM2INT(c); + if (t < 0) return FALSE; + + c = rb_funcall(this, cmp, 1, min); + t = NUM2INT(c); + if (t > 0) return FALSE; + return TRUE; +} + +Init_Comparable() +{ + M_Comparable = rb_define_module("Comparable"); + rb_define_method(M_Comparable, "==", Fcmp_eq, 1); + rb_define_method(M_Comparable, ">", Fcmp_gt, 1); + rb_define_method(M_Comparable, ">=", Fcmp_ge, 1); + rb_define_method(M_Comparable, "<", Fcmp_lt, 1); + rb_define_method(M_Comparable, "<=", Fcmp_le, 1); + rb_define_method(M_Comparable, "between", Fcmp_between, 2); + + cmp = rb_intern("<=>"); +} diff --git a/config.status b/config.status new file mode 100755 index 0000000000..7bdc7b26ed --- /dev/null +++ b/config.status @@ -0,0 +1,72 @@ +#!/bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host dyna: +# +# ./configure + +for arg +do + case "$arg" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo running ${CONFIG_SHELL-/bin/sh} ./configure + exec ${CONFIG_SHELL-/bin/sh} ./configure ;; + *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;; + esac +done + +trap 'rm -f Makefile; exit 1' 1 3 15 +PROGS='ruby' +CC='gcc' +CPP='gcc -E' +DBM='-fpcc-struct-return' +STATIC='' +YACC='bison -y' +INSTALL='/usr/bin/install -c' +INSTALL_PROGRAM='$(INSTALL)' +INSTALL_DATA='$(INSTALL) -m 644' +ALLOCA='' +LIBS=' -lm -ldbm' +srcdir='.' +DEFS=' -DHAVE_UNISTD_H=1 -DHAVE_SYSCALL_H=1 -DHAVE_A_OUT_H=1 -DDIRENT=1 -DGETGROUPS_T=gid_t -DRETSIGTYPE=void -DHAVE_GETOPT_LONG=1 -DHAVE_MEMMOVE=1 -DHAVE_STRERROR=1 -DHAVE_STRTOL=1 -DHAVE_STRTOUL=1 -DHAVE_STRDUP=1 -DHAVE_SETENV=1 -DHAVE_KILLPG=1 -DHAVE_MKDIR=1 -DHAVE_STRFTIME=1 -DHAVE_ALLOCA_H=1' +prefix='' +exec_prefix='' +prsub='' +extrasub='' + +top_srcdir=$srcdir + +CONFIG_FILES=${CONFIG_FILES-"Makefile"} +for file in .. ${CONFIG_FILES}; do if test "x$file" != x..; then + srcdir=$top_srcdir + # Remove last slash and all that follows it. Not all systems have dirname. + dir=`echo $file|sed 's%/[^/][^/]*$%%'` + if test "$dir" != "$file"; then + test "$top_srcdir" != . && srcdir=$top_srcdir/$dir + test ! -d $dir && mkdir $dir + fi + echo creating $file + rm -f $file + echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file + sed -e " +$prsub +$extrasub +s%@PROGS@%$PROGS%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@DBM@%$DBM%g +s%@STATIC@%$STATIC%g +s%@YACC@%$YACC%g +s%@INSTALL@%$INSTALL%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@ALLOCA@%$ALLOCA%g +s%@LIBS@%$LIBS%g +s%@srcdir@%$srcdir%g +s%@DEFS@%$DEFS% +" $top_srcdir/${file}.in >> $file +fi; done + + +exit 0 diff --git a/configure.in b/configure.in new file mode 100644 index 0000000000..0acb17eae5 --- /dev/null +++ b/configure.in @@ -0,0 +1,63 @@ + +dnl Process this file with autoconf to produce a configure script. +AC_INIT(ruby.h) +PROGS="ruby" +AC_SUBST(PROGS)dnl +AC_PROG_CC +AC_GCC_TRADITIONAL +if test $GCC -eq 1 ; then + DBM=-fpcc-struct-return +fi +AC_SUBST(DBM)dnl +if test "$HOSTTYPE" = sparc; then + if test $GCC -eq 1 ; then + STATIC=-static + else + STATIC=-Bstatic + fi +else + STATIC= +fi +AC_SUBST(STATIC)dnl +AC_PROG_YACC +AC_PROG_INSTALL +AC_HAVE_HEADERS(unistd.h syscall.h a.out.h) +AC_DIR_HEADER +AC_GETGROUPS_T +AC_RETSIGTYPE +AC_HAVE_FUNCS(getopt_long memmove strerror strtoul strdup strstr) +AC_HAVE_FUNCS(setenv fmod killpg mkdir strftime socket random) +AC_HAVE_FUNCS(wait4 waitpid) +if echo $DEFS | grep "HAVE_SETENV" 2>&1 > /dev/null; then + : +else + AC_HAVE_FUNCS(putenv) +fi +if echo $DEFS | grep "HAVE_STRFTIME" 2>&1 > /dev/null; then + : +else + AC_TIMEZONE + AC_COMPILE_CHECK([daylight], [], + [extern int daylight; daylight;], AC_DEFINE(HAVE_DAYLIGHT)) +fi +AC_ALLOCA +AC_WORDS_BIGENDIAN +AC_ST_BLKSIZE +AC_ST_BLOCKS +AC_ST_RDEV +AC_COMPILE_CHECK([pw_change in struct passwd], [#include <pwd.h>], +[struct passwd pw; pw.pw_change;], AC_DEFINE(PW_CHANGE)) +AC_COMPILE_CHECK([pw_quota in struct passwd], [#include <pwd.h>], +[struct passwd pw; pw.pw_quota;], AC_DEFINE(PW_QUOTA)) +AC_COMPILE_CHECK([pw_age in struct passwd], [#include <pwd.h>], +[struct passwd pw; pw.pw_age;], AC_DEFINE(PW_AGE)) +AC_COMPILE_CHECK([pw_class in struct passwd], [#include <pwd.h>], +[struct passwd pw; pw.pw_class;], AC_DEFINE(PW_CLASSS)) +AC_COMPILE_CHECK([pw_comment in struct passwd], [#include <pwd.h>], +[struct passwd pw; pw.pw_comment;], AC_DEFINE(PW_COMMENT)) +AC_COMPILE_CHECK([pw_expire in struct passwd], [#include <pwd.h>], +[struct passwd pw; pw.pw_expire;], AC_DEFINE(PW_EXPIRE)) +AC_HAVE_LIBRARY(m, [LIBS="$LIBS -lm"]) +AC_HAVE_LIBRARY(dbm, [LIBS="$LIBS -ldbm"]) +AC_HAVE_LIBRARY(socket, [LIBS="$LIBS -lsocket"]) +AC_OUTPUT(Makefile) @@ -0,0 +1,401 @@ +/************************************************ + + dbm.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Mon Jan 24 15:59:52 JST 1994 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +#ifdef USE_DBM + +#include <ndbm.h> +#include <sys/file.h> +#include <errno.h> + +VALUE C_DBM; + +extern VALUE M_Enumerable; + +static void +closeddbm() +{ + Fail("closed DBM file"); +} + +#define GetDBM(obj, dbmp) {\ + DBM **_dbm;\ + Get_Data_Struct(obj, "dbm", DBM*, _dbm);\ + dbmp = *_dbm;\ + if (dbmp == Qnil) closeddbm();\ +} + +static void +free_dbm(dbmp) + DBM **dbmp; +{ + if (*dbmp) dbm_close(*dbmp); +} + +#define MakeDBM(obj, dp) {\ + DBM **_dbm;\ + Make_Data_Struct(obj,"dbm",DBM*,Qnil,free_dbm,_dbm);\ + *_dbm=dp;\ +} + +static VALUE +Fdbm_open(class, args) + VALUE class, args; +{ + VALUE file, vmode; + DBM *dbm, **dbm2; + int mode; + VALUE obj; + + if (rb_scan_args(args, "11", &file, &vmode) == 1) { + mode = 0666; /* default value */ + } + else if (NIL_P(vmode)) { + mode = -1; /* return nil if DB not exist */ + } + else { + mode = NUM2INT(vmode); + } + Check_Type(file, T_STRING); + + dbm = Qnil; + if (mode >= 0) + dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode); + if (!dbm) + dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, mode); + if (!dbm) + dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, mode); + + if (!dbm) { + if (mode == -1) return Qnil; + rb_sys_fail(RSTRING(file)->ptr); + } + + GC_LINK; + GC_PRO3(obj, obj_alloc(class)); + MakeDBM(obj, dbm); + GC_UNLINK; + + return obj; +} + +static VALUE +Fdbm_close(obj) + VALUE obj; +{ + DBM **dbmp; + + Get_Data_Struct(obj, "dbm", DBM*, dbmp); + if (*dbmp == Qnil) Fail("already closed DBM file"); + dbm_close(*dbmp); + *dbmp = Qnil; + + return Qnil; +} + +static VALUE +Fdbm_fetch(obj, keystr) + VALUE obj, keystr; +{ + datum key, value; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbm); + value = dbm_fetch(dbm, key); + if (value.dptr == Qnil) { + return Qnil; + } + return str_new(value.dptr, value.dsize); +} + +static VALUE +Fdbm_delete(obj, keystr) + VALUE obj, keystr; +{ + datum key; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbm); + if (dbm_delete(dbm, key)) { + Fail("DBM delete failed"); + } + return obj; +} + +static VALUE +Fdbm_delete_if(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE keystr, valstr; + + GetDBM(obj, dbm); + GC_LINK; + GC_PRO2(keystr); GC_PRO2(valstr); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + keystr = str_new(key.dptr, key.dsize); + valstr = str_new(val.dptr, val.dsize); + if (rb_yield(assoc_new(keystr, valstr)) + && dbm_delete(dbm, key)) { + Fail("DBM delete failed"); + } + } + GC_UNLINK; + return obj; +} + +static VALUE +Fdbm_clear(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + if (dbm_delete(dbm, key)) { + Fail("DBM delete failed"); + } + } + return obj; +} + +static VALUE +Fdbm_store(obj, keystr, valstr) + VALUE obj, keystr, valstr; +{ + datum key, val; + DBM *dbm; + + if (valstr == Qnil) { + Fdbm_delete(obj, keystr); + return Qnil; + } + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + Check_Type(valstr, T_STRING); + val.dptr = RSTRING(valstr)->ptr; + val.dsize = RSTRING(valstr)->len; + + GetDBM(obj, dbm); + if (dbm_store(dbm, key, val, DBM_REPLACE)) { + dbm_clearerr(dbm); + if (errno == EPERM) rb_sys_fail(Qnil); + Fail("DBM store failed"); + } + return valstr; +} + +static VALUE +Fdbm_length(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + int i = 0; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + i++; + } + return INT2FIX(i); +} + +static VALUE +Fdbm_each(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + rb_yield(str_new(val.dptr, val.dsize)); + } + return obj; +} + +static VALUE +Fdbm_each_key(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + rb_yield(str_new(key.dptr, key.dsize)); + } + return obj; +} + +static VALUE +Fdbm_each_pair(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE keystr, valstr; + + GetDBM(obj, dbm); + GC_LINK; + GC_PRO2(keystr); GC_PRO2(valstr); + + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + keystr = str_new(key.dptr, key.dsize); + valstr = str_new(val.dptr, val.dsize); + rb_yield(assoc_new(keystr, valstr)); + } + GC_UNLINK; + + return obj; +} + +static VALUE +Fdbm_keys(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + VALUE ary; + + GC_LINK; + GC_PRO3(ary, ary_new()); + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + Fary_push(ary, str_new(key.dptr, key.dsize)); + } + GC_UNLINK; + return ary; +} + +static VALUE +Fdbm_values(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE ary; + + GC_LINK; + GC_PRO3(ary, ary_new()); + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + Fary_push(ary, str_new(val.dptr, val.dsize)); + } + GC_UNLINK; + return ary; +} + +static VALUE +Fdbm_has_key(obj, keystr) + VALUE obj, keystr; +{ + datum key, val; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbm); + val = dbm_fetch(dbm, key); + if (val.dptr) return TRUE; + return FALSE; +} + +static VALUE +Fdbm_has_value(obj, valstr) + VALUE obj, valstr; +{ + datum key, val; + DBM *dbm; + + Check_Type(valstr, T_STRING); + val.dptr = RSTRING(valstr)->ptr; + val.dsize = RSTRING(valstr)->len; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + if (val.dsize == RSTRING(valstr)->len && + memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) + return TRUE; + } + return FALSE; +} + +static VALUE +Fdbm_to_a(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE ary; + + GetDBM(obj, dbm); + + GC_LINK; + GC_PRO3(ary, ary_new()); + + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + Fary_push(ary, assoc_new(str_new(key.dptr, key.dsize), + str_new(val.dptr, val.dsize))); + } + + GC_UNLINK; + return ary; +} + +Init_DBM() +{ + C_DBM = rb_define_class("DBM", C_Object); + rb_include_module(C_DBM, M_Enumerable); + + rb_define_single_method(C_DBM, "open", Fdbm_open, -2); + rb_define_method(C_DBM, "close", Fdbm_close, 0); + rb_define_method(C_DBM, "[]", Fdbm_fetch, 1); + rb_define_method(C_DBM, "[]=", Fdbm_store, 2); + rb_define_method(C_DBM, "length", Fdbm_length, 0); + rb_define_method(C_DBM, "each", Fdbm_each, 0); + rb_define_method(C_DBM, "each_value", Fdbm_each, 0); + rb_define_method(C_DBM, "each_key", Fdbm_each_key, 0); + rb_define_method(C_DBM, "each_pair", Fdbm_each_pair, 0); + rb_define_method(C_DBM, "keys", Fdbm_keys, 0); + rb_define_method(C_DBM, "values", Fdbm_values, 0); + rb_define_method(C_DBM, "delete", Fdbm_delete, 1); + rb_define_method(C_DBM, "delete_if", Fdbm_delete_if, 0); + rb_define_method(C_DBM, "clear", Fdbm_clear, 0); + rb_define_method(C_DBM, "includes", Fdbm_has_key, 1); + rb_define_method(C_DBM, "has_key", Fdbm_has_key, 1); + rb_define_method(C_DBM, "has_value", Fdbm_has_value, 1); + + rb_define_method(C_DBM, "to_a", Fdbm_to_a, 0); +} +#endif /* USE_DBM */ diff --git a/defines.h b/defines.h new file mode 100644 index 0000000000..b65433468b --- /dev/null +++ b/defines.h @@ -0,0 +1,36 @@ +/************************************************ + + defines.h - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Wed May 18 00:21:44 JST 1994 + +************************************************/ +#ifndef DEFINES_H +#define DEFINES_H + +#define RUBY + +/* #include "config.h" */ + +/* define USE_DLN to load object file(.o). */ +#ifdef HAVE_A_OUT_H + +#undef USE_DLN +#ifdef USE_DLN +#define LIBC_NAME "libc.a" +#define DLN_DEFAULT_PATH "/lib:/usr/lib:." +#endif + +#endif + +/* define USE_DBM to use dbm class. */ +#define USE_DBM + +#ifdef HAVE_SYSCALL_H +/* define SAFE_SIGHANDLE to override syscall for trap. */ +#define SAFE_SIGHANDLE +#endif + +#endif diff --git a/dict.c b/dict.c new file mode 100644 index 0000000000..909a85ae81 --- /dev/null +++ b/dict.c @@ -0,0 +1,517 @@ +/************************************************ + + dict.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Mon Nov 22 18:51:18 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "st.h" + +VALUE C_Dict, C_EnvDict; +static ID hash, eq; +VALUE Fgetenv(), Fsetenv(); + +static VALUE +rb_cmp(a, b) + VALUE a, b; +{ + return rb_funcall(a, eq, 1, b)?0:1; +} + +static VALUE +rb_hash(a, mod) + VALUE a; + int mod; +{ + return rb_funcall(a, hash, 0) % mod; +} + +#define ASSOC_KEY(a) RARRAY(a)->ptr[0] +#define ASSOC_VAL(a) RARRAY(a)->ptr[1] + +VALUE +Fdic_new(class) + VALUE class; +{ + int i, max; + NEWOBJ(dic, struct RDict); + OBJSETUP(dic, class, T_DICT); + + GC_LINK; + GC_PRO(dic); + + dic->tbl = st_init_table(rb_cmp, rb_hash); + GC_UNLINK; + + return (VALUE)dic; +} + +static VALUE +Fdic_clone(dic) + struct RDict *dic; +{ + NEWOBJ(dic2, struct RDict); + CLONESETUP(dic2, dic); + + GC_LINK; + GC_PRO(dic2); + + dic2->tbl = (st_table*)st_copy(dic->tbl); + + GC_UNLINK; + + return (VALUE)dic2; +} + +static VALUE +Fdic_aref(dic, key) + struct RDict *dic; + VALUE key; +{ + VALUE val = Qnil; + + if (!st_lookup(dic->tbl, key, &val)) { + return Qnil; + } + return val; +} + +static VALUE +Fdic_delete(dic, key) + struct RDict *dic; + VALUE key; +{ + VALUE val; + + if (st_delete(dic->tbl, &key, &val)) + return val; + return Qnil; +} + +static int +dic_delete_if(key, value) + VALUE key, value; +{ + if (rb_yield(assoc_new(key, value))) + return ST_DELETE; + return ST_CONTINUE; +} + +static VALUE +Fdic_delete_if(dic) + struct RDict *dic; +{ + st_foreach(dic->tbl, dic_delete_if, Qnil); + + return (VALUE)dic; +} + +static +dic_clear(key, value) + VALUE key, value; +{ + return ST_DELETE; +} + +static VALUE +Fdic_clear(dic) + struct RDict *dic; +{ + st_foreach(dic->tbl, dic_clear, Qnil); + + return (VALUE)dic; +} + +VALUE +Fdic_aset(dic, key, val) + struct RDict *dic; + VALUE key, val; +{ + if (val == Qnil) { + Fdic_delete(dic, key); + return Qnil; + } + st_insert(dic->tbl, key, val); + return val; +} + +static VALUE +Fdic_length(dic) + struct RDict *dic; +{ + return INT2FIX(dic->tbl->num_entries); +} + +static +dic_each(key, value) + VALUE key, value; +{ + rb_yield(value); + return ST_CONTINUE; +} + +static VALUE +Fdic_each(dic) + struct RDict *dic; +{ + st_foreach(dic->tbl, dic_each); + return (VALUE)dic; +} + +static +dic_each_key(key, value) + VALUE key, value; +{ + rb_yield(key); + return ST_CONTINUE; +} + +static VALUE +Fdic_each_key(dic) + struct RDict *dic; +{ + st_foreach(dic->tbl, dic_each_key); + return (VALUE)dic; +} + +static +dic_each_pair(key, value) + VALUE key, value; +{ + rb_yield(assoc_new(key, value)); + return ST_CONTINUE; +} + +static VALUE +Fdic_each_pair(dic) + struct RDict *dic; +{ + st_foreach(dic->tbl, dic_each_pair); + return (VALUE)dic; +} + +static +dic_to_a(key, value, ary) + VALUE key, value, ary; +{ + Fary_push(ary, assoc_new(key, value)); + return ST_CONTINUE; +} + +static VALUE +Fdic_to_a(dic) + struct RDict *dic; +{ + VALUE ary; + + GC_LINK; + GC_PRO3(ary, ary_new()); + st_foreach(dic->tbl, dic_to_a, ary); + GC_UNLINK; + + return ary; +} + +static +dic_inspect(key, value, str) + VALUE key, value; + struct RString *str; +{ + VALUE str2; + ID inspect = rb_intern("_inspect"); + + if (str->len > 1) { + str_cat(str, ", ", 2); + } + GC_LINK; + GC_PRO3(str2, rb_funcall(key, inspect, 0, Qnil)); + str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + str_cat(str, "=>", 2); + str2 = rb_funcall(value, inspect, 0, Qnil); + str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + GC_UNLINK; + + return ST_CONTINUE; +} + +static VALUE +Fdic_inspect(dic) + struct RDict *dic; +{ + VALUE str; + + GC_LINK; + GC_PRO3(str, str_new2("{")); + st_foreach(dic->tbl, dic_inspect, str); + str_cat(str, "}", 1); + GC_UNLINK; + + return str; +} + +static VALUE +Fdic_to_s(dic) + VALUE dic; +{ + VALUE str; + + GC_LINK; + GC_PRO(dic); + dic = Fdic_to_a(dic); + str = Fary_to_s(dic); + GC_UNLINK; + + return str; +} + +static +dic_keys(key, value, ary) + VALUE key, value, ary; +{ + Fary_push(ary, key); + return ST_CONTINUE; +} + +static VALUE +Fdic_keys(dic) + struct RDict *dic; +{ + VALUE ary; + + GC_LINK; + GC_PRO3(ary, ary_new()); + st_foreach(dic->tbl, dic_keys, ary); + GC_UNLINK; + return ary; +} + +static +dic_values(key, value, ary) + VALUE key, value, ary; +{ + Fary_push(ary, key); + return ST_CONTINUE; +} + +static VALUE +Fdic_values(dic) + struct RDict *dic; +{ + VALUE ary; + + GC_LINK; + GC_PRO3(ary, ary_new()); + st_foreach(dic->tbl, dic_values, ary); + GC_UNLINK; + return ary; +} + +static VALUE +Fdic_has_key(dic, key) + struct RDict *dic; + VALUE key; +{ + VALUE val; + + if (st_lookup(dic->tbl, key, &val)) + return TRUE; + return FALSE; +} + +static VALUE value_found; + +static +dic_search_value(key, value, arg) + VALUE key, value, arg; +{ + if (rb_funcall(value, eq, 1, arg)) { + value_found = TRUE; + return ST_STOP; + } + return ST_CONTINUE; +} + +static VALUE +Fdic_has_value(dic, val) + struct RDict *dic; + VALUE val; +{ + value_found = FALSE; + st_foreach(dic->tbl, dic_search_value, val); + return value_found; +} + +char *index(); +extern VALUE rb_readonly_hook(); + +extern char **environ; + +static VALUE +Fenv_each(dic) + VALUE dic; +{ + char **env; + + env = environ; + while (*env) { + VALUE var, val; + char *s = index(*env, '='); + + GC_LINK; + GC_PRO3(var, str_new(*env, s-*env)); + GC_PRO3(val, str_new2(s+1)); + rb_yield(assoc_new(var, val)); + GC_UNLINK; + env++; + } + return dic; +} + +static VALUE +Fenv_delete(obj, name) + VALUE obj; + struct RString *name; +{ + int i, len; + char *nam, *val = Qnil; + + Check_Type(name, T_STRING); + nam = name->ptr; + len = strlen(nam); + for(i=0; environ[i]; i++) { + if (strncmp(environ[i], nam, len) == 0 && environ[i][len] == '=') { + val = environ[i]+len+1; + break; + } + } + while (environ[i]) { + environ[i] = environ[i+1]; + i++; + } + if (val) { + return str_new2(val); + } + return Qnil; +} + +VALUE +Fgetenv(obj, name) + VALUE obj; + struct RString *name; +{ + extern char *getenv(); + char *env; + + Check_Type(name, T_STRING); + + if (strlen(name->ptr) != name->len) + Fail("Bad environment name"); + + env = getenv(name->ptr); + if (env) { + return str_new2(env); + } + return Qnil; +} + +VALUE +Fsetenv(obj, name, value) + VALUE obj; + struct RString *name, *value; +{ + Check_Type(name, T_STRING); + if (value == Qnil) { + Fenv_delete(obj, name); + return Qnil; + } + + Check_Type(value, T_STRING); + + if (strlen(name->ptr) != name->len) + Fail("Bad environment name"); + if (strlen(value->ptr) != value->len) + Fail("Bad environment value"); + +#ifdef HAVE_SETENV + if (setenv(name->ptr, value->ptr, 1) == 0) return TRUE; +#else +#ifdef HAVE_PUTENV + { + char *str; + int len; + + str = ALLOC_N(char, name->len + value->len + 2); + sprintf("%s=%s", name->ptr, value->ptr); + if (putenv(str) == 0) return TRUE; + } +#else + Fail("setenv is not supported on this system"); +#endif +#endif + + Fail("setenv failed"); + return FALSE; /* not reached */ +} + +Init_Dict() +{ + extern VALUE C_Kernel; + extern VALUE M_Enumerable; + static VALUE envtbl; + + hash = rb_intern("hash"); + eq = rb_intern("=="); + + C_Dict = rb_define_class("Dict", C_Object); + rb_name_class(C_Dict, rb_intern("Hash")); /* alias */ + + rb_include_module(C_Dict, M_Enumerable); + + rb_define_single_method(C_Dict, "new", Fdic_new, 0); + + rb_define_method(C_Dict,"clone", Fdic_clone, 0); + + rb_define_method(C_Dict,"to_a", Fdic_to_a, 0); + rb_define_method(C_Dict,"to_s", Fdic_to_s, 0); + rb_define_method(C_Dict,"_inspect", Fdic_inspect, 0); + + rb_define_method(C_Dict,"[]", Fdic_aref, 1); + rb_define_method(C_Dict,"[]=", Fdic_aset, 2); + rb_define_method(C_Dict,"length", Fdic_length, 0); + rb_define_method(C_Dict,"each", Fdic_each, 0); + rb_define_method(C_Dict,"each_value", Fdic_each, 0); + rb_define_method(C_Dict,"each_key", Fdic_each_key, 0); + rb_define_method(C_Dict,"each_pair", Fdic_each_pair, 0); + + rb_define_method(C_Dict,"keys", Fdic_keys, 0); + rb_define_method(C_Dict,"values", Fdic_values, 0); + + rb_define_method(C_Dict,"delete", Fdic_delete, 1); + rb_define_method(C_Dict,"delete_if", Fdic_delete_if, 0); + rb_define_method(C_Dict,"clear", Fdic_clear, 0); + + rb_define_method(C_Dict,"includes", Fdic_has_key, 1); + rb_define_method(C_Dict,"has_key", Fdic_has_key, 1); + rb_define_method(C_Dict,"has_value", Fdic_has_value, 1); + + + C_EnvDict = rb_define_class("EnvDict", C_Object); + + rb_include_module(C_EnvDict, M_Enumerable); + + rb_define_method(C_EnvDict,"[]", Fgetenv, 1); + rb_define_method(C_EnvDict,"[]=", Fsetenv, 2); + rb_define_method(C_EnvDict,"each", Fenv_each, 0); + rb_define_method(C_EnvDict,"delete", Fenv_delete, 1); + envtbl = obj_alloc(C_EnvDict); + rb_define_variable("$ENV", &envtbl, Qnil, rb_readonly_hook); + + rb_define_func(C_Kernel, "getenv", Fgetenv, 1); + rb_define_func(C_Kernel, "setenv", Fsetenv, 2); +} @@ -0,0 +1,257 @@ +/************************************************ + + dir.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Wed Jan 5 09:51:01 JST 1994 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/param.h> + +/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */ +#if defined(DIRENT) || defined(_POSIX_VERSION) +#include <dirent.h> +#define NLENGTH(dirent) (strlen((dirent)->d_name)) +#else /* not (DIRENT or _POSIX_VERSION) */ +#define dirent direct +#define NLENGTH(dirent) ((dirent)->d_namlen) +#ifdef SYSNDIR +#include <sys/ndir.h> +#endif /* SYSNDIR */ +#ifdef SYSDIR +#include <sys/dir.h> +#endif /* SYSDIR */ +#ifdef NDIR +#include <ndir.h> +#endif /* NDIR */ +#endif /* not (DIRENT or _POSIX_VERSION) */ + +static VALUE C_Dir; + +static void +free_dir(dir) + DIR **dir; +{ + if (dir) closedir(*dir); +} + +static VALUE +Fdir_open(dir_class, dirname) + VALUE dir_class; + struct RString *dirname; +{ + VALUE obj; + DIR *dirp, **d; + + Check_Type(dirname, T_STRING); + + dirp = opendir(dirname->ptr); + if (dirp == NULL) Fail("Can't open directory %s", dirname->ptr); + + GC_LINK; + GC_PRO3(obj, obj_alloc(dir_class)); + Make_Data_Struct(obj, "dir", DIR*, Qnil, free_dir, d); + *d = dirp; + /* use memcpy(d, dirp, sizeof(DIR)) if needed.*/ + GC_UNLINK; + + return obj; +} + +static void +closeddir() +{ + Fail("closed directory"); +} + +#define GetDIR(obj, dirp) {\ + DIR **_dp;\ + Get_Data_Struct(obj, "dir", DIR*, _dp);\ + dirp = *_dp;\ + if (dirp == NULL) closeddir();\ +} + +static VALUE +Fdir_each(dir) + VALUE dir; +{ + extern VALUE rb_lastline; + DIR *dirp; + struct dirent *dp; + + GetDIR(dir, dirp); + for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + rb_lastline = str_new(dp->d_name, NLENGTH(dp)); + rb_yield(rb_lastline); + } + return dir; +} + +static VALUE +Fdir_tell(dir) + VALUE dir; +{ + DIR *dirp; + int pos; + + GetDIR(dir, dirp); + pos = telldir(dirp); + return int2inum(pos); +} + +static VALUE +Fdir_seek(dir, pos) + VALUE dir, pos; +{ + DIR *dirp; + + GetDIR(dir, dirp); + seekdir(dirp, NUM2INT(pos)); + return dir; +} + +static VALUE +Fdir_rewind(dir) + VALUE dir; +{ + DIR *dirp; + + GetDIR(dir, dirp); + rewinddir(dirp); + return dir; +} + +static VALUE +Fdir_close(dir) + VALUE dir; +{ + DIR **dirpp; + + Get_Data_Struct(dir, "dir", DIR*, dirpp); + if (*dirpp == NULL) Fail("already closed directory"); + closedir(*dirpp); + *dirpp = NULL; + + return Qnil; +} + +char *getenv(); + +static VALUE +Fdir_chdir(obj, args) + VALUE obj, args; +{ + VALUE path; + char *dist = ""; + + rb_scan_args(args, "01", args, &path); + if (path) { + Check_Type(path, T_STRING); + dist = RSTRING(path)->ptr; + } + else { + dist = getenv("HOME"); + if (!dist) { + dist = getenv("LOGDIR"); + } + } + + if (chdir(dist) < 0) + rb_sys_fail(Qnil); + + return Qnil; +} + +static VALUE +Fdir_getwd(dir) + VALUE dir; +{ + extern char *getwd(); + char path[MAXPATHLEN]; + + if (getwd(path) == 0) Fail(path); + + return str_new2(path); +} + +static VALUE +Fdir_chroot(dir, path) + VALUE dir, path; +{ + Check_Type(path, T_STRING); + + if (chroot(RSTRING(path)->ptr) == -1) + rb_sys_fail(Qnil); + + return Qnil; +} + +static VALUE +Fdir_mkdir(obj, args) + VALUE obj, args; +{ + VALUE path, vmode; + int mode; + + if (rb_scan_args(args, "11", &path, &vmode) == 2) { + mode = NUM2INT(vmode); + } + else { + mode = 0777; + } + + Check_Type(path, T_STRING); + if (mkdir(RSTRING(path)->ptr, mode) == -1) + rb_sys_fail(RSTRING(path)->ptr); + + return Qnil; +} + +static VALUE +Fdir_rmdir(obj, dir) + VALUE obj; + struct RString *dir; +{ + Check_Type(dir, T_STRING); + if (rmdir(dir->ptr) < 0) + rb_sys_fail(dir->ptr); + + return TRUE; +} + +Init_Dir() +{ + extern VALUE M_Enumerable; + + C_Dir = rb_define_class("Directory", C_Object); + rb_name_class(C_Dir, rb_intern("Dir")); /* alias */ + + rb_include_module(C_Dir, M_Enumerable); + + rb_define_single_method(C_Dir, "open", Fdir_open, 1); + + rb_define_method(C_Dir,"each", Fdir_each, 0); + rb_define_method(C_Dir,"rewind", Fdir_rewind, 0); + rb_define_method(C_Dir,"tell", Fdir_tell, 0); + rb_define_method(C_Dir,"seek", Fdir_seek, 1); + rb_define_method(C_Dir,"close", Fdir_close, 0); + + rb_define_single_method(C_Dir,"chdir", Fdir_chdir, -2); + rb_define_single_method(C_Dir,"getwd", Fdir_getwd, 0); + rb_define_alias(C_Dir, "pwd", "getwd"); + rb_define_single_method(C_Dir,"chroot", Fdir_chroot, 1); + rb_define_single_method(C_Dir,"mkdir", Fdir_mkdir, -2); + rb_define_single_method(C_Dir,"rmdir", Fdir_rmdir, 1); + rb_define_alias(C_Dir, "delete", "rmdir"); + rb_define_alias(C_Dir, "unlink", "rmdir"); +} @@ -0,0 +1,1088 @@ +/************************************************ + + dln.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Tue Jan 18 17:05:06 JST 1994 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include <stdio.h> +#include <sys/param.h> +#include <sys/file.h> +#include "defines.h" +#include "dln.h" +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +char *strdup(); + +extern int errno; +int dln_errno; + +static int dln_init_p = 0; + +#include <sys/stat.h> + +static char fbuf[MAXPATHLEN]; +static char *dln_find_1(); +char *getenv(); +char *index(); +int strcmp(); + +char * +dln_find_exe(fname, path) + char *fname; + char *path; +{ + if (!path) path = getenv("PATH"); + if (!path) path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:."; + return dln_find_1(fname, path, 1); +} + +char * +dln_find_file(fname, path) + char *fname; + char *path; +{ + if (!path) path = "."; + return dln_find_1(fname, path, 0); +} + +static char * +dln_find_1(fname, path, exe_flag) + char *fname; + char *path; + int exe_flag; /* non 0 if looking for executable. */ +{ + register char *dp; + register char *ep; + register char *bp; + struct stat st; + + if (fname[0] == '/') return fname; + + for (dp = path;; dp = ++ep) + { + register int l; + int i; + int fspace; + + /* extract a component */ + ep = index(dp, ':'); + if (ep == NULL) + ep = dp+strlen(dp); + + /* find the length of that component */ + l = ep - dp; + bp = fbuf; + fspace = sizeof fbuf - 2; + if (l > 0) + { + /* + ** If the length of the component is zero length, + ** start from the current directory. If the + ** component begins with "~", start from the + ** user's $HOME environment variable. Otherwise + ** take the path literally. + */ + + if (*dp == '~' && (l == 1 || dp[1] == '/')) + { + char *home; + + home = getenv("HOME"); + if (home != NULL) + { + i = strlen(home); + if ((fspace -= i) < 0) + goto toolong; + memcpy(bp, home, i); + bp += i; + } + dp++; + l--; + } + if (l > 0) + { + if ((fspace -= l) < 0) + goto toolong; + memcpy(bp, dp, l); + bp += l; + } + + /* add a "/" between directory and filename */ + if (ep[-1] != '/') + *bp++ = '/'; + } + + /* now append the file name */ + i = strlen(fname); + if ((fspace -= i) < 0) + { + toolong: + fprintf(stderr, "openpath: pathname too long (ignored)\n"); + *bp = '\0'; + fprintf(stderr, "\tDirectory \"%s\"\n", fbuf); + fprintf(stderr, "\tFile \"%s\"\n", fname); + continue; + } + memcpy(bp, fname, i + 1); + + if (stat(fbuf, &st) == 0) { + if (exe_flag == 0) return fbuf; + /* looking for executable */ +#ifdef RUBY + if (eaccess(fbuf, X_OK) == 0) return fbuf; +#else + { + uid_t uid = getuid(); + gid_t gid = getgid(); + + if (uid == st.st_uid && + (st.st_mode & S_IEXEC) || + gid == st.st_gid && + (st.st_mode & (S_IEXEC>>3)) || + st.st_mode & (S_IEXEC>>6)) { + return fbuf; + } + } +#endif + } + /* if not, and no other alternatives, life is bleak */ + if (*ep == '\0') { + dln_errno = DLN_ENOENT; + return NULL; + } + + /* otherwise try the next component in the search path */ + } +} + +#ifdef USE_DLN + +#include "st.h" +#include <ar.h> +#include <a.out.h> +#ifndef N_COMM +# define N_COMM 0x12 +#endif + +#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) + +static st_table *sym_tbl; +static st_table *undef_tbl; + +static int +dln_load_header(fd, hdrp, disp) + int fd; + struct exec *hdrp; + long disp; +{ + int size; + + lseek(fd, disp, 0); + size = read(fd, hdrp, sizeof(*hdrp)); + if (size == -1) { + dln_errno = errno; + return -1; + } + if (size != sizeof(*hdrp) || N_BADMAG(*hdrp)) { + dln_errno = DLN_ENOEXEC; + return -1; + } + return 0; +} + +#if defined(sun) && defined(sparc) +/* Sparc (Sun 4) macros */ +# undef relocation_info +# define relocation_info reloc_info_sparc +# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) +# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) +# define R_LENGTH(r) (reloc_r_length[(r)->r_type]) +static int reloc_r_rightshift[] = { + 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, +}; +static int reloc_r_bitsize[] = { + 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, +}; +static int reloc_r_length[] = { + 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; +# define R_PCREL(r) \ + ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) +# define R_SYMBOL(r) ((r)->r_index) +#else +# define R_LENGTH(r) ((r)->r_length) +# define R_PCREL(r) ((r)->r_pcrel) +# define R_SYMBOL(r) ((r)->r_symbolnum) +#endif + +static struct relocation_info * +dln_load_reloc(fd, hdrp, disp) + int fd; + struct exec *hdrp; + long disp; +{ + struct relocation_info * reloc; + int size; + + lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); + + size = hdrp->a_trsize + hdrp->a_drsize; + reloc = (struct relocation_info*)xmalloc(size); + if (reloc == NULL) { + dln_errno = errno; + return NULL; + } + + if (read(fd, reloc, size) != size) { + dln_errno = errno; + free(reloc); + return NULL; + } + + return reloc; +} + +static struct nlist * +dln_load_sym(fd, hdrp, disp) + int fd; + struct exec *hdrp; + long disp; +{ + struct nlist * buffer; + struct nlist * sym; + struct nlist * end; + long displ; + int size; + st_table *tbl; + + lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); + if (read(fd, &size, sizeof(int)) != sizeof(int)) { + goto err_noexec; + } + + buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); + if (buffer == NULL) { + dln_errno = errno; + return NULL; + } + + lseek(fd, disp + N_SYMOFF(*hdrp), 0); + if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { + free(buffer); + goto err_noexec; + } + + sym = buffer; + end = sym + hdrp->a_syms / sizeof(struct nlist); + displ = (long)buffer + (long)(hdrp->a_syms); + + while (sym < end) { + sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; + sym++; + } + return buffer; + + err_noexec: + dln_errno = DLN_ENOEXEC; + return NULL; +} + +static st_table * +dln_sym_hash(hdrp, syms) + struct exec *hdrp; + struct nlist *syms; +{ + st_table *tbl; + struct nlist *sym = syms; + struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); + + tbl = st_init_table(strcmp, st_strhash); + if (tbl == NULL) { + dln_errno = errno; + return NULL; + } + + while (sym < end) { + st_insert(tbl, sym->n_un.n_name, sym); + sym++; + } + return tbl; +} + +int +dln_init(prog) + char *prog; +{ + char *file; + int fd, size; + struct exec hdr; + struct nlist *syms; + + if (dln_init_p == 1) return; + + file = dln_find_exe(prog, NULL); + if (file == NULL) return -1; + if ((fd = open(file, O_RDONLY)) < 0) { + dln_errno = errno; + return -1; + } + + if (dln_load_header(fd, &hdr, 0) == -1) return -1; + syms = dln_load_sym(fd, &hdr, 0); + if (syms == NULL) { + close(fd); + return -1; + } + sym_tbl = dln_sym_hash(&hdr, syms); + if (sym_tbl == NULL) { /* file may be start with #! */ + char c = '\0'; + char buf[MAXPATHLEN]; + char *p; + + free(syms); + lseek(fd, 0L, 0); + if (read(fd, &c, 1) == -1) { + dln_errno = errno; + return -1; + } + if (c != '#') goto err_noexec; + if (read(fd, &c, 1) == -1) { + dln_errno = errno; + return -1; + } + if (c != '!') goto err_noexec; + + p = buf; + /* skip forwading spaces */ + while (read(fd, &c, 1) == 1) { + if (c == '\n') goto err_noexec; + if (c != '\t' && c != ' ') { + *p++ = c; + break; + } + } + /* read in command name */ + while (read(fd, p, 1) == 1) { + if (*p == '\n' || *p == '\t' || *p == ' ') break; + p++; + } + *p = '\0'; + printf("%s\n", buf); + + return dln_init(buf); + } + dln_init_p = 1; + undef_tbl = st_init_table(strcmp, st_strhash); + close(fd); + return 0; + + err_noexec: + close(fd); + dln_errno = DLN_ENOEXEC; + return -1; +} + +long +dln_load_text_data(fd, hdrp, bss, disp) + int fd; + struct exec *hdrp; + int bss; + long disp; +{ + int size; + unsigned char* addr; + + lseek(fd, disp + N_TXTOFF(*hdrp), 0); + size = hdrp->a_text + hdrp->a_data; + + if (bss == -1) size += hdrp->a_bss; + else if (bss > 1) size += bss; + + addr = (unsigned char*)xmalloc(size); + if (addr == NULL) { + dln_errno = errno; + return 0; + } + + if (read(fd, addr, size) != size) { + dln_errno = errno; + free(addr); + return 0; + } + + if (bss == -1) { + bzero(addr + hdrp->a_text + hdrp->a_data, hdrp->a_bss); + } + else if (bss > 0) { + bzero(addr + hdrp->a_text + hdrp->a_data, bss ); + } + + return (long)addr; +} + +static int +undef_print(key, value, arg) + char *key; +{ + fprintf(stderr, " %s\n", key); + return ST_CONTINUE; +} + +static +dln_undefined() +{ + fprintf(stderr, "dln: Calling undefined function\n"); + fprintf(stderr, " Undefined symbols:\n"); + st_foreach(undef_tbl, undef_print, NULL); +#ifdef RUBY + rb_exit(1); +#else + exit(1); +#endif +} + +struct undef { + char *name; + struct relocation_info reloc; + long base; + char *addr; + union { + char c; + short s; + long l; + } u; +}; + +static st_table *reloc_tbl = NULL; +static void +link_undef(name, base, reloc) + char *name; + long base; + struct relocation_info *reloc; +{ + static int u_no = 0; + struct undef *obj; + char *addr = (char*)(reloc->r_address + base); + + obj = (struct undef*)xmalloc(sizeof(struct undef)); + obj->name = strdup(name); + obj->reloc = *reloc; + obj->base = base; + switch (R_LENGTH(reloc)) { + case 0: /* byte */ + obj->u.c = *addr; + break; + case 1: /* word */ + obj->u.s = *(short*)addr; + break; + case 2: /* long */ + obj->u.l = *(long*)addr; + break; + } + if (reloc_tbl == NULL) { + reloc_tbl = st_init_table(ST_NUMCMP, ST_NUMHASH); + } + st_insert(reloc_tbl, u_no++, obj); +} + +struct reloc_arg { + char *name; + long value; +}; + +static int +reloc_undef(no, undef, arg) + int no; + struct undef *undef; + struct reloc_arg *arg; +{ + int datum; + char *address; +#if defined(sun) && defined(sparc) + unsigned int mask = 0; +#endif + + if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; + address = (char*)(undef->base + undef->reloc.r_address); + datum = arg->value; + + if (R_PCREL(&(undef->reloc))) datum -= undef->base; +#if defined(sun) && defined(sparc) + datum += undef->reloc.r_addend; + datum >>= R_RIGHTSHIFT(&(undef->reloc)); + mask = 1 << R_BITSIZE(&(undef->reloc)) - 1; + mask |= mask -1; + datum &= mask; + switch (R_LENGTH(&(undef->reloc))) { + case 0: + *address = undef->u.c; + *address &= ~mask; + *address |= datum; + break; + case 1: + *(short *)address = undef->u.s; + *(short *)address &= ~mask; + *(short *)address |= datum; + break; + case 2: + *(long *)address = undef->u.l; + *(long *)address &= ~mask; + *(long *)address |= datum; + break; + } +#else + switch (R_LENGTH(&(undef->reloc))) { + case 0: /* byte */ + *address = undef->u.c + datum; + break; + case 1: /* word */ + *(short *)address = undef->u.s + datum; + break; + case 2: /* long */ + *(long *)address = undef->u.l + datum; + break; + } +#endif + free(undef->name); + free(undef); + return ST_DELETE; +} + +static int +unlink_undef(name, value) + char *name; + long value; +{ + struct reloc_arg arg; + + arg.name = name; + arg.value = value; + st_foreach(reloc_tbl, reloc_undef, &arg); +} + +static int dln_load_1(fd, disp, need_init) + int fd; + long disp; + int need_init; +{ + static char *libc = LIBC_NAME; + struct exec hdr; + struct relocation_info *reloc = NULL; + long block = 0; + long new_common = 0; /* Length of new common */ + struct nlist *syms = NULL; + struct nlist *sym; + struct nlist *end; + int init_p = 0; + + if (dln_load_header(fd, &hdr, disp) == -1) return -1; + if (INVALID_OBJECT(hdr)) { + dln_errno = DLN_ENOEXEC; + return -1; + } + reloc = dln_load_reloc(fd, &hdr, disp); + if (reloc == NULL) return -1; + syms = dln_load_sym(fd, &hdr, disp); + if (syms == NULL) return -1; + + sym = syms; + end = syms + (hdr.a_syms / sizeof(struct nlist)); + while (sym < end) { + struct nlist *old_sym; + int value = sym->n_value; + + if (sym->n_type == (N_UNDF | N_EXT)) { + if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { + old_sym = NULL; + } + + if (value) { + if (old_sym) { + sym->n_type = N_EXT | N_COMM; + sym->n_value = old_sym->n_value; + } + else { + int rnd = + value >= sizeof(double) ? sizeof(double) - 1 + : value >= sizeof(long) ? sizeof(long) - 1 + : sizeof(short) - 1; + + sym->n_type = N_COMM; + new_common += rnd; + new_common &= ~(long)rnd; + sym->n_value = new_common; + new_common += value; + } + } + else { + if (old_sym) { + sym->n_type = N_EXT | N_COMM; + sym->n_value = old_sym->n_value; + } + else { + sym->n_value = (long)dln_undefined; + st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); + } + } + } + sym++; + } + + block = dln_load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); + if (block == 0) goto err_exit; + + sym = syms; + while (sym < end) { + struct nlist *new_sym; + char *key; + + switch (sym->n_type) { + case N_COMM: + sym->n_value += hdr.a_text + hdr.a_data; + case N_TEXT|N_EXT: + case N_DATA|N_EXT: + sym->n_value += block; + + if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 + && new_sym->n_value != (long)dln_undefined) { + dln_errno = DLN_ECONFL; + goto err_exit; + } + + key = sym->n_un.n_name; + if (st_delete(undef_tbl, &key, NULL) != 0) { + unlink_undef(key, sym->n_value); + free(key); + } + + new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); + *new_sym = *sym; + new_sym->n_un.n_name = strdup(sym->n_un.n_name); + st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); + } + sym++; + } + + /* + * First comes the text-relocation + */ + { + struct relocation_info * rel = reloc; + struct relocation_info * rel_beg = reloc + + (hdr.a_trsize/sizeof(struct relocation_info)); + struct relocation_info * rel_end = reloc + + (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); + + while (rel < rel_end) { + char *address = (char*)(rel->r_address + block); + long datum = 0; +#if defined(sun) && defined(sparc) + unsigned int mask = 0; +#endif + + if(rel >= rel_beg) + address += hdr.a_text; + + if (rel->r_extern) { /* Look it up in symbol-table */ + sym = &(syms[R_SYMBOL(rel)]); + switch (sym->n_type) { + case N_EXT|N_UNDF: + link_undef(sym->n_un.n_name, block, rel); + case N_EXT|N_COMM: + case N_COMM: + datum = sym->n_value; + break; + default: + goto err_exit; + } + } /* end.. look it up */ + else { /* is static */ + switch (R_SYMBOL(rel) & N_TYPE) { + case N_TEXT: + case N_DATA: + datum = block; + break; + case N_BSS: + datum = block + new_common; + break; + case N_ABS: + break; + } + } /* end .. is static */ + if (R_PCREL(rel)) datum -= block; + +#if defined(sun) && defined(sparc) + datum += rel->r_addend; + datum >>= R_RIGHTSHIFT(rel); + mask = 1 << R_BITSIZE(rel) - 1; + mask |= mask -1; + datum &= mask; + + switch (R_LENGTH(rel)) { + case 0: + *address &= ~mask; + *address |= datum; + break; + case 1: + *(short *)address &= ~mask; + *(short *)address |= datum; + break; + case 2: + *(long *)address &= ~mask; + *(long *)address |= datum; + break; + } +#else + switch (R_LENGTH(rel)) { + case 0: /* byte */ + if (datum < -128 || datum > 127) goto err_exit; + *address += datum; + break; + case 1: /* word */ + *(short *)address += datum; + break; + case 2: /* long */ + *(long *)address += datum; + break; + } +#endif + rel++; + } + } + + if (need_init) { + if (undef_tbl->num_entries > 0) { + if (dln_load_lib(libc) == -1) goto err_exit; + } + + sym = syms; + while (sym < end) { + char *name = sym->n_un.n_name; + if (name[0] == '_' && sym->n_value >= block + && ((bcmp (name, "_Init_", 6) == 0 + || bcmp (name, "_init_", 6) == 0) && name[6] != '_')) { + init_p = 1; + ((int (*)())sym->n_value)(); + } + sym++; + } + } + free(reloc); + free(syms); + if (need_init) { + if (init_p == 0) { + dln_errno = DLN_ENOINIT; + return -1; + } + if (undef_tbl->num_entries > 0) { + if (dln_load_lib(libc) == -1) goto err_exit; + if (undef_tbl->num_entries > 0) { + dln_errno = DLN_EUNDEF; + return -1; + } + } + } + return 0; + + err_exit: + if (syms) free(syms); + if (reloc) free(reloc); + if (block) free(block); + return -1; +} + +int +dln_load(file) + char *file; +{ + int fd; + int result; + + if (dln_init_p == 0) { + dln_errno = DLN_ENOINIT; + return -1; + } + + fd = open(file, O_RDONLY); + if (fd == -1) { + dln_errno = errno; + return -1; + } + result = dln_load_1(fd, 0, 1); + close(fd); + + return result; +} + +struct symdef { + int str_index; + int lib_offset; +}; + +static int target_offset; +static int +search_undef(key, value, lib_tbl) + char *key; + int value; + st_table *lib_tbl; +{ + static char *last = ""; + int offset; + + if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; + if (strcmp(last, key) != 0) { + last = key; + target_offset = offset; + } + return ST_STOP; +} + +char *dln_library_path = DLN_DEFAULT_PATH; + +int +dln_load_lib(lib) + char *lib; +{ + char *path, *file; + char armagic[SARMAG]; + int fd, size; + struct ar_hdr ahdr; + st_table *lib_tbl = NULL; + int *data, nsym; + struct symdef *base; + char *name_base; + + if (dln_init_p == 0) { + dln_errno = DLN_ENOINIT; + return -1; + } + + if (undef_tbl->num_entries == 0) return 0; + dln_errno = DLN_EBADLIB; + + /* library search path: */ + /* look for environment variable DLN_LIBRARY_PATH first. */ + /* then variable dln_library_path. */ + /* if path is still NULL, use "." for path. */ + path = getenv("DLN_LIBRARY_PATH"); + if (path == NULL) path = dln_library_path; + + file = dln_find_file(lib, path); + fd = open(file, O_RDONLY); + if (fd == -1) goto syserr; + size = read(fd, armagic, SARMAG); + if (fd == -1) goto syserr; + + if (size != SARMAG) { + dln_errno = DLN_ENOTLIB; + goto badlib; + } + size = read(fd, &ahdr, sizeof(ahdr)); + if (size == -1) goto syserr; + if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { + goto badlib; + } + + if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0 && ahdr.ar_name[9] == ' ') { + /* make hash table from __.SYMDEF */ + + lib_tbl = st_init_table(strcmp, st_strhash); + data = (int*)xmalloc(size); + if (data == NULL) goto syserr; + size = read(fd, data, size); + nsym = *data / sizeof(struct symdef); + base = (struct symdef*)(data + 1); + name_base = (char*)(base + nsym) + sizeof(int); + while (nsym > 0) { + char *name = name_base + base->str_index; + + st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); + nsym--; + base++; + } + for (;;) { + target_offset = -1; + st_foreach(undef_tbl, search_undef, lib_tbl); + if (target_offset == -1) break; + if (dln_load_1(fd, target_offset, 0) == -1) { + st_free_table(lib_tbl); + free(data); + goto badlib; + } + if (undef_tbl->num_entries == 0) break; + } + free(data); + st_free_table(lib_tbl); + } + else { + /* linear library, need to scan (FUTURE) */ + + for (;;) { + int offset = SARMAG; + int found = 0; + struct exec hdr; + struct nlist *syms, *sym, *end; + + while (undef_tbl->num_entries > 0) { + found = 0; + lseek(fd, offset, 0); + size = read(fd, &ahdr, sizeof(ahdr)); + if (size == -1) goto syserr; + if (size == 0) break; + if (size != sizeof(ahdr) + || sscanf(ahdr.ar_size, "%d", &size) != 1) { + goto badlib; + } + offset += sizeof(ahdr); + if (dln_load_header(fd, &hdr, offset) == -1) + goto badlib; + syms = dln_load_sym(fd, &hdr, offset); + if (syms == NULL) goto badlib; + sym = syms; + end = syms + (hdr.a_syms / sizeof(struct nlist)); + while (sym < end) { + if (sym->n_type == N_EXT|N_TEXT + && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { + break; + } + sym++; + } + if (sym < end) { + found++; + free(syms); + if (dln_load_1(fd, offset, 0) == -1) { + goto badlib; + } + } + offset += size; + if (offset & 1) offset++; + } + if (found) break; + } + } + close(fd); + return 0; + + syserr: + dln_errno = errno; + badlib: + if (fd >= 0) close(fd); + return -1; +} + +char * +dln_strerror() +{ + char *strerror(); + + switch (dln_errno) { + case DLN_ECONFL: + return "Symbol name conflict"; + case DLN_ENOINIT: + return "No inititalizer given"; + case DLN_EUNDEF: + return "Unresolved symbols"; + case DLN_ENOTLIB: + return "Not a library file"; + case DLN_EBADLIB: + return "Malformed library file"; + case DLN_EINIT: + return "Not initialized"; + default: + return strerror(dln_errno); + } +} + +dln_perror(str) + char *str; +{ + fprintf(stderr, "%s: %s\n", str, dln_strerror()); +} + +void* +dln_get_sym(name) + char *name; +{ + struct nlist *sym; + + if (st_lookup(sym_tbl, name, &sym)) + return (void*)sym->n_value; + return NULL; +} + +#ifdef TEST +xmalloc(size) + int size; +{ + return malloc(size); +} + +xcalloc(size, n) + int size, n; +{ + return calloc(size, n); +} + +main(argc, argv) + int argc; + char **argv; +{ + if (dln_init(argv[0]) == -1) { + dln_perror("dln_init"); + exit(1); + } + + while (argc > 1) { + printf("obj: %s\n", argv[1]); + if (dln_load(argv[1]) == -1) { + dln_perror("dln_load"); + exit(1); + } + argc--; + argv++; + } + if (dln_load_lib("libdln.a") == -1) { + dln_perror("dln_init"); + exit(1); + } + + if (dln_get_sym("_foo")) + printf("_foo defined\n"); + else + printf("_foo undefined\n"); +} +#endif /* TEST */ + +#else /* USE_DLN */ + +int +dln_init(file) + char *file; +{ + return 0; +} + +int +dln_load(file) + char *file; +{ + return 0; +} + +int +dln_load_lib(file) + char *file; +{ + return 0; +} + +#endif /* USE_DLN */ @@ -0,0 +1,33 @@ +/************************************************ + + dln.h - + + $Author: matz $ + $Revision: 1.1.1.1 $ + $Date: 1994/06/17 14:23:49 $ + created at: Wed Jan 19 16:53:09 JST 1994 + +************************************************/ +#ifndef DLN_H +#define DLN_H + +#include <sys/errno.h> + +int dln_init(); +int dln_load(); +int dln_load_lib(); + +extern int dln_errno; + +#define DLN_ENOENT ENOENT /* No such file or directory */ +#define DLN_ENOEXEC ENOEXEC /* Exec format error */ +#define DLN_ECONFL 101 /* Symbol name conflict */ +#define DLN_ENOINIT 102 /* No inititalizer given */ +#define DLN_EUNDEF 103 /* Undefine symbol remains */ +#define DLN_ENOTLIB 104 /* Not a library file */ +#define DLN_EBADLIB 105 /* Malformed library file */ +#define DLN_EINIT 106 /* Not initialized */ + +char *dln_strerror(); + +#endif diff --git a/enum.c b/enum.c new file mode 100644 index 0000000000..bf04757cfc --- /dev/null +++ b/enum.c @@ -0,0 +1,332 @@ +/************************************************ + + enum.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Fri Oct 1 15:15:19 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +VALUE M_Enumerable; +static ID id_each, id_match, id_equal, id_cmp; + +void +rb_each(obj) + VALUE obj; +{ + rb_funcall(obj, id_each, 0, Qnil); +} + +static void +enum_grep(i, arg) + VALUE i, *arg; +{ + if (rb_funcall(arg[0], id_match, 1, i)) { + Fary_push(arg[1], i); + } +} + +static void +enum_grep2(i, pat) + VALUE i, pat; +{ + if (rb_funcall(pat, id_match, 1, i)) { + rb_yield(i); + } +} + +static VALUE +Fenum_grep(obj, pat) + VALUE obj; +{ + if (iterator_p()) { + rb_iterate(rb_each, obj, enum_grep2, pat); + return obj; + } + else { + VALUE tmp, arg[2]; + + arg[0] = pat; arg[1] = tmp = ary_new(); + GC_LINK; + GC_PRO(tmp); + + rb_iterate(rb_each, obj, enum_grep, arg); + + GC_UNLINK; + return tmp; + } +} + +static void +enum_find(i, foundp) + VALUE i; + int *foundp; +{ + if (rb_yield(i)) { + *foundp = TRUE; + rb_break(); + } +} + +static VALUE +Fenum_find(obj) + VALUE obj; +{ + int enum_found; + + enum_found = FALSE; + rb_iterate(rb_each, obj, enum_find, &enum_found); + return enum_found; +} + +static void +enum_find_all(i, tmp) + VALUE i; +{ + if (rb_yield(i)) { + Fary_push(tmp, i); + } +} + +static VALUE +Fenum_find_all(obj) + VALUE obj; +{ + VALUE tmp; + + GC_LINK; + GC_PRO3(tmp, ary_new()); + + rb_iterate(rb_each, obj, enum_find_all, Qnil); + + GC_UNLINK; + return tmp; +} + +static void +enum_collect(i, tmp) + VALUE i; +{ + VALUE retval; + + GC_LINK; + GC_PRO3(retval, rb_yield(i)); + + if (retval) { + Fary_push(tmp, retval); + } + + GC_UNLINK; +} + +static VALUE +Fenum_collect(obj) + VALUE obj; +{ + VALUE tmp; + + GC_LINK; + GC_PRO3(tmp, ary_new()); + + rb_iterate(rb_each, obj, enum_collect, tmp); + + GC_UNLINK; + return tmp; +} + +static void +enum_reverse(i, tmp) + VALUE i, tmp; +{ + Fary_unshift(tmp, i); +} + +static VALUE +Fenum_reverse(obj) + VALUE obj; +{ + VALUE tmp; + + GC_LINK; + GC_PRO3(tmp, ary_new()); + + rb_iterate(rb_each, obj, enum_reverse, tmp); + + GC_UNLINK; + return tmp; +} + +static void +enum_all(i, ary) + VALUE i, ary; +{ + Fary_push(ary, i); +} + +static VALUE +Fenum_to_a(obj) + VALUE obj; +{ + VALUE ary; + + GC_LINK; + GC_PRO3(ary, ary_new()); + rb_iterate(rb_each, obj, enum_all, ary); + GC_UNLINK; + + return ary; +} + +static VALUE +Fenum_sort(obj) + VALUE obj; +{ + VALUE ary; + + GC_LINK; + GC_PRO3(ary, Fenum_to_a(obj)); + Fary_sort(ary); + GC_UNLINK; + return ary; +} + +static void +enum_min(i, min) + VALUE i, *min; +{ + VALUE cmp; + + if (*min == Qnil) + *min = i; + else { + cmp = rb_funcall(i, id_cmp, 1, *min); + if (FIX2INT(cmp) < 0) + *min = i; + } +} + +static VALUE +Fenum_min(obj) + VALUE obj; +{ + VALUE min; + + GC_LINK; + GC_PRO2(min); + rb_iterate(rb_each, obj, enum_min, &min); + GC_UNLINK; + return min; +} + +static void +enum_max(i, max) + VALUE i, *max; +{ + VALUE cmp; + + if (*max == Qnil) + *max = i; + else { + cmp = rb_funcall(i, id_cmp, 1, *max); + if (FIX2INT(cmp) > 0) + *max = i; + } +} + +static VALUE +Fenum_max(obj) + VALUE obj; +{ + VALUE max; + + GC_LINK; + GC_PRO2(max); + rb_iterate(rb_each, obj, enum_max, &max); + GC_UNLINK; + return max; +} + +struct i_v_pair { + int i; + VALUE v; + int found; +}; + +static void +enum_index(item, iv) + VALUE item; + struct i_v_pair *iv; +{ + if (rb_funcall(item, id_equal, 1, iv->v)) { + iv->found = 1; + rb_break(); + } + else { + iv->i++; + } +} + +static VALUE +Fenum_index(obj, val) + VALUE obj; +{ + struct i_v_pair iv; + + iv.i = 0; + iv.v = val; + iv.found = 0; + rb_iterate(rb_each, obj, enum_index, &iv); + if (iv.found) return INT2FIX(iv.i); + return Qnil; /* not found */ +} + +static void +enum_includes(item, iv) + VALUE item; + struct i_v_pair *iv; +{ + if (rb_funcall(item, id_equal, 1, iv->v)) { + iv->i = 1; + rb_break(); + } +} + +static VALUE +Fenum_includes(obj, val) + VALUE obj; +{ + struct i_v_pair iv; + + iv.i = 0; + iv.v = val; + rb_iterate(rb_each, obj, enum_includes, &iv); + if (iv.i) return TRUE; + return FALSE; +} + +Init_Enumerable() +{ + M_Enumerable = rb_define_module("Enumerable"); + + rb_define_method(M_Enumerable,"to_a", Fenum_to_a, 0); + + rb_define_method(M_Enumerable,"grep", Fenum_grep, 1); + rb_define_method(M_Enumerable,"find", Fenum_find, 0); + rb_define_method(M_Enumerable,"find_all", Fenum_find_all, 0); + rb_define_method(M_Enumerable,"collect", Fenum_collect, 0); + rb_define_method(M_Enumerable,"reverse", Fenum_reverse, 0); + rb_define_method(M_Enumerable,"min", Fenum_min, 0); + rb_define_method(M_Enumerable,"max", Fenum_max, 0); + rb_define_method(M_Enumerable,"index", Fenum_index, 1); + rb_define_method(M_Enumerable,"includes", Fenum_includes, 1); + + id_each = rb_intern("each"); + id_match = rb_intern("=~"); + id_equal = rb_intern("=="); + id_cmp = rb_intern("<=>"); +} @@ -0,0 +1,40 @@ +/************************************************ + + env.h - + + $Author$ + $Revision$ + $Date$ + created at: Mon Jul 11 11:53:03 JST 1994 + +************************************************/ +#ifndef ENV_H +#define ENV_H + +extern struct ENVIRON { + VALUE self; + int argc; + VALUE *argv; + struct RClass *current_module; + struct RClass *last_class; + char *file; + int line; + ID last_func; + ID *local_tbl; + VALUE *local_vars; + int in_eval; + struct BLOCK *block; + int iterator; + int flags; + struct ENVIRON *prev; +} *the_env; + +#define ITERATOR_P() (the_env->iterator > 0 && the_env->iterator < 3) +#define Qself the_env->self +#define the_class the_env->current_module + +#define DURING_ITERATE 1 +#define DURING_RESQUE 2 +#define DURING_CALL 4 + +#endif /* ENV_H */ diff --git a/error.c b/error.c new file mode 100644 index 0000000000..001f93df44 --- /dev/null +++ b/error.c @@ -0,0 +1,165 @@ +/************************************************ + + error.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Mon Aug 9 16:11:34 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include <stdio.h> +#include <varargs.h> + +extern char *sourcefile; +extern int sourceline; + +int nerrs; + +static void +err_sprintf(buf, fmt, args) + char *buf, *fmt; + va_list args; +{ + sprintf(buf, "%s:%d: ", sourcefile, sourceline); + vsprintf((char*)buf+strlen(buf), fmt, args); + if (buf[strlen(buf)-1] != '\n') + strcat(buf, "\n"); +} + +static void +err_print(fmt, args) + char *fmt; + va_list args; +{ + extern errstr; + char buf[BUFSIZ]; + + err_sprintf(buf, fmt, args); + if (the_env->in_eval) { + if (errstr == Qnil) { + errstr = str_new2(buf); + } + else { + str_cat(errstr, buf, strlen(buf)); + } + } + else { + fputs(buf, stderr); + } +} + +yyerror(msg) + char *msg; +{ + Error("%s", msg); +} + +Error(fmt, va_alist) + char *fmt; + va_dcl +{ + va_list args; + + va_start(args); + err_print(fmt, args); + va_end(args); + nerrs++; +} + +Warning(fmt, va_alist) + char *fmt; + va_dcl +{ + char buf[BUFSIZ]; + va_list args; + + sprintf(buf, "warning: %s", fmt); + + va_start(args); + err_print(buf, args); + va_end(args); +} + +Fatal(fmt, va_alist) + char *fmt; + va_dcl +{ + va_list args; + + va_start(args); + err_print(fmt, args); + va_end(args); + rb_exit(1); +} + +Bug(fmt, va_alist) + char *fmt; + va_dcl +{ + char buf[BUFSIZ]; + va_list args; + + sprintf(buf, "[BUG] %s", fmt); + + va_start(args); + err_print(buf, args); + va_end(args); + abort(); +} + +Fail(fmt, va_alist) + char *fmt; + va_dcl +{ + va_list args; + char buf[BUFSIZ]; + + va_start(args); + vsprintf(buf, fmt, args); + va_end(args); + + rb_fail(str_new2(buf)); +} + +rb_sys_fail(mesg) + char *mesg; +{ + char buf[BUFSIZ]; + extern int errno; + + if (mesg == Qnil) + sprintf(buf, "%s.\n", strerror(errno)); + else + sprintf(buf, "%s - %s.\n", strerror(errno), mesg); + + errno = 0; + rb_fail(str_new2(buf)); +} + +static char *builtin_types[] = { + "Nil", + "Object", + "Class", + "iClass", + "Module", + "Float", + "String", + "Regexp", + "Array", + "Fixnum", + "Dictionary", + "Data", +}; + +WrongType(x, t) + VALUE x; + int t; +{ + Fail("wrong argument type %s (expected %s)", + rb_class2name(CLASS_OF(x)), builtin_types[t]); +} @@ -0,0 +1,220 @@ +/************************************************ + + etc.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:49 $ + created at: Tue Mar 22 18:39:19 JST 1994 + +************************************************/ + +#include "ruby.h" +#include <pwd.h> +#include <grp.h> + +char *getlogin(); + +static VALUE +Fetc_getlogin(obj) + VALUE obj; +{ + char *login = getlogin(); + + if (login) + return str_new2(getlogin()); + return Qnil; +} + +static VALUE +setup_passwd(pwd) + struct passwd *pwd; +{ + VALUE pw, name, passwd, gecos, dir, shell; +#ifdef PW_CLASS + VALUE class; +#endif +#ifdef PW_COMMENT + VALUE comment; +#endif + + if (pwd == Qnil) rb_sys_fail("/etc/passwd"); + GC_LINK; + GC_PRO3(pw, str_new2(pwd->pw_name)); + GC_PRO3(passwd, str_new2(pwd->pw_passwd)); + GC_PRO3(gecos, str_new2(pwd->pw_gecos)); + GC_PRO3(dir, str_new2(pwd->pw_dir)); + GC_PRO3(shell, str_new2(pwd->pw_shell)); +#ifdef PW_CLASS + GC_PRO3(class, str_new2(pwd->pw_class)); +#endif +#ifdef PW_COMMENT + GC_PRO3(comment, str_new2(pwd->pw_comment)); +#endif + + pw = struct_new("passwd", + "name", name, + "passwd", passwd, + "uid", INT2FIX(pwd->pw_uid), + "gid", INT2FIX(pwd->pw_gid), + "gecos", gecos, + "dir", dir, + "shell", shell, +#ifdef PW_CHANGE + "change", INT2FIX(pwd->pw_change), +#endif +#ifdef PW_QUOTA + "quota", INT2FIX(pwd->pw_quota), +#endif +#ifdef PW_AGE + "age", INT2FIX(pwd->pw_age), +#endif +#ifdef PW_CLASS + "class", class, +#endif +#ifdef PW_COMMENT + "comment", comment, +#endif +#ifdef PW_EXPIRE + "expire", INT2FIX(pwd->pw_expire), +#endif + Qnil); + GC_UNLINK; + + return pw; +} + +static VALUE +Fetc_getpwuid(obj, args) + VALUE obj, args; +{ + VALUE id; + int uid; + struct passwd *pwd; + + if (rb_scan_args(args, "01", &id) == 1) { + uid = NUM2INT(id); + } + else { + uid = getuid(); + } + pwd = getpwuid(uid); + if (pwd == Qnil) Fail("can't find user for %d", uid); + return setup_passwd(pwd); +} + +static VALUE +Fetc_getpwnam(obj, nam) + VALUE obj, nam; +{ + struct passwd *pwd; + + Check_Type(nam, T_STRING); + pwd = getpwnam(RSTRING(nam)->ptr); + if (pwd == Qnil) Fail("can't find user for %s", RSTRING(nam)->ptr); + return setup_passwd(pwd); +} + +static VALUE +Fetc_passwd(obj) + VALUE obj; +{ + struct passwd *pw; + + if (iterator_p()) { + setpwent(); + while (pw = getpwent()) { + rb_yield(setup_passwd(pw)); + } + endpwent(); + return obj; + } + pw = getpwent(); + if (pw == Qnil) Fail("can't fetch next -- /etc/passwd"); + return setup_passwd(pw); +} + +static VALUE +setup_group(grp) + struct group *grp; +{ + VALUE mem, obj, name, passwd; + char **tbl; + + GC_LINK; + GC_PRO3(mem, ary_new()); + tbl = grp->gr_mem; + while (*tbl) { + Fary_push(mem, str_new2(*tbl)); + tbl++; + } + GC_PRO3(name, str_new2(grp->gr_name)); + GC_PRO3(passwd, str_new2(grp->gr_passwd)); + obj = struct_new("group", + "name", name, + "passwd", passwd, + "gid", INT2FIX(grp->gr_gid), + "mem", mem, + Qnil); + GC_UNLINK; + + return obj; +} + +static VALUE +Fetc_getgrgid(obj, id) + VALUE obj, id; +{ + int gid; + struct group *grp; + + gid = NUM2INT(id); + grp = getgrgid(gid); + if (grp == Qnil) Fail("can't find group for %d", gid); + return setup_group(grp); +} + +static VALUE +Fetc_getgrnam(obj, nam) + VALUE obj, nam; +{ + struct group *grp; + + Check_Type(nam, T_STRING); + grp = getgrnam(RSTRING(nam)->ptr); + if (grp == Qnil) Fail("can't find group for %s", RSTRING(nam)->ptr); + return setup_group(grp); +} + +static VALUE +Fetc_group(obj) + VALUE obj; +{ + struct group *grp; + + if (iterator_p()) { + setgrent(); + while (grp = getgrent()) { + rb_yield(setup_group(grp)); + } + endgrent(); + return obj; + } + return setup_group(getgrent()); +} + +VALUE M_Etc; + +Init_Etc() +{ + M_Etc = rb_define_module("Etc"); + + rb_define_mfunc(M_Etc, "getlogin", Fetc_getlogin, 0); + + rb_define_mfunc(M_Etc, "getpwuid", Fetc_getpwuid, -2); + rb_define_mfunc(M_Etc, "getpwnam", Fetc_getpwnam, 1); + rb_define_mfunc(M_Etc, "passwd", Fetc_passwd, 0); + + rb_define_mfunc(M_Etc, "getgrgid", Fetc_getgrgid, 1); + rb_define_mfunc(M_Etc, "getgrnam", Fetc_getgrnam, 1); + rb_define_mfunc(M_Etc, "group", Fetc_group, 0); +} diff --git a/eval.c b/eval.c new file mode 100644 index 0000000000..f4d6d545ae --- /dev/null +++ b/eval.c @@ -0,0 +1,1858 @@ +/************************************************ + + eval.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:23 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include "node.h" +#include "ident.h" +#include <stdio.h> +#include <setjmp.h> +#include "st.h" + +static ID match, each; +VALUE errstr, errat; +extern NODE *eval_tree; + +struct ENVIRON *the_env, *top_env; + +#define PUSH_ENV() {\ + struct ENVIRON _this;\ + if (the_env) _this = *the_env; else bzero(&_this, sizeof(_this));\ + _this.prev = the_env;\ + _this.flags = 0;\ + the_env = &_this;\ + +#define POP_ENV() the_env = the_env->prev; } + +struct BLOCK { + NODE *var; + NODE *body; + struct ENVIRON env; + int level; +}; + +#define SET_BLOCK(b,node) (b.level=tag_level,b.var=node->nd_var,\ + b.body=node->nd_body,b.env=*the_env,\ + the_env->block= &b) + +static int tag_level, target_level; +static struct tag { + int level; + jmp_buf buf; + struct gc_list *gclist; + struct ENVIRON *env; +} *prot_tag; + +#define PUSH_TAG() {\ + struct tag _this;\ + struct tag *_oldtag = prot_tag;\ + &_oldtag;\ + _this.level= ++tag_level;\ + _this.gclist= GC_List;\ + _this.env= the_env;\ + prot_tag = &_this;\ + +#define POP_TAG() \ + tag_level--;\ + prot_tag = _oldtag;\ +} + +#define EXEC_TAG() (setjmp(prot_tag->buf)) +#define JUMP_TAG(val) {\ + the_env = prot_tag->env;\ + GC_List = prot_tag->gclist;\ + longjmp(prot_tag->buf,(val));\ +} + +#define TAG_RETURN 1 +#define TAG_BREAK 2 +#define TAG_CONTINUE 3 +#define TAG_RETRY 4 +#define TAG_REDO 5 +#define TAG_FAIL 6 +#define TAG_EXIT 7 + +#define IN_BLOCK 0x08 + +static VALUE rb_eval(); +VALUE Feval(); + +VALUE Argv; +static VALUE rb_call(); +VALUE rb_apply(); + +static void asign(); + +static VALUE last_val; + +extern VALUE rb_stderr; + +extern int sourceline; +extern char *sourcefile; + +static ID last_func; +static void +error_print() +{ + if (errat) { + fwrite(RSTRING(errat)->ptr, 1, RSTRING(errat)->len, stderr); + if (last_func) { + fprintf(stderr, ":in method `%s': ", rb_id2name(last_func)); + } + else { + fprintf(stderr, ": "); + } + } + + if (errstr) { + fwrite(RSTRING(errstr)->ptr, 1, RSTRING(errstr)->len, stderr); + } + else { + fprintf(stderr, "unhandled failure.\n"); + } + rb_trap_exit(); + exit(1); +} + +main(argc, argv) + int argc; + char *argv[]; +{ + int state; + + PUSH_ENV(); + top_env = the_env; + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + rb_main(argc, argv); + } + POP_TAG(); + + switch (state) { + case 0: + break; + case TAG_RETURN: + Fatal("unexpected return"); + break; + case TAG_CONTINUE: + Fatal("unexpected continue"); + break; + case TAG_BREAK: + Fatal("unexpected break"); + break; + case TAG_REDO: + Fatal("unexpected redo"); + break; + case TAG_RETRY: + Fatal("retry outside of protect clause"); + break; + case TAG_FAIL: + PUSH_TAG() + error_print(); + POP_TAG(); + break; + case TAG_EXIT: + rb_trap_exit(); + exit(FIX2UINT(last_val)); + break; + default: + Bug("Unknown longjmp status %d", state); + break; + } + POP_ENV(); + exit(0); +} + +VALUE rb_readonly_hook(); + +VALUE Progname; + +static VALUE +Eval() +{ + int state; + NODE *tree; + + if (match == Qnil) match = rb_intern("=~"); + if (each == Qnil) each = rb_intern("each"); + + tree = eval_tree; + eval_tree = Qnil; + + return rb_eval(tree); +} + +VALUE +TopLevel(script, argc, argv) + char *script; + int argc; + char **argv; +{ + int i; + + the_class = (struct RClass*)C_Object; + + rb_define_variable("$!", &errstr, Qnil, Qnil); + errat = Qnil; /* clear for execution */ + + Progname = str_new2(script); + rb_define_variable("$0", &Progname, Qnil, Qnil); + + rb_define_variable("$ARGV", &Argv, Qnil, Qnil); + rb_define_variable("$*", &Argv, Qnil, Qnil); + Argv = ary_new2(argc); + for (i=0; i < argc; i++) { + Fary_push(Argv, str_new2(argv[i])); + } + return Eval(); +} + +void +rb_trap_eval(cmd) + VALUE cmd; +{ + PUSH_ENV(); + the_env->self = top_env->self; + the_env->current_module = top_env->current_module; + the_env->local_vars = top_env->local_vars; + the_class = (struct RClass*)C_Object; + + Feval(Qself, cmd); + POP_ENV(); +} + +static int +setup_arg_1(node, args) + NODE *node; + VALUE *args; +{ + int argc; + + if (node->type == NODE_ARRAY) { + for (argc=0; node; node=node->nd_next) argc++; + argc++; + } + else { + *args = rb_eval(node); + if (TYPE(*args) != T_ARRAY) + Fail("*`argument' must be array"); + argc = RARRAY(*args)->len + 1; + } + return argc; +} + +static void +setup_arg_2(node, args, argc, argv) + NODE *node; + VALUE args; + int argc; + VALUE *argv; +{ + int i; + + bzero(argv, sizeof(VALUE)*argc); + if (node->type == NODE_ARRAY) { + for (i=1;node;node=node->nd_next) { + argv[i++] = rb_eval(node->nd_head); + } + } + else { + for (i=1;i<argc;i++) { + argv[i] = RARRAY(args)->ptr[i-1]; + } + } +} + +#define SETUP_ARGS {\ + VALUE args;\ + GC_LINK;\ + GC_PRO2(args);\ + argc = setup_arg_1(node->nd_args, &args);\ + argv = (VALUE*)alloca(sizeof(VALUE)*argc);\ + GC_PRO4(argv, argc);\ + setup_arg_2(node->nd_args, args, argc, argv);\ + GC_UNLINK;\ +} + +static VALUE +rb_eval(node) + register NODE *node; +{ + int state; + int go_out = 0; + VALUE result; + + &go_out; + again: + if (node == Qnil) return Qnil; + + sourceline = node->line; + sourcefile = node->src; + +#ifdef SAFE_SIGHANDLE + { + extern int trap_pending; + + if (trap_pending) { + rb_trap_exec(); + } + } +#endif + + switch (node->type) { + case NODE_BLOCK: + while (node->nd_next) { + rb_eval(node->nd_head); + node = node->nd_next; + } + node = node->nd_head; + goto again; + + case NODE_SELF: + return Qself; + + case NODE_NIL: + return Qnil; + + case NODE_IF: + if (rb_eval(node->nd_cond)) { + node = node->nd_body; + } + else { + node = node->nd_else; + } + if (node) goto again; + return Qnil; + + case NODE_UNLESS: + { + VALUE res; + + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + res = rb_eval(node->nd_cond); + } + POP_TAG(); + if (state == 0) + ; + else if (state == TAG_FAIL) { + res = Qnil; + } + else { + JUMP_TAG(state); + } + + if (res == Qnil) { + node = node->nd_body; + } + else { + node = node->nd_else; + } + if (node) goto again; + return res; + } + + case NODE_CASE: + { + VALUE val; + + GC_LINK; + GC_PRO3(val, rb_eval(node->nd_head)); + + node = node->nd_body; + while (node) { + if (node->type == NODE_WHEN) { + NODE *tag = node->nd_head; + + while (tag) { + if (rb_funcall(rb_eval(tag->nd_head), match, 1, val)){ + result = rb_eval(node->nd_body); + goto exit_case; + } + tag = tag->nd_next; + } + } + else { + result = rb_eval(node); + goto exit_case; + } + node = node->nd_next; + } + exit_case: + GC_UNLINK; + } + return result; + + case NODE_WHILE: + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + while_cont: + while (rb_eval(node->nd_cond)) { + while_redo: + rb_eval(node->nd_body); + } + break; + case TAG_REDO: + goto while_redo; + case TAG_CONTINUE: + goto while_cont; + default: + go_out++; + case TAG_BREAK: + break; + } + while_out: + POP_TAG(); + if (go_out) JUMP_TAG(state); + return Qnil; + + case NODE_UNTIL: + for (;;) { + VALUE res; + + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + res = rb_eval(node->nd_cond); + break; + + case TAG_FAIL: + res = Qnil; + break; + + default: + go_out++; + } + POP_TAG(); + if (go_out) JUMP_TAG(state); + if (res) return res; + + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + until_redo: + rb_eval(node->nd_body); + break; + case TAG_REDO: + goto until_redo; + case TAG_CONTINUE: + break; + case TAG_BREAK: + goto until_break; + default: + go_out++; + } + POP_TAG(); + if (go_out) JUMP_TAG(state); + } + until_break: + break; + + case NODE_DO: + case NODE_FOR: + { + struct BLOCK block; + + PUSH_ENV(); + SET_BLOCK(block, node); + PUSH_TAG(); + + state = EXEC_TAG(); + if (state == 0) { + if (node->type == NODE_DO) { + the_env->iterator = 1; + rb_eval(node->nd_iter); + } + else { + VALUE recv; + + GC_LINK; + GC_PRO2(recv); + recv = rb_eval(node->nd_iter); + the_env->iterator = 1; + result = rb_call(CLASS_OF(recv), recv, each, 1, Qnil, + MTH_METHOD); + GC_UNLINK; + } + } + POP_TAG(); + POP_ENV(); + switch (state) { + case 0: + break; + case IN_BLOCK|TAG_BREAK: + if (target_level != tag_level) { + JUMP_TAG(state); + } + result = Qnil; + break; + case IN_BLOCK|TAG_RETURN: + if (target_level == tag_level) { + state = TAG_RETURN; + } + /* fall through */ + default: + JUMP_TAG(state); + } + } + return result; + + case NODE_YIELD: + { + VALUE val; + + GC_LINK; + GC_PRO3(val, rb_eval(node->nd_stts)); + result = rb_yield(val); + GC_UNLINK; + } + return result; + + case NODE_PROT: + GC_LINK; + GC_PRO2(result); + + PUSH_TAG(); + + switch (state = EXEC_TAG()) { + case 0: + retry_entry: + result = rb_eval(node->nd_head); + break; + + case TAG_FAIL: + if (node->nd_resq) { + if (node->nd_resq == (NODE*)1) { + state = 0; + } + else { + PUSH_TAG(); + state = EXEC_TAG(); + if (state == 0) result = rb_eval(node->nd_resq); + POP_TAG(); + if (state == TAG_RETRY) { + goto retry_entry; + } + } + if (state == 0) { + errstr = errat = Qnil; + last_func = 0; + } + } + break; + } + POP_TAG(); + + /* ensure clause */ + rb_eval(node->nd_ensr); + GC_UNLINK; + + if (state != 0) { + JUMP_TAG(state); + } + return result; + + case NODE_AND: + if ((result = rb_eval(node->nd_1st)) == Qnil) return result; + node = node->nd_2nd; + goto again; + + case NODE_OR: + if ((result = rb_eval(node->nd_1st)) != Qnil) return result; + node = node->nd_2nd; + goto again; + + case NODE_DOT3: + if (node->nd_state == 0) { + if (rb_eval(node->nd_beg)) { + node->nd_state = 1; + return TRUE; + } + return FALSE; + } + else { + if (rb_eval(node->nd_end)) { + node->nd_state = 0; + } + return TRUE; + } + break; + + case NODE_BREAK: + JUMP_TAG(TAG_BREAK); + break; + + case NODE_CONTINUE: + JUMP_TAG(TAG_CONTINUE); + break; + + case NODE_RETRY: + JUMP_TAG(TAG_RETRY); + break; + + case NODE_RETURN: + if (node->nd_stts) last_val = rb_eval(node->nd_stts); + JUMP_TAG(TAG_RETURN); + break; + + case NODE_CALL: + case NODE_CALL2: + { + VALUE recv, *argv; + int argc, last_iter; + enum mth_scope scope; + + last_iter = the_env->iterator; + the_env->iterator = 0; /* recv & args are not iter. */ + recv = node->nd_recv?rb_eval(node->nd_recv):Qself; + if (node->nd_args) { + SETUP_ARGS; + } + else { + argc = 1; + argv = &recv; + } + the_env->iterator = last_iter; /* restore iter. level */ + + scope = node->nd_recv?MTH_METHOD:MTH_FUNC; + return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope); + } + break; + + case NODE_SUPER: + case NODE_ZSUPER: + { + int last_iter; + int i, argc; + VALUE *argv; + + last_iter = the_env->iterator; /* recv & args are not iter. */ + the_env->iterator = 0; + + if (node->nd_args) { + SETUP_ARGS; + } + else if (node->type == NODE_ZSUPER) { + argc = the_env->argc; + argv = the_env->argv; + } + else { + argc = 1; + argv = Qnil; + } + + /* restore iter. level */ + switch (last_iter) { + case 1: /* SUPER called as iter. */ + case 2: /* iter. called SUPER */ + the_env->iterator = 1; + break; + default: /* otherwise SUPER is not iter. */ + break; + } + + result = rb_call(the_env->last_class->super, Qself, + the_env->last_func, argc, argv, Qnil, MTH_FUNC); + the_env->iterator = last_iter; + } + return result; + + case NODE_SCOPE: + { + VALUE result; + + PUSH_ENV(); + PUSH_TAG(); + if (node->nd_cnt > 0) { + the_env->local_vars = ALLOC_N(VALUE, node->nd_cnt); + bzero(the_env->local_vars, sizeof(VALUE)*node->nd_cnt); + the_env->local_tbl = node->nd_tbl; + } + else { + the_env->local_vars = Qnil; + the_env->local_tbl = Qnil; + } + if ((state = EXEC_TAG()) == 0) { + result = rb_eval(node->nd_body); + } + POP_TAG(); + if (the_env->local_vars) free(the_env->local_vars); + POP_ENV(); + if (state != 0) JUMP_TAG(state); + + return result; + } + + case NODE_MASGN: + { + VALUE val = rb_eval(node->nd_value); + NODE *list = node->nd_head; + int i, len; + + GC_LINK; + GC_PRO(val); + if (TYPE(val) != T_ARRAY) { + val = rb_funcall(val, rb_intern("to_a"), 0, Qnil); + if (TYPE(val) != T_ARRAY) { + Bug("to_a did not return Array"); + } + } + len = RARRAY(val)->len; + for (i=0; list && i<len; i++) { + asign(list->nd_head, RARRAY(val)->ptr[i]); + list = list->nd_next; + } + while (list) { + asign(list->nd_head, Qnil); + list = list->nd_next; + } + GC_UNLINK; + return val; + } + + case NODE_LASGN: + if (the_env->local_vars == Qnil) + Bug("unexpected local variable asignment"); + return the_env->local_vars[node->nd_cnt] = rb_eval(node->nd_value); + + case NODE_GASGN: + { + VALUE val; + + GC_LINK; GC_PRO3(val, rb_eval(node->nd_value)); + rb_gvar_set(node->nd_entry, val); + GC_UNLINK; + return val; + } + case NODE_IASGN: + { + VALUE val; + + GC_LINK; GC_PRO3(val, rb_eval(node->nd_value)); + rb_ivar_set(node->nd_vid, val); + GC_UNLINK; + return val; + } + case NODE_CASGN: + { + VALUE val; + + GC_LINK; GC_PRO3(val, rb_eval(node->nd_value)); + rb_const_set(node->nd_vid, val); + GC_UNLINK; + return val; + } + break; + + case NODE_LVAR: + if (the_env->local_vars == Qnil) + Bug("unexpected local variable"); + return the_env->local_vars[node->nd_cnt]; + + case NODE_GVAR: + return rb_gvar_get(node->nd_entry); + case NODE_IVAR: + return rb_ivar_get(node->nd_vid); + case NODE_MVAR: + return rb_mvar_get(node->nd_vid); + + case NODE_CVAR: + { + VALUE val = rb_const_get(node->nd_vid); + node->type = NODE_CONST; + node->nd_cval = val; + return val; + } + + case NODE_CONST: + return node->nd_cval; + + case NODE_HASH: + { + extern VALUE C_Dict; + extern VALUE Fdic_new(); + NODE *list; + + VALUE hash = Fdic_new(C_Dict); + VALUE key, val; + + GC_LINK; + GC_PRO(hash); GC_PRO2(key); GC_PRO2(val); + list = node->nd_head; + while (list) { + key = rb_eval(list->nd_head); + list = list->nd_next; + if (list == Qnil) + Bug("odd number list for hash"); + val = rb_eval(list->nd_head); + list = list->nd_next; + Fdic_aset(hash, key, val); + } + GC_UNLINK; + return hash; + } + break; + + case NODE_ZARRAY: /* zero length list */ + return ary_new(); + + case NODE_ARRAY: + { + VALUE ary; + int i; + NODE *list; + + GC_LINK; + for (i=0, list=node; list; list=list->nd_next) i++; + GC_PRO3(ary, ary_new2(i)); + for (i=0;node;node=node->nd_next) { + RARRAY(ary)->ptr[i++] = rb_eval(node->nd_head); + RARRAY(ary)->len = i; + } + GC_UNLINK; + + return ary; + } + break; + + case NODE_STR: + return str_new3(node->nd_lit); + + case NODE_LIT: + return node->nd_lit; + + case NODE_ATTRSET: + if (the_env->argc != 2) + Fail("Wrong # of arguments(%d for 1)", the_env->argc - 1); + return rb_ivar_set(node->nd_vid, the_env->argv[1]); + + case NODE_ARGS: + { + NODE *local; + int i, len; + + local = node->nd_frml; + for (i=0; local; local=local->nd_next,i++) + ; + + len = the_env->argc - 1; + if (i > len || (node->nd_rest == -1 && i < len)) + Fail("Wrong # of arguments(%d for %d)", len, i); + + local = node->nd_frml; + if (the_env->local_vars == Qnil) + Bug("unexpected local variable asignment"); + + for (i=1;local;i++) { + the_env->local_vars[(int)local->nd_head] = the_env->argv[i]; + local = local->nd_next; + } + if (node->nd_rest >= 0) { + if (the_env->argc == 1) + the_env->local_vars[node->nd_rest] = ary_new(); + else + the_env->local_vars[node->nd_rest] = + ary_new4(the_env->argc-i, the_env->argv+i); + } + } + return Qnil; + + case NODE_DEFN: + { + rb_add_method(the_class,node->nd_mid,node->nd_defn,node->nd_scope); + } + return Qnil; + + case NODE_DEFS: + { + VALUE recv = rb_eval(node->nd_recv); + + if (recv == Qnil) { + Fail("Can't define method \"%s\" for nil", + rb_id2name(node->nd_mid)); + } + rb_add_method(rb_single_class(recv), + node->nd_mid, node->nd_defn, MTH_METHOD); + } + return Qnil; + + case NODE_UNDEF: + { + rb_add_method(the_class, node->nd_mid, Qnil, MTH_UNDEF); + } + return Qnil; + + case NODE_ALIAS: + { + rb_alias(the_class, node->nd_new, node->nd_old); + } + return Qnil; + + case NODE_CLASS: + { + VALUE super, class; + + if (node->nd_super) { + super = rb_id2class(node->nd_super); + if (super == Qnil) { + Fail("undefined superclass %s", + rb_id2name(node->nd_super)); + } + } + else { + super = C_Object; + } + if (class = rb_id2class(node->nd_cname)) { + if (verbose) { + Warning("redefine class %s", rb_id2name(node->nd_cname)); + } + unliteralize(class); + } + + PUSH_ENV(); + the_class = (struct RClass*) + rb_define_class_id(node->nd_cname, super); + Qself = (VALUE)the_class; + + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + rb_eval(node->nd_body); + } + POP_TAG(); + POP_ENV(); + if (state) JUMP_TAG(state); + } + return Qnil; + + case NODE_MODULE: + { + VALUE module; + + if (module = rb_id2class(node->nd_cname)) { + if (verbose) { + Warning("redefine module %s", rb_id2name(node->nd_cname)); + } + unliteralize(module); + } + + PUSH_ENV(); + the_class = (struct RClass*)rb_define_module_id(node->nd_cname); + Qself = (VALUE)the_class; + + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + rb_eval(node->nd_body); + } + POP_TAG(); + POP_ENV(); + if (state) JUMP_TAG(state); + } + return Qnil; + + case NODE_INC: + { + struct RClass *module; + + module = (struct RClass*)rb_id2class(node->nd_modl); + if (module == Qnil) { + Fail("undefined module %s", rb_id2name(node->nd_modl)); + } + rb_include_module(the_class, module); + } + return Qnil; + + default: + Bug("unknown node type %d", node->type); + } + return Qnil; /* not reached */ +} + +VALUE +obj_responds_to(obj, msg) + VALUE obj; + struct RString *msg; +{ + ID id; + + if (FIXNUM_P(msg)) { + id = FIX2INT(msg); + } + else { + Check_Type(msg, T_STRING); + id = rb_intern(msg->ptr); + } + + if (rb_get_method_body(CLASS_OF(obj), id, 0, MTH_FUNC)) { + return TRUE; + } + return FALSE; +} + +void +rb_exit(status) + int status; +{ + last_val = INT2FIX(status); + JUMP_TAG(TAG_EXIT); +} + +VALUE +Fexit(obj, args) + VALUE obj, args; +{ + VALUE status; + + if (rb_scan_args(args, "01", &status) == 1) { + Need_Fixnum(status); + } + else { + status = INT2FIX(0); + } + last_val = status; + JUMP_TAG(TAG_EXIT); + + return Qnil; /* not reached */ +} + +void +rb_break() +{ + if (the_env->flags & DURING_ITERATE) { + JUMP_TAG(TAG_BREAK); + } + else { + Fatal("unexpected break"); + } +} + +void +rb_redo() +{ + if (the_env->flags & DURING_ITERATE) { + JUMP_TAG(TAG_REDO); + } + else { + Fatal("unexpected redo"); + } +} + +void +rb_retry() +{ + if (the_env->flags & DURING_RESQUE) { + JUMP_TAG(TAG_RETRY); + } + else { + Fatal("unexpected retry"); + } +} + +void +rb_fail(mesg) + VALUE mesg; +{ + char buf[BUFSIZ]; + + if (errat == Qnil || sourcefile) { + if (the_env->last_func) { + last_func = the_env->last_func; + } + sprintf(buf, "%s:%d", sourcefile, sourceline); + errat = str_new2(buf); + } + + if (mesg) { + if (RSTRING(mesg)->ptr[RSTRING(mesg)->len - 1] == '\n') { + errstr = mesg; + } + else { + errstr = Fstr_clone(mesg); + str_cat(errstr, "\n", 1); + } + } + + if (prot_tag->level == 0) error_print(); + JUMP_TAG(TAG_FAIL); +} + +VALUE +Ffail(self, args) + VALUE self, args; +{ + VALUE mesg; + + rb_scan_args(args, "01", &mesg); + + if (mesg) Check_Type(mesg, T_STRING); + rb_fail(mesg); + + return Qnil; /* not reached */ +} + +iterator_p() +{ + return ITERATOR_P(); +} + +VALUE +rb_yield(val) + VALUE val; +{ + struct BLOCK *block; + int state; + int go_out; + VALUE result; + int cnt; + + &go_out; + block = the_env->block; + if (!ITERATOR_P()) { + Fail("yield called out of iterator"); + } + + PUSH_ENV(); + block->env.prev = the_env->prev; + the_env = &(block->env); + the_env->flags = the_env->prev->flags; + if (block->var) { + asign(block->var, val); + } + + go_out = 0; + PUSH_TAG(); + switch (state = EXEC_TAG()) { + retry: + case 0: + if (block->body->type == NODE_CFUNC) { + the_env->flags |= DURING_ITERATE; + result = (*block->body->nd_cfnc)(val, block->body->nd_argc); + } + else { + result = rb_eval(block->body); + } + break; + case TAG_RETRY: + goto retry; + case TAG_CONTINUE: + break; + case TAG_BREAK: + case TAG_RETURN: + target_level = block->level; + state = IN_BLOCK|state; + default: + go_out++; + break; + } + POP_TAG(); + POP_ENV(); + if (go_out) JUMP_TAG(state); + + return result; +} + +static void +asign(lhs, val) + NODE *lhs; + VALUE val; +{ + switch (lhs->type) { + case NODE_GASGN: + rb_gvar_set(lhs->nd_entry, val); + break; + + case NODE_IASGN: + rb_ivar_set(lhs->nd_vid, val); + break; + + case NODE_LASGN: + if (the_env->local_vars == Qnil) + Bug("unexpected iterator variable asignment"); + the_env->local_vars[lhs->nd_cnt] = val; + break; + + case NODE_CASGN: + rb_const_set(lhs->nd_vid, val); + break; + + case NODE_CALL: + { + VALUE recv; + GC_LINK; + GC_PRO3(recv, rb_eval(lhs->nd_recv)); + if (lhs->nd_args->nd_head == Qnil) { + /* attr set */ + rb_funcall(recv, lhs->nd_mid, 1, val); + } + else { + /* array set */ + VALUE args; + + GC_PRO3(args, rb_eval(lhs->nd_args)); + RARRAY(args)->ptr[RARRAY(args)->len-1] = val; + rb_apply(recv, lhs->nd_mid, args); + } + GC_UNLINK; + } + break; + + default: + Bug("bug in iterator variable asignment"); + break; + } +} + +VALUE +rb_iterate(it_proc, data1, bl_proc, data2) + VALUE (*it_proc)(), (*bl_proc)(); + char *data1, *data2; +{ + int state; + VALUE retval; + NODE *node = NEW_CFUNC(bl_proc, data2); + struct BLOCK block; + + PUSH_ENV(); + block.level = tag_level; + block.var = Qnil; + block.body = node; + block.env = *the_env; + the_env->block = █ + PUSH_TAG(); + + state = EXEC_TAG(); + if (state == 0) { + the_env->iterator = 1; + retval = (*it_proc)(data1); + } + POP_TAG(); + POP_ENV(); + + freenode(node); + + switch (state) { + case 0: + break; + case IN_BLOCK|TAG_BREAK: + if (target_level != tag_level) { + JUMP_TAG(state); + } + retval = Qnil; + break; + case IN_BLOCK|TAG_RETURN: + if (target_level == tag_level) { + state = TAG_RETURN; + } + /* fall through */ + default: + JUMP_TAG(state); + } + + return retval; +} + +VALUE +rb_resque(b_proc, data1, r_proc, data2) + VALUE (*b_proc)(), (*r_proc)(); + char *data1, *data2; +{ + int state; + int go_out; + VALUE result; + + &go_out; + go_out = 0; + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + retry_entry: + result = (*b_proc)(data1); + break; + + case TAG_FAIL: + if (r_proc) { + PUSH_TAG(); + state = EXEC_TAG(); + if (state == 0) { + the_env->flags |= DURING_RESQUE; + result = (*r_proc)(data2); + } + POP_TAG(); + switch (state) { + case TAG_RETRY: + goto retry_entry; + case 0: + break; + default: + go_out++; + break; + } + } + if (state == 0) { + errstr = errat = Qnil; + } + break; + + default: + break; + } + POP_TAG(); + if (go_out) JUMP_TAG(state); + + return result; +} + +VALUE +rb_ensure(b_proc, data1, e_proc, data2) + VALUE (*b_proc)(), (*e_proc)(); + char *data1, *data2; +{ + int state; + VALUE result; + + GC_LINK; + GC_PRO2(result); + PUSH_TAG(); + if ((state = EXEC_TAG()) == 0) { + result = (*b_proc)(data1); + } + POP_TAG(); + + (*e_proc)(data2); + if (state != 0) { + JUMP_TAG(state); + } + GC_UNLINK; + return result; +} + +struct st_table *new_idhash(); + +static void +rb_undefined(obj, id) + VALUE obj, id; +{ + VALUE desc = obj_as_string(obj); + + if (RSTRING(desc)->len > 160) { + desc = Fkrn_to_s(obj); + } + Fail("undefined method `%s' for \"%s\"(%s)", + rb_id2name(NUM2INT(id)), + RSTRING(desc)->ptr, + rb_class2name(CLASS_OF(obj))); +} + +static VALUE +rb_call(class, recv, mid, argc, argv, scope) + struct RClass *class; + VALUE recv, *argv; + int argc; + ID mid; + enum mth_scope scope; +{ + int state; + int go_out = 0; + int c = argc - 1; + NODE *body; + VALUE result; + + &go_out; + PUSH_ENV(); + the_env->flags |= DURING_CALL; + the_env->argc = argc; + the_env->argv = argv; + Qself = recv; + if (argv) argv[0] = recv; + if (the_env->iterator != 0) the_env->iterator++; + + if ((body = rb_get_method_body(class, mid, 1, scope)) == Qnil) { + rb_undefined(recv, mid); + } + + if (body->type == NODE_CFUNC) { + int len = body->nd_argc; + + if (len >= 0 && c != len) { + Fail("Wrong # of arguments for(%d for %d)", c, body->nd_argc); + } + + if (len == -2) { + result = (*body->nd_cfnc)(recv, ary_new4(argc-1, argv+1)); + } + else if (len == -1) { + result = (*body->nd_cfnc)(argc, argv); + } + else if (len >= 0) { + switch (c) { + case 0: + result = (*body->nd_cfnc)(recv); + break; + case 1: + result = (*body->nd_cfnc)(recv, argv[1]); + break; + case 2: + result = (*body->nd_cfnc)(recv, argv[1], argv[2]); + break; + case 3: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3]); + break; + case 4: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4]); + break; + case 5: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5]); + break; + case 6: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6]); + break; + case 7: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7]); + break; + case 8: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8]); + break; + case 9: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9]); + break; + case 10: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9], + argv[7], argv[8], argv[9], + argv[10]); + break; + case 11: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9], + argv[7], argv[8], argv[9], + argv[10], argv[11]); + break; + case 12: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9], + argv[7], argv[8], argv[9], + argv[10], argv[11], argv[12]); + break; + case 13: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9], + argv[7], argv[8], argv[9], + argv[10], argv[11], argv[12], + argv[13]); + break; + case 14: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9], + argv[7], argv[8], argv[9], + argv[10], argv[11], argv[12], + argv[13], argv[14]); + break; + case 15: + result = (*body->nd_cfnc)(recv, argv[1], argv[2], argv[3], + argv[4], argv[5], argv[6], + argv[7], argv[8], argv[9], + argv[7], argv[8], argv[9], + argv[10], argv[11], argv[12], + argv[13], argv[14], argv[15]); + break; + default: + Fail("too many arguments(%d)", len); + break; + } + } + else { + Bug("bad argc(%d) specified for `%s(%s)'", + len, rb_class2name(class), rb_id2name(mid)); + } + } + else { + the_env->file = sourcefile; + the_env->line = sourceline; + the_env->local_vars = Qnil; + the_env->local_tbl = Qnil; + + PUSH_TAG(); + switch (state = EXEC_TAG()) { + case 0: + result = rb_eval(body); + break; + case TAG_CONTINUE: + Fatal("unexpected continue"); + break; + case TAG_BREAK: + Fatal("unexpected break"); + break; + case TAG_REDO: + Fatal("unexpected redo"); + break; + case TAG_RETRY: + Fatal("retry outside of protect clause"); + break; + case TAG_RETURN: + result = last_val; + break; + default: + go_out++; + } + POP_TAG(); + } + + POP_ENV(); + + if (go_out) JUMP_TAG(state); + + return result; +} + +VALUE +rb_apply(recv, mid, args) + VALUE recv, args; + ID mid; +{ + VALUE *argv; + int argc, i; + + argc = RARRAY(args)->len + 1; + argv = (VALUE*)alloca(sizeof(VALUE)*argc); + for (i=1;i<argc;i++) { + argv[i] = RARRAY(args)->ptr[i-1]; + } + argv[0] = Qnil; + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, MTH_FUNC); +} + +VALUE +Fapply(recv, args) + VALUE recv, args; +{ + VALUE vid, rest; + ID mid; + + rb_scan_args(args, "1*", &vid, &rest); + if (TYPE(vid) == T_STRING) { + mid = rb_intern(RSTRING(vid)->ptr); + } + else { + mid = NUM2INT(vid); + } + return rb_apply(recv, mid, rest); +} + +#include <varargs.h> + +VALUE +rb_funcall(recv, mid, n, va_alist) + VALUE recv; + ID mid; + int n; + va_dcl +{ + va_list ar; + int argc; + VALUE *argv; + + if (n > 0) { + int i; + + argc = n + 1; + argv = (VALUE*)alloca(sizeof(VALUE)*argc); + + va_start(ar); + for (i=1;i<argc;i++) { + argv[i] = va_arg(ar, VALUE); + } + argv[0] = Qnil; + va_end(ar); + } + else { + argc = 1; + argv = Qnil; + } + + return rb_call(CLASS_OF(recv), recv, mid, argc, argv, MTH_FUNC); +} + +VALUE +Fcaller(obj, args) + VALUE obj, args; +{ + VALUE level, file, res, ary; + int lev; + struct ENVIRON *e; + + rb_scan_args(args, "01", &level); + if (level == Qnil) { + lev = 1; + } + else { + lev = FIX2UINT(level); + } + if (lev < 0) Fail("negative level: %d", lev); + + e = the_env; + + while (lev > 0) { + e = e->prev; + if (e == Qnil) Fail("no caller"); + if (!(e->flags & DURING_CALL)) continue; + lev--; + } + if (e->file == Qnil) Fail("initial frame"); + + GC_LINK; + GC_PRO3(file, str_new2(e->file)); + GC_PRO3(ary, e->argv?ary_new4(e->argc, e->argv):ary_new3(1, Qself)); + res = ary_new3(4, file, INT2FIX(e->line), + str_new2(rb_id2name(e->last_func)), ary); + GC_UNLINK; + + return res; +} + +int in_eval = 0; +extern int nerrs; + +VALUE +Feval(obj, src) + VALUE obj; + struct RString *src; +{ + VALUE result; + int state; + NODE *node; + char *oldsrc = sourcefile; + + Check_Type(src, T_STRING); + PUSH_TAG(); + PUSH_ENV(); + the_env->in_eval = 1; + node = eval_tree; + + if (the_env->prev) { + the_class = the_env->prev->current_module; + } + else { + the_class = (struct RClass*)C_Object; + } + + if ((state = EXEC_TAG()) == 0) { + lex_setsrc("(eval)", src->ptr, src->len); + eval_tree = Qnil; + yyparse(); + sourcefile = oldsrc; + if (nerrs == 0) + result = Eval(); + freenode(eval_tree); + } + eval_tree = node; + POP_ENV(); + POP_TAG(); + if (state) printf("exception in eval()\n"); + if (state) JUMP_TAG(state); + + if (nerrs > 0) { + VALUE mesg; + + GC_LINK; + GC_PRO3(mesg, errstr); + nerrs = 0; + errstr = str_new2("syntax error in eval():\n"); + str_cat(errstr, RSTRING(mesg)->ptr, RSTRING(mesg)->len); + rb_fail(errstr); + GC_UNLINK; + } + + return result; +} + +VALUE rb_load_path; + +char *dln_find_file(); + +static char* +find_file(file) + char *file; +{ + extern VALUE rb_load_path; + VALUE sep, vpath; + char *path, *found; + + if (file[0] == '/') return file; + + GC_LINK; + GC_PRO2(sep); GC_PRO2(vpath); + + if (rb_load_path) { + Check_Type(rb_load_path, T_ARRAY); + sep = str_new2(":"); + vpath = ary_join(rb_load_path, sep); + path = RSTRING(vpath)->ptr; + obj_free(sep); + sep = Qnil; + } + else { + path = Qnil; + } + + found = dln_find_file(file, path); + if (found == Qnil) Fail("No such file to load -- %s", file); + + if (vpath) obj_free(vpath); + GC_UNLINK; + + return found; +} + +VALUE +Fload(obj, fname) + VALUE obj; + struct RString *fname; +{ + extern VALUE TopSelf; + int state; + VALUE result; + NODE *node; + char *file; + + Check_Type(fname, T_STRING); + file = find_file(fname->ptr); + +#ifdef USE_DLN + { + static int rb_dln_init = 0; + extern char *rb_dln_argv0; + int len = strlen(file); + + if (len > 2 && file[len-1] == 'o' && file[len-2] == '.') { + if (rb_dln_init == 0 && dln_init(rb_dln_argv0) == -1) { + Fail("%s: %s", rb_dln_argv0, dln_strerror()); + } + + if (dln_load(file) == -1) + Fail(dln_strerror()); + + return TRUE; + } + } +#endif + + PUSH_TAG(); + PUSH_ENV(); + the_class = (struct RClass*)C_Object; + Qself = TopSelf; + the_env->in_eval = 1; + node = eval_tree; + state = EXEC_TAG(); + if (state == 0) { + eval_tree = Qnil; + rb_load_file(file); + if (nerrs == 0) { + result = Eval(); + } + freenode(eval_tree); + } + eval_tree = node; + POP_ENV(); + POP_TAG(); + if (nerrs > 0) { + rb_fail(errstr); + } + if (state) JUMP_TAG(state); + + return TRUE; +} + +static VALUE rb_loadfiles; + +Frequire(obj, fname) + VALUE obj; + struct RString *fname; +{ + char *file; + VALUE *p, *pend; + + Check_Type(fname, T_STRING); + file = find_file(fname->ptr); + + p = RARRAY(rb_loadfiles)->ptr; + pend = p+ RARRAY(rb_loadfiles)->len; + while (p < pend) { + Check_Type(*p, T_STRING); + if (strcmp(RSTRING(*p)->ptr, file) == 0) return FALSE; + } + Fary_push(rb_loadfiles, str_new2(file)); + + Fload(obj, fname); + return TRUE; +} + +char *getenv(); +char *index(); + +#ifndef RUBY_LIB +#define RUBY_LIB "/usr/local/lib/ruby:." +#endif + +#define RUBY_LIB_SEP ':' + +static void +addpath(path) + char *path; +{ + char *p, *s; + + if (path == Qnil) return; + + p = s = path; + while (*p) { + while (*p == RUBY_LIB_SEP) p++; + if (s = index(p, RUBY_LIB_SEP)) { + Fary_push(rb_load_path, str_new(p, (int)(s-p))); + p = s + 1; + } + else { + Fary_push(rb_load_path, str_new2(p)); + break; + } + } +} + +Init_load() +{ + extern VALUE C_Kernel; + extern VALUE rb_check_str(); + char *path; + + rb_define_variable("$LOAD_PATH", &rb_load_path, Qnil, rb_check_str); + rb_load_path = ary_new(); + rb_define_variable("$LOAD_FILES", &rb_load_path, Qnil, rb_readonly_hook); + rb_loadfiles = ary_new(); + addpath(getenv("RUBYLIB")); + addpath(RUBY_LIB); + + rb_define_func(C_Kernel, "load", Fload, 1); + rb_define_func(C_Kernel, "require", Frequire, 1); +} diff --git a/file.c b/file.c new file mode 100644 index 0000000000..7001a2f559 --- /dev/null +++ b/file.c @@ -0,0 +1,1059 @@ + +/************************************************ + + file.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:26 $ + created at: Mon Nov 15 12:24:34 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "io.h" +#include <sys/time.h> +#include <sys/param.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +char *strdup(); + +extern VALUE C_IO; +VALUE C_File; + +VALUE time_new(); + +VALUE +file_open(fname, mode) + char *fname, *mode; +{ + VALUE port; + OpenFile *fptr; + + GC_LINK; + GC_PRO3(port, obj_alloc(C_File)); + + MakeOpenFile(port, fptr); + fptr->mode = io_mode_flags(mode); + + fptr->f = fopen(fname, mode); + if (fptr->f == NULL) { + if (errno == EMFILE) { + gc(); + fptr->f = fopen(fname, mode); + } + if (fptr->f == NULL) { + rb_sys_fail(fname); + } + } + + fptr->path = strdup(fname); + + GC_UNLINK; + + return port; +} + +static VALUE +Ffile_tell(obj) + VALUE obj; +{ + OpenFile *fptr; + long pos; + + GetOpenFile(obj, fptr); + + pos = ftell(fptr->f); + if (ferror(fptr->f) != 0) rb_sys_fail(Qnil); + + return int2inum(pos); +} + +static VALUE +Ffile_seek(obj, offset, ptrname) + VALUE obj, offset, ptrname; +{ + OpenFile *fptr; + long pos; + + Check_Type(ptrname, T_FIXNUM); + + GetOpenFile(obj, fptr); + + pos = fseek(fptr->f, NUM2INT(offset), NUM2INT(ptrname)); + if (pos != 0) rb_sys_fail(Qnil); + + return obj; +} + +static VALUE +Ffile_rewind(obj) + VALUE obj; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + if (fseek(fptr->f, 0L, 0) != 0) rb_sys_fail(Qnil); + + return obj; +} + +static VALUE +Ffile_eof(obj) + VALUE obj; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + if (feof(fptr->f) == 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_path(obj) + VALUE obj; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + return str_new2(fptr->path); +} + +static VALUE +Ffile_isatty(obj) + VALUE obj; +{ + return FALSE; +} + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> + +static VALUE +stat_new(st) + struct stat *st; +{ + VALUE obj, data, atime, mtime, ctime, stat; + + if (st == Qnil) Bug("stat_new() called with nil"); + + GC_LINK; + GC_PRO3(atime, time_new(st->st_atime, 0)); + GC_PRO3(mtime, time_new(st->st_mtime, 0)); + GC_PRO3(ctime, time_new(st->st_ctime, 0)); + + stat = struct_new("stat", + "dev", INT2FIX((int)st->st_dev), + "ino", INT2FIX((int)st->st_ino), + "mode", INT2FIX((int)st->st_mode), + "nlink", INT2FIX((int)st->st_nlink), + "uid", INT2FIX((int)st->st_uid), + "gid", INT2FIX((int)st->st_gid), +#ifdef HAVE_ST_RDEV + "rdev", INT2FIX((int)st->st_rdev), +#else + "rdev", INT2FIX(0), +#endif + "size", INT2FIX((int)st->st_size), +#ifdef HAVE_ST_BLKSIZE + "blksize", INT2FIX((int)st->st_blksize), +#else + "blksize", INT2FIX(0), +#endif +#ifdef HAVE_ST_BLOCKS + "blocks", INT2FIX((int)st->st_blocks), +#else + "blocks", INT2FIX(0), +#endif + "atime", atime, + "mtime", mtime, + "ctime", ctime, + Qnil); + GC_UNLINK; + + return stat; +} + +static char lastpath[MAXPATHLEN]; +static struct stat laststat; + +cache_stat(path, st) + char *path; + struct stat *st; +{ + if (strcmp(lastpath, path) == 0) { + *st = laststat; + return 0; + } + if (stat(path, st) == -1) + return -1; + strcpy(lastpath, path); + laststat = *st; + + return 0; +} + +static VALUE +Ffile_stat(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) == -1) { + rb_sys_fail(fname->ptr); + } + return stat_new(&st); +} + +static VALUE +Ffile_stat2(obj) + VALUE obj; +{ + OpenFile *fptr; + struct stat st; + + GetOpenFile(obj, fptr); + if (fstat(fileno(fptr->f), &st) == -1) { + rb_sys_fail(fptr->path); + } + return stat_new(&st); +} + +static VALUE +Ffile_lstat(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (lstat(fname->ptr, &st) == -1) { + rb_sys_fail(fname->ptr); + } + return stat_new(&st); +} + +static VALUE +Ffile_lstat2(obj) + VALUE obj; +{ + OpenFile *fptr; + struct stat st; + + GetOpenFile(obj, fptr); + if (lstat(fptr->path, &st) == -1) { + rb_sys_fail(fptr->path); + } + return stat_new(&st); +} + +#define HAS_GETGROUPS + +static int +group_member(gid) + GETGROUPS_T gid; +{ + GETGROUPS_T egid; + + if (getgid() == gid || getegid() == gid) + return TRUE; + +#ifdef HAS_GETGROUPS +#ifndef NGROUPS +#define NGROUPS 32 +#endif + { + GETGROUPS_T gary[NGROUPS]; + int anum; + + anum = getgroups(NGROUPS, gary); + while (--anum >= 0) + if (gary[anum] == gid) + return TRUE; + } +#endif + return FALSE; +} + +#ifndef S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +int +eaccess(path, mode) + char *path; + int mode; +{ + extern int group_member (); + struct stat st; + static int euid = -1; + + if (cache_stat(path, &st) < 0) return (-1); + + if (euid == -1) + euid = geteuid (); + + if (euid == 0) + { + /* Root can read or write any file. */ + if (mode != X_OK) + return 0; + + /* Root can execute any file that has any one of the execute + bits set. */ + if (st.st_mode & S_IXUGO) + return 0; + } + + if (st.st_uid == euid) /* owner */ + mode <<= 6; + else if (group_member (st.st_gid)) + mode <<= 3; + + if (st.st_mode & mode) return 0; + + return -1; +} + +static VALUE +Ffile_d(obj, fname) + VALUE obj; + struct RString *fname; +{ +#ifndef S_ISDIR +# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#endif + + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISDIR(st.st_mode)) return TRUE; + return FALSE; +} + +static VALUE +Ffile_p(obj, fname) + VALUE obj; + struct RString *fname; +{ +#ifdef S_IFIFO +# ifndef S_ISFIFO +# define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO) +# endif + + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISFIFO(st.st_mode)) return TRUE; + +#endif + return FALSE; +} + +static VALUE +Ffile_l(obj, fname) + VALUE obj; + struct RString *fname; +{ +#ifndef S_ISLNK +# ifdef _S_ISLNK +# define S_ISLNK(m) _S_ISLNK(m) +# else +# ifdef _S_IFLNK +# define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK) +# else +# ifdef S_IFLNK +# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) +# endif +# endif +# endif +#endif + +#ifdef S_ISLNK + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISLNK(st.st_mode)) return TRUE; + +#endif + return FALSE; +} + +Ffile_S(obj, fname) + VALUE obj; + struct RString *fname; +{ +#ifndef S_ISSOCK +# ifdef _S_ISSOCK +# define S_ISSOCK(m) _S_ISSOCK(m) +# else +# ifdef _S_IFSOCK +# define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK) +# else +# ifdef S_IFSOCK +# define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK) +# endif +# endif +# endif +#endif + +#ifdef S_ISSOCK + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISSOCK(st.st_mode)) return TRUE; + +#endif + return FALSE; +} + +static VALUE +Ffile_b(obj, fname) + VALUE obj; + struct RString *fname; +{ +#ifndef S_ISBLK +# ifdef S_IFBLK +# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK) +# endif +#endif + +#ifdef S_ISBLK + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISBLK(st.st_mode)) return TRUE; + +#endif + return FALSE; +} + +static VALUE +Ffile_c(obj, fname) + VALUE obj; + struct RString *fname; +{ +#ifndef S_ISCHR +# define S_ISCHR(m) ((m & S_IFMT) == S_IFCHR) +#endif + + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISBLK(st.st_mode)) return TRUE; + + return FALSE; +} + +static VALUE +Ffile_e(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_r(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); + if (eaccess(fname->ptr, R_OK) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_R(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); + if (access(fname->ptr, R_OK) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_w(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); + if (eaccess(fname->ptr, W_OK) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_W(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); + if (access(fname->ptr, W_OK) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_x(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); + if (eaccess(fname->ptr, X_OK) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_X(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); + if (access(fname->ptr, X_OK) < 0) return FALSE; + return TRUE; +} + +static VALUE +Ffile_f(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (S_ISREG(st.st_mode)) return TRUE; + return FALSE; +} + +static VALUE +Ffile_z(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (st.st_size == 0) return TRUE; + return FALSE; +} + +static VALUE +Ffile_s(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (st.st_size == 0) return FALSE; + return int2inum(st.st_size); +} + +static VALUE +Ffile_owned(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (st.st_uid == geteuid()) return TRUE; + return FALSE; +} + +static VALUE +Ffile_grpowned(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) return FALSE; + if (st.st_gid == getegid()) return TRUE; + return FALSE; +} + +#if defined(S_ISUID) || defined(S_ISGID) || defined(S_ISVTX) +static VALUE +check3rdbyte(file, mode) + char *file; + int mode; +{ + struct stat st; + + if (cache_stat(file, &st) < 0) return FALSE; + if (st.st_mode & mode) return TRUE; + return FALSE; +} +#endif + +static VALUE +Ffile_suid(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); +#ifdef S_ISUID + return check3rdbyte(fname->ptr, S_ISUID); +#else + return FALSE; +#endif +} + +static VALUE +Ffile_sgid(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); +#ifdef S_ISGID + return check3rdbyte(fname->ptr, S_ISGID); +#else + return FALSE; +#endif +} + +static VALUE +Ffile_sticky(obj, fname) + VALUE obj; + struct RString *fname; +{ + Check_Type(fname, T_STRING); +#ifdef S_ISVTX + return check3rdbyte(fname->ptr, S_ISVTX); +#else + return FALSE; +#endif +} + +static VALUE +Ffile_atime(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr); + return time_new(st.st_atime, 0); +} + +static VALUE +Ffile_atime2(obj) + VALUE obj; +{ + OpenFile *fptr; + struct stat st; + + GetOpenFile(obj, fptr); + if (fstat(fileno(fptr->f), &st) == -1) { + rb_sys_fail(fptr->path); + } + return time_new(st.st_atime, 0); +} + +static VALUE +Ffile_mtime(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr); + return time_new(st.st_mtime, 0); +} + +static VALUE +Ffile_mtime2(obj) + VALUE obj; +{ + OpenFile *fptr; + struct stat st; + + GetOpenFile(obj, fptr); + if (fstat(fileno(fptr->f), &st) == -1) { + rb_sys_fail(fptr->path); + } + return time_new(st.st_mtime, 0); +} + +static VALUE +Ffile_ctime(obj, fname) + VALUE obj; + struct RString *fname; +{ + struct stat st; + + Check_Type(fname, T_STRING); + if (cache_stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr); + return time_new(st.st_ctime, 0); +} + +static VALUE +Ffile_ctime2(obj) + VALUE obj; +{ + OpenFile *fptr; + struct stat st; + + GetOpenFile(obj, fptr); + if (fstat(fileno(fptr->f), &st) == -1) { + rb_sys_fail(fptr->path); + } + return time_new(st.st_ctime, 0); +} + +static VALUE +Ffile_chmod(obj, args) + VALUE obj, args; +{ + VALUE vmode; + VALUE rest; + int mode, i, len; + VALUE path; + + rb_scan_args(args, "1*", &vmode, &rest); + mode = NUM2INT(vmode); + + len = RARRAY(rest)->len; + for (i=0; i<len; i++) { + path = RARRAY(rest)->ptr[i]; + Check_Type(path, T_STRING); + if (chmod(RSTRING(path)->ptr, mode) == -1) + rb_sys_fail(RSTRING(path)->ptr); + } + + return Qnil; +} + +static VALUE +Ffile_chmod2(obj, vmode) + VALUE obj, vmode; +{ + OpenFile *fptr; + int mode; + + mode = NUM2INT(vmode); + + GetOpenFile(obj, fptr); + if (fchmod(fileno(fptr->f), mode) == -1) + rb_sys_fail(fptr->path); + + return obj; +} + +static VALUE +Ffile_chown(obj, args) + VALUE obj, args; +{ + VALUE o, g, rest; + int owner, group; + int i, len; + + len = rb_scan_args(args, "2*", &o, &g, &rest); + if (o == Qnil) { + owner = -1; + } + else { + owner = NUM2INT(o); + } + if (g == Qnil) { + group = -1; + } + else { + group = NUM2INT(g); + } + + len -= 2; + for (i=0; i<len; i++) { + Check_Type(RARRAY(rest)->ptr[i], T_STRING); + } + + for (i=0; i<len; i++) { + if (chown(RSTRING(RARRAY(rest)->ptr[i])->ptr, owner, group) < 0) + rb_sys_fail(RSTRING(RARRAY(rest)->ptr[i])->ptr); + } + + return INT2FIX(i); +} + +Ffile_chown2(obj, owner, group) + VALUE obj, owner, group; +{ + OpenFile *fptr; + int mode; + + GetOpenFile(obj, fptr); + if (fchown(fileno(fptr->f), NUM2INT(owner), NUM2INT(group)) == -1) + rb_sys_fail(fptr->path); + + return obj; +} + +struct timeval *time_timeval(); + +static VALUE +Ffile_utime(obj, args) + VALUE obj, args; +{ + VALUE atime, mtime, rest; + struct timeval tvp[2]; + int i, len; + + len = rb_scan_args(args, "2*", &atime, &mtime, &rest); + + tvp[0] = *time_timeval(atime); + tvp[1] = *time_timeval(mtime); + + len -= 2; + for (i=0; i<len; i++) { + Check_Type(RARRAY(rest)->ptr[i], T_STRING); + } + + for (i=0; i<len; i++) { + if (utimes(RSTRING(RARRAY(rest)->ptr[i])->ptr, tvp) < 0) + rb_sys_fail(RSTRING(RARRAY(rest)->ptr[i])->ptr); + } + + return INT2FIX(i); +} + +static VALUE +Ffile_link(obj, from, to) + VALUE obj; + struct RString *from, *to; +{ + Check_Type(from, T_STRING); + Check_Type(to, T_STRING); + + if (link(from->ptr, to->ptr) < 0) + rb_sys_fail(from->ptr); + return TRUE; +} + +static VALUE +Ffile_symlink(obj, from, to) + VALUE obj; + struct RString *from, *to; +{ + Check_Type(from, T_STRING); + Check_Type(to, T_STRING); + + if (symlink(from->ptr, to->ptr) < 0) + rb_sys_fail(from->ptr); + return TRUE; +} + +Ffile_readlink(obj, path) + VALUE obj; + struct RString *path; +{ + char buf[MAXPATHLEN]; + int cc; + + Check_Type(path, T_STRING); + + if ((cc = readlink(path->ptr, buf, MAXPATHLEN)) < 0) + rb_sys_fail(path->ptr); + + return str_new(buf, cc); +} + +static VALUE +Ffile_unlink(obj, args) + VALUE obj; + struct RArray *args; +{ + int i, len; + + len = args->len; + for (i=0; i<len; i++) { + Check_Type(args->ptr[i], T_STRING); + } + for (i=0; i<len; i++) { + if (unlink(RSTRING(args->ptr[i])->ptr) < 0) + rb_sys_fail(RSTRING(args->ptr[i])->ptr); + } + + return INT2FIX(i); +} + +static VALUE +Ffile_rename(obj, from, to) + VALUE obj; + struct RString *from, *to; +{ + Check_Type(from, T_STRING); + Check_Type(to, T_STRING); + + if (rename(from->ptr, to->ptr) == -1) + rb_sys_fail(from->ptr); + + return TRUE; +} + +static VALUE +Ffile_umask(argc, argv) + int argc; + VALUE *argv; +{ + VALUE mask; + int omask; + + if (argc == 1) { + int omask = umask(0); + umask(omask); + } + else if (argc == 2) { + omask = umask(NUM2INT(argv[1])); + } + else { + Fail("wrong # of argument"); + } + return INT2FIX(omask); +} + +static VALUE +Ffile_truncate(obj, path, len) + VALUE obj, len; + struct RString *path; +{ + Check_Type(path, T_STRING); + + if (truncate(path->ptr, NUM2INT(len)) < 0) + rb_sys_fail(path->ptr); + return TRUE; +} + +static VALUE +Ffile_truncate2(obj, len) + VALUE obj, len; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + + if (!(fptr->mode & FMODE_WRITABLE)) { + Fail("not opened for writing"); + } + if (ftruncate(fileno(fptr->f), NUM2INT(len)) < 0) + rb_sys_fail(fptr->path); + return TRUE; +} + +static VALUE +Ffile_fcntl(obj, req, arg) + VALUE obj, req; + struct RString *arg; +{ + io_ctl(obj, req, arg, 0); + return obj; +} + +Init_File() +{ + C_File = rb_define_class("File", C_IO); + + rb_define_single_method(C_File, "stat", Ffile_stat, 1); + rb_define_single_method(C_File, "lstat", Ffile_lstat, 1); + + rb_define_single_method(C_File, "d", Ffile_d, 1); + rb_define_single_method(C_File, "isdirectory", Ffile_d, 1); + rb_define_single_method(C_File, "a", Ffile_e, 1); + rb_define_single_method(C_File, "e", Ffile_e, 1); + rb_define_single_method(C_File, "exists", Ffile_e, 1); + rb_define_single_method(C_File, "r", Ffile_r, 1); + rb_define_single_method(C_File, "readable", Ffile_r, 1); + rb_define_single_method(C_File, "R", Ffile_R, 1); + rb_define_single_method(C_File, "w", Ffile_w, 1); + rb_define_single_method(C_File, "writable", Ffile_w, 1); + rb_define_single_method(C_File, "W", Ffile_W, 1); + rb_define_single_method(C_File, "x", Ffile_x, 1); + rb_define_single_method(C_File, "executable", Ffile_x, 1); + rb_define_single_method(C_File, "X", Ffile_X, 1); + rb_define_single_method(C_File, "f", Ffile_f, 1); + rb_define_single_method(C_File, "isfile", Ffile_f, 1); + rb_define_single_method(C_File, "z", Ffile_z, 1); + rb_define_single_method(C_File, "s", Ffile_s, 1); + rb_define_single_method(C_File, "size", Ffile_s, 1); + rb_define_single_method(C_File, "O", Ffile_owned, 1); + rb_define_single_method(C_File, "owned", Ffile_owned, 1); + rb_define_single_method(C_File, "G", Ffile_grpowned, 1); + + rb_define_single_method(C_File, "p", Ffile_p, 1); + rb_define_single_method(C_File, "ispipe", Ffile_p, 1); + rb_define_single_method(C_File, "l", Ffile_l, 1); + rb_define_single_method(C_File, "issymlink", Ffile_l, 1); + rb_define_single_method(C_File, "S", Ffile_S, 1); + rb_define_single_method(C_File, "issocket", Ffile_S, 1); + + rb_define_single_method(C_File, "b", Ffile_b, 1); + rb_define_single_method(C_File, "c", Ffile_c, 1); + + rb_define_single_method(C_File, "u", Ffile_suid, 1); + rb_define_single_method(C_File, "setuid", Ffile_suid, 1); + rb_define_single_method(C_File, "g", Ffile_sgid, 1); + rb_define_single_method(C_File, "setgid", Ffile_sgid, 1); + rb_define_single_method(C_File, "k", Ffile_sticky, 1); + + rb_define_single_method(C_File, "atime", Ffile_atime, 1); + rb_define_single_method(C_File, "mtime", Ffile_mtime, 1); + rb_define_single_method(C_File, "ctime", Ffile_ctime, 1); + + rb_define_single_method(C_File, "utime", Ffile_utime, -1); + rb_define_single_method(C_File, "chmod", Ffile_chmod, -2); + rb_define_single_method(C_File, "chown", Ffile_chown, -1); + + rb_define_single_method(C_File, "link", Ffile_link, 2); + rb_define_single_method(C_File, "symlink", Ffile_symlink, 2); + rb_define_single_method(C_File, "readlink", Ffile_readlink, 1); + + rb_define_single_method(C_File, "unlink", Ffile_unlink, -1); + rb_define_single_method(C_File, "delete", Ffile_unlink, -1); + rb_define_single_method(C_File, "rename", Ffile_rename, 2); + rb_define_single_method(C_File, "umask", Ffile_umask, -1); + rb_define_single_method(C_File, "truncate", Ffile_truncate, 2); + + rb_define_method(C_File, "stat", Ffile_stat2, 0); + rb_define_method(C_File, "lstat", Ffile_lstat2, 0); + + rb_define_method(C_File, "atime", Ffile_atime2, 0); + rb_define_method(C_File, "mtime", Ffile_mtime2, 0); + rb_define_method(C_File, "ctime", Ffile_ctime2, 0); + + rb_define_method(C_File, "chmod", Ffile_chmod2, 1); + rb_define_method(C_File, "chown", Ffile_chown2, 2); + rb_define_method(C_File, "truncate", Ffile_truncate2, 1); + + rb_define_method(C_File, "tell", Ffile_tell, 0); + rb_define_method(C_File, "seek", Ffile_seek, 2); + rb_define_method(C_File, "rewind", Ffile_rewind, 0); + rb_define_method(C_File, "isatty", Ffile_isatty, 0); + rb_define_method(C_File, "eof", Ffile_eof, 0); + + rb_define_method(C_IO, "fcntl", Ffile_fcntl, 2); + + rb_define_method(C_File, "path", Ffile_path, 0); +} @@ -0,0 +1,490 @@ +/************************************************ + + gc.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:27 $ + created at: Tue Oct 5 09:44:46 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include "st.h" +#include <stdio.h> + +void *malloc(); +void *calloc(); +void *realloc(); + +struct gc_list *GC_List = Qnil; +static struct gc_list *Global_List = Qnil; +static unsigned long bytes_alloc = 0, gc_threshold = 1000000; + +static mark_tbl(); + +void * +xmalloc(size) + unsigned long size; +{ + void *mem; + + bytes_alloc += size; + if (size == 0) size = 1; + mem = malloc(size); + if (mem == Qnil) { + gc(); + bytes_alloc += size; + mem = malloc(size); + if (mem == Qnil) + Fatal("failed to allocate memory"); + } + + return mem; +} + +void * +xcalloc(n, size) + unsigned long n, size; +{ + void *mem; + + mem = xmalloc(n * size); + bzero(mem, n * size); + + return mem; +} + +void * +xrealloc(ptr, size) + void *ptr; + unsigned long size; +{ + void *mem; + + mem = realloc(ptr, size); + if (mem == Qnil) { + gc(); + mem = realloc(ptr, size); + if (mem == Qnil) + Fatal("failed to allocate memory(realloc)"); + } + + return mem; +} + +void +rb_global_variable(var) + VALUE *var; +{ + struct gc_list *tmp; + + tmp = (struct gc_list*)xmalloc(sizeof(struct gc_list)); + tmp->next = Global_List; + tmp->varptr = var; + tmp->n = 1; + Global_List = tmp; +} + +static struct RBasic *object_list = Qnil; +static struct RBasic *literal_list = Qnil; +static unsigned long fl_current = FL_MARK; +static unsigned long fl_old = 0L; + +static int dont_gc; + +VALUE +Fgc_enable() +{ + int old = dont_gc; + + dont_gc = Qnil; + return old; +} + +VALUE +Fgc_disable() +{ + int old = dont_gc; + + dont_gc = TRUE; + return old; +} + +VALUE +Fgc_threshold(obj) + VALUE obj; +{ + return INT2FIX(gc_threshold); +} + +VALUE +Fgc_set_threshold(obj, val) + VALUE obj, val; +{ + int old = gc_threshold; + + gc_threshold = NUM2INT(val); + return INT2FIX(old); +} + +#include <sys/types.h> +#include <sys/times.h> + +static Fgc_begin() +{ + return Qnil; +} + +static Fgc_end() +{ + return Qnil; +} + +VALUE M_GC; + +static ID start_hook, end_hook; + +struct RBasic * +newobj(size) + unsigned long size; +{ + struct RBasic *obj = Qnil; + + if (bytes_alloc + size > gc_threshold) { + gc(); + } + obj = (struct RBasic*)xmalloc(size); + obj->next = object_list; + object_list = obj; + obj->flags = fl_current; + obj->iv_tbl = Qnil; + + return obj; +} + +literalize(obj) + struct RBasic *obj; +{ + struct RBasic *ptr = object_list; + + if (NIL_P(obj) || FIXNUM_P(obj)) return; + + FL_SET(obj, FL_LITERAL); + if (ptr == obj) { + object_list = ptr->next; + obj->next = literal_list; + literal_list = obj; + + return; + } + + while (ptr && ptr->next) { + if (ptr->next == obj) { + ptr->next = obj->next; + obj->next = literal_list; + literal_list = obj; + + return; + } + ptr = ptr->next; + } + Bug("0x%x is not a object.", obj); +} + +void +unliteralize(obj) + struct RBasic *obj; +{ + struct RBasic *ptr = literal_list; + + if (NIL_P(obj) || FIXNUM_P(obj)) return; + + if (!FL_TEST(obj, FL_LITERAL)) return; + FL_UNSET(obj, FL_LITERAL); + + if (ptr == obj) { + literal_list = ptr->next; + goto unlit; + } + + while (ptr->next) { + if (ptr->next == obj) { + ptr->next = obj->next; + } + ptr = ptr->next; + goto unlit; + } + Bug("0x%x is not a literal object.", obj); + + unlit: + obj->next = object_list; + object_list = obj; + obj->flags &= ~FL_MARK; + obj->flags |= fl_current; + return; +} + +extern st_table *rb_global_tbl; +extern st_table *rb_class_tbl; + +gc() +{ + struct gc_list *list; + struct ENVIRON *env; + int i, max; + + rb_funcall(M_GC, start_hook, 0, Qnil); + + if (dont_gc) return; + dont_gc++; + fl_old = fl_current; + fl_current = ~fl_current & FL_MARK; + + /* mark env stack */ + for (env = the_env; env; env = env->prev) { + mark(env->self); + for (i=1, max=env->argc; i<max; i++) { + mark(env->argv[i]); + } + if (env->local_vars) { + for (i=0, max=env->local_tbl[0]; i<max; i++) + mark(env->local_vars[i]); + } + } + + /* mark protected C variables */ + for (list=GC_List; list; list=list->next) { + VALUE *v = list->varptr; + for (i=0, max = list->n; i<max; i++) { + mark(*v); + v++; + } + } + + /* mark protected global variables */ + for (list = Global_List; list; list = list->next) { + mark(*list->varptr); + } + + mark_global_tbl(); + mark_tbl(rb_class_tbl); + + mark_trap_list(); + + sweep(); + bytes_alloc = 0; + dont_gc--; + + rb_funcall(M_GC, end_hook, 0, Qnil); +} + +static +mark_entry(key, value) + ID key; + VALUE value; +{ + mark(value); + return ST_CONTINUE; +} + +static +mark_tbl(tbl) + st_table *tbl; +{ + st_foreach(tbl, mark_entry, 0); +} + +static +mark_dicentry(key, value) + ID key; + VALUE value; +{ + mark(key); + mark(value); + return ST_CONTINUE; +} + +static +mark_dict(tbl) + st_table *tbl; +{ + st_foreach(tbl, mark_dicentry, 0); +} + +mark(obj) + register struct RBasic *obj; +{ + if (obj == Qnil) return; + if (FIXNUM_P(obj)) return; + if ((obj->flags & FL_MARK) == fl_current) return; + + obj->flags &= ~FL_MARK; + obj->flags |= fl_current; + + switch (obj->flags & T_MASK) { + case T_NIL: + case T_FIXNUM: + Bug("mark() called for broken object"); + break; + } + + if (obj->iv_tbl) mark_tbl(obj->iv_tbl); + switch (obj->flags & T_MASK) { + case T_OBJECT: + mark(obj->class); + break; + case T_ICLASS: + mark(RCLASS(obj)->super); + if (RCLASS(obj)->c_tbl) mark_tbl(RCLASS(obj)->c_tbl); + mark_tbl(RCLASS(obj)->m_tbl); + break; + case T_CLASS: + mark(RCLASS(obj)->super); + case T_MODULE: + if (RCLASS(obj)->c_tbl) mark_tbl(RCLASS(obj)->c_tbl); + mark_tbl(RCLASS(obj)->m_tbl); + mark(RBASIC(obj)->class); + break; + case T_ARRAY: + { + int i, len = RARRAY(obj)->len; + VALUE *ptr = RARRAY(obj)->ptr; + + for (i=0; i < len; i++) + mark(ptr[i]); + } + break; + case T_DICT: + mark_dict(RDICT(obj)->tbl); + break; + case T_STRING: + if (RSTRING(obj)->orig) mark(RSTRING(obj)->orig); + break; + case T_DATA: + if (RDATA(obj)->dmark) (*RDATA(obj)->dmark)(DATA_PTR(obj)); + break; + case T_REGEXP: + case T_FLOAT: + case T_METHOD: + case T_BIGNUM: + break; + case T_STRUCT: + { + int i, len = RSTRUCT(obj)->len; + struct kv_pair *ptr = RSTRUCT(obj)->tbl; + + for (i=0; i < len; i++) + mark(ptr[i].value); + } + break; + default: + Bug("mark(): unknown data type %d", obj->flags & T_MASK); + } +} + +sweep() +{ + register struct RBasic *link = object_list; + register struct RBasic *next; + + if (link && (link->flags & FL_MARK) == fl_old) { + object_list = object_list->next; + obj_free(link); + link = object_list; + } + + while (link && link->next) { + if ((link->next->flags & FL_MARK) == fl_old) { + next = link->next->next; + obj_free(link->next); + link->next = next; + continue; + } + link = link->next; + } +} + +static +freemethod(key, body) + ID key; + char *body; +{ + freenode(body); + return ST_CONTINUE; +} + +obj_free(obj) + struct RBasic *obj; +{ + switch (obj->flags & T_MASK) { + case T_NIL: + case T_FIXNUM: + Bug("obj_free() called for broken object"); + break; + } + + if (obj->iv_tbl) st_free_table(obj->iv_tbl); + switch (obj->flags & T_MASK) { + case T_OBJECT: + break; + case T_MODULE: + case T_CLASS: + st_foreach(RCLASS(obj)->m_tbl, freemethod); + st_free_table(RCLASS(obj)->m_tbl); + if (RCLASS(obj)->c_tbl) + st_free_table(RCLASS(obj)->c_tbl); + break; + case T_STRING: + if (RSTRING(obj)->orig == Qnil) free(RSTRING(obj)->ptr); + break; + case T_ARRAY: + free(RARRAY(obj)->ptr); + break; + case T_DICT: + st_free_table(RDICT(obj)->tbl); + break; + case T_REGEXP: + reg_free(RREGEXP(obj)->ptr); + free(RREGEXP(obj)->str); + break; + case T_DATA: + if (RDATA(obj)->dfree) (*RDATA(obj)->dfree)(DATA_PTR(obj)); + break; + case T_ICLASS: + /* iClass shares table with the module */ + case T_FLOAT: + break; + case T_METHOD: + freenode(RMETHOD(obj)->node); + break; + case T_STRUCT: + free(RSTRUCT(obj)->name); + free(RSTRUCT(obj)->tbl); + break; + case T_BIGNUM: + free(RBIGNUM(obj)->digits); + break; + default: + Bug("sweep(): unknown data type %d", obj->flags & T_MASK); + } + free(obj); +} + +Init_GC() +{ + M_GC = rb_define_module("GC"); + rb_define_single_method(M_GC, "start", gc, 0); + rb_define_single_method(M_GC, "enable", Fgc_enable, 0); + rb_define_single_method(M_GC, "disable", Fgc_disable, 0); + rb_define_single_method(M_GC, "threshold", Fgc_threshold, 0); + rb_define_single_method(M_GC, "threshold=", Fgc_set_threshold, 1); + rb_define_single_method(M_GC, "start_hook", Fgc_begin, 0); + rb_define_single_method(M_GC, "end_hook", Fgc_end, 0); + rb_define_func(M_GC, "garbage_collect", gc, 0); + + start_hook = rb_intern("start_hook"); + end_hook = rb_intern("end_hook"); +} diff --git a/ident.h b/ident.h new file mode 100644 index 0000000000..8047c272ca --- /dev/null +++ b/ident.h @@ -0,0 +1,25 @@ +/************************************************ + + ident.h - + + $Author: matz $ + $Revision: 1.1.1.1 $ + $Date: 1994/06/17 14:23:49 $ + created at: Mon Jan 31 16:23:19 JST 1994 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#ifndef IDENT_H +#define IDENT_H + +#define ID_SCOPE_MASK 0x07 +#define ID_LOCAL 0x00 +#define ID_ATTRSET 0x04 +#define ID_INSTANCE 0x02 +#define ID_GLOBAL 0x03 +#define ID_CONST 0x06 +#define ID_VARMASK 0x02 + +#endif diff --git a/inits.c b/inits.c new file mode 100644 index 0000000000..58d686d912 --- /dev/null +++ b/inits.c @@ -0,0 +1,50 @@ +/************************************************ + + inits.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Tue Dec 28 16:01:58 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +rb_call_inits() +{ + Init_sym(); + Init_var_tables(); + Init_Object(); + Init_GC(); + Init_Comparable(); + Init_Enumerable(); + Init_Numeric(); + Init_Bignum(); + Init_Array(); + Init_Dict(); + Init_Struct(); + Init_String(); + Init_Regexp(); + Init_pack(); + Init_Range(); + Init_IO(); + Init_Dir(); + Init_Time(); + Init_Random(); + Init_process(); + Init_Etc(); + Init_load(); + Init_Math(); +#ifdef USE_DBM + Init_DBM(); +#endif +#ifdef HAVE_SOCKET + Init_Socket(); +#endif + /* new Inits comes between here.. */ + + /* .. and here. */ + Init_version(); +} @@ -0,0 +1,1221 @@ +/************************************************ + + io.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:29 $ + created at: Fri Oct 15 18:08:59 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "io.h" +#include <ctype.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +VALUE rb_ad_string(); + +VALUE C_IO; +extern VALUE C_File; + +VALUE rb_stdin, rb_stdout, rb_stderr, rb_defout; + +VALUE FS, OFS; +VALUE RS, ORS; + +ID id_write; + +extern char *inplace; + +/* writing functions */ +static VALUE +Fio_write(obj, str) + VALUE obj; + struct RString *str; +{ + OpenFile *fptr; + FILE *f; + VALUE out; + int n; + + if (TYPE(str) != T_STRING) + str = (struct RString*)obj_as_string(str); + + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_WRITABLE)) { + Fail("not opened for writing"); + } + + f = (fptr->f2) ? fptr->f2 : fptr->f; + if (f == NULL) Fail("closed stream"); + + if (str->len == 0) return INT2FIX(0); + + n = fwrite(str->ptr, sizeof(char), str->len, f); + if (n == 0 || ferror(f)) { + rb_sys_fail(fptr->path); + } + if (fptr->mode & FMODE_SYNC) { + fflush(f); + } + + return INT2FIX(n); +} + +static VALUE +Fio_puts(obj, str) + VALUE obj, str; +{ + Fio_write(obj, str); + return obj; +} + +static VALUE +Fio_flush(obj) + VALUE obj; +{ + OpenFile *fptr; + FILE *f; + + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_WRITABLE)) { + Fail("not opend for writing"); + } + f = (fptr->f2) ? fptr->f2 : fptr->f; + if (f == NULL) Fail("closed stream"); + + if (fflush(f) == EOF) rb_sys_fail(Qnil); + + return obj; +} + +static VALUE +Fio_eof(obj) + VALUE obj; +{ + OpenFile *fptr; + int ch; + + GetOpenFile(obj, fptr); +#ifdef STDSTDIO /* (the code works without this) */ + if (fptr->f->_cnt > 0) /* cheat a little, since */ + return FALSE; /* this is the most usual case */ +#endif + + ch = getc(fptr->f); + if (ch != EOF) { + (void)ungetc(ch, fptr->f); + return FALSE; + } +#ifdef STDSTDIO + if (fptr->f->_cnt < -1) + fptr->f->_cnt = -1; +#endif + return TRUE; +} + +static VALUE +Fio_sync(obj) + VALUE obj; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + return (fptr->mode & FMODE_SYNC) ? TRUE : FALSE; +} + +static VALUE +Fio_set_sync(obj, mode) + VALUE obj, mode; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + if (mode) { + fptr->mode |= FMODE_SYNC; + } + else { + fptr->mode &= ~FMODE_SYNC; + } + return mode; +} + +static VALUE +Fio_fileno(obj) + VALUE obj; +{ + OpenFile *fptr; + int f; + + GetOpenFile(obj, fptr); + f = fileno(fptr->f); + return INT2FIX(f); +} + +/* reading functions */ +static VALUE +read_all(port) + VALUE port; +{ + OpenFile *fptr; + VALUE str; + char buf[BUFSIZ]; + int n; + + GetOpenFile(port, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opend for reading"); + } + if (fptr->f == NULL) Fail("closed stream"); + + GC_LINK; + GC_PRO3(str, str_new(0, 0)); + + for (;;) { + n = fread(buf, 1, BUFSIZ, fptr->f); + if (n == 0) { + if (feof(fptr->f)) break; + rb_sys_fail(Qnil); + } + str_cat(str, buf, n); + } + + GC_UNLINK; + return str; +} + +static VALUE +Fio_read(obj, args) + VALUE obj, args; +{ + OpenFile *fptr; + int n, lgt; + VALUE len, str; + + if (rb_scan_args(args, "01", &len) == 0) { + return read_all(obj); + } + + lgt = NUM2INT(len); + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opend for reading"); + } + if (fptr->f == NULL) Fail("closed stream"); + + str = str_new(0, lgt); + + n = fread(RSTRING(str)->ptr, 1, RSTRING(str)->len, fptr->f); + if (n == 0) { + if (feof(fptr->f)) return Qnil; + rb_sys_fail(Qnil); + } + + RSTRING(str)->len = n; + RSTRING(str)->ptr[n] = '\0'; + + return str; +} + +static void +io_gets(str) + VALUE str; +{ + rb_break(); +} + +void rb_each(); + +VALUE rb_lastline; +static VALUE lineno; + +static VALUE +Fio_gets(obj) + VALUE obj; +{ + OpenFile *fptr; + FILE *f; + struct RString *str; + int c, newline; + int rslen; + + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opend for reading"); + } + f = fptr->f; + if (f == NULL) Fail("closed stream"); + + GC_LINK; + GC_PRO2(str); + + if (RS) { + rslen = RSTRING(RS)->len; + if (rslen == 0) { + newline = '\n'; + } + else { + newline = RSTRING(RS)->ptr[rslen-1]; + } + } + else { + newline = 0777; /* non matching char */ + rslen = 1; + } + + if (rslen == 0 && c == '\n') { + do { + c = getc(f); + if (c != '\n') { + ungetc(c,f); + break; + } + } while (c != EOF); + } + + { + char buf[8192]; + char *bp, *bpe = buf + sizeof buf - 3; + char *ptr; + int append = 0; + + again: + bp = buf; + while ((c = getc(f)) != EOF && (*bp++ = c) != newline && bp < bpe) + ; + + if (c == EOF && !append && bp == buf) { + str = Qnil; + goto return_gets; + } + + if (append) + str_cat(str, buf, bp - buf); + else + str = (struct RString*)str_new(buf, bp - buf); + + if (c != EOF + && + (c != newline + || + (rslen > 1 + && + (str->len < rslen + || + memcmp(str->ptr+str->len-rslen, RSTRING(RS)->ptr, rslen) + ) + ) + ) + ) { + append = 1; + goto again; + } + } + + return_gets: + if (rslen == 0 && c == '\n') { + while (c != EOF) { + c = getc(f); + if (c != '\n') { + ungetc(c, f); + break; + } + } + } + + GC_UNLINK; + + if (str) { + fptr->lineno++; + lineno = INT2FIX(fptr->lineno); + return rb_lastline = (VALUE)str; + } + return Qnil; +} + +static VALUE +Fio_each(obj) + VALUE obj; +{ + VALUE str; + + GC_PRO2(str); + while (str = Fio_gets(obj)) { + rb_yield(str); + } + return Qnil; +} + +static VALUE +Fio_each_byte(obj) + VALUE obj; +{ + OpenFile *fptr; + FILE *f; + int c; + + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opend for reading"); + } + f = fptr->f; + if (f == NULL) Fail("closed stream"); + + while ((c = getc(f)) != EOF) { + rb_yield(INT2FIX(c & 0xff)); + } + if (ferror(f) != 0) rb_sys_fail(Qnil); + return obj; +} + +static VALUE +Fio_getc(obj) + VALUE obj; +{ + OpenFile *fptr; + FILE *f; + int c; + + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opend for reading"); + } + f = fptr->f; + if (f == NULL) Fail("closed stream"); + + c = getc(f); + if (c == EOF) { + if (ferror(f) != 0) rb_sys_fail(Qnil); + return Qnil; + } + return INT2FIX(c & 0xff); +} + +static VALUE +Fio_isatty(obj) + VALUE obj; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + if (fptr->f == NULL) Fail("closed stream"); + if (isatty(fileno(fptr->f)) == 0) + return FALSE; + + return TRUE; +} + +static VALUE +Fio_close(obj) + VALUE obj; +{ + OpenFile *fptr; + + GetOpenFile(obj, fptr); + + if (fptr->f2 != NULL) { + fclose(fptr->f2); + } + if (fptr->f != NULL) { + fclose(fptr->f); + } + fptr->f = fptr->f2 = NULL; + if (fptr->pid) { + rb_syswait(fptr->pid); + fptr->pid = 0; + } + return Qnil; +} + +static VALUE +Fio_syswrite(obj, str) + VALUE obj, str; +{ + OpenFile *fptr; + FILE *f; + int n; + + if (TYPE(str) != T_STRING) + str = obj_as_string(str); + + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_WRITABLE)) { + Fail("not opend for writing"); + } + f = (fptr->f2) ? fptr->f2 : fptr->f; + if (f == NULL) Fail("closed stream"); + + n = write(fileno(f), RSTRING(str)->ptr, RSTRING(str)->len); + + if (n == -1) rb_sys_fail(Qnil); + + return INT2FIX(n); +} + +static VALUE +Fio_sysread(obj, len) + VALUE obj, len; +{ + OpenFile *fptr; + int n, ilen; + VALUE str; + + ilen = NUM2INT(len); + GetOpenFile(obj, fptr); + if (!(fptr->mode & FMODE_READABLE)) { + Fail("not opend for reading"); + } + if (fptr->f == NULL) Fail("closed stream"); + + str = str_new(0, ilen); + + n = read(fileno(fptr->f), RSTRING(str)->ptr, RSTRING(str)->len); + + if (n == -1) rb_sys_fail(Qnil); + if (n == 0) return Qnil; /* EOF */ + + RSTRING(str)->len = n; + RSTRING(str)->ptr[n] = '\0'; + return str; +} + +void +io_free_OpenFile(fptr) + OpenFile *fptr; +{ + if (fptr->f != NULL) { + fclose(fptr->f); + } + if (fptr->f2 != NULL) { + fclose(fptr->f2); + } + if (fptr->path) { + free(fptr->path); + } + if (fptr->pid) { + rb_syswait(fptr->pid); + } +} + +static VALUE +Fio_binmode(obj) + VALUE obj; +{ +#ifdef MSDOS + OpenFile *fptr; + + GetOpenFile(obj, fptr); + if (setmode(fileno(fptr), O_BINARY) == -1) + rb_sys_fail(Qnil); +#endif + return obj; +} + +VALUE obj_alloc(); + +io_mode_flags(mode) + char *mode; +{ + int flags = 0; + + switch (mode[0]) { + case 'r': + flags |= FMODE_READABLE; + break; + case 'w': + flags |= FMODE_WRITABLE; + break; + case 'a': + flags |= FMODE_WRITABLE; + break; + default: + Fail("illegal access mode"); + } + if (mode[1] == '+') { + flags |= FMODE_READABLE | FMODE_WRITABLE; + } + + return flags; +} + +FILE * +rb_fdopen(fd, mode) + int fd; + char *mode; +{ + FILE *f; + + f = fdopen(fd, mode); + if (f == NULL) { + if (errno = EMFILE) { + gc(); + f = fdopen(fd, mode); + } + if (f == NULL) { + rb_sys_fail(Qnil); + } + } + return f; +} + +static VALUE +pipe_open(pname, mode) + char *pname, *mode; +{ + VALUE port; + OpenFile *fptr; + + int pid, pr[2], pw[2]; + int doexec; + + GC_LINK; + GC_PRO3(port, obj_alloc(C_IO)); + + MakeOpenFile(port, fptr); + fptr->mode = io_mode_flags(mode); + + if ((fptr->mode & FMODE_READABLE) && pipe(pr) == -1 || + (fptr->mode & FMODE_WRITABLE) && pipe(pw) == -1) + rb_sys_fail(Qnil); + + doexec = (strcmp("-", pname) != 0); + if (!doexec) { + fflush(stdin); /* is it really needed? */ + fflush(stdout); + fflush(stderr); + } + + retry: + switch (pid = (doexec?vfork():fork())) { + case 0: /* child */ + if (fptr->mode & FMODE_READABLE) { + close(pr[0]); + dup2(pr[1], 1); + close(pr[1]); + } + if (fptr->mode & FMODE_WRITABLE) { + close(pw[1]); + dup2(pw[0], 0); + close(pw[0]); + } + + if (doexec) { + rb_proc_exec(pname); + _exit(127); + } + return Qnil; + + case -1: /* fork failed */ + if (errno == EAGAIN) { + sleep(5); + goto retry; + } + break; + + default: /* parent */ + if (fptr->mode & FMODE_READABLE) close(pr[1]); + if (fptr->mode & FMODE_WRITABLE) close(pw[0]); + } + if (pid == -1) { + close(pr[0]); close(pw[1]); + rb_sys_fail(Qnil); + } + + fptr->pid = pid; + if (fptr->mode & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r"); + if (fptr->mode & FMODE_WRITABLE) fptr->f2 = rb_fdopen(pw[1], "w"); + + GC_UNLINK; + + return port; +} + +static VALUE +Fopen(self, args) + VALUE self, args; +{ + char *mode; + VALUE port; + int pipe = 0; + VALUE pname, pmode; + + rb_scan_args(args, "11", &pname, &pmode); + Check_Type(pname, T_STRING); + if (pmode == Qnil) { + mode = "r"; + } + else { + Check_Type(pmode, T_STRING); + if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 2) + Fail("illegal access mode"); + mode = RSTRING(pmode)->ptr; + } + + if (RSTRING(pname)->ptr[0] == '|') { + port = pipe_open(RSTRING(pname)->ptr+1, mode); + } + else { + port = file_open(RSTRING(pname)->ptr, mode); + } + + return port; +} + +static VALUE +Fprintf(argc, argv) + int argc; + VALUE argv[]; +{ + VALUE out, str; + + if (argc == 1) return Qnil; + if (TYPE(argv[1]) == T_STRING) { + out = rb_defout; + } + else if (rb_get_method_body(CLASS_OF(argv[1]), id_write, 0, MTH_FUNC)) { + out = argv[1]; + argv++; + argc--; + } + else { + Fail("output must responds to `write'"); + } + + GC_LINK; + GC_PRO3(str, Fsprintf(argc, argv)); + + rb_funcall(out, id_write, 1, str); + + GC_UNLINK; + + return Qnil; +} + +static void +obj_print(obj) + VALUE obj; +{ + int i; + + Fio_write(rb_defout, obj); +} + +static VALUE +Fprint(argc, argv) + int argc; + VALUE argv[]; +{ + int i; + + /* if no argument given, print recv */ + if (argc == 1) { + obj_print(argv[0]); + } + else { + for (i=1; i<argc; i++) { + obj_print(argv[i]); + if (OFS && i>1) { + obj_print(OFS); + } + } + } + if (ORS) { + obj_print(ORS); + } + + return Qnil; +} + +static VALUE +prep_stdio(f, mode) + FILE *f; + int mode; +{ + VALUE obj = obj_alloc(C_IO); + OpenFile *fp; + + GC_LINK; + GC_PRO(obj); + MakeOpenFile(obj, fp); + fp->f = f; + fp->mode = mode; + GC_UNLINK; + + return obj; +} + +static VALUE filename = Qnil, file = Qnil; +static int gets_lineno; +static int init_p = 0, next_p = 0; + +static int +next_argv() +{ + extern VALUE Argv; + char *fn; + + if (init_p == 0) { + if (RARRAY(Argv)->len > 0) { + next_p = 1; + } + else { + next_p = -1; + file = rb_stdin; + } + init_p = 1; + gets_lineno = 0; + } + + retry: + if (next_p == 1) { + next_p = 0; + if (RARRAY(Argv)->len > 0) { + filename = Fary_shift(Argv); + fn = RSTRING(filename)->ptr; + if (RSTRING(filename)->len == 1 && fn[0] == '-') { + file = rb_stdin; + if (inplace) { + rb_defout = rb_stdout; + } + } + else { + FILE *fr = fopen(fn, "r"); + + if (inplace) { + struct stat st, st2; + VALUE str; + FILE *fw; + + if (!*inplace) { + Fatal("Can't do inplace edit without backup"); + } + if (rb_defout != rb_stdout) { + Fio_close(rb_defout); + } + fstat(fileno(fr), &st); + str = str_new2(fn); + str_cat(str, inplace, strlen(inplace)); + if (rename(fn, RSTRING(str)->ptr) < 0) { + Warning("Can't rename %s to %s: %s, skipping file", + fn, RSTRING(str)->ptr, strerror(errno)); + fclose(fr); + goto retry; + } + obj_free(str); + fw = fopen(fn, "w"); + 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); + } + rb_defout = prep_stdio(fw, FMODE_WRITABLE); + } + file = prep_stdio(fr, FMODE_READABLE); + } + } + else { + init_p = 0; + return FALSE; + } + } + return TRUE; +} + +static VALUE +Fgets(obj) + VALUE obj; +{ + VALUE line; + + retry: + if (!next_argv()) return Qnil; + line = Fio_gets(file); + if (line == Qnil && next_p != -1) { + Fio_close(file); + next_p = 1; + goto retry; + } + + gets_lineno++; + lineno = INT2FIX(gets_lineno); + + return line; +} + +static VALUE +Feof(obj) + VALUE obj; +{ + if (init_p == 0 && !next_argv()) + return TRUE; + if (Fio_eof(file)) { + next_p = 1; + return TRUE; + } + return FALSE; +} + +static VALUE +Fgetc(obj) + VALUE obj; +{ + return Fio_getc(rb_stdin); +} + +static VALUE +Freadlines(obj) + VALUE obj; +{ + VALUE line, ary; + + GC_LINK; + GC_PRO2(line); + GC_PRO3(ary, ary_new()); + + while (line = Fgets(obj)) { + Fary_push(ary, line); + } + + GC_UNLINK; + return ary; +} + +VALUE +rb_check_str(val, id) + VALUE val; + ID id; +{ + if (val == Qnil) return TRUE; + if (TYPE(val) != T_STRING) { + Fail("value of %s must be String", rb_id2name(id)); + } + return TRUE; +} + +static VALUE +Fsystem2(obj, str) + VALUE obj; + struct RString *str; +{ + VALUE port, result; + OpenFile *fptr; + int mask; + + Check_Type(str, T_STRING); + GC_LINK; + GC_PRO3(port, pipe_open(str->ptr, "r")); + GC_PRO2(result); + + result = read_all(port); + + GetOpenFile(port, fptr); + rb_syswait(fptr->pid); + fptr->pid = 0; + + obj_free(port); + GC_UNLINK; + + return result; +} + +struct timeval *time_timeval(); + +#ifdef __linux__ +# define READ_PENDING(fp) ((fp)->_gptr < (fp)->_egptr > 0) +#else +# ifdef __SLBF +# define READ_PENDING(fp) ((fp)->_r > 0) +# else +# define READ_PENDING(fp) ((fp)->_cnt != 0) +# endif +#endif + +static VALUE +Fselect(obj, args) + VALUE obj, args; +{ + VALUE read, write, except, timeout, res, list; + fd_set rset, wset, eset, pset; + fd_set *rp, *wp, *ep; + struct timeval time, *tp, timerec; + OpenFile *fptr; + int i, max = 0, n; + int interrupt = 0; + + rb_scan_args(args, "13", &read, &write, &except, &timeout); + if (timeout) { + tp = time_timeval(timeout); + } + else { + tp = NULL; + } + + FD_ZERO(&pset); + if (read) { + int pending = 0; + + Check_Type(read, T_ARRAY); + rp = &rset; + FD_ZERO(rp); + for (i=0; i<RARRAY(read)->len; i++) { + GetOpenFile(RARRAY(read)->ptr[i], fptr); + FD_SET(fileno(fptr->f), rp); + if (READ_PENDING(fptr->f)) { /* check for buffered data */ + pending++; + FD_SET(fileno(fptr->f), &pset); + } + if (max < fileno(fptr->f)) max = fileno(fptr->f); + } + if (pending) { /* no blocking if there's buffered data */ + timerec.tv_sec = timerec.tv_usec = 0; + tp = &timerec; + } + } + else + rp = NULL; + + if (write) { + Check_Type(write, T_ARRAY); + wp = &wset; + FD_ZERO(wp); + for (i=0; i<RARRAY(write)->len; i++) { + GetOpenFile(RARRAY(write)->ptr[i], fptr); + FD_SET(fileno(fptr->f), wp); + if (max > fileno(fptr->f)) max = fileno(fptr->f); + if (fptr->f2) { + FD_SET(fileno(fptr->f2), wp); + if (max < fileno(fptr->f2)) max = fileno(fptr->f2); + } + } + } + else + wp = NULL; + + if (except) { + Check_Type(except, T_ARRAY); + ep = &eset; + FD_ZERO(ep); + for (i=0; i<RARRAY(except)->len; i++) { + GetOpenFile(RARRAY(except)->ptr[i], 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 > fileno(fptr->f2)) max = fileno(fptr->f2); + } + } + } + else + ep = NULL; + + max++; + + retry: + if ((n = select(max, rp, wp, ep, tp)) < 0) { + if (errno == EINTR) { + if (tp == NULL) goto retry; + interrupt = 1; + } + rb_sys_fail(Qnil); + } + if (n == 0) return Qnil; + + GC_LINK; + GC_PRO3(res, ary_new2(3)); + RARRAY(res)->ptr[0] = rp?ary_new():Qnil; + RARRAY(res)->len++; + RARRAY(res)->ptr[1] = wp?ary_new():Qnil; + RARRAY(res)->len++; + RARRAY(res)->ptr[2] = ep?ary_new():Qnil; + RARRAY(res)->len++; + + if (interrupt == 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)) { + Fary_push(list, RARRAY(read)->ptr[i]); + } + } + } + + if (wp) { + list = RARRAY(res)->ptr[1]; + for (i=0; i< RARRAY(write)->len; i++) { + GetOpenFile(RARRAY(write)->ptr[i], fptr); + if (FD_ISSET(fileno(fptr->f), rp)) { + Fary_push(list, RARRAY(write)->ptr[i]); + } + else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), rp)) { + Fary_push(list, RARRAY(write)->ptr[i]); + } + } + } + + if (ep) { + list = RARRAY(res)->ptr[2]; + for (i=0; i< RARRAY(except)->len; i++) { + GetOpenFile(RARRAY(except)->ptr[i], fptr); + if (FD_ISSET(fileno(fptr->f), rp)) { + Fary_push(list, RARRAY(except)->ptr[i]); + } + else if (fptr->f2 && FD_ISSET(fileno(fptr->f2), rp)) { + Fary_push(list, RARRAY(except)->ptr[i]); + } + } + } + } + + GC_UNLINK; + return res; +} + +void +io_ctl(obj, req, arg, io_p) + VALUE obj, req; + struct RString *arg; + int io_p; +{ + int cmd = NUM2INT(req); + OpenFile *fptr; + int len, fd; + + GetOpenFile(obj, fptr); + +#ifdef IOCPARM_MASK +#ifndef IOCPARM_LEN +#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK) +#endif +#endif +#ifdef IOCPARM_LEN + len = IOCPARM_LEN(cmd); /* on BSDish systes we're safe */ +#else + len = 256; /* otherwise guess at what's safe */ +#endif + + Check_Type(arg, T_STRING); + str_modify(arg); + + if (arg->len < len) { + str_grow(arg, len+1); + } + arg->ptr[len] = 17; + fd = fileno(fptr->f); + if (io_p?ioctl(fd, cmd, arg->ptr):fcntl(fd, cmd, arg->ptr)<0) { + rb_sys_fail(fptr->path); + } + if (arg->ptr[len] != 17) { + Fail("Return value overflowed string"); + } +} + +static VALUE +Fio_ioctl(obj, req, arg) + VALUE obj, req; + struct RString *arg; +{ + io_ctl(obj, req, arg, 1); + return obj; +} + +static VALUE +Fio_defget(obj) + VALUE obj; +{ + return rb_defout; +} + +static VALUE +Fio_defset(obj, val) + VALUE obj, val; +{ + return rb_defout = val; +} + +extern VALUE M_Enumerable; +VALUE rb_readonly_hook(); + +Init_IO() +{ + extern VALUE C_Kernel; + + rb_define_func(C_Kernel, "open", Fopen, -2); + rb_define_func(C_Kernel, "printf", Fprintf, -1); + rb_define_method(C_Kernel, "print", Fprint, -1); + rb_define_func(C_Kernel, "gets", Fgets, 0); + rb_define_func(C_Kernel, "eof", Feof, 0); + rb_define_alias(C_Kernel,"readline", "gets"); + rb_define_func(C_Kernel, "getc", Fgetc, 0); + rb_define_func(C_Kernel, "system2", Fsystem2, 1); + rb_define_func(C_Kernel, "select", Fselect, -2); + + rb_define_func(C_Kernel, "readlines", Freadlines, 0); + + C_IO = rb_define_class("IO", C_Object); + rb_include_module(C_IO, M_Enumerable); + + rb_define_variable("$;", &FS, Qnil, rb_check_str); + rb_define_variable("$,", &OFS, Qnil, rb_check_str); + + RS = str_new2("\n"); + rb_define_variable("$/", &RS, Qnil, rb_check_str); + rb_define_variable("$\\", &ORS, Qnil, rb_check_str); + + rb_define_variable("$FILENAME", &filename, Qnil, rb_readonly_hook); + rb_global_variable(&file); + + rb_define_variable("$.", &lineno, Qnil, Qnil); + rb_define_variable("$_", &rb_lastline, Qnil, Qnil); + + rb_define_method(C_IO, "each", Fio_each, 0); + rb_define_method(C_IO, "each_byte", Fio_each_byte, 0); + + rb_define_method(C_IO, "syswrite", Fio_syswrite, 1); + rb_define_method(C_IO, "sysread", Fio_sysread, 1); + + rb_define_method(C_IO, "fileno", Fio_fileno, 0); + rb_define_method(C_IO, "sync", Fio_sync, 0); + rb_define_method(C_IO, "sync=", Fio_set_sync, 1); + + rb_define_alias(C_IO, "readlines", "to_a"); + + rb_define_method(C_IO, "read", Fio_read, -2); + rb_define_method(C_IO, "write", Fio_write, 1); + rb_define_method(C_IO, "gets", Fio_gets, 0); + rb_define_alias(C_IO, "readlines", "gets"); + rb_define_method(C_IO, "getc", Fio_getc, 0); + rb_define_method(C_IO, "puts", Fio_puts, 1); + rb_define_method(C_IO, "<<", Fio_puts, 1); + rb_define_method(C_IO, "flush", Fio_flush, 0); + rb_define_method(C_IO, "eof", Fio_eof, 0); + + rb_define_method(C_IO, "close", Fio_close, 0); + + rb_define_method(C_IO, "isatty", Fio_isatty, 0); + rb_define_method(C_IO, "binmode", Fio_binmode, 0); + + rb_define_method(C_IO, "ioctl", Fio_ioctl, 2); + + rb_stdin = prep_stdio(stdin, FMODE_READABLE); + rb_define_variable("$stdin", &rb_stdin, Qnil, rb_readonly_hook); + rb_stdout = prep_stdio(stdout, FMODE_WRITABLE); + rb_define_variable("$stdout", &rb_stdout, Qnil, rb_readonly_hook); + rb_stderr = prep_stdio(stderr, FMODE_WRITABLE); + rb_define_variable("$stderr", &rb_stderr, Qnil, rb_readonly_hook); + rb_defout = rb_stdout; + rb_global_variable(&rb_defout); + rb_define_single_method(C_IO, "default", Fio_defget, 0); + rb_define_single_method(C_IO, "default=", Fio_defset, 1); + + id_write = rb_intern("write"); + Init_File(); +} @@ -0,0 +1,47 @@ +/************************************************ + + io.h - + + $Author: matz $ + $Revision: 1.1.1.1 $ + $Date: 1994/06/17 14:23:50 $ + created at: Fri Nov 12 16:47:09 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#ifndef IO_H +#define IO_H + +#include <stdio.h> +#include <errno.h> + +typedef struct { + FILE *f; /* stdio ptr for read/write */ + FILE *f2; /* additional ptr for rw pipes */ + int mode; /* mode flags */ + int pid; /* child's pid (for pipes) */ + int lineno; /* number of lines read */ + char *path; /* pathname for file */ +} OpenFile; + +#define FMODE_READABLE 1 +#define FMODE_WRITABLE 2 +#define FMODE_READWRITE 3 +#define FMODE_SYNC 4 + +#define GetOpenFile(obj,fp) Get_Data_Struct(obj, "fd", OpenFile, fp) + +void io_free_OpenFile(); + +#define MakeOpenFile(obj, fp) {\ + Make_Data_Struct(obj, "fd", OpenFile, Qnil, io_free_OpenFile, fp);\ + fp->f = fp->f2 = NULL;\ + fp->mode = 0;\ + fp->pid = 0;\ + fp->lineno = 0;\ + fp->path = NULL;\ +} + +#endif diff --git a/math.c b/math.c new file mode 100644 index 0000000000..b6fbb063bc --- /dev/null +++ b/math.c @@ -0,0 +1,125 @@ +/************************************************ + + math.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Tue Jan 25 14:12:56 JST 1994 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include <math.h> + +VALUE M_Math; +VALUE float_new(); + +#define Need_Float(x) \ +if (FIXNUM_P(x)) {\ + (x) = (struct RFloat*)float_new((double)FIX2INT(x));\ +} else {\ + Check_Type(x, T_FLOAT);\ +} + +#define Need_Float2(x,y) {\ + GC_LINK;\ + GC_PRO(x);\ + Need_Float(x);\ + Need_Float(y);\ + GC_UNLINK;\ +} + +static VALUE +Fmath_atan2(obj, x, y) + VALUE obj; + struct RFloat *x, *y; +{ + Need_Float2(x, y); + return float_new(atan2(x->value, x->value)); +} + +static VALUE +Fmath_cos(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + + return float_new(cos(x->value)); +} + +static VALUE +Fmath_sin(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + + return float_new(sin(x->value)); +} + +static VALUE +Fmath_tan(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + + return float_new(tan(x->value)); +} + +static VALUE +Fmath_exp(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + return float_new(exp(x->value)); +} + +static VALUE +Fmath_log(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + return float_new(log(x->value)); +} + +static VALUE +Fmath_log10(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + return float_new(log10(x->value)); +} + +static VALUE +Fmath_sqrt(obj, x) + VALUE obj; + struct RFloat *x; +{ + Need_Float(x); + return float_new(log10(x->value)); + + if (x->value < 0.0) Fail("square root for negative number"); + return float_new(sqrt(x->value)); +} + +Init_Math() +{ + M_Math = rb_define_module("Math"); + + rb_define_mfunc(M_Math, "atan2", Fmath_atan2, 2); + rb_define_mfunc(M_Math, "cos", Fmath_cos, 1); + rb_define_mfunc(M_Math, "sin", Fmath_sin, 1); + rb_define_mfunc(M_Math, "tan", Fmath_tan, 1); + + rb_define_mfunc(M_Math, "exp", Fmath_exp, 1); + rb_define_mfunc(M_Math, "log", Fmath_log, 1); + rb_define_mfunc(M_Math, "log10", Fmath_log10, 1); + rb_define_mfunc(M_Math, "sqrt", Fmath_sqrt, 1); +} diff --git a/methods.c b/methods.c new file mode 100644 index 0000000000..d861323444 --- /dev/null +++ b/methods.c @@ -0,0 +1,145 @@ +/************************************************ + + methods.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Fri Oct 1 17:25:07 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "ident.h" +#include "env.h" +#include "node.h" + +#define CACHE_SIZE 577 +#if 0 +#define EXPR1(c,m) (((int)(c)*(m))>>0) +#else +#define EXPR1(c,m) ((int)(c)^(m)) +#endif + +#define TRIAL 3 + +struct hash_entry { /* method hash table. */ + ID mid; /* method's id */ + struct RClass *class; /* receiver's class */ + struct RClass *origin; /* where method defined */ + struct RMethod *method; + enum mth_scope scope; +}; + +static struct hash_entry cache[CACHE_SIZE]; + +static struct RMethod* +search_method(class, id, origin) + struct RClass *class, **origin; + ID id; +{ + struct RMethod *body; + NODE *list; + + while (!st_lookup(class->m_tbl, id, &body)) { + class = class->super; + if (class == Qnil) return Qnil; + } + + if (body->origin) + *origin = body->origin; + else + *origin = class; + return body; +} + +NODE* +rb_get_method_body(class, id, envset, scope) + struct RClass *class; + ID id; + int envset; + enum mth_scope scope; +{ + int pos, i; + int cscope; + struct RMethod *method; + + /* is it in the method cache? */ + pos = EXPR1(class, id) % CACHE_SIZE; + if (cache[pos].class != class || cache[pos].mid != id) { + /* not in the cache */ + struct RMethod *body; + struct RClass *origin; + + if ((body = search_method(class, id, &origin)) == Qnil) { + return Qnil; + } + /* store in cache */ + cache[pos].mid = id; + cache[pos].class = class; + cache[pos].origin = origin; + cache[pos].method = body; + cache[pos].scope = body->scope; + } + + cscope = cache[pos].scope; + method = cache[pos].method; + if (cscope == MTH_UNDEF) return Qnil; + if (cscope == MTH_FUNC && scope == MTH_METHOD) return Qnil; + if (envset) { + the_env->last_func = method->id; + the_env->last_class = cache[pos].origin; + } + return method->node; +} + +void +rb_alias(class, name, def) + struct RClass *class; + ID name, def; +{ + struct RMethod *body; + + if (st_lookup(class->m_tbl, name, &body)) { + if (verbose) { + Warning("redefine %s", rb_id2name(name)); + } + unliteralize(body); + } + body = search_method(class, def, &body); + st_insert(class->m_tbl, name, body); +} + +void +rb_clear_cache(body) + struct RMethod *body; +{ + int i; + + for (i = 0; i< CACHE_SIZE; i++ ) { + if (cache[i].method == body) { + cache[i].class = Qnil; + cache[i].mid = Qnil; + } + } +} + +void +rb_clear_cache2(class) + struct RClass *class; +{ + + class = class->super; + while (class) { + int i; + + for (i = 0; i< CACHE_SIZE; i++ ) { + if (cache[i].origin == class) { + cache[i].class = Qnil; + cache[i].mid = Qnil; + } + } + class = class->super; + } +} diff --git a/missing.c b/missing.c new file mode 100644 index 0000000000..ef2651ee94 --- /dev/null +++ b/missing.c @@ -0,0 +1,67 @@ +/* + * Do all necessary includes here, so that we don't have to worry about + * overlapping includes in the files in missing.d. + */ + +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "ruby.h" + +#ifndef __STDC__ +#define const +#endif /* !__STDC__ */ + +#ifdef STDC_HEADERS +#include <string.h> +#endif + +#ifndef HAVE_MEMMOVE +#include "missing/memmove.c" +#endif + +#ifndef HAVE_STRERROR +#include "missing/strerror.c" +#endif + +#ifndef HAVE_STRTOUL +#include "missing/strtoul.c" +#endif + +#ifndef HAVE_STRFTIME +#include "missing/strftime.c" +#endif + +#ifndef HAVE_STRSTR +#include "missing/strstr.c" +#endif + +#ifndef HAVE_GETOPT_LONG +#include "missing/getopt.h" +#include "missing/getopt.c" +#include "missing/getopt1.c" +#endif + +#ifndef HAVE_MKDIR +#include "missing/mkdir.c" +#endif + +#ifndef HAVE_STRDUP +char * +strdup(str) + char *str; +{ + extern char *xmalloc(); + char *tmp; + int len = strlen(str) + 1; + + tmp = xmalloc(len); + if (tmp == NULL) return NULL; + bcopy(str, tmp, len); + + return tmp; +} +#endif diff --git a/missing/CVS/Entries b/missing/CVS/Entries new file mode 100644 index 0000000000..2c02d6e353 --- /dev/null +++ b/missing/CVS/Entries @@ -0,0 +1,9 @@ +/getopt.c/0.26/Wed Jun 1 23:41:18 1994 Mon Apr 18 12:30:25 1994// +/getopt.h/0.26/Wed Jun 1 23:41:18 1994 Mon Apr 18 12:30:25 1994// +/getopt1.c/0.26/Wed Jun 1 23:41:18 1994 Mon Apr 18 12:30:25 1994// +/memmove.c/0.26/Wed Jun 1 23:41:18 1994 Mon Apr 18 12:30:25 1994// +/mkdir.c/1.1/Wed Jun 1 23:41:18 1994 Wed Jun 1 23:38:35 1994// +/strerror.c/0.26/Wed Jun 1 23:41:18 1994 Mon Apr 18 12:30:25 1994// +/strftime.c/0.26/Wed Jun 1 23:41:19 1994 Mon Apr 18 12:30:25 1994// +/strtol.c/0.26/Wed Jun 1 23:41:19 1994 Mon Apr 18 12:30:25 1994// +/strtoul.c/0.26/Wed Jun 1 23:41:19 1994 Mon Apr 18 12:30:25 1994// diff --git a/missing/CVS/Repository b/missing/CVS/Repository new file mode 100644 index 0000000000..a7ac69cf13 --- /dev/null +++ b/missing/CVS/Repository @@ -0,0 +1 @@ +/work/cvsroot/ruby/missing diff --git a/missing/getopt.c b/missing/getopt.c new file mode 100644 index 0000000000..bbf345c33c --- /dev/null +++ b/missing/getopt.c @@ -0,0 +1,662 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to [email protected] + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef GAWK +#include "config.h" +#endif + +#include <stdio.h> + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#include <string.h> +#endif /* GNU C library. */ + + +#ifndef __STDC__ +#define const +#endif + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +#define GETOPT_COMPAT + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +#include <string.h> +#define my_index strchr +#define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (string, chr) + char *string; + int chr; +{ + while (*string) + { + if (*string == chr) + return string; + string++; + } + return 0; +} + +static void +my_bcopy (from, to, size) + char *from, *to; + int size; +{ + int i; + for (i = 0; i < size; i++) + to[i] = from[i]; +} +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); + char **temp = (char **) malloc (nonopts_size); + + /* Interchange the two blocks of data in ARGV. */ + + my_bcopy (&argv[first_nonopt], temp, nonopts_size); + my_bcopy (&argv[last_nonopt], &argv[first_nonopt], + (optind - last_nonopt) * sizeof (char *)); + my_bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size); + + free(temp); + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound = 0; + extern int strncmp(); + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); + } + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/missing/getopt.h b/missing/getopt.h new file mode 100644 index 0000000000..de027434f7 --- /dev/null +++ b/missing/getopt.h @@ -0,0 +1,128 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2, 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +enum _argtype +{ + no_argument, + required_argument, + optional_argument +}; + +#if __STDC__ +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/missing/getopt1.c b/missing/getopt1.c new file mode 100644 index 0000000000..eb06338ab3 --- /dev/null +++ b/missing/getopt1.c @@ -0,0 +1,162 @@ +/* Getopt for GNU. + Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifdef LIBC +/* For when compiled as part of the GNU C library. */ +#include <ansidecl.h> +#endif + +#ifndef RUBY +#include "getopt.h" +#endif + +#ifndef __STDC__ +#define const +#endif + +#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC) +#include <stdlib.h> +#else /* STDC_HEADERS or __GNU_LIBRARY__ */ +char *getenv (); +#endif /* STDC_HEADERS or __GNU_LIBRARY__ */ + +#if !defined (NULL) +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + +#ifdef TEST + +#include <stdio.h> + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/missing/memmove.c b/missing/memmove.c new file mode 100644 index 0000000000..09e64702b6 --- /dev/null +++ b/missing/memmove.c @@ -0,0 +1,24 @@ +/* + * memmove --- move memories. + * + * We supply this routine for those systems that aren't standard yet. + */ + +char * +memmove (dst, src, n) + char *dst, *src; + int n; +{ + char *ret = dst; + + if (src < dst) { + src += n; + dst += n; + while (n--) + *--dst = *--src; + } + else if (dst < src) + while (n--) + *dst++ = *src++; + return ret; +} diff --git a/missing/mkdir.c b/missing/mkdir.c new file mode 100644 index 0000000000..5225e586d9 --- /dev/null +++ b/missing/mkdir.c @@ -0,0 +1,103 @@ +/* + * Written by Robert Rother, Mariah Corporation, August 1985. + * + * If you want it, it's yours. All I ask in return is that if you + * figure out how to do this in a Bourne Shell script you send me + * a copy. + * sdcsvax!rmr or rmr@uscd + * + * Severely hacked over by John Gilmore to make a 4.2BSD compatible + * subroutine. 11Mar86; hoptoad!gnu + * + * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir, + * subroutine didn't return EEXIST. It does now. + */ + +#include <sys/stat.h> +/* + * Make a directory. + */ +int +mkdir (dpath, dmode) + char *dpath; + int dmode; +{ + int cpid, status; + struct stat statbuf; + + if (stat (dpath, &statbuf) == 0) + { + errno = EEXIST; /* Stat worked, so it already exists */ + return -1; + } + + /* If stat fails for a reason other than non-existence, return error */ + if (errno != ENOENT) + return -1; + + switch (cpid = fork ()) + { + + case -1: /* Error in fork() */ + return (-1); /* Errno is set already */ + + case 0: /* Child process */ + /* + * Cheap hack to set mode of new directory. Since this + * child process is going away anyway, we zap its umask. + * FIXME, this won't suffice to set SUID, SGID, etc. on this + * directory. Does anybody care? + */ + status = umask (0); /* Get current umask */ + status = umask (status | (0777 & ~dmode)); /* Set for mkdir */ + execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); + _exit (-1); /* Can't exec /bin/mkdir */ + + default: /* Parent process */ + while (cpid != wait (&status)); /* Wait for kid to finish */ + } + + if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) + { + errno = EIO; /* We don't know why, but */ + return -1; /* /bin/mkdir failed */ + } + + return 0; +} + +int +rmdir (dpath) + char *dpath; +{ + int cpid, status; + struct stat statbuf; + + if (stat (dpath, &statbuf) != 0) + { + /* Stat just set errno. We don't have to */ + return -1; + } + + switch (cpid = fork ()) + { + + case -1: /* Error in fork() */ + return (-1); /* Errno is set already */ + + case 0: /* Child process */ + execl ("/bin/rmdir", "rmdir", dpath, (char *) 0); + _exit (-1); /* Can't exec /bin/mkdir */ + + default: /* Parent process */ + while (cpid != wait (&status)); /* Wait for kid to finish */ + } + + if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) + { + errno = EIO; /* We don't know why, but */ + return -1; /* /bin/mkdir failed */ + } + + return 0; +} diff --git a/missing/strerror.c b/missing/strerror.c new file mode 100644 index 0000000000..44013b3892 --- /dev/null +++ b/missing/strerror.c @@ -0,0 +1,19 @@ +/* + * strerror.c --- Map an integer error number into a printable string. + */ + +extern int sys_nerr; +extern char *sys_errlist[]; + +static char msg[50]; + +char * +strerror(error) + int error; +{ + if ((error <= sys_nerr) && (error > 0)) { + return sys_errlist[error]; + } + sprintf (msg, "Unknown error (%d)", error); + return msg; +} diff --git a/missing/strftime.c b/missing/strftime.c new file mode 100644 index 0000000000..36a325aa51 --- /dev/null +++ b/missing/strftime.c @@ -0,0 +1,781 @@ +/* + * strftime.c + * + * Public-domain implementation of ANSI C library routine. + * + * It's written in old-style C for maximal portability. + * However, since I'm used to prototypes, I've included them too. + * + * If you want stuff in the System V ascftime routine, add the SYSV_EXT define. + * For extensions from SunOS, add SUNOS_EXT. + * For stuff needed to implement the P1003.2 date command, add POSIX2_DATE. + * For VMS dates, add VMS_EXT. + * For complete POSIX semantics, add POSIX_SEMANTICS. + * + * The code for %c, %x, and %X is my best guess as to what's "appropriate". + * This version ignores LOCALE information. + * It also doesn't worry about multi-byte characters. + * So there. + * + * This file is also shipped with GAWK (GNU Awk), gawk specific bits of + * code are included if GAWK is defined. + * + * Arnold Robbins + * January, February, March, 1991 + * Updated March, April 1992 + * Updated April, 1993 + * Updated February, 1994 + * Updated May, 1994 + * + * Fixes from [email protected] + * February 1991, May 1992 + * Fixes from Tor Lillqvist [email protected] + * May, 1993 + * Further fixes from [email protected] + * February 1994 + */ + +#ifndef RUBY +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <time.h> +#endif +#if defined(TM_IN_SYS_TIME) || ! defined(RUBY) +#include <sys/types.h> +#include <sys/time.h> +#endif + +/* defaults: season to taste */ +#define SYSV_EXT 1 /* stuff in System V ascftime routine */ +#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */ +#define POSIX2_DATE 1 /* stuff in Posix 1003.2 date command */ +#define VMS_EXT 1 /* include %v for VMS date format */ +#ifndef RUBY +#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */ +#endif + +#if defined(POSIX2_DATE) +#if ! defined(SYSV_EXT) +#define SYSV_EXT 1 +#endif +#if ! defined(SUNOS_EXT) +#define SUNOS_EXT 1 +#endif +#endif + +#if defined(POSIX2_DATE) +#define adddecl(stuff) stuff +#else +#define adddecl(stuff) +#endif + +#undef strchr /* avoid AIX weirdness */ + +#ifndef __STDC__ +#define const /**/ +extern void *malloc(); +extern void *realloc(); +extern void tzset(); +extern char *strchr(); +extern char *getenv(); +static int weeknumber(); +adddecl(static int iso8601wknum();) +#else +extern void *malloc(unsigned count); +extern void *realloc(void *ptr, unsigned count); +extern void tzset(void); +extern char *strchr(const char *str, int ch); +extern char *getenv(const char *v); +static int weeknumber(const struct tm *timeptr, int firstweekday); +adddecl(static int iso8601wknum(const struct tm *timeptr);) +#endif + +#ifdef __GNUC__ +#define inline __inline__ +#else +#define inline /**/ +#endif + +#define range(low, item, hi) max(low, min(item, hi)) + +#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) +extern char *tzname[2]; +extern int daylight; +#endif + +/* min --- return minimum of two numbers */ + +#ifndef __STDC__ +static inline int +min(a, b) +int a, b; +#else +static inline int +min(int a, int b) +#endif +{ + return (a < b ? a : b); +} + +/* max --- return maximum of two numbers */ + +#ifndef __STDC__ +static inline int +max(a, b) +int a, b; +#else +static inline int +max(int a, int b) +#endif +{ + return (a > b ? a : b); +} + +/* strftime --- produce formatted time */ + +#ifndef __STDC__ +size_t +strftime(s, maxsize, format, timeptr) +char *s; +size_t maxsize; +const char *format; +const struct tm *timeptr; +#else +size_t +strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) +#endif +{ + char *endp = s + maxsize; + char *start = s; + auto char tbuf[100]; + int i; + static short first = 1; +#ifdef POSIX_SEMANTICS + static char *savetz = NULL; + static int savetzlen = 0; + char *tz; +#endif /* POSIX_SEMANTICS */ +#ifndef HAVE_TM_ZONE + extern char *timezone(); + struct timeval tv; + struct timezone zone; +#endif /* HAVE_TM_ZONE */ + + /* various tables, useful in North America */ + static const char *days_a[] = { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat", + }; + static const char *days_l[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", + }; + static const char *months_a[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + static const char *months_l[] = { + "January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December", + }; + static const char *ampm[] = { "AM", "PM", }; + + if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0) + return 0; + + /* quick check if we even need to bother */ + if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) + return 0; + +#ifndef POSIX_SEMANTICS + if (first) { + tzset(); + first = 0; + } +#else /* POSIX_SEMANTICS */ + tz = getenv("TZ"); + if (first) { + if (tz != NULL) { + int tzlen = strlen(tz); + + savetz = (char *) malloc(tzlen + 1); + if (savetz != NULL) { + savetzlen = tzlen + 1; + strcpy(savetz, tz); + } + } + tzset(); + first = 0; + } + /* if we have a saved TZ, and it is different, recapture and reset */ + if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) { + i = strlen(tz) + 1; + if (i > savetzlen) { + savetz = (char *) realloc(savetz, i); + if (savetz) { + savetzlen = i; + strcpy(savetz, tz); + } + } else + strcpy(savetz, tz); + tzset(); + } +#endif /* POSIX_SEMANTICS */ + + for (; *format && s < endp - 1; format++) { + tbuf[0] = '\0'; + if (*format != '%') { + *s++ = *format; + continue; + } + again: + switch (*++format) { + case '\0': + *s++ = '%'; + goto out; + + case '%': + *s++ = '%'; + continue; + + case 'a': /* abbreviated weekday name */ + if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) + strcpy(tbuf, "?"); + else + strcpy(tbuf, days_a[timeptr->tm_wday]); + break; + + case 'A': /* full weekday name */ + if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) + strcpy(tbuf, "?"); + else + strcpy(tbuf, days_l[timeptr->tm_wday]); + break; + +#ifdef SYSV_EXT + case 'h': /* abbreviated month name */ +#endif + case 'b': /* abbreviated month name */ + if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) + strcpy(tbuf, "?"); + else + strcpy(tbuf, months_a[timeptr->tm_mon]); + break; + + case 'B': /* full month name */ + if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) + strcpy(tbuf, "?"); + else + strcpy(tbuf, months_l[timeptr->tm_mon]); + break; + + case 'c': /* appropriate date and time representation */ + sprintf(tbuf, "%s %s %2d %02d:%02d:%02d %d", + days_a[range(0, timeptr->tm_wday, 6)], + months_a[range(0, timeptr->tm_mon, 11)], + range(1, timeptr->tm_mday, 31), + range(0, timeptr->tm_hour, 23), + range(0, timeptr->tm_min, 59), + range(0, timeptr->tm_sec, 61), + timeptr->tm_year + 1900); + break; + + case 'd': /* day of the month, 01 - 31 */ + i = range(1, timeptr->tm_mday, 31); + sprintf(tbuf, "%02d", i); + break; + + case 'H': /* hour, 24-hour clock, 00 - 23 */ + i = range(0, timeptr->tm_hour, 23); + sprintf(tbuf, "%02d", i); + break; + + case 'I': /* hour, 12-hour clock, 01 - 12 */ + i = range(0, timeptr->tm_hour, 23); + if (i == 0) + i = 12; + else if (i > 12) + i -= 12; + sprintf(tbuf, "%02d", i); + break; + + case 'j': /* day of the year, 001 - 366 */ + sprintf(tbuf, "%03d", timeptr->tm_yday + 1); + break; + + case 'm': /* month, 01 - 12 */ + i = range(0, timeptr->tm_mon, 11); + sprintf(tbuf, "%02d", i + 1); + break; + + case 'M': /* minute, 00 - 59 */ + i = range(0, timeptr->tm_min, 59); + sprintf(tbuf, "%02d", i); + break; + + case 'p': /* am or pm based on 12-hour clock */ + i = range(0, timeptr->tm_hour, 23); + if (i < 12) + strcpy(tbuf, ampm[0]); + else + strcpy(tbuf, ampm[1]); + break; + + case 'S': /* second, 00 - 61 */ + i = range(0, timeptr->tm_sec, 61); + sprintf(tbuf, "%02d", i); + break; + + case 'U': /* week of year, Sunday is first day of week */ + sprintf(tbuf, "%02d", weeknumber(timeptr, 0)); + break; + + case 'w': /* weekday, Sunday == 0, 0 - 6 */ + i = range(0, timeptr->tm_wday, 6); + sprintf(tbuf, "%d", i); + break; + + case 'W': /* week of year, Monday is first day of week */ + sprintf(tbuf, "%02d", weeknumber(timeptr, 1)); + break; + + case 'x': /* appropriate date representation */ + sprintf(tbuf, "%s %s %2d %d", + days_a[range(0, timeptr->tm_wday, 6)], + months_a[range(0, timeptr->tm_mon, 11)], + range(1, timeptr->tm_mday, 31), + timeptr->tm_year + 1900); + break; + + case 'X': /* appropriate time representation */ + sprintf(tbuf, "%02d:%02d:%02d", + range(0, timeptr->tm_hour, 23), + range(0, timeptr->tm_min, 59), + range(0, timeptr->tm_sec, 61)); + break; + + case 'y': /* year without a century, 00 - 99 */ + i = timeptr->tm_year % 100; + sprintf(tbuf, "%02d", i); + break; + + case 'Y': /* year with century */ + sprintf(tbuf, "%d", 1900 + timeptr->tm_year); + break; + + case 'Z': /* time zone name or abbrevation */ +#ifdef HAVE_TZNAME +#ifdef HAVE_DAYLIGHT + i = (daylight && timeptr->tm_isdst); /* 0 or 1 */ +#else + i = timeptr->tm_isdst; +#endif + strcpy(tbuf, tzname[i]); +#else +#ifdef HAVE_TM_ZONE + strcpy(tbuf, timeptr->tm_zone); +#else + gettimeofday(& tv, & zone); + strcpy(tbuf, timezone(zone.tz_minuteswest, + timeptr->tm_isdst)); +#endif +#endif + break; + +#ifdef SYSV_EXT + case 'n': /* same as \n */ + tbuf[0] = '\n'; + tbuf[1] = '\0'; + break; + + case 't': /* same as \t */ + tbuf[0] = '\t'; + tbuf[1] = '\0'; + break; + + case 'D': /* date as %m/%d/%y */ + strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); + break; + + case 'e': /* day of month, blank padded */ + sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31)); + break; + + case 'r': /* time as %I:%M:%S %p */ + strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr); + break; + + case 'R': /* time as %H:%M */ + strftime(tbuf, sizeof tbuf, "%H:%M", timeptr); + break; + + case 'T': /* time as %H:%M:%S */ + strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); + break; +#endif + +#ifdef SUNOS_EXT + case 'k': /* hour, 24-hour clock, blank pad */ + sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23)); + break; + + case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ + i = range(0, timeptr->tm_hour, 23); + if (i == 0) + i = 12; + else if (i > 12) + i -= 12; + sprintf(tbuf, "%2d", i); + break; +#endif + + +#ifdef VMS_EXT + case 'v': /* date as dd-bbb-YYYY */ + sprintf(tbuf, "%02d-%3.3s-%4d", + range(1, timeptr->tm_mday, 31), + months_a[range(0, timeptr->tm_mon, 11)], + timeptr->tm_year + 1900); + for (i = 3; i < 6; i++) + if (islower(tbuf[i])) + tbuf[i] = toupper(tbuf[i]); + break; +#endif + + +#ifdef POSIX2_DATE + case 'C': + sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100); + break; + + + case 'E': + case 'O': + /* POSIX locale extensions, ignored for now */ + goto again; + + case 'V': /* week of year according ISO 8601 */ +#if defined(RUBY) && defined(VMS_EXT) + { + extern int do_lint; + extern void warning(); + static int warned = 0; + + if (! warned && do_lint) { + warned = 1; + warning( + "conversion %%V added in P1003.2; for VMS style date, use %%v"); + } + } +#endif + sprintf(tbuf, "%02d", iso8601wknum(timeptr)); + break; + + case 'u': + /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */ + sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 : + timeptr->tm_wday); + break; +#endif /* POSIX2_DATE */ + default: + tbuf[0] = '%'; + tbuf[1] = *format; + tbuf[2] = '\0'; + break; + } + i = strlen(tbuf); + if (i) { + if (s + i < endp - 1) { + strcpy(s, tbuf); + s += i; + } else + return 0; + } + } +out: + if (s < endp && *format == '\0') { + *s = '\0'; + return (s - start); + } else + return 0; +} + +/* isleap --- is a year a leap year? */ + +#ifndef __STDC__ +static int +isleap(year) +int year; +#else +static int +isleap(int year) +#endif +{ + return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); +} + + +#ifdef POSIX2_DATE +/* iso8601wknum --- compute week number according to ISO 8601 */ + +#ifndef __STDC__ +static int +iso8601wknum(timeptr) +const struct tm *timeptr; +#else +static int +iso8601wknum(const struct tm *timeptr) +#endif +{ + /* + * From 1003.2: + * If the week (Monday to Sunday) containing January 1 + * has four or more days in the new year, then it is week 1; + * otherwise it is the highest numbered week of the previous + * (52 or 53) year, and the next week is week 1. + * + * ADR: This means if Jan 1 was Monday through Thursday, + * it was week 1, otherwise week 52 or 53. + * + * XPG4 erroneously included POSIX.2 rationale text in the + * main body of the standard. Thus it requires week 53. + */ + + int weeknum, jan1day, diff; + + /* get week number, Monday as first day of the week */ + weeknum = weeknumber(timeptr, 1); + + /* + * With thanks and tip of the hatlo to [email protected] + * + * What day of the week does January 1 fall on? + * We know that + * (timeptr->tm_yday - jan1.tm_yday) MOD 7 == + * (timeptr->tm_wday - jan1.tm_wday) MOD 7 + * and that + * jan1.tm_yday == 0 + * and that + * timeptr->tm_wday MOD 7 == timeptr->tm_wday + * from which it follows that. . . + */ + jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7); + if (jan1day < 0) + jan1day += 7; + + /* + * If Jan 1 was a Monday through Thursday, it was in + * week 1. Otherwise it was last year's highest week, which is + * this year's week 0. + * + * What does that mean? + * If Jan 1 was Monday, the week number is exactly right, it can + * never be 0. + * If it was Tuesday through Thursday, the weeknumber is one + * less than it should be, so we add one. + * Otherwise, Friday, Saturday or Sunday, the week number is + * OK, but if it is 0, it needs to be 52 or 53. + */ + switch (jan1day) { + case 1: /* Monday */ + break; + case 2: /* Tuesday */ + case 3: /* Wednedsday */ + case 4: /* Thursday */ + weeknum++; + break; + case 5: /* Friday */ + case 6: /* Saturday */ + case 0: /* Sunday */ + if (weeknum == 0) { +#ifdef USE_BROKEN_XPG4 + /* XPG4 (as of March 1994) says 53 unconditionally */ + weeknum = 53; +#else + /* get week number of last week of last year */ + struct tm dec31ly; /* 12/31 last year */ + dec31ly = *timeptr; + dec31ly.tm_year--; + dec31ly.tm_mon = 11; + dec31ly.tm_mday = 31; + dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; + dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900); + weeknum = iso8601wknum(& dec31ly); +#endif + } + break; + } + return weeknum; +} +#endif + +/* weeknumber --- figure how many weeks into the year */ + +/* With thanks and tip of the hatlo to [email protected] */ + +#ifndef __STDC__ +static int +weeknumber(timeptr, firstweekday) +const struct tm *timeptr; +int firstweekday; +#else +static int +weeknumber(const struct tm *timeptr, int firstweekday) +#endif +{ + int wday = timeptr->tm_wday; + int ret; + + if (firstweekday == 1) { + if (wday == 0) /* sunday */ + wday = 6; + else + wday--; + } + ret = ((timeptr->tm_yday + 7 - wday) / 7); + if (ret < 0) + ret = 0; + return ret; +} + +#if 0 +/* ADR --- I'm loathe to mess with ado's code ... */ + +Date: Wed, 24 Apr 91 20:54:08 MDT +From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK> +To: [email protected] + +Hi Arnold, +in a process of fixing of strftime() in libraries on Atari ST I grabbed +some pieces of code from your own strftime. When doing that it came +to mind that your weeknumber() function compiles a little bit nicer +in the following form: +/* + * firstweekday is 0 if starting in Sunday, non-zero if in Monday + */ +{ + return (timeptr->tm_yday - timeptr->tm_wday + + (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7; +} +How nicer it depends on a compiler, of course, but always a tiny bit. + + Cheers, + Michal +#endif + +#ifdef TEST_STRFTIME + +/* + * NAME: + * tst + * + * SYNOPSIS: + * tst + * + * DESCRIPTION: + * "tst" is a test driver for the function "strftime". + * + * OPTIONS: + * None. + * + * AUTHOR: + * Karl Vogel + * Control Data Systems, Inc. + * + * BUGS: + * None noticed yet. + * + * COMPILE: + * cc -o tst -DTEST_STRFTIME strftime.c + */ + +/* ADR: I reformatted this to my liking, and deleted some unneeded code. */ + +#ifndef NULL +#include <stdio.h> +#endif +#include <sys/time.h> +#include <string.h> + +#define MAXTIME 132 + +/* + * Array of time formats. + */ + +static char *array[] = +{ + "(%%A) full weekday name, var length (Sunday..Saturday) %A", + "(%%B) full month name, var length (January..December) %B", + "(%%C) Century %C", + "(%%D) date (%%m/%%d/%%y) %D", + "(%%E) Locale extensions (ignored) %E", + "(%%H) hour (24-hour clock, 00..23) %H", + "(%%I) hour (12-hour clock, 01..12) %I", + "(%%M) minute (00..59) %M", + "(%%O) Locale extensions (ignored) %O", + "(%%R) time, 24-hour (%%H:%%M) %R", + "(%%S) second (00..61) %S", + "(%%T) time, 24-hour (%%H:%%M:%%S) %T", + "(%%U) week of year, Sunday as first day of week (00..53) %U", + "(%%V) week of year according to ISO 8601 %V", + "(%%W) week of year, Monday as first day of week (00..53) %W", + "(%%X) appropriate locale time representation (%H:%M:%S) %X", + "(%%Y) year with century (1970...) %Y", + "(%%Z) timezone (EDT), or blank if timezone not determinable %Z", + "(%%a) locale's abbreviated weekday name (Sun..Sat) %a", + "(%%b) locale's abbreviated month name (Jan..Dec) %b", + "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c", + "(%%d) day of the month (01..31) %d", + "(%%e) day of the month, blank-padded ( 1..31) %e", + "(%%h) should be same as (%%b) %h", + "(%%j) day of the year (001..366) %j", + "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k", + "(%%l) hour, 12-hour clock, blank pad ( 0..12) %l", + "(%%m) month (01..12) %m", + "(%%p) locale's AM or PM based on 12-hour clock %p", + "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r", + "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u", + "(%%v) VAX date (dd-bbb-YYYY) %v", + "(%%w) day of week (0..6, Sunday == 0) %w", + "(%%x) appropriate locale date representation %x", + "(%%y) last two digits of year (00..99) %y", + (char *) NULL +}; + +/* main routine. */ + +int +main(argc, argv) +int argc; +char **argv; +{ + long time(); + + char *next; + char string[MAXTIME]; + + int k; + int length; + + struct tm *tm; + + long clock; + + /* Call the function. */ + + clock = time((long *) 0); + tm = localtime(&clock); + + for (k = 0; next = array[k]; k++) { + length = strftime(string, MAXTIME, next, tm); + printf("%s\n", string); + } + + exit(0); +} +#endif /* TEST_STRFTIME */ diff --git a/missing/strstr.c b/missing/strstr.c new file mode 100644 index 0000000000..ff28ebffd6 --- /dev/null +++ b/missing/strstr.c @@ -0,0 +1,73 @@ +/* + * strstr.c -- + * + * Source code for the "strstr" library routine. + * + * Copyright 1988-1991 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appears in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#ifndef lint +static char rcsid[] = "$Header: /work/cvsroot/ruby/missing/strstr.c,v 1.1 1994/06/27 15:49:21 matz Exp $ SPRITE (Berkeley)"; +#endif /* not lint */ + +/* + *---------------------------------------------------------------------- + * + * strstr -- + * + * Locate the first instance of a substring in a string. + * + * Results: + * If string contains substring, the return value is the + * location of the first matching instance of substring + * in string. If string doesn't contain substring, the + * return value is 0. Matching is done on an exact + * character-for-character basis with no wildcards or special + * characters. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +strstr(string, substring) + register char *string; /* String to search. */ + char *substring; /* Substring to try to find in string. */ +{ + register char *a, *b; + + /* First scan quickly through the two strings looking for a + * single-character match. When it's found, then compare the + * rest of the substring. + */ + + b = substring; + if (*b == 0) { + return string; + } + for ( ; *string != 0; string += 1) { + if (*string != *b) { + continue; + } + a = string; + while (1) { + if (*b == 0) { + return string; + } + if (*a++ != *b++) { + break; + } + } + b = substring; + } + return (char *) 0; +} diff --git a/missing/strtol.c b/missing/strtol.c new file mode 100644 index 0000000000..4941f43b91 --- /dev/null +++ b/missing/strtol.c @@ -0,0 +1,84 @@ +/* + * strtol.c -- + * + * Source code for the "strtol" library procedure. + * + * Copyright 1988 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include <ctype.h> + + +/* + *---------------------------------------------------------------------- + * + * strtol -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +long int +strtol(string, endPtr, base) + char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + char **endPtr; /* Where to store address of terminating + * character, or NULL. */ + int base; /* Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + int result; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * Check for a sign. + */ + + if (*p == '-') { + p += 1; + result = -(strtoul(p, endPtr, base)); + } else { + if (*p == '+') { + p += 1; + } + result = strtoul(p, endPtr, base); + } + if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { + *endPtr = string; + } + return result; +} diff --git a/missing/strtoul.c b/missing/strtoul.c new file mode 100644 index 0000000000..f16f2ad9cf --- /dev/null +++ b/missing/strtoul.c @@ -0,0 +1,184 @@ +/* + * strtoul.c -- + * + * Source code for the "strtoul" library procedure. + * + * Copyright 1988 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +#include <ctype.h> + +/* + * The table below is used to convert from ASCII digits to a + * numerical equivalent. It maps from '0' through 'z' to integers + * (100 for non-digit characters). + */ + +static char cvtIn[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ + 100, 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, + 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35}; + +/* + *---------------------------------------------------------------------- + * + * strtoul -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long int +strtoul(string, endPtr, base) + char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + char **endPtr; /* Where to store address of terminating + * character, or NULL. */ + int base; /* Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + register unsigned long int result = 0; + register unsigned digit; + int anyDigits = 0; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * If no base was provided, pick one from the leading characters + * of the string. + */ + + if (base == 0) + { + if (*p == '0') { + p += 1; + if (*p == 'x') { + p += 1; + base = 16; + } else { + + /* + * Must set anyDigits here, otherwise "0" produces a + * "no digits" error. + */ + + anyDigits = 1; + base = 8; + } + } + else base = 10; + } else if (base == 16) { + + /* + * Skip a leading "0x" from hex numbers. + */ + + if ((p[0] == '0') && (p[1] == 'x')) { + p += 2; + } + } + + /* + * Sorry this code is so messy, but speed seems important. Do + * different things for base 8, 10, 16, and other. + */ + + if (base == 8) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 7) { + break; + } + result = (result << 3) + digit; + anyDigits = 1; + } + } else if (base == 10) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 9) { + break; + } + result = (10*result) + digit; + anyDigits = 1; + } + } else if (base == 16) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit > 15) { + break; + } + result = (result << 4) + digit; + anyDigits = 1; + } + } else { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit >= base) { + break; + } + result = result*base + digit; + anyDigits = 1; + } + } + + /* + * See if there were any digits at all. + */ + + if (!anyDigits) { + p = string; + } + + if (endPtr != 0) { + *endPtr = p; + } + + return result; +} diff --git a/newver.rb b/newver.rb new file mode 100755 index 0000000000..48ff38954b --- /dev/null +++ b/newver.rb @@ -0,0 +1,14 @@ +#! ./ruby +f = open("version.h", "r") +f.gets() +f.close + +if $_ =~ /"(\d+)\.(\d+)"/; + f = open("version.h", "w") + i = $2.to_i + 1 + date = Time.now.strftime("%d %b %y") + printf("ruby version %d.%0d (%s)\n", $1, i, date) + printf(f, "#define RUBY_VERSION \"%d.%0d\"\n", $1, i) + printf(f, "#define VERSION_DATE \"%s\"\n", date) + f.close +end diff --git a/node.h b/node.h new file mode 100644 index 0000000000..2e4c134214 --- /dev/null +++ b/node.h @@ -0,0 +1,216 @@ +/************************************************ + + node.h - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Fri May 28 15:14:02 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#ifndef NODE_H +#define NODE_H + +enum node_type { + NODE_CFUNC, + NODE_SCOPE, + NODE_BLOCK, + NODE_IF, + NODE_CASE, + NODE_WHEN, + NODE_UNLESS, + NODE_WHILE, + NODE_UNTIL, + NODE_DO, + NODE_FOR, + NODE_PROT, + NODE_AND, + NODE_OR, + NODE_MASGN, + NODE_LASGN, + NODE_GASGN, + NODE_IASGN, + NODE_CASGN, + NODE_CALL, + NODE_CALL2, + NODE_SUPER, + NODE_ZSUPER, + NODE_ARRAY, + NODE_ZARRAY, + NODE_HASH, + NODE_REDO, + NODE_BREAK, + NODE_CONTINUE, + NODE_RETURN, + NODE_RETRY, + NODE_YIELD, + NODE_LVAR, + NODE_GVAR, + NODE_IVAR, + NODE_MVAR, + NODE_CVAR, + NODE_CONST, + NODE_LIT, + NODE_STR, + NODE_ARGS, + NODE_DEFN, + NODE_DEFS, + NODE_ALIAS, + NODE_UNDEF, + NODE_CLASS, + NODE_MODULE, + NODE_INC, + NODE_DOT3, + NODE_ATTRSET, + NODE_SELF, + NODE_NIL, +}; + +typedef struct node { + enum node_type type; + char *src; + unsigned int line; + union { + struct node *node; + ID id; + VALUE value; + VALUE (*cfunc)(); + ID *tbl; + enum mth_scope scope; + } u1; + union { + struct node *node; + ID id; + int argc; + } u2; + union { + struct node *node; + ID id; + int state; + struct global_entry *entry; + int cnt; + VALUE value; + } u3; +} NODE; + +#define nd_head u1.node +#define nd_last u2.node +#define nd_next u3.node + +#define nd_cond u1.node +#define nd_body u2.node +#define nd_else u3.node +#define nd_break u3.state + +#define nd_resq u2.node +#define nd_ensr u3.node + +#define nd_1st u1.node +#define nd_2nd u2.node + +#define nd_stts u1.node + +#define nd_entry u3.entry +#define nd_vid u1.id +#define nd_cflag u2.id +#define nd_cval u3.value + +#define nd_cnt u3.cnt +#define nd_tbl u1.tbl + +#define nd_var u1.node +#define nd_ibdy u2.node +#define nd_iter u3.node + +#define nd_value u2.node + +#define nd_lit u1.value + +#define nd_frml u1.node +#define nd_rest u2.argc + +#define nd_recv u1.node +#define nd_mid u2.id +#define nd_args u3.node + +#define nd_scope u1.scope +#define nd_defn u3.node + +#define nd_new u1.id +#define nd_old u2.id + +#define nd_cfnc u1.cfunc +#define nd_argc u2.argc + +#define nd_cname u1.id +#define nd_super u3.id + +#define nd_modl u1.id + +#define nd_beg u1.node +#define nd_end u2.node +#define nd_state u3.state + +#define nd_rval u3.node + +#define NEW_DEFN(i,d,m) newnode(NODE_DEFN,m,i,d) +#define NEW_DEFS(r,i,d) newnode(NODE_DEFS,r,i,d) +#define NEW_CFUNC(f,c) newnode(NODE_CFUNC,f,c,Qnil) +#define NEW_RFUNC(b1,b2) NEW_SCOPE(block_append(b1,b2)) +#define NEW_SCOPE(b) newnode(NODE_SCOPE, local_tbl(),(b),local_cnt(0)) +#define NEW_BLOCK(a) newnode(NODE_BLOCK,a,Qnil,Qnil) +#define NEW_IF(c,t,e) newnode(NODE_IF,c,t,e) +#define NEW_UNLESS(c,t,e) newnode(NODE_UNLESS,c,t,e) +#define NEW_CASE(h,b) newnode(NODE_CASE,h,b,Qnil) +#define NEW_WHEN(c,t,e) newnode(NODE_WHEN,c,t,e) +#define NEW_WHILE(c,b) newnode(NODE_WHILE,c,b,Qnil) +#define NEW_UNTIL(c,b) newnode(NODE_UNTIL,c,b,Qnil) +#define NEW_FOR(v,i,b) newnode(NODE_FOR,v,b,i) +#define NEW_DO(v,i,b) newnode(NODE_DO,v,b,i) +#define NEW_PROT(b,ex,en) newnode(NODE_PROT,b,ex,en) +#define NEW_REDO() newnode(NODE_REDO,Qnil,Qnil,Qnil) +#define NEW_BREAK() newnode(NODE_BREAK,Qnil,Qnil,Qnil) +#define NEW_CONT() newnode(NODE_CONTINUE,Qnil,Qnil,Qnil) +#define NEW_RETRY() newnode(NODE_RETRY,Qnil,Qnil,Qnil) +#define NEW_RET(s) newnode(NODE_RETURN,s,Qnil,Qnil) +#define NEW_YIELD(a) newnode(NODE_YIELD,a,Qnil,Qnil) +#define NEW_LIST(a) NEW_ARRAY(a) +#define NEW_ARRAY(a) newnode(NODE_ARRAY,a,Qnil,Qnil) +#define NEW_ZARRAY() newnode(NODE_ZARRAY,Qnil,Qnil,Qnil) +#define NEW_HASH(a) newnode(NODE_HASH,a,Qnil,Qnil) +#define NEW_AND(a,b) newnode(NODE_AND,a,b,Qnil) +#define NEW_OR(a,b) newnode(NODE_OR,a,b,Qnil) +#define NEW_MASGN(l,val) newnode(NODE_MASGN,l,val,Qnil) +#define NEW_GASGN(v,val) newnode(NODE_GASGN,v,val,rb_global_entry(v)) +#define NEW_LASGN(v,val) newnode(NODE_LASGN,v,val,local_cnt(v)) +#define NEW_IASGN(v,val) newnode(NODE_IASGN,v,val,Qnil) +#define NEW_CASGN(v,val) newnode(NODE_CASGN,v,val,Qnil) +#define NEW_GVAR(v) newnode(NODE_GVAR,v,Qnil,rb_global_entry(v)) +#define NEW_LVAR(v) newnode(NODE_LVAR,v,Qnil,local_cnt(v)) +#define NEW_IVAR(v) newnode(NODE_IVAR,v,Qnil,Qnil) +#define NEW_MVAR(v) newnode(NODE_MVAR,v,Qnil,Qnil) +#define NEW_CVAR(v) newnode(NODE_CVAR,v,Qnil,Qnil) +#define NEW_LIT(l) newnode(NODE_LIT,l,Qnil,Qnil) +#define NEW_STR(s) newnode(NODE_STR,s,Qnil,Qnil) +#define NEW_CALL(r,m,a) newnode(NODE_CALL,r,m,a) +#define NEW_CALL2(r,m,a) newnode(NODE_CALL2,r,m,a) +#define NEW_SUPER(a) newnode(NODE_SUPER,Qnil,Qnil,a) +#define NEW_ZSUPER() newnode(NODE_ZSUPER,Qnil,Qnil,Qnil) +#define NEW_ARGS(f,r) newnode(NODE_ARGS,f,r,Qnil) +#define NEW_ALIAS(n,o) newnode(NODE_ALIAS,n,o,Qnil) +#define NEW_UNDEF(i) newnode(NODE_UNDEF,Qnil,i,Qnil) +#define NEW_CLASS(n,b,s) newnode(NODE_CLASS,n,NEW_SCOPE(b),s) +#define NEW_MODULE(n,b) newnode(NODE_MODULE,n,NEW_SCOPE(b),Qnil) +#define NEW_INC(m) newnode(NODE_INC,m,Qnil,Qnil) +#define NEW_DOT3(b,e) newnode(NODE_DOT3,b,e,0) +#define NEW_ATTRSET(a) newnode(NODE_ATTRSET,a,Qnil,Qnil) +#define NEW_SELF() newnode(NODE_SELF,Qnil,Qnil,Qnil) +#define NEW_NIL() newnode(NODE_NIL,Qnil,Qnil,Qnil) + +NODE *newnode(); +NODE *rb_get_method_body(); +void freenode(); + +#endif diff --git a/numeric.c b/numeric.c new file mode 100644 index 0000000000..34d82134b4 --- /dev/null +++ b/numeric.c @@ -0,0 +1,962 @@ +/************************************************ + + numeric.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:32 $ + created at: Fri Aug 13 18:33:09 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include <math.h> + +static ID coerce; +static ID to_i; + +VALUE C_Numeric; +VALUE C_Float; +VALUE C_Integer; +VALUE C_Fixnum; + +extern VALUE C_Range; +double big2dbl(); + +static +num_coerce_bin(this, other) + VALUE this, other; +{ + return rb_funcall(rb_funcall(other, coerce, 1, this), + the_env->last_func, 1, other); +} + +static VALUE +Fnum_uplus(num) + VALUE num; +{ + return num; +} + +static VALUE +Fnum_uminus(num) + VALUE num; +{ + return rb_funcall(rb_funcall(num, coerce, 1, INT2FIX(0)), '-', 1, num); +} + +static VALUE +Fnum_dot2(left, right) + VALUE left, right; +{ + Need_Fixnum(left); + Need_Fixnum(right); + return range_new(C_Range, left, right); +} + +static VALUE +Fnum_upto(from, to) + VALUE from, to; +{ + int i, end; + + end = NUM2INT(to); + for (i = NUM2INT(from); i <= end; i++) { + rb_yield(INT2FIX(i)); + } + + return from; +} + +static VALUE +Fnum_downto(from, to) + VALUE from, to; +{ + int i, end; + + end = NUM2INT(to); + for (i=NUM2INT(from); i >= end; i--) { + rb_yield(INT2FIX(i)); + } + + return from; +} + +static VALUE +Fnum_step(from, to, step) + VALUE from, to; +{ + int i, end, diff; + + end = NUM2INT(to); + diff = NUM2INT(step); + + if (diff == 0) { + Fail("step cannot be 0"); + } + else if (diff > 0) { + for (i=NUM2INT(from); i <= end; i+=diff) { + rb_yield(INT2FIX(i)); + } + } + else { + for (i=NUM2INT(from); i >= end; i+=diff) { + rb_yield(INT2FIX(i)); + } + } + return from; +} + +static VALUE +Fnum_dotimes(num) + VALUE num; +{ + int i, end; + + end = NUM2INT(num); + for (i=0; i<end; i++) { + rb_yield(INT2FIX(i)); + } + return num; +} + +static VALUE +Fnum_divmod(x, y) + VALUE x, y; +{ + VALUE div, mod; + + GC_LINK; + GC_PRO3(div, rb_funcall(x, '/', 1, y)); + GC_PRO3(mod, rb_funcall(x, '%', 1, y)); + GC_UNLINK; + + return assoc_new(div, mod); +} + +static VALUE +Fnum_is_int(num) + VALUE num; +{ + return FALSE; +} + +VALUE +float_new(flt) + double flt; +{ + NEWOBJ(flo, struct RFloat); + OBJSETUP(flo, C_Float, T_FLOAT); + + flo->value = flt; + return (VALUE)flo; +} + +static VALUE +Fflo_new(flo) + struct RFloat *flo; +{ + Check_Type(flo, T_FLOAT); + { + NEWOBJ(flo2, struct RFloat); + CLONESETUP(flo2, flo); + + flo2->value = flo->value; + return (VALUE)flo2; + } +} + +static VALUE +Fflo_to_s(flt) + struct RFloat *flt; +{ + char buf[32]; + + sprintf(buf, "%g", flt->value); + + return str_new2(buf); +} + +static VALUE +Fflo_coerce(this, other) + VALUE this, other; +{ + switch (TYPE(other)) { + case T_FIXNUM: + return float_new((double)FIX2INT(other)); + case T_FLOAT: + return other; + case T_BIGNUM: + return Fbig_to_f(other); + default: + Fail("can't coerce %s to Float", rb_class2name(CLASS_OF(other))); + } + /* not reached */ + return Qnil; +} + +static VALUE +Fflo_uminus(flt) + struct RFloat *flt; +{ + return float_new(-flt->value); +} + +static VALUE +Fflo_plus(x, y) + struct RFloat *x, *y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + return float_new(x->value + (double)FIX2INT(y)); + case T_BIGNUM: + return float_new(x->value + big2dbl(y)); + case T_FLOAT: + return float_new(x->value + y->value); + case T_STRING: + return Fstr_plus(obj_as_string(x), y); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Fflo_minus(x, y) + struct RFloat *x, *y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + return float_new(x->value - (double)FIX2INT(y)); + case T_BIGNUM: + return float_new(x->value - big2dbl(y)); + case T_FLOAT: + return float_new(x->value - y->value); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Fflo_mul(x, y) + struct RFloat *x, *y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + return float_new(x->value * (double)FIX2INT(y)); + case T_BIGNUM: + return float_new(x->value * big2dbl(y)); + case T_FLOAT: + return float_new(x->value * y->value); + case T_STRING: + return Fstr_times(y, INT2FIX((int)x->value)); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Fflo_div(x, y) + struct RFloat *x, *y; +{ + int f_y; + double d; + + switch (TYPE(y)) { + case T_FIXNUM: + f_y = FIX2INT(y); + if (f_y == 0) Fail("devided by 0"); + return float_new(x->value / (double)f_y); + case T_BIGNUM: + d = big2dbl(y); + if (d == 0.0) Fail("devided by 0"); + return float_new(x->value + d); + case T_FLOAT: + if (y->value == 0.0) Fail("devided by 0"); + return float_new(x->value / y->value); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Fflo_mod(x, y) + struct RFloat *x, *y; +{ + double value; + + switch (TYPE(y)) { + case T_FIXNUM: + value = (double)FIX2INT(y); + break; + case T_BIGNUM: + value = big2dbl(y); + break; + case T_FLOAT: + value = y->value; + break; + default: + return num_coerce_bin(x, y); + } +#ifdef HAVE_FMOD + { + value = fmod(x->value, value); + } +#else + { + double value1 = x->value; + double value2; + + modf(value1/value, &value2); + value = value1 - value2 * value; + } +#endif + + return float_new(value); +} + +Fflo_pow(x, y) + struct RFloat *x, *y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + return float_new(pow(x->value, (double)FIX2INT(y))); + case T_BIGNUM: + return float_new(pow(x->value, big2dbl(y))); + case T_FLOAT: + return float_new(pow(x->value, y->value)); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Fflo_eq(x, y) + struct RFloat *x, *y; +{ + switch (TYPE(y)) { + case T_NIL: + return Qnil; + case T_FIXNUM: + if (x->value == FIX2INT(y)) return TRUE; + return FALSE; + case T_BIGNUM: + return float_new(x->value == big2dbl(y)); + case T_FLOAT: + return (x->value == y->value)?TRUE:FALSE; + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Fflo_hash(num) + struct RFloat *num; +{ + double d; + char *c; + int i, hash; + + d = num->value; + c = (char*)&d; + for (hash=0, i=0; i<sizeof(double);i++) { + hash += c[i] * 971; + } + if (hash < 0) hash = -hash; + return INT2FIX(hash); +} + +static VALUE +Fflo_cmp(x, y) + struct RFloat *x, *y; +{ + double a, b; + + a = x->value; + switch (TYPE(y)) { + case T_FIXNUM: + b = (double)FIX2INT(y); + break; + + case T_BIGNUM: + b = big2dbl(y); + break; + + case T_FLOAT: + b = y->value; + break; + + default: + return num_coerce_bin(x, y); + } + if (a == b) return INT2FIX(0); + if (a > b) return INT2FIX(1); + return INT2FIX(-1); +} + +static VALUE +Fflo_to_i(num) + struct RFloat *num; +{ + double f = num->value; + int val; + + if (!FIXABLE(f)) { + return dbl2big(f); + } + val = f; + return INT2FIX(val); +} + +static VALUE +Fflo_to_f(num) + VALUE num; +{ + return num; +} + +static VALUE +Fflo_clone(flt) + struct RFloat *flt; +{ + VALUE flt2 = float_new(flt->value); + CLONESETUP(flt2, flt); + return flt2; +} + +static VALUE +Fflo_abs(flt) + struct RFloat *flt; +{ + double val = fabs(flt->value); + return float_new(val); +} + +int +num2int(val) + VALUE val; +{ + int result; + + if (val == Qnil) return 0; + + switch (TYPE(val)) { + case T_FIXNUM: + result = FIX2INT(val); + break; + + case T_FLOAT: + if (RFLOAT(val)->value <= (double) LONG_MAX + && RFLOAT(val)->value >= (double) LONG_MIN) { + result = (int)RFLOAT(val)->value; + } + else { + Fail("float %g out of rang of integer", RFLOAT(val)->value); + } + break; + + case T_BIGNUM: + return big2int(val); + + default: + Fail("failed to convert %s into int", rb_class2name(CLASS_OF(val))); + break; + } + return result; +} + +static VALUE +to_fixnum(val) + VALUE val; +{ + return rb_funcall(val, to_i, 0); +} + +static VALUE +fail_to_fixnum(val) + VALUE val; +{ + Fail("failed to convert %s into fixnum", rb_class2name(CLASS_OF(val))); +} + +VALUE +num2fix(val) + VALUE val; +{ + int v; + + if (val == Qnil) return INT2FIX(0); + switch (TYPE(val)) { + case T_FIXNUM: + return val; + + case T_FLOAT: + case T_BIGNUM: + v = num2int(val); + if (!FIXABLE(v)) + Fail("integer %d out of rang of Fixnum", v); + return INT2FIX(v); + + default: + return rb_resque(to_fixnum, val, fail_to_fixnum, val); + } +} + +static VALUE +Fint_is_int(num) + VALUE num; +{ + return TRUE; +} + +static VALUE +Fint_chr(num) + VALUE num; +{ + char c; + int i = NUM2INT(num); + + if (i < 0 || 0xff < i) + Fail("%d out of char range", i); + c = i; + return str_new(&c, 1); +} + +VALUE +Ffix_clone(num) + VALUE num; +{ + return num; +} + +static VALUE +Ffix_uminus(num) + VALUE num; +{ + return int2inum(-FIX2INT(num)); +} + +VALUE +fix2str(x, base) + VALUE x; + int base; +{ + char fmt[3], buf[12]; + + fmt[0] = '%'; fmt[2] = '\0'; + if (base == 10) fmt[1] = 'd'; + else if (base == 16) fmt[1] = 'x'; + else if (base == 8) fmt[1] = 'o'; + else Fail("fixnum cannot treat base %d", base); + + sprintf(buf, fmt, FIX2INT(x)); + return str_new2(buf); +} + +VALUE +Ffix_to_s(in) + VALUE in; +{ + return fix2str(in, 10); +} + +static VALUE +Ffix_plus(x, y) + VALUE x; + struct RFloat *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) { + VALUE big1, big2; + GC_LINK; + GC_PRO3(big1, int2big(a)); + GC_PRO3(big2, int2big(b)); + r = Fbig_plus(big1, big2); + GC_UNLINK; + } + return r; + } + case T_FLOAT: + return float_new((double)FIX2INT(x) + y->value); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Ffix_minus(x, y) + VALUE x; + struct RFloat *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) { + VALUE big1, big2; + GC_LINK; + GC_PRO3(big1, int2big(a)); + GC_PRO3(big2, int2big(b)); + r = Fbig_minus(big1, big2); + GC_UNLINK; + } + return r; + } + case T_FLOAT: + return float_new((double)FIX2INT(x) - y->value); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Ffix_mul(x, y) + VALUE x; + struct RFloat *y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + { + int a = FIX2INT(x), b = FIX2INT(y); + int c = a * b; + VALUE r = INT2FIX(c); + + if (FIX2INT(r) != c) { + VALUE big1, big2; + GC_LINK; + GC_PRO3(big1, int2big(a)); + GC_PRO3(big2, int2big(b)); + r = Fbig_mul(big1, big2); + GC_UNLINK; + } + return r; + } + case T_FLOAT: + return float_new((double)FIX2INT(x) * y->value); + default: + return num_coerce_bin(x, y); + } +} + +static VALUE +Ffix_div(x, y) + VALUE x; + struct RFloat *y; +{ + int i; + + if (TYPE(y) == T_FIXNUM) { + i = FIX2INT(y); + if (i == 0) Fail("devided by 0"); + i = FIX2INT(x)/i; + return INT2FIX(i); + } + return num_coerce_bin(x, y); +} + +static VALUE +Ffix_mod(x, y) + VALUE x, y; +{ + int mod, i; + + if (TYPE(y) == T_FIXNUM) { + i = FIX2INT(y); + if (i == 0) Fail("devided by 0"); + i = FIX2INT(x)%i; + return INT2FIX(i); + } + return num_coerce_bin(x, y); +} + +static VALUE +Ffix_pow(x, y) + VALUE x, y; +{ + extern double pow(); + int result; + + if (FIXNUM_P(y)) { + result = pow((double)FIX2INT(x), (double)FIX2INT(y)); + return int2inum(result); + } + else if (NIL_P(y)) { + return INT2FIX(1); + } + else { + return num_coerce_bin(x, y); + } +} + +static VALUE +Ffix_equal(x, y) + VALUE x, y; +{ + if (FIXNUM_P(y)) { + return (FIX2INT(x) == FIX2INT(y))?TRUE:FALSE; + } + else if (NIL_P(y)) { + return Qnil; + } + else { + return num_coerce_bin(x, y); + } +} + +static VALUE +Ffix_cmp(x, y) + VALUE x, y; +{ + if (FIXNUM_P(y)) { + int a = FIX2INT(x), b = FIX2INT(y); + + if (a == b) return INT2FIX(0); + if (a > b) return INT2FIX(1); + return INT2FIX(-1); + } + else { + return num_coerce_bin(x, y); + } +} + +static VALUE +Ffix_dot2(left, right) + VALUE left, right; +{ + Need_Fixnum(right); + return range_new(C_Range, left, right); +} + +static VALUE +Ffix_rev(num) + VALUE num; +{ + unsigned long val = FIX2UINT(num); + + val = ~val; + return INT2FIX(val); +} + +static VALUE +Ffix_and(x, y) + VALUE x, y; +{ + long val; + + if (TYPE(y) == T_BIGNUM) { + return Fbig_and(y, x); + } + val = NUM2INT(x) & NUM2INT(y); + return int2inum(val); +} + +static VALUE +Ffix_or(x, y) + VALUE x, y; +{ + long val; + + if (TYPE(y) == T_BIGNUM) { + return Fbig_or(y, x); + } + val = NUM2INT(x) | NUM2INT(y); + return INT2FIX(val); +} + +static VALUE +Ffix_xor(x, y) + VALUE x, y; +{ + long val; + + if (TYPE(y) == T_BIGNUM) { + return Fbig_xor(y, x); + } + val = NUM2INT(x) ^ NUM2INT(y); + return INT2FIX(val); +} + +static VALUE +Ffix_lshift(x, y) + VALUE x, y; +{ + long val, width; + + val = NUM2INT(x); + width = NUM2INT(y); + if (width > (sizeof(VALUE)*CHAR_BIT-1) + || (unsigned)val>>(sizeof(VALUE)*CHAR_BIT-width) > 0) { + VALUE big; + GC_LINK; + GC_PRO3(big, int2big(val)); + big = Fbig_lshift(big, y); + GC_UNLINK; + return big; + } + val = val << width; + return int2inum(val); +} + +static VALUE +Ffix_rshift(x, y) + VALUE x, y; +{ + long val; + + val = RSHIFT(NUM2INT(x), NUM2INT(y)); + return INT2FIX(val); +} + +static VALUE +Ffix_aref(fix, idx) + VALUE fix, idx; +{ + unsigned long val = FIX2INT(fix); + int i = FIX2INT(idx); + + if (i < 0 || sizeof(VALUE)*CHAR_BIT-1 < i) + return INT2FIX(0); + if (val & (1<<i)) + return INT2FIX(1); + return INT2FIX(0); +} + +static VALUE +Ffix_to_i(num) + VALUE num; +{ + return num; +} + +static VALUE +Ffix_to_f(num) + VALUE num; +{ + double val; + + val = (double)FIX2INT(num); + + return float_new(val); +} + +static VALUE +Ffix_class(fix) + VALUE fix; +{ + return C_Fixnum; +} + +static Ffix_abs(fix) + VALUE fix; +{ + int i = FIX2INT(fix); + + if (fix < 0) i = -i; + + return int2inum(fix); +} + +static VALUE +Ffix_id2name(fix) + VALUE fix; +{ + char *name = rb_id2name(FIX2UINT(fix)); + if (name) return str_new2(name); + return Qnil; +} + +extern VALUE M_Comparable; +extern Fkrn_inspect(); + +Init_Numeric() +{ + coerce = rb_intern("coerce"); + to_i = rb_intern("to_i"); + + C_Numeric = rb_define_class("Numeric", C_Object); + rb_include_module(C_Numeric, M_Comparable); + rb_define_method(C_Numeric, "+@", Fnum_uplus, 0); + rb_define_method(C_Numeric, "-@", Fnum_uminus, 0); + rb_define_method(C_Numeric, "..", Fnum_dot2, 1); + + rb_define_method(C_Numeric, "upto", Fnum_upto, 1); + rb_define_method(C_Numeric, "downto", Fnum_downto, 1); + rb_define_method(C_Numeric, "step", Fnum_step, 2); + rb_define_method(C_Numeric, "times", Fnum_dotimes, 0); + rb_define_method(C_Numeric, "is_integer", Fnum_is_int, 0); + rb_define_method(C_Numeric, "_inspect", Fkrn_inspect, 0); + + C_Integer = rb_define_class("Integer", C_Numeric); + rb_define_method(C_Integer, "is_integer", Fint_is_int, 0); + rb_define_method(C_Integer, "chr", Fint_chr, 0); + + C_Fixnum = rb_define_class("Fixnum", C_Integer); + rb_define_method(C_Fixnum, "to_s", Ffix_to_s, 0); + rb_define_method(C_Fixnum, "class", Ffix_class, 0); + rb_define_method(C_Fixnum, "clone", Ffix_clone, 0); + + rb_define_method(C_Fixnum, "id2name", Ffix_id2name, 0); + + rb_define_method(C_Fixnum, "-@", Ffix_uminus, 0); + rb_define_method(C_Fixnum, "+", Ffix_plus, 1); + rb_define_method(C_Fixnum, "-", Ffix_minus, 1); + rb_define_method(C_Fixnum, "*", Ffix_mul, 1); + rb_define_method(C_Fixnum, "/", Ffix_div, 1); + rb_define_method(C_Fixnum, "%", Ffix_mod, 1); + rb_define_method(C_Fixnum, "**", Ffix_pow, 1); + + rb_define_method(C_Fixnum, "abs", Ffix_abs, 0); + + rb_define_method(C_Fixnum, "==", Ffix_equal, 1); + rb_define_method(C_Fixnum, "<=>", Ffix_cmp, 1); + rb_define_method(C_Fixnum, "..", Ffix_dot2, 1); + + rb_define_method(C_Fixnum, "~", Ffix_rev, 0); + rb_define_method(C_Fixnum, "&", Ffix_and, 1); + rb_define_method(C_Fixnum, "|", Ffix_or, 1); + rb_define_method(C_Fixnum, "^", Ffix_xor, 1); + rb_define_method(C_Fixnum, "[]", Ffix_aref, 1); + + rb_define_method(C_Fixnum, "<<", Ffix_lshift, 1); + rb_define_method(C_Fixnum, ">>", Ffix_rshift, 1); + + rb_define_method(C_Fixnum, "to_i", Ffix_to_i, 0); + rb_define_method(C_Fixnum, "to_f", Ffix_to_f, 0); + + C_Float = rb_define_class("Float", C_Numeric); + rb_define_single_method(C_Float, "new", Fflo_new, 1); + rb_define_method(C_Float, "clone", Fflo_clone, 0); + rb_define_method(C_Float, "to_s", Fflo_to_s, 0); + rb_define_method(C_Float, "coerce", Fflo_coerce, 1); + rb_define_method(C_Float, "-@", Fflo_uminus, 0); + rb_define_method(C_Float, "+", Fflo_plus, 1); + rb_define_method(C_Float, "-", Fflo_minus, 1); + rb_define_method(C_Float, "*", Fflo_mul, 1); + rb_define_method(C_Float, "/", Fflo_div, 1); + rb_define_method(C_Float, "%", Fflo_mod, 1); + rb_define_method(C_Float, "**", Fflo_pow, 1); + rb_define_method(C_Float, "==", Fflo_eq, 1); + rb_define_method(C_Float, "<=>", Fflo_cmp, 1); + rb_define_method(C_Float, "hash", Fflo_hash, 0); + rb_define_method(C_Float, "to_i", Fflo_to_i, 0); + rb_define_method(C_Float, "to_f", Fflo_to_f, 0); + rb_define_method(C_Float, "abs", Fflo_abs, 0); +} diff --git a/object.c b/object.c new file mode 100644 index 0000000000..fd00c2f618 --- /dev/null +++ b/object.c @@ -0,0 +1,458 @@ +/************************************************ + + object.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Thu Jul 15 12:01:24 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include "node.h" +#include "st.h" +#include <stdio.h> + +VALUE C_Kernel; +VALUE C_Object; +VALUE C_Module; +VALUE C_Class; +VALUE C_Nil; +VALUE C_Data; +VALUE C_Method; + +struct st_table *new_idhash(); + +VALUE Fsprintf(); +VALUE Ffail(); +VALUE Fexit(); +VALUE Feval(); +VALUE Fapply(); +VALUE Fdefined(); +VALUE Fcaller(); + +VALUE obj_responds_to(); +VALUE obj_alloc(); +VALUE Ffix_clone(); + +static ID eq, match; + +static VALUE +P_true(obj) + VALUE obj; +{ + return TRUE; +} + +static VALUE +P_false(obj) + VALUE obj; +{ + return FALSE; +} + +static VALUE +Fkrn_equal(obj, other) + VALUE obj, other; +{ + if (obj == other) return TRUE; + return FALSE; +} + +static VALUE +Fkrn_hash(obj) + VALUE obj; +{ + return obj; +} + +static VALUE +Fkrn_to_a(obj) + VALUE obj; +{ + return ary_new3(1, obj); +} + +static VALUE +Fkrn_id(obj) + VALUE obj; +{ + return obj | FIXNUM_FLAG; +} + +static VALUE +Fkrn_noteq(obj, other) + VALUE obj, other; +{ + if (rb_funcall(obj, eq, 1, other)) { + return FALSE; + } + return TRUE; +} + +static VALUE +Fkrn_nmatch(obj, other) + VALUE obj, other; +{ + if (rb_funcall(obj, match, 1, other)) { + return FALSE; + } + return TRUE; +} + +static VALUE +Fkrn_class(obj) + struct RBasic *obj; +{ + return obj->class; +} + +VALUE +Fkrn_to_s(obj) + VALUE obj; +{ + char buf[256]; + + sprintf(buf, "#<%s: 0x%x>", rb_class2name(CLASS_OF(obj)), obj); + return str_new2(buf); +} + +VALUE +Fkrn_inspect(obj) + VALUE obj; +{ + return rb_funcall(obj, rb_intern("to_s"), 0, Qnil); +} + +static +obj_inspect(id, value, str) + ID id; + VALUE value; + struct RString *str; +{ + VALUE str2; + char *ivname; + + if (str->ptr[0] == '-') { + str->ptr[0] = '#'; + } + else { + str_cat(str, ", ", 2); + } + GC_LINK; + ivname = rb_id2name(id); + str_cat(str, ivname, strlen(ivname)); + str_cat(str, "=", 1); + GC_PRO3(str2, rb_funcall(value, rb_intern("_inspect"), 0, Qnil)); + str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + GC_UNLINK; + + return ST_CONTINUE; +} + +static VALUE +Fobj_inspect(obj) + struct RBasic *obj; +{ + VALUE str; + char buf[256]; + + if (FIXNUM_P(obj) || !obj->iv_tbl) return Fkrn_to_s(obj); + + GC_LINK; + sprintf(buf, "-<%s: ", rb_class2name(CLASS_OF(obj))); + GC_PRO3(str, str_new2(buf)); + st_foreach(obj->iv_tbl, obj_inspect, str); + str_cat(str, ">", 1); + GC_UNLINK; + + return str; +} + +VALUE +obj_is_member_of(obj, c) + VALUE obj, c; +{ + struct RClass *class = (struct RClass*)CLASS_OF(obj); + + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + break; + default: + Fail("class or module required"); + } + + while (FL_TEST(class, FL_SINGLE)) { + class = class->super; + } + if (c == (VALUE)class) return TRUE; + return FALSE; +} + +VALUE +obj_is_kind_of(obj, c) + VALUE obj, c; +{ + struct RClass *class = (struct RClass*)CLASS_OF(obj); + + switch (TYPE(c)) { + case T_MODULE: + case T_CLASS: + break; + default: + Fail("class or module required"); + } + + while (class) { + if ((VALUE)class == c || RCLASS(class)->m_tbl == RCLASS(c)->m_tbl) + return TRUE; + class = class->super; + } + return FALSE; +} + +static VALUE +Fobj_clone(obj) + VALUE obj; +{ + VALUE clone; + + Check_Type(obj, T_OBJECT); + + clone = obj_alloc(RBASIC(obj)->class); + GC_LINK; + GC_PRO(clone); + if (RBASIC(obj)->iv_tbl) { + RBASIC(clone)->iv_tbl = st_copy(RBASIC(obj)->iv_tbl); + } + RBASIC(clone)->class = single_class_clone(RBASIC(obj)->class); + GC_UNLINK; + + return clone; +} + +static VALUE +Fiterator_p() +{ + if (the_env->iterator > 1 && the_env->iterator < 4) return TRUE; + return FALSE; +} + +static VALUE +Fnil_to_s(obj) + VALUE obj; +{ + return str_new2("nil"); +} + +static VALUE +Fnil_class(nil) + VALUE nil; +{ + return C_Nil; +} + +static VALUE +Fnil_plus(x, y) + VALUE x, y; +{ + switch (TYPE(y)) { + case T_FIXNUM: + case T_FLOAT: + case T_STRING: + case T_ARRAY: + return y; + default: + Fail("tried to add %s(%s) to nil", + RSTRING(obj_as_string(y))->ptr, rb_class2name(CLASS_OF(y))); + } + return Qnil; /* not reached */ +} + +static VALUE +Fmain_to_s(obj) + VALUE obj; +{ + return str_new2("main"); +} + +VALUE +obj_alloc(class) + VALUE class; +{ + NEWOBJ(obj, struct RObject); + OBJSETUP(obj, class, T_OBJECT); + + return (VALUE)obj; +} + +static VALUE +Fcls_new(class, args) + VALUE class, args; +{ + return obj_alloc(class); +} + +static VALUE +Fcls_to_s(class) + VALUE class; +{ + return str_new2(rb_class2name(class)); +} + +static VALUE +Fcls_attr(class, args) + VALUE class, args; +{ + VALUE name, pub; + + rb_scan_args(args, "11", &name, &pub); + Check_Type(name, T_STRING); + rb_define_attr(class, RSTRING(name)->ptr, pub); + return Qnil; +} + +static VALUE +Fcant_clone(obj) + VALUE obj; +{ + Fail("can't clone %s", rb_class2name(CLASS_OF(obj))); +} + +static VALUE +Fdata_class(data) + VALUE data; +{ + return C_Data; +} + +static VALUE boot_defclass(name, super) + char *name; + VALUE super; +{ + struct RClass *obj = (struct RClass*)class_new(super); + + rb_name_class(obj, rb_intern(name)); + return (VALUE)obj; +} + +VALUE TopSelf; + +Init_Object() +{ + VALUE metaclass; + + C_Kernel = boot_defclass("Kernel", Qnil); + C_Object = boot_defclass("Object", C_Kernel); + C_Module = boot_defclass("Module", C_Object); + C_Class = boot_defclass("Class", C_Module); + + metaclass = RBASIC(C_Kernel)->class = single_class_new(C_Class); + metaclass = RBASIC(C_Object)->class = single_class_new(metaclass); + metaclass = RBASIC(C_Module)->class = single_class_new(metaclass); + metaclass = RBASIC(C_Class)->class = single_class_new(metaclass); + + /* + * +-------nil +---------------------+ + * | ^ | | + * | | | | + * | Kernel----->(Kernel) | + * | ^ ^ ^ ^ | + * | | | | | | + * | +---+ +-----+ | +---+ | + * | | +------|---+ | | + * | | | | | | + * +->Nil->(Nil) Object---->(Object) | + * ^ ^ ^ ^ | + * | | | | | + * | | +-------+ | | + * | | | | | + * | +---------+ +------+ | + * | | | | | + * +--------+ | Module--->(Module) | + * | | ^ ^ | + * OtherClass-->(OtherClass) | | | + * Class---->(Class) | + * ^ | + * | | + * +-----+ + * + * + all metaclasses are instance of class Class + */ + + rb_define_method(C_Kernel, "is_nil", P_false, 0); + rb_define_method(C_Kernel, "!", P_false, 0); + rb_define_method(C_Kernel, "==", Fkrn_equal, 1); + rb_define_alias(C_Kernel, "equal", "=="); + rb_define_method(C_Kernel, "hash", Fkrn_hash, 0); + rb_define_method(C_Kernel, "id", Fkrn_id, 0); + rb_define_method(C_Kernel, "class", Fkrn_class, 0); + rb_define_method(C_Kernel, "!=", Fkrn_noteq, 1); + rb_define_alias(C_Kernel, "=~", "=="); + rb_define_method(C_Kernel, "!~", Fkrn_nmatch, 1); + + rb_define_method(C_Kernel, "to_a", Fkrn_to_a, 0); + rb_define_method(C_Kernel, "to_s", Fkrn_to_s, 0); + rb_define_method(C_Kernel, "_inspect", Fkrn_inspect, 0); + + rb_define_func(C_Kernel, "caller", Fcaller, -2); + rb_define_func(C_Kernel, "fail", Ffail, -2); + rb_define_func(C_Kernel, "exit", Fexit, -2); + rb_define_func(C_Kernel, "eval", Feval, 1); + rb_define_func(C_Kernel, "defined", Fdefined, 1); + rb_define_func(C_Kernel, "sprintf", Fsprintf, -1); + rb_define_alias(C_Kernel, "format", "sprintf"); + rb_define_func(C_Kernel, "iterator_p", Fiterator_p, 0); + + rb_define_method(C_Kernel, "apply", Fapply, -2); + + rb_define_const(C_Kernel, "%TRUE", TRUE); + rb_define_const(C_Kernel, "%FALSE", FALSE); + + rb_define_method(C_Object, "_inspect", Fobj_inspect, 0); + + rb_define_method(C_Object, "responds_to", obj_responds_to, 1); + rb_define_method(C_Object, "is_member_of", obj_is_member_of, 1); + rb_define_method(C_Object, "is_kind_of", obj_is_kind_of, 1); + rb_define_method(C_Object, "clone", Fobj_clone, 0); + + rb_define_method(C_Module, "to_s", Fcls_to_s, 0); + rb_define_method(C_Module, "clone", Fcant_clone, 0); + rb_define_func(C_Module, "attr", Fcls_attr, -2); + + rb_define_method(C_Class, "new", Fcls_new, -2); + + C_Nil = rb_define_class("Nil", C_Kernel); + rb_define_method(C_Nil, "to_s", Fnil_to_s, 0); + rb_define_method(C_Nil, "clone", Ffix_clone, 0); + rb_define_method(C_Nil, "class", Fnil_class, 0); + + rb_define_method(C_Nil, "is_nil", P_true, 0); + rb_define_method(C_Nil, "!", P_true, 0); + + /* for compare cascading. */ + rb_define_method(C_Nil, ">", P_false, 1); + rb_define_alias(C_Nil, ">=", ">"); + rb_define_alias(C_Nil, "<", ">"); + rb_define_alias(C_Nil, "<=", ">"); + + /* default addition */ + rb_define_method(C_Nil, "+", Fnil_plus, 1); + + C_Data = rb_define_class("Data", C_Kernel); + rb_define_method(C_Data, "clone", Fcant_clone, 0); + rb_define_method(C_Data, "class", Fdata_class, 0); + + C_Method = rb_define_class("Method", C_Kernel); + rb_define_method(C_Data, "clone", Fcant_clone, 0); + + eq = rb_intern("=="); + match = rb_intern("=~"); + + Qself = TopSelf = obj_alloc(C_Object); + rb_define_single_method(TopSelf, "to_s", Fmain_to_s, 0); +} diff --git a/pack.c b/pack.c new file mode 100644 index 0000000000..18de67efea --- /dev/null +++ b/pack.c @@ -0,0 +1,849 @@ +/************************************************ + + pack.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Thu Feb 10 15:17:05 JST 1994 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include <ctype.h> +#include <sys/types.h> + +#define swaps(x) ((((x)&0xFF)<<8) + (((x)>>8)&0xFF)) +#define swapl(x) ((((x)&0xFF)<<24) \ + +(((x)>>24)&0xFF) \ + +(((x)&0x0000FF00)<<8) \ + +(((x)&0x00FF0000)>>8) ) +#ifdef WORDS_BIGENDIAN +#define ntohs(x) (x) +#define ntohl(x) (x) +#define htons(x) (x) +#define htonl(x) (x) +#define htovs(x) swaps(x) +#define htovl(x) swapl(x) +#define vtohs(x) swaps(x) +#define vtohl(x) swapl(x) +#else /* LITTLE ENDIAN */ +#define ntohs(x) swaps(x) +#define ntohl(x) swapl(x) +#define htons(x) swaps(x) +#define htonl(x) swapl(x) +#define htovs(x) (x) +#define htovl(x) (x) +#define vtohs(x) (x) +#define vtohl(x) (x) +#endif + +extern VALUE C_String, C_Array; +double atof(); + +static char *toofew = "too few arguments"; + +int strtoul(); +static void encodes(); + +static VALUE +Fpck_pack(ary, fmt) + struct RArray *ary; + struct RString *fmt; +{ + static char *nul10 = "\0\0\0\0\0\0\0\0\0\0"; + static char *spc10 = " "; + char *p, *pend; + VALUE res, from; + char type; + int items, len, idx; + char *ptr; + int plen; + + Check_Type(fmt, T_STRING); + + p = fmt->ptr; + pend = fmt->ptr + fmt->len; + GC_LINK; + GC_PRO2(from); + GC_PRO3(res, str_new(0, 0)); + + items = ary->len; + idx = 0; + +#define NEXTFROM (items-- > 0 ? ary->ptr[idx++] : Fail(toofew)) + + while (p < pend) { + type = *p++; /* get data type */ + + if (*p == '*') { /* set data length */ + len = index("@Xxu", type) ? 0 : items; + p++; + } + else if (isdigit(*p)) { + len = strtoul(p, &p, 10); + } + else { + len = 1; + } + + switch (type) { + case 'A': case 'a': + case 'B': case 'b': + case 'H': case 'h': + from = NEXTFROM; + if (from == Qnil) { + ptr = Qnil; + plen = 0; + } + else { + from = obj_as_string(from); + ptr = RSTRING(from)->ptr; + plen = RSTRING(from)->len; + } + + if (p[-1] == '*') + len = plen; + + switch (type) { + case 'a': + if (plen > len) + str_cat(res, ptr, len); + else { + str_cat(res, ptr, plen); + len == plen; + while (len >= 10) { + str_cat(res, nul10, 10); + len -= 10; + } + str_cat(res, nul10, len); + } + break; + + case 'A': + if (plen > len) + str_cat(res, ptr, len); + else { + str_cat(res, ptr, plen); + len == plen; + while (len >= 10) { + str_cat(res, spc10, 10); + len -= 10; + } + str_cat(res, spc10, len); + } + break; + + case 'b': + { + int byte = 0; + int i; + + for (i=0; i++ < len; ptr++) { + if (*ptr & 1) + byte |= 128; + if (i & 7) + byte >>= 1; + else { + char c = byte & 0xff; + str_cat(res, &c, 1); + byte = 0; + } + } + if (len & 7) { + char c; + byte >>= 7 - (len & 7); + c = byte & 0xff; + str_cat(res, &c, 1); + } + } + break; + + case 'B': + { + int byte = 0; + int i; + + for (i=0; i++ < len; ptr++) { + byte |= *ptr & 1; + if (i & 7) + byte <<= 1; + else { + char c = byte & 0xff; + str_cat(res, &c, 1); + byte = 0; + } + } + if (len & 7) { + char c; + byte <<= 7 - (len & 7); + c = byte & 0xff; + str_cat(res, &c, 1); + } + } + break; + + case 'h': + { + int byte = 0; + int i; + + for (i=0; i++ < len; ptr++) { + if (isxdigit(*ptr)) { + if (isalpha(*ptr)) + byte |= (((*ptr & 15) + 9) & 15) << 4; + else + byte |= (*ptr & 15) << 4; + if (i & 1) + byte >>= 4; + else { + char c = byte & 0xff; + str_cat(res, &c, 1); + byte = 0; + } + } + } + if (len & 1) { + char c = byte & 0xff; + str_cat(res, &c, 1); + } + } + break; + + case 'H': + { + int byte = 0; + int i; + + for (i=0; i++ < len; ptr++) { + if (isxdigit(*ptr)) { + if (isalpha(*ptr)) + byte |= ((*ptr & 15) + 9) & 15; + else + byte |= *ptr & 15; + if (i & 1) + byte <<= 4; + else { + char c = byte & 0xff; + str_cat(res, &c, 1); + byte = 0; + } + } + } + if (len & 1) { + char c = byte & 0xff; + str_cat(res, &c, 1); + } + } + break; + } + break; + + case 'c': + case 'C': + while (len-- > 0) { + char c; + + from = NEXTFROM; + if (from == Qnil) c = 0; + else { + c = NUM2INT(from); + } + str_cat(res, &c, sizeof(char)); + } + break; + + case 's': + case 'S': + while (len-- > 0) { + short s; + + from = NEXTFROM; + if (from == Qnil) s = 0; + else { + s = NUM2INT(from); + } + str_cat(res, &s, sizeof(short)); + } + break; + + case 'i': + case 'I': + while (len-- > 0) { + int i; + + from = NEXTFROM; + if (from == Qnil) i = 0; + else { + i = NUM2INT(from); + } + str_cat(res, &i, sizeof(int)); + } + break; + + case 'l': + case 'L': + while (len-- > 0) { + long l; + + from = NEXTFROM; + if (from == Qnil) l = 0; + else { + l = NUM2INT(from); + } + str_cat(res, &l, sizeof(long)); + } + break; + + case 'n': + while (len-- > 0) { + short s; + + from = NEXTFROM; + if (from == Qnil) s = 0; + else { + s = NUM2INT(from); + } + s = htons(s); + str_cat(res, &s, sizeof(short)); + } + break; + + case 'N': + while (len-- > 0) { + long l; + + from = NEXTFROM; + if (from == Qnil) l = 0; + else { + l = NUM2INT(from); + } + l = htonl(l); + str_cat(res, &l, sizeof(long)); + } + break; + + case 'f': + case 'F': + while (len-- > 0) { + float f; + + from = NEXTFROM; + switch (TYPE(from)) { + case T_FLOAT: + f = RFLOAT(from)->value; + break; + case T_STRING: + f = atof(RSTRING(from)->ptr); + default: + f = (float)NUM2INT(from); + break; + } + str_cat(res, &f, sizeof(float)); + } + break; + + case 'd': + case 'D': + while (len-- > 0) { + double d; + + from = NEXTFROM; + switch (TYPE(from)) { + case T_FLOAT: + d = RFLOAT(from)->value; + break; + case T_STRING: + d = atof(RSTRING(from)->ptr); + default: + d = (double)NUM2INT(from); + break; + } + str_cat(res, &d, sizeof(double)); + } + break; + + case 'v': + while (len-- > 0) { + short s; + + from = NEXTFROM; + if (from == Qnil) s = 0; + else { + s = NUM2INT(from); + } + s = htovs(s); + str_cat(res, &s, sizeof(short)); + } + break; + + case 'V': + while (len-- > 0) { + long l; + + from = NEXTFROM; + if (from == Qnil) l = 0; + else { + l = NUM2INT(from); + } + l = htovl(l); + str_cat(res, &l, sizeof(long)); + } + break; + + case 'x': + grow: + while (len >= 10) { + str_cat(res, nul10, 10); + len -= 10; + } + str_cat(res, nul10, len); + break; + + case 'X': + shrink: + if (RSTRING(res)->len < len) + Fail("X outside of string"); + RSTRING(res)->len -= len; + RSTRING(res)->ptr[RSTRING(res)->len] = '\0'; + break; + + case '@': + len -= RSTRING(res)->len; + if (len > 0) goto grow; + len = -len; + if (len > 0) goto shrink; + break; + + case '%': + Fail("% may only be used in unpack"); + break; + + case 'u': + from = obj_as_string(NEXTFROM); + ptr = RSTRING(from)->ptr; + plen = RSTRING(from)->len; + + if (len <= 1) + len = 45; + else + len = len / 3 * 3; + while (plen > 0) { + int todo; + + if (plen > len) + todo = len; + else + todo = plen; + encodes(res, ptr, todo); + plen -= todo; + ptr += todo; + } + break; + + default: + break; + } + } + GC_UNLINK; + + return res; +} + +static void +encodes(str, s, len) + struct RString *str; + char *s; + int len; +{ + char hunk[4]; + char *p, *pend; + + p = str->ptr + str->len; + *hunk = len + ' '; + str_cat(str, hunk, 1); + while (len > 0) { + hunk[0] = ' ' + (077 & (*s >> 2)); + hunk[1] = ' ' + (077 & ((*s << 4) & 060 | (s[1] >> 4) & 017)); + hunk[2] = ' ' + (077 & ((s[1] << 2) & 074 | (s[2] >> 6) & 03)); + hunk[3] = ' ' + (077 & (s[2] & 077)); + str_cat(str, hunk, 4); + s += 3; + len -= 3; + } + pend = str->ptr + str->len; + while (p < pend) { + if (*p == ' ') + *p = '`'; + p++; + } + str_cat(str, "\n", 1); +} + +static VALUE +Fpck_unpack(str, fmt) + struct RString *str, *fmt; +{ + static char *hexdigits = "0123456789abcdef0123456789ABCDEFx"; + char *s, *send; + char *p, *pend; + VALUE ary; + char type; + int len; + + Check_Type(fmt, T_STRING); + + s = str->ptr; + send = s + str->len; + p = fmt->ptr; + pend = p + fmt->len; + + GC_LINK; + GC_PRO3(ary, ary_new()); + while (p < pend) { + retry: + type = *p++; + if (*p == '*') { + len = send - s; + p++; + } + else if (isdigit(*p)) { + len = strtoul(p, &p, 10); + } + else { + len = (type != '@'); + } + + switch (type) { + case '%': + Fail("% is not supported(yet)"); + break; + + case 'A': + if (len > send - s) len = send - s; + { + char *t = s + len - 1; + + while (t >= s) { + if (*t != ' ' && *t != '\0') break; + t--; + len--; + } + } + case 'a': + if (len > send - s) len = send - s; + Fary_push(ary, str_new(s, len)); + s += len; + break; + + case 'b': + { + VALUE bitstr; + char *t; + int bits, i; + + if (p[-1] == '*' || len > (send - s) * 8) + len = (send - s) * 8; + Fary_push(ary, bitstr = str_new(0, len + 1)); + t = RSTRING(bitstr)->ptr; + for (i=0; i<len; i++) { + if (i & 7) bits >>= 1; + else bits = *s++; + *t++ = (bits & 1) ? '1' : '0'; + } + *t = '\0'; + } + break; + + case 'B': + { + VALUE bitstr; + char *t; + int bits, i; + + if (p[-1] == '*' || len > (send - s) * 8) + len = (send - s) * 8; + Fary_push(ary, bitstr = str_new(0, len + 1)); + t = RSTRING(bitstr)->ptr; + for (i=0; i<len; i++) { + if (i & 7) bits <<= 1; + else bits = *s++; + *t++ = (bits & 128) ? '1' : '0'; + } + *t = '\0'; + } + break; + + case 'h': + { + VALUE bitstr; + char *t; + int bits, i; + + if (p[-1] == '*' || len > (send - s) * 2) + len = (send - s) * 2; + Fary_push(ary, bitstr = str_new(0, len + 1)); + t = RSTRING(bitstr)->ptr; + for (i=0; i<len; i++) { + if (i & 1) + bits >>= 4; + else + bits = *s++; + *t++ = hexdigits[bits & 15]; + } + *t = '\0'; + } + break; + + case 'H': + { + VALUE bitstr; + char *t; + int bits, i; + + if (p[-1] == '*' || len > (send - s) * 2) + len = (send - s) * 2; + Fary_push(ary, bitstr = str_new(0, len + 1)); + t = RSTRING(bitstr)->ptr; + for (i=0; i<len; i++) { + if (i & 1) + bits <<= 4; + else + bits = *s++; + *t++ = hexdigits[(bits >> 4) & 15]; + } + *t = '\0'; + } + break; + + case 'c': + if (len > send - s) + len = send - s; + while (len-- > 0) { + char c = *s++; + Fary_push(ary, INT2FIX(c)); + } + break; + + case 'C': + if (len > send - s) + len = send - s; + while (len-- > 0) { + unsigned char c = *s++; + Fary_push(ary, INT2FIX(c)); + } + break; + + case 's': + if (len >= (send - s) / sizeof(short)) + len = (send - s) / sizeof(short); + while (len-- > 0) { + short tmp; + memcpy(&tmp, s, sizeof(short)); + s += sizeof(short); + Fary_push(ary, INT2FIX(tmp)); + } + break; + + case 'S': + if (len >= (send - s) / sizeof(unsigned short)) + len = (send - s) / sizeof(unsigned short); + while (len-- > 0) { + unsigned short tmp; + memcpy(&tmp, s, sizeof(unsigned short)); + s += sizeof(unsigned short); + Fary_push(ary, INT2FIX(tmp)); + } + break; + + case 'i': + if (len >= (send - s) / sizeof(int)) + len = (send - s) / sizeof(int); + while (len-- > 0) { + int tmp; + memcpy(&tmp, s, sizeof(int)); + s += sizeof(int); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'I': + if (len >= (send - s) / sizeof(unsigned int)) + len = (send - s) / sizeof(unsigned int); + while (len-- > 0) { + unsigned int tmp; + memcpy(&tmp, s, sizeof(unsigned int)); + s += sizeof(unsigned int); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'l': + if (len >= (send - s) / sizeof(long)) + len = (send - s) / sizeof(long); + while (len-- > 0) { + long tmp; + memcpy(&tmp, s, sizeof(long)); + s += sizeof(long); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'L': + if (len >= (send - s) / sizeof(unsigned long)) + len = (send - s) / sizeof(unsigned long); + while (len-- > 0) { + unsigned long tmp; + memcpy(&tmp, s, sizeof(unsigned long)); + s += sizeof(unsigned long); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'n': + if (len >= (send - s) / sizeof(short)) + len = (send - s) / sizeof(short); + while (len-- > 0) { + short tmp; + memcpy(&tmp, s, sizeof(short)); + s += sizeof(short); + tmp = ntohs(tmp); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'N': + if (len >= (send - s) / sizeof(long)) + len = (send - s) / sizeof(long); + while (len-- > 0) { + long tmp; + memcpy(&tmp, s, sizeof(long)); + s += sizeof(long); + tmp = ntohl(tmp); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'F': + case 'f': + if (len >= (send - s) / sizeof(float)) + len = (send - s) / sizeof(float); + while (len-- > 0) { + float tmp; + memcpy(&tmp, s, sizeof(float)); + s += sizeof(float); + Fary_push(ary, float_new((double)tmp)); + } + break; + + case 'D': + case 'd': + if (len >= (send - s) / sizeof(double)) + len = (send - s) / sizeof(double); + while (len-- > 0) { + double tmp; + memcpy(&tmp, s, sizeof(double)); + s += sizeof(double); + Fary_push(ary, float_new(tmp)); + } + break; + + case 'v': + if (len >= (send - s) / sizeof(short)) + len = (send - s) / sizeof(short); + while (len-- > 0) { + short tmp; + memcpy(&tmp, s, sizeof(short)); + s += sizeof(short); + tmp = vtohs(tmp); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'V': + if (len >= (send - s) / sizeof(long)) + len = (send - s) / sizeof(long); + while (len-- > 0) { + long tmp; + memcpy(&tmp, s, sizeof(long)); + s += sizeof(long); + tmp = vtohl(tmp); + Fary_push(ary, int2inum(tmp)); + } + break; + + case 'u': + { + VALUE str = str_new(0, (send - s)*3/4); + char *ptr = RSTRING(str)->ptr; + + while (s < send && *s > ' ' && *s < 'a') { + int a,b,c,d; + char hunk[4]; + + hunk[3] = '\0'; + len = (*s++ - ' ') & 077; + while (len > 0) { + if (s < send && *s >= ' ') + a = (*s++ - ' ') & 077; + else + a = 0; + if (s < send && *s >= ' ') + b = (*s++ - ' ') & 077; + else + b = 0; + if (s < send && *s >= ' ') + c = (*s++ - ' ') & 077; + else + c = 0; + if (s < send && *s >= ' ') + d = (*s++ - ' ') & 077; + else + d = 0; + hunk[0] = a << 2 | b >> 4; + hunk[1] = b << 4 | c >> 2; + hunk[2] = c << 6 | d; + memcpy(ptr, hunk, len > 3 ? 3 : len); + ptr += 3; + len -= 3; + } + if (s[0] == '\n') + s++; + else if (s[1] == '\n') /* possible checksum byte */ + s += 2; + } + Fary_push(ary, str); + } + break; + + case '@': + s = str->ptr + len; + break; + + case 'X': + if (len > s - str->ptr) + Fail("X outside of string"); + s -= len; + break; + + case 'x': + if (len > send - s) + Fail("x outside of string"); + s += len; + break; + + default: + break; + } + } + + GC_UNLINK; + return ary; +} + +Init_pack() +{ + rb_define_method(C_Array, "pack", Fpck_pack, 1); + rb_define_method(C_String, "unpack", Fpck_unpack, 1); +} diff --git a/parse.y b/parse.y new file mode 100644 index 0000000000..0f4f640934 --- /dev/null +++ b/parse.y @@ -0,0 +1,2585 @@ +/************************************************ + + parse.y - + + $Author: matz $ + $Date: 1994/06/27 15:48:34 $ + created at: Fri May 28 18:02:42 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +%{ + +#define YYDEBUG 1 +#include "ruby.h" +#include "env.h" +#include "node.h" +#include "st.h" + +#include "ident.h" +#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_variable_id(id) (is_id_nonop(id)&&((id)&ID_VARMASK)) +#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) + +struct op_tbl { + ID tok; + char *name; +}; + +NODE *eval_tree = Qnil; +static int in_regexp; + +enum { + KEEP_STATE = 0, /* don't change lex_state. */ + EXPR_BEG, /* ignore newline, +/- is a sign. */ + EXPR_MID, /* newline significant, +/- is a sign. */ + EXPR_END, /* +/- is a operator. newline significant */ +}; + +static int lex_state; + +static ID cur_class = Qnil, cur_mid = Qnil; +static int in_module, in_single; + +static void value_expr(); +static NODE *cond(); +static NODE *cond2(); + +static NODE *block_append(); +static NODE *list_append(); +static NODE *list_concat(); +static NODE *list_copy(); +static NODE *call_op(); + +static NODE *asignable(); +static NODE *aryset(); +static NODE *attrset(); + +static void push_local(); +static void pop_local(); +static int local_cnt(); +static int local_id(); +static ID *local_tbl(); + +struct global_entry* rb_global_entry(); + +static void init_top_local(); +static void setup_top_local(); +%} + +%union { + struct node *node; + VALUE val; + ID id; +} + +%token CLASS + MODULE + DEF + FUNC + UNDEF + INCLUDE + IF + THEN + ELSIF + ELSE + CASE + WHEN + UNLESS + UNTIL + WHILE + FOR + IN + DO + USING + PROTECT + RESQUE + ENSURE + END + REDO + BREAK + CONTINUE + RETURN + YIELD + SUPER + RETRY + SELF + NIL + +%token <id> IDENTIFIER GVAR IVAR CONSTANT +%token <val> INTEGER FLOAT STRING REGEXP + +%type <node> singleton inc_list +%type <val> literal numeric +%type <node> compexpr exprs expr expr2 primary var_ref +%type <node> if_tail opt_else cases resque ensure opt_using +%type <node> call_args opt_args args f_arglist f_args f_arg +%type <node> assoc_list assocs assoc +%type <node> mlhs mlhs_head mlhs_tail lhs +%type <id> superclass variable symbol +%type <id> fname fname0 op rest_arg end_mark + +%token UPLUS /* unary+ */ +%token UMINUS /* unary- */ +%token POW /* ** */ +%token CMP /* <=> */ +%token EQ /* == */ +%token NEQ /* != <> */ +%token GEQ /* >= */ +%token LEQ /* <= */ +%token AND OR /* && and || */ +%token MATCH NMATCH /* =~ and !~ */ +%token DOT2 DOT3 /* .. and ... */ +%token AREF ASET /* [] and []= */ +%token LSHFT RSHFT /* << and >> */ +%token COLON2 /* :: */ +%token <id> SELF_ASGN /* +=, -= etc. */ +%token ASSOC /* => */ + +/* + * precedence table + */ + +%left YIELD RETURN +%right '=' SELF_ASGN +%right COLON2 +%nonassoc DOT2 DOT3 +%left OR +%left AND +%left '|' '^' +%left '&' +%nonassoc CMP EQ NEQ MATCH NMATCH +%left '>' GEQ '<' LEQ +%left LSHFT RSHFT +%left '+' '-' +%left '*' '/' '%' +%right POW +%right '!' '~' UPLUS UMINUS + +%token LAST_TOKEN + +%% +program : { + lex_state = EXPR_BEG; + init_top_local(); + } + compexpr + { + eval_tree = block_append(eval_tree, $2); + setup_top_local(); + } + +compexpr : exprs opt_term + +exprs : /* none */ + { + $$ = Qnil; + } + | expr + | exprs term expr + { + $$ = block_append($1, $3); + } + | exprs error expr + { + yyerrok; + $$ = $1; + } + +expr : CLASS IDENTIFIER superclass + { + if (cur_class || cur_mid || in_single) + Error("nested class definition"); + cur_class = $2; + push_local(); + } + compexpr + END end_mark + { + if ($7 && $7 != CLASS) { + Error("unmatched end keyword(expected `class')"); + } + $$ = NEW_CLASS($2, $5, $3); + pop_local(); + cur_class = Qnil; + } + | MODULE IDENTIFIER + { + if (cur_class != Qnil) + Error("nested module definition"); + cur_class = $2; + in_module = 1; + push_local(); + } + compexpr + END end_mark + { + if ($6 && $6 != MODULE) { + Error("unmatched end keyword(expected `module')"); + } + $$ = NEW_MODULE($2, $4); + pop_local(); + cur_class = Qnil; + in_module = 0; + } + | DEF fname + { + if (cur_mid || in_single) + Error("nested method definition"); + cur_mid = $2; + push_local(); + } + f_arglist compexpr + END end_mark + { + if ($7 && $7 != DEF) { + Error("unmatched end keyword(expected `def')"); + } + $$ = NEW_DEFN($2, NEW_RFUNC($4, $5), MTH_METHOD); + pop_local(); + cur_mid = Qnil; + } + | DEF FUNC fname + { + if (cur_mid || in_single) + Error("nested method definition"); + cur_mid = $3; + push_local(); + } + f_arglist compexpr + END end_mark + { + if ($8 && $8 != DEF) { + Error("unmatched end keyword(expected `def')"); + } + $$ = NEW_DEFN($3, NEW_RFUNC($5, $6), MTH_FUNC); + pop_local(); + cur_mid = Qnil; + } + | DEF singleton '.' fname + { + value_expr($2); + in_single++; + push_local(); + } + f_arglist + compexpr + END end_mark + { + if ($9 && $9 != DEF) { + Error("unmatched end keyword(expected `def')"); + } + $$ = NEW_DEFS($2, $4, NEW_RFUNC($6, $7)); + pop_local(); + in_single--; + } + | UNDEF fname + { + $$ = NEW_UNDEF($2); + } + | DEF fname fname + { + $$ = NEW_ALIAS($2, $3); + } + | INCLUDE inc_list + { + if (cur_mid || in_single) + Error("include appeared in method definition"); + $$ = $2; + } + | mlhs '=' args + { + NODE *rhs; + + if ($3->nd_next == Qnil) { + rhs = $3->nd_head; + free($3); + } + else { + rhs = $3; + } + + $$ = NEW_MASGN($1, rhs); + } + | expr2 + + +mlhs : mlhs_head + | mlhs_head mlhs_tail + { + $$ = list_concat($1, $2); + } + +mlhs_head : variable comma + { + $$ = NEW_LIST(asignable($1, Qnil)); + } + | primary '[' args rbracket comma + { + $$ = NEW_LIST(aryset($1, $3, Qnil)); + } + | primary '.' IDENTIFIER comma + { + $$ = NEW_LIST(attrset($1, $3, Qnil)); + } + +mlhs_tail : lhs + { + $$ = NEW_LIST($1); + } + | mlhs_tail comma lhs + { + $$ = list_append($1, $3); + } + +lhs : variable + { + $$ = asignable($1, Qnil); + } + | primary '[' args rbracket + { + $$ = aryset($1, $3, Qnil); + } + | primary '.' IDENTIFIER + { + $$ = attrset($1, $3, Qnil); + } + +superclass : /* none */ + { + $$ = Qnil; + } + | ':' IDENTIFIER + { + $$ = $2; + } + +inc_list : IDENTIFIER + { + $$ = NEW_INC($1); + } + | inc_list comma IDENTIFIER + { + $$ = block_append($1, NEW_INC($3)); + } + | error + { + $$ = Qnil; + } + | inc_list comma error + +fname : fname0 + | IVAR + +fname0 : IDENTIFIER + | IDENTIFIER '=' + { + ID id = $1; + + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + $$ = id; + } + | op + +op : COLON2 { $$ = COLON2; } + | DOT2 { $$ = DOT2; } + | '|' { $$ = '|'; } + | '^' { $$ = '^'; } + | '&' { $$ = '&'; } + | CMP { $$ = CMP; } + | EQ { $$ = EQ; } + | NEQ { $$ = NEQ; } + | MATCH { $$ = MATCH; } + | NMATCH { $$ = NMATCH; } + | '>' { $$ = '>'; } + | GEQ { $$ = GEQ; } + | '<' { $$ = '<'; } + | LEQ { $$ = LEQ; } + | LSHFT { $$ = LSHFT; } + | RSHFT { $$ = RSHFT; } + | '+' { $$ = '+'; } + | '-' { $$ = '-'; } + | '*' { $$ = '*'; } + | '/' { $$ = '/'; } + | '%' { $$ = '%'; } + | POW { $$ = POW; } + | '!' { $$ = '!'; } + | '~' { $$ = '~'; } + | '!' '@' { $$ = '!'; } + | '~' '@' { $$ = '~'; } + | '-' '@' { $$ = UMINUS; } + | '+' '@' { $$ = UPLUS; } + | '[' ']' { $$ = AREF; } + | '[' ']' '=' { $$ = ASET; } + +f_arglist : '(' f_args rparen + { + $$ = $2; + } + | term + { + $$ = Qnil; + } + +f_args : /* no arg */ + { + $$ = Qnil; + } + | f_arg + { + $$ = NEW_ARGS($1, -1); + } + | f_arg comma rest_arg + { + $$ = NEW_ARGS($1, $3); + } + | rest_arg + { + $$ = NEW_ARGS(Qnil, $1); + } + | f_arg error + { + $$ = NEW_ARGS($1, -1); + } + | error + { + $$ = Qnil; + } + +f_arg : IDENTIFIER + { + if (!is_local_id($1)) + Error("formal argument must be local variable"); + $$ = NEW_LIST(local_cnt($1)); + } + | f_arg comma IDENTIFIER + { + if (!is_local_id($3)) + Error("formal argument must be local variable"); + $$ = list_append($1, local_cnt($3)); + } + +rest_arg : '*' IDENTIFIER + { + if (!is_local_id($2)) + Error("rest argument must be local variable"); + $$ = local_cnt($2); + } + +singleton : var_ref + { + if ($1->type == NODE_SELF) { + $$ = NEW_SELF(); + } + else if ($1->type == NODE_NIL) { + Error("Can't define single method for nil."); + freenode($1); + $$ = Qnil; + } + else { + $$ = $1; + } + } + | '(' compexpr rparen + { + switch ($2->type) { + case NODE_STR: + case NODE_LIT: + case NODE_ARRAY: + case NODE_ZARRAY: + Error("Can't define single method for literals."); + default: + break; + } + $$ = $2; + } + +expr2 : IF expr2 then + compexpr + if_tail + END end_mark + { + if ($7 && $7 != IF) { + Error("unmatched end keyword(expected `if')"); + } + $$ = NEW_IF(cond($2), $4, $5); + } + | UNLESS expr2 then + compexpr opt_else END end_mark + { + if ($7 && $7 != UNLESS) { + Error("unmatched end keyword(expected `if')"); + } + $$ = NEW_UNLESS(cond($2), $4, $5); + } + | CASE expr2 opt_term + cases + END end_mark + { + if ($6 && $6 != CASE) { + Error("unmatched end keyword(expected `case')"); + } + value_expr($2); + $$ = NEW_CASE($2, $4); + } + | WHILE expr2 term compexpr END end_mark + { + if ($6 && $6 != WHILE) { + Error("unmatched end keyword(expected `while')"); + } + $$ = NEW_WHILE(cond($2), $4); + } + | UNTIL expr2 term compexpr END end_mark + { + if ($6 && $6 != UNTIL) { + Error("unmatched end keyword(expected `until')"); + } + $$ = NEW_UNTIL(cond($2), $4); + } + | FOR lhs IN expr2 term + compexpr + END end_mark + { + if ($8 && $8 != FOR) { + Error("unmatched end keyword(expected `for')"); + } + value_expr($4); + $$ = NEW_FOR($2, $4, $6); + } + | DO expr2 opt_using + compexpr + END end_mark + { + if ($6 && $6 != DO) { + Error("unmatched end keyword(expected `do')"); + } + value_expr($2); + $$ = NEW_DO($3, $2, $4); + } + | PROTECT + compexpr + resque + ensure + END end_mark + { + if ($6 && $6 != PROTECT) { + Error("unmatched end keyword(expected `protect')"); + } + if ($3 == Qnil && $4 == Qnil) { + Warning("useless protect clause"); + $$ = $2; + } + else { + $$ = NEW_PROT($2, $3, $4); + } + } + | REDO + { + $$ = NEW_REDO(); + } + | BREAK + { + $$ = NEW_BREAK(); + } + | CONTINUE + { + $$ = NEW_CONT(); + } + | RETRY + { + $$ = NEW_RETRY(); + } + | RETURN expr2 + { + value_expr($2); + if (!cur_mid && !in_single) + Error("return appeared outside of method"); + $$ = NEW_RET($2); + } + | RETURN + { + if (!cur_mid && !in_single) + Error("return appeared outside of method"); + $$ = NEW_RET(Qnil); + } + | variable '=' expr2 + { + value_expr($3); + $$ = asignable($1, $3); + } + | primary '[' args rbracket '=' expr2 + { + value_expr($6); + $$ = aryset($1, $3, $6); + } + | primary '.' IDENTIFIER '=' expr2 + { + value_expr($5); + $$ = attrset($1, $3, $5); + } + | variable SELF_ASGN expr2 + { + NODE *val; + + value_expr($3); + if (is_local_id($1)) { + val = NEW_LVAR($1); + } + else if (is_global_id($1)) { + val = NEW_GVAR($1); + } + else if (is_instance_id($1)) { + val = NEW_IVAR($1); + } + else { + val = NEW_CVAR($1); + } + $$ = asignable($1, call_op(val, $2, 1, $3)); + } + | primary '[' args rbracket SELF_ASGN expr2 + { + NODE *rval, *args; + value_expr($1); + value_expr($6); + + args = list_copy($3); + rval = NEW_CALL2($1, AREF, args); + + args = list_append($3, call_op(rval, $5, 1, $6)); + $$ = NEW_CALL($1, ASET, args); + } + | primary '.' IDENTIFIER SELF_ASGN expr2 + { + ID id = $3; + NODE *rval; + + value_expr($1); + value_expr($5); + + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + + rval = call_op(NEW_CALL2($1, $3, Qnil), $4, 1, $5); + $$ = NEW_CALL($1, id, NEW_LIST(rval)); + } + | YIELD expr2 + { + value_expr($2); + $$ = NEW_YIELD($2); + } + | expr2 DOT2 expr2 + { + $$ = call_op($1, DOT2, 1, $3); + } + | expr2 DOT3 expr2 + { + $$ = NEW_DOT3(cond2($1), cond2($3)); + } + | expr2 '+' expr2 + { + $$ = call_op($1, '+', 1, $3); + } + | expr2 '-' expr2 + { + $$ = call_op($1, '-', 1, $3); + } + | expr2 '*' expr2 + { + $$ = call_op($1, '*', 1, $3); + } + | expr2 '/' expr2 + { + $$ = call_op($1, '/', 1, $3); + } + | expr2 '%' expr2 + { + $$ = call_op($1, '%', 1, $3); + } + | expr2 POW expr2 + { + $$ = call_op($1, POW, 1, $3); + } + | '+' expr2 %prec UPLUS + { + $$ = call_op($2, UPLUS, 0); + + } + | '-' expr2 %prec UMINUS + { + $$ = call_op($2, UMINUS, 0); + } + | expr2 '|' expr2 + { + $$ = call_op($1, '|', 1, $3); + } + | expr2 '^' expr2 + { + $$ = call_op($1, '^', 1, $3); + } + | expr2 '&' expr2 + { + $$ = call_op($1, '&', 1, $3); + } + | expr2 CMP expr2 + { + $$ = call_op($1, CMP, 1, $3); + } + | expr2 '>' expr2 + { + $$ = call_op($1, '>', 1, $3); + } + | expr2 GEQ expr2 + { + $$ = call_op($1, GEQ, 1, $3); + } + | expr2 '<' expr2 + { + $$ = call_op($1, '<', 1, $3); + } + | expr2 LEQ expr2 + { + $$ = call_op($1, LEQ, 1, $3); + } + | expr2 EQ expr2 + { + $$ = call_op($1, EQ, 1, $3); + } + | expr2 NEQ expr2 + { + $$ = call_op($1, NEQ, 1, $3); + } + | expr2 MATCH expr2 + { + $$ = call_op($1, MATCH, 1, $3); + } + | expr2 NMATCH expr2 + { + $$ = call_op($1, NMATCH, 1, $3); + } + | '!' expr2 + { + $$ = call_op(cond($2), '!', 0); + } + | '~' expr2 + { + $$ = call_op($2, '~', 0); + } + | expr2 LSHFT expr2 + { + $$ = call_op($1, LSHFT, 1, $3); + } + | expr2 RSHFT expr2 + { + $$ = call_op($1, RSHFT, 1, $3); + } + | expr2 COLON2 expr2 + { + $$ = call_op($1, COLON2, 1, $3); + } + | expr2 AND expr2 + { + $$ = NEW_AND(cond($1), cond($3)); + } + | expr2 OR expr2 + { + $$ = NEW_OR(cond($1), cond($3)); + } + |primary + { + $$ = $1; + } + +then : term + | THEN + | term THEN + +if_tail : opt_else + | ELSIF expr2 then + compexpr + if_tail + { + $$ = NEW_IF(cond($2), $4, $5); + } + +opt_else : /* none */ + { + $$ = Qnil; + } + | ELSE compexpr + { + $$ = $2; + } + +opt_using : term + { + $$ = Qnil; + } + | opt_term USING lhs term + { + $$ = $3; + } + +cases : opt_else + | WHEN args term + compexpr + cases + { + $$ = NEW_WHEN($2, $4, $5); + } + +resque : /* none */ + { + $$ = Qnil; + } + | RESQUE compexpr + { + if ($2 == Qnil) + $$ = (NODE*)1; + else + $$ = $2; + } + +ensure : /* none */ + { + $$ = Qnil; + } + | ENSURE compexpr + { + $$ = $2; + } + +call_args : /* none */ + { + $$ = Qnil; + } + | args + | '*' exprs + { + $$ = $2; + } + | args comma '*' exprs + { + $$ = call_op($1, '+', 1, $4); + } + +opt_args : /* none */ + { + $$ = Qnil; + } + | args + +args : expr2 + { + value_expr($1); + $$ = NEW_LIST($1); + } + | args comma expr2 + { + value_expr($3); + $$ = list_append($1, $3); + } + +primary : var_ref + | '(' compexpr rparen + { + $$ = $2; + } + + | STRING + { + literalize($1); + $$ = NEW_STR($1); + } + | primary '[' args rbracket + { + value_expr($1); + $$ = NEW_CALL($1, AREF, $3); + } + | literal + { + literalize($1); + $$ = NEW_LIT($1); + } + | '[' opt_args rbracket + { + if ($2 == Qnil) + $$ = NEW_ZARRAY(); /* zero length array*/ + else { + $$ = $2; + } + } + | lbrace assoc_list rbrace + { + $$ = NEW_HASH($2); + } + | primary '.' IDENTIFIER '(' call_args rparen + { + value_expr($1); + $$ = NEW_CALL($1, $3, $5); + } + | primary '.' IDENTIFIER + { + value_expr($1); + $$ = NEW_CALL($1, $3, Qnil); + } + | IDENTIFIER '(' call_args rparen + { + $$ = NEW_CALL(Qnil, $1, $3); + } + | IVAR '(' call_args rparen + { + $$ = NEW_CALL(Qnil, $1, $3); + } + | SUPER '(' call_args rparen + { + if (!cur_mid && !in_single) + Error("super called outside of method"); + $$ = NEW_SUPER($3); + } + | SUPER + { + if (!cur_mid && !in_single) + Error("super called outside of method"); + $$ = NEW_ZSUPER(); + } + +literal : numeric + | '\\' symbol + { + $$ = INT2FIX($2); + } + | '/' {in_regexp = 1;} REGEXP + { + $$ = $3; + } + +symbol : fname0 + | IVAR + | GVAR + | CONSTANT + +numeric : INTEGER + | FLOAT + +variable : IDENTIFIER + | IVAR + | GVAR + | CONSTANT + | NIL + { + $$ = NIL; + } + | SELF + { + $$ = SELF; + } + +var_ref : variable + { + if ($1 == SELF) { + $$ = NEW_SELF(); + } + else if ($1 == NIL) { + $$ = NEW_NIL(); + } + else if (is_local_id($1)) { + if (local_id($1)) + $$ = NEW_LVAR($1); + else + $$ = NEW_MVAR($1); + } + else if (is_global_id($1)) { + $$ = NEW_GVAR($1); + } + else if (is_instance_id($1)) { + $$ = NEW_IVAR($1); + } + else if (is_const_id($1)) { + $$ = NEW_CVAR($1); + } + } + +assoc_list : /* none */ + { + $$ = Qnil; + } + | assocs + +assocs : assoc + | assocs comma assoc + { + $$ = list_concat($1, $3); + } + +assoc : expr2 ASSOC expr2 + { + $$ = NEW_LIST($1); + $$ = list_append($$, $3); + } + +end_mark : CLASS { $$ = CLASS; } + | MODULE { $$ = MODULE; } + | DEF { $$ = DEF; } + | FUNC { $$ = FUNC; } + | IF { $$ = IF; } + | UNLESS { $$ = UNLESS; } + | CASE { $$ = CASE; } + | WHILE { $$ = WHILE; } + | UNTIL { $$ = UNTIL; } + | FOR { $$ = FOR; } + | DO { $$ = DO; } + | PROTECT { $$ = PROTECT; } + | { $$ = Qnil;} + +opt_term : /* none */ + | term + +term : sc + | nl + +sc : ';' { yyerrok; } +nl : '\n' { yyerrok; } + +rparen : ')' { yyerrok; } +rbracket : ']' { yyerrok; } +lbrace : '{' { yyerrok; } +rbrace : '}' { yyerrok; } +comma : ',' { yyerrok; } +%% + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include "regex.h" + +#define is_identchar(c) ((c)!=-1&&(isalnum(c) || (c) == '_' || ismbchar(c))) + +static char *tokenbuf = NULL; +static int tokidx, toksiz = 0; + +char *xmalloc(); +char *xrealloc(); +VALUE newregexp(); +VALUE newstring(); +VALUE newfloat(); +VALUE newinteger(); +char *strdup(); + +#define EXPAND_B 1 +#define LEAVE_BS 2 + +static void read_escape(); + +char *sourcefile; /* current source file */ +int sourceline; /* current line no. */ + +static char *lex_p; +static int lex_len; + +lex_setsrc(src, ptr, len) + char *src; + char *ptr; + int len; +{ + sourcefile = (char*)strdup(src); + + sourceline = 1; + lex_p = ptr; + lex_len = len; +} + +#define nextc() ((--lex_len>=0)?(*lex_p++):-1) +#define pushback() (lex_len++, lex_p--) + +#define tokfix() (tokenbuf[tokidx]='\0') +#define tok() tokenbuf +#define toklen() tokidx +#define toknow() &toknbuf[tokidx] + +char * +newtok() +{ + tokidx = 0; + if (!tokenbuf) { + toksiz = 60; + tokenbuf = ALLOC_N(char, 60); + } + if (toksiz > 1024) { + REALLOC_N(tokenbuf, char, 60); + } + return tokenbuf; +} + +void +tokadd(c) + char c; +{ + if (tokidx >= toksiz) { + toksiz *= 2; + REALLOC_N(tokenbuf, char, toksiz); + } + tokenbuf[tokidx++] = c; +} + +#define LAST(v) ((v)-1 + sizeof(v)/sizeof(v[0])) + +static struct kwtable { + char *name; + int id; + int state; +} kwtable [] = { + "__END__", 0, KEEP_STATE, + "break", BREAK, EXPR_END, + "case", CASE, KEEP_STATE, + "class", CLASS, KEEP_STATE, + "continue", CONTINUE, EXPR_END, + "def", DEF, KEEP_STATE, + "do", DO, KEEP_STATE, + "else", ELSE, EXPR_BEG, + "elsif", ELSIF, EXPR_BEG, + "end", END, EXPR_END, + "ensure", ENSURE, EXPR_BEG, + "for", FOR, KEEP_STATE, + "func", FUNC, KEEP_STATE, + "if", IF, KEEP_STATE, + "in", IN, EXPR_BEG, + "include", INCLUDE, EXPR_BEG, + "module", MODULE, KEEP_STATE, + "nil", NIL, EXPR_END, + "protect", PROTECT, KEEP_STATE, + "redo", REDO, EXPR_END, + "resque", RESQUE, EXPR_BEG, + "retry", RETRY, EXPR_END, + "return", RETURN, EXPR_MID, + "self", SELF, EXPR_END, + "super", SUPER, EXPR_END, + "then", THEN, EXPR_BEG, + "undef", UNDEF, EXPR_BEG, + "unless", UNLESS, EXPR_BEG, + "until", UNTIL, EXPR_BEG, + "using", USING, KEEP_STATE, + "when", WHEN, EXPR_BEG, + "while", WHILE, KEEP_STATE, + "yield", YIELD, EXPR_BEG, +}; + +yylex() +{ + register int c; + struct kwtable *low = kwtable, *mid, *high = LAST(kwtable); + int last; + + if (in_regexp) { + int in_brack = 0; + int re_start = sourceline; + + in_regexp = 0; + newtok(); + while (c = nextc()) { + switch (c) { + case '[': + in_brack = 1; + break; + case ']': + in_brack = 0; + break; + case '\\': + if ((c = nextc()) == -1) { + sourceline = re_start; + Error("unterminated regexp meets end of file"); + return 0; + } + else if (c == '\n') { + sourceline++; + } + else if (in_brack && c == 'b') { + tokadd('\b'); + } + else { + pushback(); + read_escape(LEAVE_BS); + } + continue; + + case '/': /* end of the regexp */ + if (in_brack) + break; + + tokfix(); + yylval.val = regexp_new(tok(), toklen()); + lex_state = EXPR_END; + return REGEXP; + + case -1: + Error("unterminated regexp"); + return 0; + + default: + if (ismbchar(c)) { + tokadd(c); + c = nextc(); + } + break; + } + tokadd(c); + } + } + +retry: + switch (c = nextc()) { + case '\0': + case '\004': + case '\032': + case -1: /* end of script. */ + return 0; + + /* white spaces */ + case ' ': case '\t': case '\f': case '\r': + goto retry; + + case '#': /* it's a comment */ + while ((c = nextc()) != '\n') { + if (c == -1) + return 0; + } + /* fall through */ + case '\n': + sourceline++; + if (lex_state == EXPR_BEG) goto retry; + lex_state = EXPR_BEG; + return '\n'; + + case '*': + lex_state = EXPR_BEG; + if ((c = nextc()) == '*') { + if (nextc() == '=') { + yylval.id = POW; + return SELF_ASGN; + } + pushback(); + return POW; + } + else if (c == '=') { + yylval.id = '*'; + return SELF_ASGN; + } + pushback(); + return '*'; + + case '!': + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + return NEQ; + } + if (c == '~') { + return NMATCH; + } + pushback(); + return '!'; + + case '=': + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + return EQ; + } + if (c == '~') { + return MATCH; + } + else if (c == '>') { + return ASSOC; + } + pushback(); + return '='; + + case '<': + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + if ((c = nextc()) == '>') { + return CMP; + } + pushback(); + return LEQ; + } + if (c == '<') { + if (nextc() == '=') { + yylval.id = LSHFT; + return SELF_ASGN; + } + pushback(); + return LSHFT; + } + pushback(); + return '<'; + + case '>': + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + return GEQ; + } + if (c == '>') { + if (nextc() == '=') { + yylval.id = RSHFT; + return SELF_ASGN; + } + pushback(); + return RSHFT; + } + pushback(); + return '>'; + + case '"': + { + int strstart = sourceline; + + newtok(); + while ((c = nextc()) != '"') { + if (c == -1) { + sourceline = strstart; + Error("unterminated string meets end of file"); + return 0; + } + if (ismbchar(c)) { + tokadd(c); + c = nextc(); + } + else if (c == '\n') { + sourceline++; + } + else if (c == '\\') { + c = nextc(); + if (c == '\n') { + sourceline++; + } + else if (c == '"') { + tokadd(c); + } + else { + pushback(); + read_escape(LEAVE_BS | EXPAND_B); + } + continue; + } + tokadd(c); + } + tokfix(); + yylval.val = str_new(tok(), toklen()); + lex_state = EXPR_END; + return STRING; + } + + case '\'': + { + int strstart = sourceline; + + newtok(); + while ((c = nextc()) != '\'') { + if (c == -1) { + sourceline = strstart; + Error("unterminated string meets end of file"); + return 0; + } + if (ismbchar(c)) { + tokadd(c); + c = nextc(); + } + else if (c == '\n') { + sourceline++; + } + else if (c == '\\') { + c = nextc(); + switch (c) { + case '\n': + sourceline++; + continue; + + case '\'': + c = '\''; + break; + case '\\': + c = '\\'; + break; + + default: + tokadd('\\'); + } + } + tokadd(c); + } + tokfix(); + yylval.val = str_new(tok(), toklen()); + lex_state = EXPR_END; + return STRING; + } + + case '?': + if ((c = nextc()) == '\\') { + newtok(); + read_escape(EXPAND_B); + c = tok()[0]; + } + c &= 0xff; + yylval.val = INT2FIX(c); + lex_state = EXPR_END; + return INTEGER; + + case '&': + lex_state = EXPR_BEG; + if ((c = nextc()) == '&') { + return AND; + } + else if (c == '=') { + yylval.id = '&'; + return SELF_ASGN; + } + pushback(); + return '&'; + + case '|': + lex_state = EXPR_BEG; + if ((c = nextc()) == '|') { + return OR; + } + else if (c == '=') { + yylval.id = '|'; + return SELF_ASGN; + } + pushback(); + return '|'; + + case '+': + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + c = nextc(); + pushback(); + if (isdigit(c)) { + goto start_num; + } + } + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + yylval.id = '+'; + return SELF_ASGN; + } + pushback(); + return '+'; + + case '-': + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + c = nextc(); + pushback(); + if (isdigit(c)) { + c = '-'; + goto start_num; + } + } + lex_state = EXPR_BEG; + if ((c = nextc()) == '=') { + yylval.id = '-'; + return SELF_ASGN; + } + pushback(); + return '-'; + + case '.': + if ((c = nextc()) == '.') { + if ((c = nextc()) == '.') { + return DOT3; + } + pushback(); + lex_state = EXPR_BEG; + return DOT2; + } + pushback(); + if (!isdigit(c)) { + lex_state = EXPR_BEG; + return '.'; + } + c = '.'; + /* fall through */ + + start_num: + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int is_float, seen_point, seen_e; + + lex_state = EXPR_END; + newtok(); + if (c == '0') { + c = nextc(); + if (c == 'x' || c == 'X') { + /* hexadecimal */ + while (c = nextc()) { + if (!isxdigit(c)) break; + tokadd(c); + } + pushback(); + tokfix(); + yylval.val = str2inum(tok(), 16); + return INTEGER; + } + else if (c >= '0' && c <= '9') { + /* octal */ + do { + tokadd(c); + c = nextc(); + } while (c >= '0' && c <= '9'); + pushback(); + tokfix(); +#if 0 + yylval.val = INT2FIX(strtoul(tok(), Qnil, 8)); +#else + yylval.val = str2inum(tok(), 8); +#endif + return INTEGER; + } + } + if (c == '-' || c == '+') { + tokadd(c); + c = nextc(); + } + + is_float = seen_point = seen_e = 0; + + for (;;) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + tokadd(c); + break; + + case '.': + if (seen_point) { + goto decode_num; + } + c = nextc(); + if (!isdigit(c)) { + pushback(); + goto decode_num; + } + tokadd('.'); + tokadd(c); + is_float++; + seen_point++; + break; + + case 'e': + case 'E': + if (seen_e) { + goto decode_num; + } + tokadd(c); + seen_e++; + is_float++; + if ((c = nextc()) == '-' || c == '+') + tokadd(c); + else + continue; + break; + + case '_': /* `_' in decimal just ignored */ + break; + + default: + goto decode_num; + } + c = nextc(); + } + + decode_num: + pushback(); + tokfix(); + if (is_float) { + double atof(); + + yylval.val = float_new(atof(tok())); + return FLOAT; + } + yylval.val = str2inum(tok(), 10); + return INTEGER; + } + + case ']': + case '}': + case ')': + lex_state = EXPR_END; + return c; + + case ':': + lex_state = EXPR_BEG; + if (nextc() == ':') { + return COLON2; + } + pushback(); + return ':'; + + case '/': + lex_state = EXPR_BEG; + if (nextc() == '=') { + yylval.id = '/'; + return SELF_ASGN; + } + pushback(); + return c; + + case '^': + lex_state = EXPR_BEG; + if (nextc() == '=') { + yylval.id = '^'; + return SELF_ASGN; + } + pushback(); + return c; + + case ',': + case ';': + case '`': + case '[': + case '(': + case '{': + case '~': + lex_state = EXPR_BEG; + return c; + + case '\\': + c = nextc(); + if (c == '\n') goto retry; /* skip \\n */ + lex_state = EXPR_BEG; + pushback(); + return '\\'; + + case '%': + if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { + /* class constant */ + newtok(); + tokadd('%'); + c = nextc(); + break; + } + else { + lex_state = EXPR_BEG; + if (nextc() == '=') { + yylval.id = '%'; + return SELF_ASGN; + } + pushback(); + return c; + } + + case '$': + newtok(); + tokadd(c); + c = nextc(); + switch (c) { + case '*': /* $*: argv */ + case '$': /* $$: pid */ + case '?': /* $?: last status */ + case '!': /* $!: error string */ + case '@': /* $@: error position */ + case '/': /* $/: input record separator */ + case '\\': /* $\: output record separator */ + case ',': /* $,: output field separator */ + case '.': /* $.: last read line number */ + case '_': /* $_: last read line string */ + case '&': /* $&: last match */ + case '~': /* $~: match-data */ + case '=': /* $=: ignorecase */ + tokadd(c); + tokadd('\0'); + goto id_fetch; + + default: + if (is_identchar(c)) + break; + pushback(); + return tok()[0]; + } + break; + + case '@': + c = nextc(); + if (!is_identchar(c)) { + pushback(); + return '@'; + } + newtok(); + tokadd('@'); + break; + + default: + if (c != '_' && !isalpha(c) && !ismbchar(c)) { + Error("Invalid char '%c' in expression", c); + goto retry; + } + + newtok(); + break; + } + + while (is_identchar(c)) { + tokadd(c); + if (ismbchar(c)) { + c = nextc(); + tokadd(c); + } + c = nextc(); + } + pushback(); + tokfix(); + + /* See if it is a reserved word. */ + while (low <= high) { + mid = low + (high - low)/2; + if (( c = strcmp(mid->name, tok())) == 0) { + if (mid->state != KEEP_STATE) { + lex_state = mid->state; + } + return mid->id; + } + else if (c < 0) { + low = mid + 1; + } + else { + high = mid - 1; + } + } + + id_fetch: + lex_state = EXPR_END; + yylval.id = rb_intern(tok()); + switch (tok()[0]) { + case '%': + return CONSTANT; + case '$': + return GVAR; + case '@': + return IVAR; + default: + return IDENTIFIER; + } +} + +static void +read_escape(flag) + int flag; +{ + char c; + + switch (c = nextc()) { + case '\\': /* Backslash */ + tokadd('\\'); + break; + + case 'n': /* newline */ + tokadd('\n'); + break; + + case 't': /* horizontal tab */ + tokadd('\t'); + break; + + case 'r': /* carriage-return */ + tokadd('\r'); + break; + + case 'f': /* form-feed */ + tokadd('\r'); + break; + + case 'v': /* vertical tab */ + tokadd('\13'); + break; + + case 'a': + tokadd('\a'); + break; + + case 'e': /* escape */ + tokadd(033); + break; + + case 'M': + if ((c = nextc()) != '-') { + Error("Invalid escape character syntax"); + tokadd('\0'); + return; + } + if ((c = nextc()) == '\\') { + read_escape(flag); + tokenbuf[tokidx-1] |= 0200; /* kludge */ + } + else { + tokadd((c & 0xff) | 0200); + } + break; + + case 'C': + if ((c = nextc()) != '-') { + Error("Invalid escape character syntax"); + tokadd('\0'); + return; + } + case '^': + if ((c = nextc())== '\\') { + read_escape (flag); + tokenbuf[tokidx-1] &= 0237; /* kludge */ + } + else if (c == '?') + tokadd(0177); + else + tokadd(c & 0237); + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + { /* octal constant */ + register int i = c - '0'; + register int count = 0; + + while (++count < 3) { + if ((c = nextc()) >= '0' && c <= '7') { + i *= 8; + i += c - '0'; + } + else { + pushback(); + break; + } + } + tokadd(i&0xff); + } + break; + + case 'x': /* hex constant */ + { + register int i = c - '0'; + register int count = 0; + + while (++count < 2) { + c = nextc(); + if ((c = nextc()) >= '0' && c <= '9') { + i *= 16; + i += c - '0'; + } + else if ((int)index("abcdefABCDEF", (c = nextc()))) { + i *= 16; + i += toupper(c) - 'A' + 10; + } + else { + pushback(); + break; + } + } + tokadd(i&0xff); + } + break; + + case 'b': /* backspace */ + if (flag & EXPAND_B) { + tokadd('\b'); + return; + } + /* go turough */ + default: + if (flag & LEAVE_BS) { + tokadd('\\'); + } + tokadd(c); + break; + } +} + +NODE* +newnode(type, a0, a1, a2) + enum node_type type; + NODE *a0, *a1, *a2; +{ + NODE *n = ALLOC(NODE); + + n->type = type; + n->line = sourceline; + n->src = sourcefile; + + n->u1.node = a0; + n->u2.node = a1; + n->u3.node = a2; + + return n; +} + +static NODE* +block_append(head, tail) + NODE *head, *tail; +{ + extern int verbose; + + if (tail == Qnil) return head; + if (head == Qnil) return tail; + + if (head->type != NODE_BLOCK) + head = NEW_BLOCK(head); + + if (head->nd_last == Qnil) head->nd_last = head; + + if (verbose) { + switch (head->nd_last->nd_head->type) { + case NODE_BREAK: + case NODE_CONTINUE: + case NODE_REDO: + case NODE_RETURN: + case NODE_RETRY: + Warning("statement not reached"); + break; + + default: + break; + } + } + + if (tail->type == NODE_BLOCK) { + head->nd_last->nd_next = tail; + head->nd_last = tail->nd_last; + } + else { + head->nd_last->nd_next = NEW_BLOCK(tail); + head->nd_last = head->nd_last->nd_next; + } + return head; +} + +static NODE* +list_append(head, tail) + NODE *head, *tail; +{ + if (head == Qnil) return NEW_ARRAY(tail); + + if (head->nd_last == Qnil) head->nd_last = head; + + head->nd_last->nd_next = NEW_ARRAY(tail); + head->nd_last = head->nd_last->nd_next; + return head; +} + +static NODE* +list_concat(head, tail) + NODE *head, *tail; +{ + NODE *last; + + if (head->type != NODE_ARRAY || tail->type != NODE_ARRAY) + Bug("list_concat() called with non-list"); + + last = (head->nd_last)?head->nd_last:head; + last->nd_next = tail; + head->nd_last = tail->nd_last; + + return head; +} + +static NODE* +list_copy(list) + NODE *list; +{ + NODE *tmp; + + if (list == Qnil) return Qnil; + + tmp = Qnil; + while(list) { + tmp = list_append(tmp, list->nd_head); + list = list->nd_next; + } + return tmp; +} + +void freenode(node) + NODE *node; +{ + if (node == Qnil) return; + + switch (node->type) { + case NODE_BLOCK: + case NODE_ARRAY: + freenode(node->nd_head); + freenode(node->nd_next); + break; + case NODE_IF: + case NODE_WHEN: + case NODE_PROT: + freenode(node->nd_cond); + freenode(node->nd_body); + freenode(node->nd_else); + break; + case NODE_CASE: + case NODE_WHILE: + case NODE_UNTIL: + case NODE_AND: + case NODE_OR: + freenode(node->nd_head); + freenode(node->nd_body); + break; + case NODE_DO: + case NODE_FOR: + freenode(node->nd_ibdy); + freenode(node->nd_iter); + break; + case NODE_LASGN: + case NODE_GASGN: + case NODE_IASGN: + freenode(node->nd_value); + break; + case NODE_CALL: + case NODE_SUPER: + freenode(node->nd_recv); + case NODE_CALL2: + freenode(node->nd_args); + break; + case NODE_DEFS: + freenode(node->nd_recv); + break; + case NODE_RETURN: + case NODE_YIELD: + freenode(node->nd_stts); + break; + case NODE_STR: + case NODE_LIT: + unliteralize(node->nd_lit); + break; + case NODE_CONST: + unliteralize(node->nd_cval); + break; + case NODE_ARGS: + freenode(node->nd_frml); + break; + case NODE_SCOPE: + free(node->nd_tbl); + freenode(node->nd_body); + break; + case NODE_DEFN: + case NODE_ZARRAY: + case NODE_CFUNC: + case NODE_BREAK: + case NODE_CONTINUE: + case NODE_RETRY: + case NODE_LVAR: + case NODE_GVAR: + case NODE_IVAR: + case NODE_MVAR: + case NODE_CLASS: + case NODE_MODULE: + case NODE_INC: + case NODE_NIL: + break; + default: + Bug("freenode: unknown node type %d", node->type); + break; + } + free(node); +} + +struct call_arg { + ID id; + VALUE recv; + int narg; + VALUE arg; +}; + +static VALUE +call_lit(arg) + struct call_arg *arg; +{ + return rb_funcall(arg->recv, arg->id, arg->narg, arg->arg); +} + +static VALUE +except_lit() +{ + extern VALUE errstr; + + Error("%s", RSTRING(errstr)->ptr); + return Qnil; +} + +static NODE * +call_op(recv, id, narg, arg1) + NODE *recv; + ID id; + int narg; + NODE *arg1; +{ + NODE *args; + + value_expr(recv); + if (narg == 1) + value_expr(arg1); + + if (recv->type != NODE_LIT || recv->type != NODE_STR + || (narg == 0 && id == '~' + && (TYPE(recv->nd_lit)==T_REGEXP || TYPE(recv->nd_lit)==T_STRING)) + || arg1->type == NODE_LIT || arg1->type == NODE_STR) { + if (narg > 0) { + args = NEW_ARRAY(arg1); + args->nd_argc = 1; + } + else { + args = Qnil; + } + return NEW_CALL(recv, id, args); + } + else { + struct call_arg arg_data; + NODE *result; + + arg_data.recv = recv->nd_lit; + arg_data.id = id; + arg_data.narg = narg; + if (narg == 1) arg_data.arg = arg1->nd_lit; + result = NEW_LIT(rb_resque(call_lit, &arg_data, except_lit, Qnil)); + freenode(recv); + if (narg == 1) freenode(arg1); + return result; + } +} + +static NODE* +asignable(id, val) + ID id; + NODE *val; +{ + NODE *lhs; + + if (id == SELF) { + lhs = Qnil; + Error("Can't change the value of self"); + } + else if (id == NIL) { + lhs = Qnil; + Error("Can't asign to nil"); + } + else if (is_local_id(id)) { + lhs = NEW_LASGN(id, val); + } + else if (is_global_id(id)) { + lhs = NEW_GASGN(id, val); + } + else if (is_instance_id(id)) { + lhs = NEW_IASGN(id, val); + } + else if (is_const_id(id)) { + if (cur_mid || in_single) + Error("class constant asigned in method body"); + lhs = NEW_CASGN(id, val); + } + else { + Bug("bad id for variable"); + } + return lhs; +} + +static NODE * +aryset(recv, idx, val) + NODE *recv, *idx, *val; +{ + NODE *args; + + value_expr(recv); + return NEW_CALL(recv, ASET, list_append(idx, val)); +} + +static NODE * +attrset(recv, id, val) + NODE *recv, *val; + ID id; +{ + value_expr(recv); + + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + + return NEW_CALL(recv, id, NEW_ARRAY(val)); +} + +static void +value_expr(node) + NODE *node; +{ + switch (node->type) { + case NODE_RETURN: + case NODE_CONTINUE: + case NODE_BREAK: + case NODE_REDO: + case NODE_RETRY: + Error("void value expression"); + break; + + case NODE_BLOCK: + if (node->nd_last) + return value_expr(node->nd_last->nd_head); + break; + + default: + break; + } +} + +static NODE* +cond(node) + NODE *node; +{ + value_expr(node); + if (node->type == NODE_STR) { + return call_op(NEW_GVAR(rb_intern("$_")),MATCH,1,node); + } + else if (node->type == NODE_LIT && TYPE(node->nd_lit) == T_REGEXP) { + return call_op(node,MATCH,1,NEW_GVAR(rb_intern("$_"))); + } + return node; +} + +static NODE* +cond2(node) + NODE *node; +{ + node = cond(node); + if (node->type == NODE_LIT) { + if (FIXNUM_P(node->nd_lit)) { + return call_op(node,EQ,1,NEW_GVAR(rb_intern("$."))); + } + } + return node; +} + +st_table *new_idhash(); + +static struct local_vars { + ID *tbl; + int cnt; + struct local_vars *next; +} *lvtbl; + +static void +push_local() +{ + struct local_vars *local; + + local = ALLOC(struct local_vars); + local->next = lvtbl; + local->cnt = 0; + local->tbl = Qnil; + lvtbl = local; +} + +void +pop_local() +{ + struct local_vars *local = lvtbl; + + lvtbl = local->next; + if (local->tbl) local->tbl[0] = local->cnt; + free(local); +} + +static ID* +local_tbl() +{ + return lvtbl->tbl; +} + +static int +local_cnt(id) + ID id; +{ + int cnt, max; + + if (id == 0) return lvtbl->cnt; + + for (cnt=0, max=lvtbl->cnt; cnt<max ;cnt++) { + if (lvtbl->tbl[cnt+1] == id) return cnt; + } + + if (lvtbl->tbl == Qnil) + lvtbl->tbl = ALLOC_N(ID, 2); + else + REALLOC_N(lvtbl->tbl, ID, lvtbl->cnt+2); + + lvtbl->tbl[lvtbl->cnt+1] = id; + return lvtbl->cnt++; +} + +static int +local_id(id) + ID id; +{ + int i, max; + + if (lvtbl == Qnil) return FALSE; + for (i=1, max=lvtbl->cnt+1; i<max; i++) { + if (lvtbl->tbl[i] == id) return TRUE; + } + return FALSE; +} + +static void +init_top_local() +{ + if (lvtbl == Qnil) { + push_local(); + } + else if (the_env->local_tbl) { + lvtbl->cnt = the_env->local_tbl[0]; + } + else { + lvtbl->cnt = 0; + } + lvtbl->tbl = the_env->local_tbl; +} + +static void +setup_top_local() +{ + if (lvtbl->cnt > 0) { + if (the_env->local_vars == Qnil) { + the_env->local_vars = ALLOC_N(VALUE, lvtbl->cnt); + bzero(the_env->local_vars, lvtbl->cnt * sizeof(VALUE)); + } + else { + int i; + + REALLOC_N(the_env->local_vars, VALUE, lvtbl->cnt); + for (i=lvtbl->tbl[0]; i<lvtbl->cnt; i++) { + the_env->local_vars[i] = Qnil; + } + } + lvtbl->tbl[0] = lvtbl->cnt; + the_env->local_tbl = lvtbl->tbl; + } + else { + the_env->local_vars = Qnil; + } +} + +void +yyappend_print() +{ + eval_tree = + block_append(eval_tree, NEW_CALL(Qnil, rb_intern("print"), + NEW_ARRAY(NEW_GVAR(rb_intern("$_"))))); +} + +void +yywhole_loop(chop, split) + int chop, split; +{ + if (split) { + eval_tree = + block_append(NEW_GASGN(rb_intern("$F"), + NEW_CALL(NEW_GVAR(rb_intern("$_")), + rb_intern("split"), Qnil)), + eval_tree); + } + if (chop) { + eval_tree = + block_append(NEW_CALL(NEW_GVAR(rb_intern("$_")), + rb_intern("chop"), Qnil), eval_tree); + } + eval_tree = NEW_WHILE(NEW_CALL(0,rb_intern("gets"),0),eval_tree); +} + +static struct op_tbl rb_op_tbl[] = { + DOT2, "..", + '+', "+", + '-', "-", + '+', "+(binary)", + '-', "-(binary)", + '*', "*", + '/', "/", + '%', "%", + POW, "**", + UPLUS, "+(unary)", + UMINUS, "-(unary)", + UPLUS, "+@", + UMINUS, "-@", + '|', "|", + '^', "^", + '&', "&", + CMP, "<=>", + '>', ">", + GEQ, ">=", + '<', "<", + LEQ, "<=", + EQ, "==", + NEQ, "!=", + MATCH, "=~", + NMATCH, "!~", + '!', "!", + '~', "~", + '!', "!(unary)", + '~', "~(unary)", + '!', "!@", + '~', "~@", + AREF, "[]", + ASET, "[]=", + LSHFT, "<<", + RSHFT, ">>", + COLON2, "::", + Qnil, Qnil, +}; + +char *rb_id2name(); +char *rb_class2name(); + +st_table *rb_symbol_tbl; + +#define sym_tbl rb_symbol_tbl + +void +Init_sym() +{ + int strcmp(); + + sym_tbl = st_init_table(strcmp, st_strhash); +} + +ID +rb_intern(name) + char *name; +{ + static ID last_id = LAST_TOKEN; + int id; + int last; + + if (st_lookup(sym_tbl, name, &id)) + return id; + + id = ++last_id; + id <<= 3; + switch (name[0]) { + case '$': + id |= ID_GLOBAL; + break; + case '@': + id |= ID_INSTANCE; + break; + case '%': + if (name[1] != '\0') { + id |= ID_CONST; + break; + } + /* fall through */ + default: + if (name[0] != '_' && !isalpha(name[0]) && !ismbchar(name[0])) { + /* operator */ + int i; + + id = Qnil; + for (i=0; rb_op_tbl[i].tok; i++) { + if (strcmp(rb_op_tbl[i].name, name) == 0) { + id = rb_op_tbl[i].tok; + break; + } + } + if (id == Qnil) Bug("Unknown operator `%s'", name); + break; + } + last = strlen(name)-1; + if (name[last] == '=') { + /* attribute asignment */ + char *buf = (char*)alloca(last+1); + + strncpy(buf, name, last); + buf[last] = '\0'; + id = rb_intern(buf); + id &= ~ID_SCOPE_MASK; + id |= ID_ATTRSET; + } + else { + id |= ID_LOCAL; + } + break; + } + st_add_direct(sym_tbl, strdup(name), id); + return id; +} + +static char *find_ok; + +static +id_find(name, id1, id2) + char *name; + ID id1, id2; +{ + if (id1 == id2) { + find_ok = name; + return ST_STOP; + } + return ST_CONTINUE; +} + +char * +rb_id2name(id) + ID id; +{ + find_ok = Qnil; + + if (id < LAST_TOKEN) { + int i = 0; + + for (i=0; rb_op_tbl[i].tok; i++) { + if (rb_op_tbl[i].tok == id) + return rb_op_tbl[i].name; + } + } + + st_foreach(sym_tbl, id_find, id); + if (!find_ok && is_attrset_id(id)) { + char *res; + ID id2; + + id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL; + res = rb_id2name(id2); + + if (res) { + char *buf = (char*)alloca(strlen(res)+2); + + strcpy(buf, res); + strcat(buf, "="); + rb_intern(buf); + return rb_id2name(id); + } + } + return find_ok; +} + +char * +rb_class2name(class) + struct RClass *class; +{ + extern st_table *rb_class_tbl; + + find_ok = Qnil; + + switch (TYPE(class)) { + case T_CLASS: + case T_MODULE: + case T_ICLASS: + break; + default: + Fail("0x%x is not a class/module", class); + } + + while (FL_TEST(class, FL_SINGLE)) { + class = (struct RClass*)class->super; + } + + st_foreach(rb_class_tbl, id_find, class); + if (find_ok) { + return rb_id2name((ID)find_ok); + } + Bug("class 0x%x not named", class); +} diff --git a/process.c b/process.c new file mode 100644 index 0000000000..7a1dd398c5 --- /dev/null +++ b/process.c @@ -0,0 +1,849 @@ +/************************************************ + + process.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Tue Aug 10 14:30:50 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include "st.h" +VALUE rb_readonly_hook(); + +static VALUE +get_pid() +{ + return INT2FIX(getpid()); +} + +static VALUE +get_ppid() +{ + return INT2FIX(getppid()); +} + +static VALUE status; + +#if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4) +static st_table *pid_tbl; +#else +# define WAIT_CALL +#endif + +int +rb_waitpid(pid, flags) + int pid; + int flags; +{ + int result, st; + +#ifdef HAVE_WAITPID + result = waitpid(pid, &st, flags); +#else +#ifdef HAVE_WAIT4 + result = wait4(pid, &st, flags, NULL); +#else + if (pid_tbl && st_lookup(pid_tbl, pid, &st)) { + status = INT2FIX(st); + st_delete(pid_tbl, &pid, NULL); + return pid; + } + + if (flags) + Fail("Can't do waitpid with flags"); + + for (;;) { + result = wait(&st); + if (result < 0) return -1; + if (result == pid) { + break; + } + if (!pid_tbl) + pid_tbl = st_init_table(ST_NUMCMP, ST_NUMHASH); + st_insert(pid_tbl, pid, st); + } +#endif +#endif + status = INT2FIX(st); + return result; +} + +#ifndef WAIT_CALL +static int wait_pid; +static int wait_status; + +static wait_each(key, value) + int key, value; +{ + wait_pid = key; + wait_status = value; + return ST_DELETE; +} +#endif + +static VALUE +Fwait(obj) +{ + int pid, state; + +#ifndef WAIT_CALL + wait_status = -1; + st_foreach(pid_tbl, wait_each, NULL); + if (wait_status != -1) { + status = wait_status; + return wait_pid; + } +#endif + + if ((pid = wait(&state)) < 0) { + if (errno == ECHILD) return Qnil; + rb_sys_fail(Qnil); + } + status = INT2FIX(state); + return INT2FIX(pid); +} + +static VALUE +Fwaitpid(obj, vpid, vflags) + VALUE obj, vpid, vflags; +{ + int pid, flags; + + if (vflags == Qnil) flags = Qnil; + else flags = FIX2UINT(vflags); + + if ((pid = rb_waitpid(FIX2UINT(vpid), flags)) < 0) + rb_sys_fail(Qnil); + return INT2FIX(pid); +} + +char *strtok(); + +rb_proc_exec(str) + char *str; +{ + char *s = str, *t; + char **argv, **a; + + for (s=str; *s; s++) { + if (*s != ' ' && !isalpha(*s) && index("*?{}[]<>()~&|\\$;'`\"\n",*s)) { + execl("/bin/sh", "sh", "-c", str, (char *)NULL); + return -1; + } + } + a = argv = (char**)alloca(((s - str)/2+2)*sizeof(char*)); + s = (char*)alloca(s - str + 1); + strcpy(s, str); + if (*a++ = strtok(s, " \t")) { + while (t = strtok(NULL, " \t")) { + *a++ = t; + } + *a = NULL; + } + if (argv[0]) { + execvp(argv[0], argv); + } + return -1; +} + +static VALUE +Fexec(obj, str) + VALUE obj; + struct RString *str; +{ + Check_Type(str, T_STRING); + rb_proc_exec(str->ptr); + rb_sys_fail(str->ptr); +} + +static VALUE +Ffork(obj) + VALUE obj; +{ + int pid; + + switch (pid = fork()) { + case 0: + return Qnil; + + case -1: + rb_sys_fail(Qnil); + break; + + default: + return INT2FIX(pid); + } +} + +static VALUE +F_exit(obj, status) + VALUE obj, status; +{ + int code = -1; + + if (FIXNUM_P(status)) { + code = INT2FIX(status); + } + + _exit(code); + + /* not reached */ + return Qnil; +} + +void +rb_syswait(pid) + int pid; +{ + RETSIGTYPE (*hfunc)(), (*ifunc)(), (*qfunc)(); + + hfunc = signal(SIGHUP, SIG_IGN); + ifunc = signal(SIGINT, SIG_IGN); + qfunc = signal(SIGQUIT, SIG_IGN); + + if (rb_waitpid(pid, 0) < 0) rb_sys_fail("wait"); + + signal(SIGHUP, hfunc); + signal(SIGINT, ifunc); + signal(SIGQUIT, qfunc); +} + +static VALUE +Fsystem(obj, str) + VALUE obj; + struct RString *str; +{ + int pid, w; + + Check_Type(str, T_STRING); + + fflush(stdin); /* is it really needed? */ + fflush(stdout); + fflush(stderr); + if (*str->ptr == '\0') return INT2FIX(0); + + retry: + switch (pid = vfork()) { + case 0: + rb_proc_exec(str->ptr); + _exit(127); + break; /* not reached */ + + case -1: + if (errno == EAGAIN) { + sleep(5); + goto retry; + } + rb_sys_fail(str->ptr); + break; + + default: + rb_syswait(pid); + } + + return status; +} + +static struct signals { + char *signm; + int signo; +} siglist [] = { +#ifdef SIGHUP + "HUP", SIGHUP, +#endif +#ifdef SIGINT + "INT", SIGINT, +#endif +#ifdef SIGQUIT + "QUIT", SIGQUIT, +#endif +#ifdef SIGILL + "ILL", SIGILL, +#endif +#ifdef SIGTRAP + "TRAP", SIGTRAP, +#endif +#ifdef SIGIOT + "IOT", SIGIOT, +#endif +#ifdef SIGABRT + "ABRT", SIGABRT, +#endif +#ifdef SIGEMT + "EMT", SIGEMT, +#endif +#ifdef SIGFPE + "FPE", SIGFPE, +#endif +#ifdef SIGKILL + "KILL", SIGKILL, +#endif +#ifdef SIGBUS + "BUS", SIGBUS, +#endif +#ifdef SIGSEGV + "SEGV", SIGSEGV, +#endif +#ifdef SIGSYS + "SYS", SIGSYS, +#endif +#ifdef SIGPIPE + "PIPE", SIGPIPE, +#endif +#ifdef SIGALRM + "ALRM", SIGALRM, +#endif +#ifdef SIGTERM + "TERM", SIGTERM, +#endif +#ifdef SIGURG + "URG", SIGURG, +#endif +#ifdef SIGSTOP + "STOP", SIGSTOP, +#endif +#ifdef SIGTSTP + "TSTP", SIGTSTP, +#endif +#ifdef SIGCONT + "CONT", SIGCONT, +#endif +#ifdef SIGCHLD + "CHLD", SIGCHLD, +#endif +#ifdef SIGCLD + "CLD", SIGCLD, +#else +# ifdef SIGCHLD + "CLD", SIGCHLD, +# endif +#endif +#ifdef SIGTTIN + "TTIN", SIGTTIN, +#endif +#ifdef SIGTTOU + "TTOU", SIGTTOU, +#endif +#ifdef SIGIO + "IO", SIGIO, +#endif +#ifdef SIGXCPU + "XCPU", SIGXCPU, +#endif +#ifdef SIGXFSZ + "XFSZ", SIGXFSZ, +#endif +#ifdef SIGVTALRM + "VTALRM", SIGVTALRM, +#endif +#ifdef SIGPROF + "PROF", SIGPROF, +#endif +#ifdef SIGWINCH + "WINCH", SIGWINCH, +#endif +#ifdef SIGUSR1 + "USR1", SIGUSR1, +#endif +#ifdef SIGUSR2 + "USR2", SIGUSR2, +#endif +#ifdef SIGLOST + "LOST", SIGLOST, +#endif +#ifdef SIGMSG + "MSG", SIGMSG, +#endif +#ifdef SIGPWR + "PWR", SIGPWR, +#endif +#ifdef SIGPOLL + "POLL", SIGPOLL, +#endif +#ifdef SIGDANGER + "DANGER", SIGDANGER, +#endif +#ifdef SIGMIGRATE + "MIGRATE", SIGMIGRATE, +#endif +#ifdef SIGPRE + "PRE", SIGPRE, +#endif +#ifdef SIGGRANT + "GRANT", SIGGRANT, +#endif +#ifdef SIGRETRACT + "RETRACT", SIGRETRACT, +#endif +#ifdef SIGSOUND + "SOUND", SIGSOUND, +#endif + NULL, 0, +}; + +static int +signm2signo(nm) + char *nm; +{ + struct signals *sigs; + + for (sigs = siglist; sigs->signm; sigs++) + if (strcmp(sigs->signm, nm) == 0) + return sigs->signo; + return 0; +} + +static VALUE +Fkill(argc, argv) + int argc; + VALUE *argv; +{ + int sig; + int i; + + if (argc < 3) + Fail("wrong # of arguments -- kill(sig, pid...)"); + switch (TYPE(argv[1])) { + case T_FIXNUM: + sig = FIX2UINT(argv[1]); + break; + + case T_STRING: + { + int negative = 0; + + char *s = RSTRING(argv[1])->ptr; + if (*s == '-') { + negative++; + s++; + } + if (strncmp("SIG", s, 3) == 0) + s += 3; + if((sig = signm2signo(s)) == 0) + Fail("Unrecognized signal name `%s'", s); + + if (negative) + sig = -sig; + } + break; + + default: + Fail("bad signal type %s", rb_class2name(CLASS_OF(argv[1]))); + break; + } + + if (sig < 0) { + sig = -sig; + for (i=2; i<argc; i++) { + int pid = NUM2INT(argv[i]); +#ifdef HAS_KILLPG + if (killpg(pid, sig) < 0) +#else + if (kill(-pid, sig) < 0) +#endif + rb_sys_fail(Qnil); + } + } + else { + for (i=2; i<argc; i++) { + Check_Type(argv[i], T_FIXNUM); + if (kill(FIX2UINT(argv[i]), sig) < 0) + rb_sys_fail(Qnil); + } + } + return INT2FIX(i-2); +} + +static VALUE trap_list[NSIG]; +#ifdef SAFE_SIGHANDLE +static int trap_pending_list[NSIG]; +int trap_pending; +static int trap_immediate; +#endif + +void +mark_trap_list() +{ + int i; + + for (i=0; i<NSIG; i++) { + if (trap_list[i]) + mark(trap_list[i]); + } +} + +static RETSIGTYPE +sighandle(sig) + int sig; +{ + if (sig >= NSIG || trap_list[sig] == Qnil) + Fail("trap_handler: Bad signal %d", sig); + +#ifndef HAVE_BSD_SIGNALS + signal(sig, sighandle); +#endif + +#ifdef SAFE_SIGHANDLE + if (trap_immediate) + rb_trap_eval(trap_list[sig]); + else { + trap_pending++; + trap_pending_list[sig]++; + } +#else + rb_trap_eval(trap_list[sig]); +#endif +} + +void +rb_trap_exit() +{ + if (trap_list[0]) + rb_trap_eval(trap_list[0]); +} + +#if defined(SAFE_SIGHANDLE) +rb_trap_exec() +{ + int i; + + trap_pending = 0; + for (i=0; i<NSIG; i++) { + if (trap_pending_list[i]) { + trap_pending_list[i] = 0; + rb_trap_eval(trap_list[i]); + } + } +} + +#ifdef HAVE_SYSCALL_H +#include <syscall.h> + +#ifdef SYS_read +int +read(fd, buf, nbytes) + int fd, nbytes; + char *buf; +{ + int res; + + trap_immediate++; + res = syscall(SYS_read, fd, buf, nbytes); + trap_immediate = 0; + return res; +} +#endif /* SYS_read */ + +#ifdef SYS_wait +int +wait(status) + union wait *status; +{ + int res; + + trap_immediate++; + res = syscall(SYS_wait, status); + trap_immediate =0; + return res; +} +#endif /* SYS_wait */ + +#ifdef SYS_sigpause +int +sigpause(mask) + int mask; +{ + int res; + + trap_immediate++; + res = syscall(SYS_sigpause, mask); + trap_immediate =0; + return res; +} +#endif /* SYS_sigpause */ + +/* linux syscall(select) doesn't work file. */ +#if defined(SYS_select) && !defined(linux) +#include <sys/types.h> + +int +select(nfds, readfds, writefds, exceptfds, timeout) + int nfds; + fd_set *readfds, *writefds, *exceptfds; + struct timeval *timeout; +{ + int res; + + trap_immediate++; + res = syscall(SYS_select, nfds, readfds, writefds, exceptfds, timeout); + trap_immediate =0; + return res; +} +#endif /* SYS_select */ + +#endif /* HAVE_SYSCALL_H */ +#endif /* SAFE_SIGHANDLE */ + +static VALUE +Ftrap(argc, argv) + int argc; + VALUE *argv; +{ + RETSIGTYPE (*func)(); + VALUE command; + int i, sig; + int mask; + + if (argc < 3) + Fail("wrong # of arguments -- kill(cmd, sig...)"); + + /* disable interrupt */ + mask = sigblock(~0); + + func = sighandle; + + if (argv[1] == Qnil) { + func = SIG_IGN; + command = Qnil; + } + else { + Check_Type(argv[1], T_STRING); + command = argv[1]; + if (RSTRING(argv[1])->len == 0) { + func = SIG_IGN; + } + else if (RSTRING(argv[1])->len == 7) { + if (strncmp(RSTRING(argv[1])->ptr, "SIG_IGN", 7) == 0) { + func = SIG_IGN; + } + else if (strncmp(RSTRING(argv[1])->ptr, "SIG_DFL", 7) == 0) { + func = SIG_DFL; + } + else if (strncmp(RSTRING(argv[1])->ptr, "DEFAULT", 7) == 0) { + func = SIG_DFL; + } + } + else if (RSTRING(argv[1])->len == 6) { + if (strncmp(RSTRING(argv[1])->ptr, "IGNORE", 6) == 0) { + func = SIG_IGN; + } + } + } + if (func == SIG_IGN || func == SIG_DFL) + command = Qnil; + + for (i=2; i<argc; i++) { + if (TYPE(argv[i]) == T_STRING) { + char *s = RSTRING(argv[i])->ptr; + + if (strncmp("SIG", s, 3) == 0) + s += 3; + sig = signm2signo(s); + if (sig == 0 && strcmp(s, "EXIT") != 0) + Fail("Invalid signal SIG%s", s); + } + else { + sig = NUM2INT(argv[i]); + } + if (i < 0 || i > NSIG) + Fail("Invalid signal no %d", sig); + + signal(sig, sighandle); + trap_list[sig] = command; + /* enable at least specified signal. */ + mask &= ~sigmask(sig); + } + sigsetmask(mask); + return Qnil; +} + +Fsleep(argc, argv) + int argc; + VALUE *argv; +{ + int beg, end; + + beg = time(0); + if (argc == 1) { + sleep((32767<<16)+32767); + } + else if (argc == 2) { + sleep(NUM2INT(argv[1])); + } + else { + Fail("wrong # of arguments"); + } + + end = time(0) - beg; + + return int2inum(end); +} + +static VALUE +Fproc_getpgrp(obj, args) + VALUE obj, args; +{ + VALUE vpid; + int pid, pgrp; + + rb_scan_args(args, "01", &vpid); + if (vpid == Qnil) { + pid = 0; + } + else { + pid = NUM2INT(vpid); + } + + pgrp = getpgrp(pid); + return INT2FIX(pgrp); +} + +static VALUE +Fproc_setpgrp(obj, pid, pgrp) + VALUE obj, pid, pgrp; +{ + int ipid, ipgrp; + + ipid = NUM2INT(pid); + ipgrp = NUM2INT(pgrp); + + if (getpgrp(ipid, ipgrp) == -1) rb_sys_fail(Qnil); + + return Qnil; +} + +static VALUE +Fproc_getpriority(obj, which, who) + VALUE obj, which, who; +{ + int prio, iwhich, iwho; + + iwhich = NUM2INT(which); + iwho = NUM2INT(who); + + prio = getpriority(iwhich, iwho); + if (prio == -1) rb_sys_fail(Qnil); + return INT2FIX(prio); +} + +static VALUE +Fproc_setpriority(obj, which, who, prio) + VALUE obj, which, who, prio; +{ + int iwhich, iwho, iprio; + + iwhich = NUM2INT(which); + iwho = NUM2INT(who); + iprio = NUM2INT(prio); + + if (setpriority(iwhich, iwho, iprio) == -1) + rb_sys_fail(Qnil); + return Qnil; +} + +static VALUE +Fproc_getuid(obj) + VALUE obj; +{ + int uid = getuid(); + return INT2FIX(uid); +} + +static VALUE +Fproc_setuid(obj, id) + VALUE obj, id; +{ + int uid; + + uid = NUM2INT(id); +#ifdef HAVE_SETRUID + setruid(uid); +#else +#ifdef HAVE_SETREUID + setreuid(uid, -1); +#else + { + if (geteuid() == uid) + setuid(uid); + else + Fail("getruid not implemented"); + } +#endif +#endif + return INT2FIX(uid); +} + +static VALUE +Fproc_geteuid(obj) + VALUE obj; +{ + int euid = geteuid(); + return INT2FIX(euid); +} + +static VALUE +Fproc_seteuid(obj, euid) + VALUE obj, euid; +{ + if (seteuid(NUM2INT(euid)) == -1) + rb_sys_fail(Qnil); + return euid; +} + +VALUE M_Process; +Init_process() +{ + extern VALUE C_Kernel; + + rb_define_variable("$$", Qnil, get_pid, rb_readonly_hook); + rb_define_variable("$?", &status, Qnil, rb_readonly_hook); + rb_define_func(C_Kernel, "exec", Fexec, 1); + rb_define_func(C_Kernel, "fork", Ffork, 0); + rb_define_func(C_Kernel, "_exit", Ffork, 1); + rb_define_func(C_Kernel, "wait", Fwait, 0); + rb_define_func(C_Kernel, "waitpid", Fwaitpid, 2); + rb_define_func(C_Kernel, "system", Fsystem, 1); + rb_define_func(C_Kernel, "kill", Fkill, -1); + rb_define_func(C_Kernel, "trap", Ftrap, -1); + rb_define_func(C_Kernel, "sleep", Fsleep, -1); + + M_Process = rb_define_module("Process"); + + rb_define_single_method(M_Process, "fork", Ffork, 0); + rb_define_single_method(M_Process, "_exit", Ffork, 1); + rb_define_single_method(M_Process, "wait", Fwait, 0); + rb_define_single_method(M_Process, "waitpid", Fwaitpid, 2); + rb_define_single_method(M_Process, "kill", Fkill, -1); + + rb_define_mfunc(M_Process, "pid", get_pid, 0); + rb_define_mfunc(M_Process, "ppid", get_ppid, 0); + + rb_define_mfunc(M_Process, "getpgrp", Fproc_getpgrp, -2); + rb_define_mfunc(M_Process, "setpgrp", Fproc_setpgrp, 2); + + rb_define_mfunc(M_Process, "getpriority", Fproc_getpriority, 2); + rb_define_mfunc(M_Process, "setpriority", Fproc_setpriority, 3); + + rb_define_const(M_Process, "%PRIO_PROCESS", INT2FIX(PRIO_PROCESS)); + rb_define_const(M_Process, "%PRIO_PGRP", INT2FIX(PRIO_PGRP)); + rb_define_const(M_Process, "%PRIO_USER", INT2FIX(PRIO_USER)); + + rb_define_single_method(M_Process, "uid", Fproc_getuid, 0); + rb_define_method(M_Process, "uid", Fproc_getuid, 0); + rb_define_single_method(M_Process, "uid=", Fproc_setuid, 1); + rb_define_method(M_Process, "uid=", Fproc_setuid, 1); + rb_define_single_method(M_Process, "euid", Fproc_geteuid, 0); + rb_define_method(M_Process, "euid", Fproc_geteuid, 0); + rb_define_single_method(M_Process, "euid=", Fproc_seteuid, 1); + rb_define_method(M_Process, "euid=", Fproc_seteuid, 1); +} diff --git a/random.c b/random.c new file mode 100644 index 0000000000..ed21c7ec2b --- /dev/null +++ b/random.c @@ -0,0 +1,80 @@ +/************************************************ + + random.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Fri Dec 24 16:39:21 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +static int first = 1; +static char state[256]; + +static VALUE +Fsrand(obj, args) + VALUE obj, args; +{ + int seed, old; +#ifdef HAVE_RANDOM + static int saved_seed; +#endif + + if (rb_scan_args(args, "01", &seed) == 0) { + seed = time(0); + } + else { + seed = NUM2INT(seed); + } + +#ifdef HAVE_RANDOM + if (first == 1) { + initstate(1, state, sizeof state); + first = 0; + } + else { + setstate(state); + } + + srandom(seed); + old = saved_seed; + saved_seed = seed; + + return int2inum(old); +#else + old = srand(seed); + return int2inum(old); +#endif +} + +static VALUE +Frand(obj, max) + VALUE obj, max; +{ + int val; + +#ifdef HAVE_RANDOM + if (first == 1) { + initstate(1, state, sizeof state); + first = 0; + } + val = random() % NUM2INT(max); +#else + val = rand() % NUM2INT(max); +#endif + + if (val < 0) val = -val; + return int2inum(val); +} + +Init_Random() +{ + extern VALUE C_Kernel; + + rb_define_func(C_Kernel, "srand", Fsrand, -2); + rb_define_func(C_Kernel, "rand", Frand, 1); +} diff --git a/range.c b/range.c new file mode 100644 index 0000000000..816ce27a1a --- /dev/null +++ b/range.c @@ -0,0 +1,149 @@ +/************************************************ + + range.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:50 $ + created at: Thu Aug 19 17:46:47 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +VALUE M_Comparable; +VALUE C_Range; + +static ID next, eq; + +VALUE +range_new(class, start, end) + VALUE class, start, end; +{ + VALUE obj; + + if (!obj_is_kind_of(start, M_Comparable) || TYPE(start) != TYPE(end)) { + Fail("bad value for range"); + } + + obj = obj_alloc(class); + + rb_iv_set(obj, "start", start); + rb_iv_set(obj, "end", end); + + return obj; +} + +static VALUE +Frng_match(rng, obj) + VALUE rng, obj; +{ + VALUE beg, end; + + beg = rb_iv_get(rng, "start"); + end = rb_iv_get(rng, "end"); + + if (FIXNUM_P(beg) && FIXNUM_P(obj)) { + if (FIX2INT(beg) <= FIX2INT(obj) && FIX2INT(obj) <= FIX2INT(end)) { + return TRUE; + } + return FALSE; + } + else { + if (rb_funcall(beg, rb_intern("<="), 1, obj) && + rb_funcall(end, rb_intern(">="), 1, obj)) { + return TRUE; + } + return FALSE; + } +} + +static VALUE +Frng_each(obj) + VALUE obj; +{ + VALUE b, e, current; + + b = rb_iv_get(obj, "start"); + e = rb_iv_get(obj, "end"); + + if (FIXNUM_P(b)) { /* fixnum is a special case(for performance) */ + int beg, end, i; + + beg = FIX2INT(b); + end = FIX2INT(e); + + for (i=beg; i<=end; i++) { + rb_yield(INT2FIX(i)); + } + } + else { + GC_LINK; + GC_PRO3(current, b); + for (;;) { + rb_yield(current); + if (rb_funcall(current, eq, 1, e)) break; + current = rb_funcall(current, next, 0); + } + GC_UNLINK; + } + + return Qnil; +} + +static VALUE +Frng_start(obj) + VALUE obj; +{ + VALUE b; + + b = rb_iv_get(obj, "start"); + return b; +} + +static VALUE +Frng_end(obj) + VALUE obj; +{ + VALUE e; + + e = rb_iv_get(obj, "end"); + return e; +} + +static VALUE +Frng_to_s(obj) + VALUE obj; +{ + int beg, end; + VALUE fmt, str, args[4]; + + + beg = rb_iv_get(obj, "start"); + end = rb_iv_get(obj, "end"); + + GC_LINK; + GC_PRO3(fmt, str_new2("%d..%d")); + args[0] = obj; args[1] = fmt; args[2]= beg; args[3] = end; + str = Fsprintf(4, args); + GC_UNLINK; + + return str; +} + +extern VALUE M_Enumerable; + +Init_Range() +{ + C_Range = rb_define_class("Range", C_Object); + rb_include_module(C_Range, M_Enumerable); + rb_define_method(C_Range, "=~", Frng_match, 1); + rb_define_method(C_Range, "each", Frng_each, 0); + rb_define_method(C_Range, "start", Frng_start, 0); + rb_define_method(C_Range, "end", Frng_end, 0); + rb_define_method(C_Range, "to_s", Frng_to_s, 0); + + eq = rb_intern("=="); + next = rb_intern("next"); +} @@ -0,0 +1,442 @@ +/************************************************ + + re.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:36 $ + created at: Mon Aug 9 18:24:49 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "re.h" + +/* Generate compiled regular expressions */ +#if 'a' == 97 /* it's ascii */ +static char casetable[] = { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + /* ' ' '!' '"' '#' '$' '%' '&' ''' */ + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + /* '(' ')' '*' '+' ',' '-' '.' '/' */ + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + /* '0' '1' '2' '3' '4' '5' '6' '7' */ + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + /* '8' '9' ':' ';' '<' '=' '>' '?' */ + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + /* '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' */ + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + /* 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' */ + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + /* 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' */ + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + /* 'X' 'Y' 'Z' '[' '\' ']' '^' '_' */ + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + /* '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' */ + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + /* 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' */ + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + /* 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' */ + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + /* 'x' 'y' 'z' '{' '|' '}' '~' */ + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', + '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', +}; +#else +>>> "You lose. You will need a translation table for your character set." <<< +#endif + +#define min(a,b) (((a)>(b))?(b):(a)) + +int +str_cicmp(str1, str2) + struct RString *str1, *str2; +{ + int len, i; + char *p1, *p2; + + len = min(str1->len, str2->len); + p1 = str1->ptr; p2 = str2->ptr; + + for (i = 0; i < len; i++, p1++, p2++) { + if (casetable[*p1] != casetable[*p2]) + return casetable[*p1] - casetable[*p2]; + } + return str1->len - str2->len; +} + +Regexp* +make_regexp(s, len) +char *s; +int len; +{ + Regexp *rp; + char *err; + register int c; + + /* Handle escaped characters first. */ + + /* Build a copy of the string (in dest) with the + escaped characters translated, and generate the regex + from that. + */ + + rp = ALLOC(Regexp); + bzero((char *)rp, sizeof(Regexp)); + rp->pat.buffer = ALLOC_N(char, 16); + rp->pat.allocated = 16; + rp->pat.fastmap = ALLOC_N(char, 256); + + if ((err = re_compile_pattern(s, (size_t)len, &(rp->pat))) != NULL) + Fail("%s: /%s/", err, s); + return rp; +} + +struct match { + UINT len; + char *ptr; + struct re_registers regs; +}; + +static void +free_match(data) + struct match *data; +{ + free(data->ptr); +} + +VALUE last_match_data; + +int +research(reg, str, start, ignorecase) + struct RRegexp *reg; + struct RString *str; + int start; + int ignorecase; +{ + int result; + + if (ignorecase) + reg->ptr->pat.translate = casetable; + else + reg->ptr->pat.translate = NULL; + + if (start >= str->len) return -1; + result = re_search(&(reg->ptr->pat), str->ptr, str->len, + start, str->len - start, &(reg->ptr->regs)); + + if (result >= 0) { + struct RData *obj; + struct match *data; + int beg, i; + + obj = (struct RData*)newobj(sizeof(struct RData)+sizeof(struct match)); + OBJSETUP(obj, C_Data, T_DATA); + obj->dfree = free_match; + data = (struct match*)DATA_PTR(obj); + bzero(data, sizeof(struct match)); + beg = reg->ptr->regs.start[0]; + data->len = reg->ptr->regs.end[0] - beg; + data->ptr = ALLOC_N(char, data->len+1); + memcpy(data->ptr, str->ptr + beg, data->len); + data->ptr[data->len] = '\0'; + for (i=0; i<RE_NREGS; i++) { + if (reg->ptr->regs.start[i] == -1) break; + data->regs.start[i] = reg->ptr->regs.start[i] - beg; + data->regs.end[i] = reg->ptr->regs.end[i] - beg; + } + last_match_data = (VALUE)obj; + } + + return result; +} + +static VALUE +nth_match(nth) + int nth; +{ + if (nth >= RE_NREGS) { + Fail("argument out of range %d, %d", nth, RE_NREGS); + } + if (last_match_data) { + int start, end, len; + struct match *match; + + match = (struct match*)DATA_PTR(last_match_data); + if (nth == 0) return str_new(match->ptr, match->len); + start = match->regs.start[nth]; + if (start == -1) return Qnil; + end = match->regs.end[nth]; + len = end - start; + return str_new(match->ptr + start, len); + } + return Qnil; +} + +VALUE +re_last_match(id) + ID id; +{ + return nth_match(0); +} + +#ifdef __STDC__ +#define CONCAT(a,b) a##b +#else +#define CONCAT(a,b) a/**/b +#endif + +#define GET_MATCH(n) CONCAT(get_macth,n) +#define GET_MATCH_FUNC(n) GET_MATCH(n)(id) ID id; { return nth_match(n); } + +GET_MATCH_FUNC(1); +GET_MATCH_FUNC(2); +GET_MATCH_FUNC(3); +GET_MATCH_FUNC(4); +GET_MATCH_FUNC(5); +GET_MATCH_FUNC(6); +GET_MATCH_FUNC(7); +GET_MATCH_FUNC(8); +GET_MATCH_FUNC(9); + +static VALUE +store_match_data(val) + struct RArray *val; +{ + Check_Type(val, T_DATA); + return (VALUE)val; +} + +void +reg_free(rp) +Regexp *rp; +{ + free(rp->pat.buffer); + free(rp->pat.fastmap); + free(rp); +} + +void +reg_error(s) +const char *s; +{ + Fail(s); +} + +VALUE ignorecase; +VALUE C_Regexp; + +static VALUE +regexp_new_1(class, s, len) + VALUE class; + char *s; + int len; +{ + NEWOBJ(re, struct RRegexp); + OBJSETUP(re, class, T_REGEXP); + + re->ptr = make_regexp(s, len); + re->str = ALLOC_N(char, len+1); + memcpy(re->str, s, len); + re->str[len] = '\0'; + re->len = len; + return (VALUE)re; +} + +VALUE +regexp_new(s, len) + char *s; + int len; +{ + return regexp_new_1(C_Regexp, s, len); +} + +static VALUE str_cache, reg_cache; + +VALUE +re_regcomp(str) + struct RString *str; +{ + if (str_cache && RSTRING(str_cache)->len == str->len && + memcmp(RSTRING(str_cache)->ptr, str->ptr, str->len)) + return reg_cache; + + str_cache = (VALUE)str; + return reg_cache = regexp_new(str->ptr, str->len); +} + +VALUE +Freg_match(re, str) + struct RRegexp *re; + struct RString *str; +{ + int start; + + Check_Type(str, T_STRING); + start = research(re, str, 0, ignorecase); + if (start == -1) { + return Qnil; + } + return INT2FIX(start); +} + +VALUE +Freg_match2(re) + struct RRegexp *re; +{ + extern VALUE rb_lastline; + int start; + + if (TYPE(rb_lastline) != T_STRING) + Fail("$_ is not a string"); + + start = research(re, rb_lastline, 0, ignorecase); + if (start == -1) { + return Qnil; + } + return INT2FIX(start); +} + +static VALUE +Freg_compile(re, str) + VALUE re; + struct RString *str; +{ + Check_Type(str, T_STRING); + return regexp_new_1(re, str->ptr, str->ptr); +} + +static VALUE +Freg_new(re, src) + VALUE re, src; +{ + switch (TYPE(src)) { + case T_STRING: + return regexp_new_1(re, RREGEXP(src)->ptr, RREGEXP(src)->len); + + case T_REGEXP: + return regexp_new_1(re, RREGEXP(src)->str, RREGEXP(src)->len); + + default: + Check_Type(src, T_REGEXP); + } + /* not reached */ + return Qnil; +} + +static VALUE +Freg_clone(re) + struct RRegexp *re; +{ + return regexp_new_1(CLASS_OF(re), re->str, re->len); +} + +VALUE +re_regsub(str) + struct RString *str; +{ + VALUE val; + char *p, *s, *e, c; + int no, len; + + p = s = str->ptr; + e = s + str->len; + + GC_LINK; + GC_PRO2(val); + while (s < e) { + c = *s++; + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *s && *s <= '9') + no = *s++ - '0'; + else + no = -1; + + if (no >= 0 || c == '\\') { + if (val == Qnil) { + val = str_new(p, s-p-2); + } + else { + str_cat(val, p, s-p-2); + } + p = s; + } + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*s == '\\' || *s == '&')) + p = ++s; + } else if (last_match_data) { + struct match *match; + +#define BEG(no) match->regs.start[no] +#define END(no) match->regs.end[no] + + match = (struct match*)DATA_PTR(last_match_data); + if (BEG(no) == -1) continue; + str_cat(val, match->ptr+BEG(no), END(no)-BEG(no)); + } + } + GC_UNLINK; + + if (val == Qnil) return (VALUE)str; + if (RSTRING(val)->len == 0) { + obj_free(val); /* free for cost */ + return (VALUE)str; + } + return val; +} + +long reg_syntax = RE_SYNTAX_POSIX_EXTENDED; +VALUE rb_readonly_hook(); + +void +Init_Regexp() +{ + (void) re_set_syntax(reg_syntax); + + rb_define_variable("$~", last_match_data, Qnil, store_match_data); + + rb_define_variable("$&", Qnil, re_last_match, rb_readonly_hook); + + rb_define_variable("$1", Qnil, GET_MATCH(1), rb_readonly_hook); + rb_define_variable("$2", Qnil, GET_MATCH(2), rb_readonly_hook); + rb_define_variable("$3", Qnil, GET_MATCH(3), rb_readonly_hook); + rb_define_variable("$4", Qnil, GET_MATCH(4), rb_readonly_hook); + rb_define_variable("$5", Qnil, GET_MATCH(5), rb_readonly_hook); + rb_define_variable("$6", Qnil, GET_MATCH(6), rb_readonly_hook); + rb_define_variable("$7", Qnil, GET_MATCH(7), rb_readonly_hook); + rb_define_variable("$8", Qnil, GET_MATCH(8), rb_readonly_hook); + rb_define_variable("$9", Qnil, GET_MATCH(9), rb_readonly_hook); + + rb_define_variable("$=", &ignorecase, Qnil, Qnil); + + C_Regexp = rb_define_class("Regexp", C_Object); + rb_define_single_method(C_Regexp, "new", Freg_new, 1); + rb_define_single_method(C_Regexp, "compile", Freg_compile, 1); + + rb_define_method(C_Regexp, "=~", Freg_match, 1); + rb_define_method(C_Regexp, "~", Freg_match2, 0); + + rb_global_variable(&str_cache); + rb_global_variable(®_cache); +} @@ -0,0 +1,28 @@ +/************************************************ + + re.h - + + $Author: matz $ + $Revision: 1.1.1.1 $ + $Date: 1994/06/17 14:23:50 $ + created at: Thu Sep 30 14:18:32 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#ifndef RE_H +#define RE_H + +#include <sys/types.h> +#include <stdio.h> + +#include "regex.h" +typedef struct Regexp { + struct re_pattern_buffer pat; + struct re_registers regs; +} Regexp; + +VALUE re_regcomp(); +VALUE re_regsub(); +#endif diff --git a/regex.c b/regex.c new file mode 100644 index 0000000000..ae6db7cfaa --- /dev/null +++ b/regex.c @@ -0,0 +1,3237 @@ +/* Extended regular expression matching and search library. + Copyright (C) 1985, 1989-90 Free Software Foundation, Inc. + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. */ +/* Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) + Last change: May 21, 1993 by t^2 */ + + +/* To test, compile with -Dtest. This Dtestable feature turns this into + a self-contained program which reads a pattern, describes how it + compiles, then reads a string and searches for it. + + On the other hand, if you compile with both -Dtest and -Dcanned you + can run some tests we've already thought of. */ + + +/* We write fatal error messages on standard error. */ +#include <stdio.h> + +/* isalpha(3) etc. are used for the character classes. */ +#include <ctype.h> + +#ifdef emacs + +/* The `emacs' switch turns on certain special matching commands + that make sense only in emacs. */ + +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +#else /* not emacs */ + +#define RUBY +#include <sys/types.h> + +#ifdef __STDC__ +#define P(s) s +#define MALLOC_ARG_T size_t +#else +#define P(s) () +#define MALLOC_ARG_T unsigned +#define volatile +#define const +#endif + +/* #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(sparc) && !defined(__GNUC__) +#include <alloca.h> +#else +char *alloca (); +#endif +#endif /* __GNUC__ */ + +#define FREE_AND_RETURN_VOID(stackb) return +#define FREE_AND_RETURN(stackb,val) return(val) +#define DOUBLE_STACK(stackx,stackb,len) \ + (stackx = (unsigned char **) alloca (2 * len \ + * sizeof (unsigned char *)),\ + /* Only copy what is in use. */ \ + (unsigned char **) memcpy (stackx, stackb, len * sizeof (char *))) +#else /* NO_ALLOCA defined */ +#define FREE_AND_RETURN_VOID(stackb) free(stackb);return +#define FREE_AND_RETURN(stackb,val) free(stackb);return(val) +#define DOUBLE_STACK(stackx,stackb,len) \ + (unsigned char **)xrealloc (stackb, 2 * len * sizeof (unsigned char *)) +#endif /* NO_ALLOCA */ + +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_2 P((int, char *, char *, int, int )); +static int memcmp_translate P((unsigned char *, unsigned char *, + int, unsigned char *)); +long re_set_syntax P((long)); + +/* 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 + +#define SYNTAX(c) re_syntax_table[c] + + +#ifdef SYNTAX_TABLE + +char *re_syntax_table; + +#else /* not SYNTAX_TABLE */ + +static char re_syntax_table[256]; +static void init_syntax_once P((void)); + + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + 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; + + /* 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; + + done = 1; +} + +#endif /* SYNTAX_TABLE */ +#undef P +#endif /* emacs */ + + +/* Sequents are missing isgraph. */ +#ifndef isgraph +#define isgraph(c) (isprint((c)) && !isspace((c))) +#endif + +/* Get the interface, including the syntax bits. */ +#include "regex.h" + + +/* These are the command codes that appear in compiled regular + expressions, one per byte. Some command codes are followed by + argument bytes. A command code can specify any interpretation + whatsoever for its arguments. Zero-bytes may appear in the compiled + regular expression. + + The value of `exactn' is needed in search.c (search_buffer) in emacs. + So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of + `exactn' we use here must also be 1. */ + +enum regexpcode + { + unused=0, + exactn=1, /* Followed by one byte giving n, then by n literal bytes. */ + begline, /* Fail unless at beginning of line. */ + endline, /* Fail unless at end of line. */ + jump, /* Followed by two bytes giving relative address to jump to. */ + 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 + address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* Jump, and push a dummy failure point. This + failure point will be thrown away if an attempt + is made to use it for a failure. A + construct + makes this before the first repeat. Also + use it as an intermediary kind of jump when + compiling an or construct. */ + 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 + address is followed by two bytes containing n. */ + jump_n, /* Similar to jump, but jump n times only; also the relative + address following is in turn followed by yet two more bytes + containing n. */ + set_number_at, /* Set the following relative location to the + subsequent number. */ + anychar, /* Matches any (more or less) one character. */ + charset, /* Matches any one char belonging to specified set. + First following byte is number of bitmap bytes. + Then come bytes for a bitmap saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set. */ + charset_not, /* Same parameters as charset, but match any character + that is not one of those specified. */ + start_memory, /* Start remembering the text that is matched, for + storing in a memory register. Followed by one + byte containing the register number. Register numbers + must be in the range 0 through RE_NREGS. */ + stop_memory, /* Stop remembering the text that is matched + 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. */ + duplicate, /* Match a duplicate of something remembered. + Followed by one byte containing the index of the memory + register. */ + before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + begbuf, /* Succeeds if at beginning of buffer. */ + endbuf, /* Succeeds if at end of buffer. */ + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + wordbound, /* Succeeds if at a word boundary. */ + notwordbound,/* Succeeds if not at a word boundary. */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, + e.g., Sword. */ + notsyntaxspec /* Matches any character whose syntax differs from + that specified. */ + }; + + +/* Number of failure points to allocate space for initially, + when matching. If this number is exceeded, more space is allocated, + so it is not a hard limit. */ + +#ifndef NFAILURES +#define NFAILURES 80 +#endif + +#ifdef CHAR_UNSIGNED +#define SIGN_EXTEND_CHAR(c) ((c)>(char)127?(c)-256:(c)) /* for IBM RT */ +#endif +#ifndef SIGN_EXTEND_CHAR +#define SIGN_EXTEND_CHAR(x) (x) +#endif + + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ +#define STORE_NUMBER(destination, number) \ + { (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; } + +/* 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; } + + +/* 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; } + +/* 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; } + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit-mask comprised of the various bits + defined in regex.h. */ + +long +re_set_syntax (syntax) + long syntax; +{ + long ret; + + ret = obscure_syntax; + obscure_syntax = syntax; + return ret; +} + +/* Set by re_set_syntax to the current regexp syntax to recognize. */ +#ifdef EUC +#define DEFAULT_MBCTYPE RE_MBCTYPE_EUC +#else +#ifdef SJIS +#define DEFAULT_MBCTYPE RE_MBCTYPE_SJIS +#else +#define DEFAULT_MBCTYPE 0 +#endif +#endif +long obscure_syntax = DEFAULT_MBCTYPE; + + +/* Macros for re_compile_pattern, which is found below these definitions. */ + +#define CHAR_CLASS_MAX_LENGTH 6 + +/* Fetch the next character in the uncompiled pattern, translating it if + necessary. */ +#define PATFETCH(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; \ + if (translate && !ismbchar (c)) \ + c = (unsigned char) translate[(unsigned char) c]; } + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + {if (p == pend) goto end_of_pattern; \ + c = * (unsigned char *) p++; } + +#define PATUNFETCH p-- + + +/* 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) \ + { \ + while (b - bufp->buffer + (n) >= bufp->allocated) \ + EXTEND_BUFFER; \ + } + +/* Make sure we have one more byte of buffer space and then add CH to it. */ +#define BUFPUSH(ch) \ + { \ + GET_BUFFER_SPACE (1); \ + *b++ = (char) (ch); \ + } + +/* 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; \ + 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); \ + 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 (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } + +/* Set the bit for character C in a character set list. */ +#define SET_LIST_BIT(c) \ + (b[(unsigned char) (c) / BYTEWIDTH] \ + |= 1 << ((unsigned char) (c) % BYTEWIDTH)) + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (isdigit (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +/* Subroutines for re_compile_pattern. */ +/* static void store_jump (), insert_jump (), store_jump_n (), + insert_jump_n (), insert_op_2 (); */ + +#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 EXTRACT_MBC(p) \ + ((unsigned char)(p)[0] << 8 | (unsigned char)(p)[1]) +#define EXTRACT_MBC_AND_INCR(p) \ + ((p) += 2, (unsigned char)(p)[-2] << 8 | (unsigned char)(p)[-1]) + +#define EXTRACT_UNSIGNED(p) \ + ((unsigned char)(p)[0] | (unsigned char)(p)[1] << 8) +#define EXTRACT_UNSIGNED_AND_INCR(p) \ + ((p) += 2, (unsigned char)(p)[-2] | (unsigned char)(p)[-1] << 8) + +/* Handle (mb)?charset(_not)?. + + Structure of mbcharset(_not)? in compiled pattern. + + struct { + unsinged char id; mbcharset(_not)? + unsigned char sbc_size; + 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. + } intervals[mbc_size]; + }; */ + +static void +#ifdef __STDC__ +set_list_bits (unsigned short c1, unsigned short c2, + unsigned char *b, const unsigned char *translate) +#else +set_list_bits (c1, c2, b, translate) + unsigned short c1, c2; + unsigned char *b; + const unsigned char *translate; +#endif +{ + enum regexpcode op = (enum regexpcode) b[-2]; + unsigned char sbc_size = b[-1]; + unsigned short mbc_size = EXTRACT_UNSIGNED (&b[sbc_size]); + unsigned short c, beg, end, upb; + + if (c1 > c2) + return; + if (c1 < 1 << BYTEWIDTH) { + upb = c2; + if (1 << BYTEWIDTH <= upb) + upb = (1 << BYTEWIDTH) - 1; /* The last single-byte char */ + if (sbc_size <= 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; + } + if (!translate) { + for (; c1 <= upb; c1++) + if (!ismbchar (c1)) + SET_LIST_BIT (c1); + } + else + for (; c1 <= upb; c1++) + if (!ismbchar (c1)) + SET_LIST_BIT (translate[c1]); + if (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 = (beg + upb) >> 1; + + if (c1 - 1 > EXTRACT_MBC (&b[mid*4 + 2])) + beg = mid + 1; + else + upb = mid; + } + + for (end = beg, upb = mbc_size; end < upb; ) { + unsigned short mid = (end + upb) >> 1; + + if (c2 >= EXTRACT_MBC (&b[mid*4]) - 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 (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); + mbc_size += beg + 1 - end; + STORE_NUMBER (&b[-2], mbc_size); +} + +static int +#ifdef __STDC__ +is_in_list (unsigned short c, const unsigned char *b) +#else +is_in_list (c, b) + unsigned short c; + const unsigned char *b; +#endif +{ + unsigned short size; + int in = (enum regexpcode) b[-1] == charset_not; + + size = *b++; + if (c < 1 << BYTEWIDTH) { + if (c / BYTEWIDTH < size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH) + in = !in; + } + else { + unsigned short i, j; + + b += size + 2; + size = EXTRACT_UNSIGNED (&b[-2]); + + for (i = 0, j = size; i < j; ) { + unsigned short k = (i + j) >> 1; + + if (c > EXTRACT_MBC (&b[k*4 + 2])) + i = k + 1; + else + j = k; + } + if (i < size && EXTRACT_MBC (&b[i*4]) <= c + && ((unsigned char) c != '\n' && (unsigned char) c != '\0')) + in = !in; + } + return in; +} + +/* re_compile_pattern takes a regular-expression string + and converts it into a buffer full of byte commands for matching. + + PATTERN is the address of the pattern string + SIZE is the length of it. + BUFP is a struct re_pattern_buffer * which points to the info + on where to store the byte commands. + This structure contains a char * which points to the + actual space, which should have been obtained with malloc. + re_compile_pattern may use realloc to grow the buffer space. + + The number of bytes of commands can be found out by looking in + the `struct re_pattern_buffer' that bufp pointed to, after + re_compile_pattern returns. */ + +char * +re_compile_pattern (pattern, size, bufp) + char *pattern; + size_t size; + struct re_pattern_buffer *bufp; +{ + register char *b = bufp->buffer; + register char *p = pattern; + char *pend = pattern + size; + register unsigned c, c1; + char *p0; + unsigned char *translate = (unsigned char *) bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell whether a new exact-match + character can be added to that command or requires a new `exactn' + command. */ + + char *pending_exact = 0; + + /* Address of the place where a forward-jump should go to the end of + the containing expression. Each alternative of an `or', except the + last, ends with a forward-jump of this sort. */ + + char *fixup_jump = 0; + + /* Address of start of the most recently finished expression. + This tells postfix * where to find the start of its operand. */ + + char *laststart = 0; + + /* In processing a repeat, 1 means zero matches is allowed. */ + + char zero_times_ok; + + /* In processing a repeat, 1 means many matches is allowed. */ + + char many_times_ok; + + /* Address of beginning of regexp, or inside of last \(. */ + + char *begalt = b; + + /* 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; + + /* Place in pattern (i.e., the {) to which to go back if the interval + is invalid. */ + char *beg_interval = 0; + + /* Stack of information saved by \( and restored by \). + Four stack elements are pushed by each \(: + First, the value of b. + Second, the value of fixup_jump. + Third, the value of regnum. + Fourth, the value of begalt. */ + + int stackb[40]; + int *stackp = stackb; + int *stacke = stackb + 40; + int *stackt; + + /* 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; + + bufp->fastmap_accurate = 0; + +#ifndef emacs +#ifndef SYNTAX_TABLE + /* Initialize the syntax table. */ + init_syntax_once(); +#endif +#endif + + 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) + { + PATFETCH (c); + + switch (c) + { + case '$': + { + char *p1 = p; + /* When testing what follows the $, + look past the \-constructs that don't consume anything. */ + if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + while (p1 != pend) + { + if (*p1 == '\\' && p1 + 1 != pend + && (p1[1] == '<' || p1[1] == '>' + || p1[1] == '`' || p1[1] == '\'' +#ifdef emacs + || p1[1] == '=' +#endif + || p1[1] == 'b' || p1[1] == 'B')) + p1 += 2; + else + break; + } + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (! (obscure_syntax & 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; + } + /* $ 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 ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && p1 != pend) + goto invalid_pattern; + if (p1 == pend || *p1 == '\n' + || (obscure_syntax & RE_CONTEXT_INDEP_OPS) + || (obscure_syntax & RE_NO_BK_PARENS + ? *p1 == ')' + : *p1 == '\\' && p1[1] == ')') + || (obscure_syntax & RE_NO_BK_VBAR + ? *p1 == '|' + : *p1 == '\\' && p1[1] == '|')) + { + BUFPUSH (endline); + break; + } + goto normal_char; + } + case '^': + /* ^ means succeed if at beg of line, but only if no preceding + pattern. */ + + if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) && laststart) + goto invalid_pattern; + if (laststart && p - 2 >= pattern && p[-2] != '\n' + && !(obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + if (obscure_syntax & RE_TIGHT_VBAR) + { + if (p != pattern + 1 + && ! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + BUFPUSH (begline); + begalt = b; + } + else + BUFPUSH (begline); + break; + + case '+': + case '?': + if ((obscure_syntax & RE_BK_PLUS_QM) + || (obscure_syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern, char not special. */ + if (!laststart) + { + if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) + goto invalid_pattern; + else if (! (obscure_syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + /* If there is a sequence of repetition chars, + collapse it down to just one. */ + zero_times_ok = 0; + many_times_ok = 0; + while (1) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + if (p == pend) + break; + PATFETCH (c); + if (c == '*') + ; + else if (!(obscure_syntax & RE_BK_PLUS_QM) + && (c == '+' || c == '?')) + ; + else if ((obscure_syntax & RE_BK_PLUS_QM) + && c == '\\') + { + /* int c1; */ + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + c = c1; + } + else + { + PATUNFETCH; + break; + } + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { + /* If more than one repetition is allowed, put in at the + end a backward relative jump from b to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). */ + GET_BUFFER_SPACE (3); + store_jump (b, maybe_finalize_jump, laststart - 3); + b += 3; /* Because store_jump put stuff here. */ + } + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + insert_jump (on_failure_jump, laststart, b + 3, b); + pending_exact = 0; + b += 3; + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + dummy-failure before the initial on-failure-jump + instruction of the loop. This effects a skip over that + instruction the first time we hit that loop. */ + GET_BUFFER_SPACE (6); + insert_jump (dummy_failure_jump, laststart, laststart + 6, b); + b += 3; + } + break; + + case '.': + laststart = b; + BUFPUSH (anychar); + break; + + case '[': + if (p == pend) + goto invalid_pattern; + while (b - bufp->buffer + > bufp->allocated - 9 - (1 << BYTEWIDTH) / BYTEWIDTH) + EXTEND_BUFFER; + + laststart = b; + if (*p == '^') + { + BUFPUSH (charset_not); + p++; + } + else + BUFPUSH (charset); + p0 = p; + + BUFPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + /* Clear the whole map */ + memset (b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); + + if ((obscure_syntax & RE_HAT_NOT_NEWLINE) && b[-2] == charset_not) + SET_LIST_BIT ('\n'); + + + /* Read in characters and ranges, setting map bits. */ + while (1) + { + int size; + + 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; + while (b + size + 1 > bufp->buffer + bufp->allocated) + EXTEND_BUFFER; + } + /* Don't translate while fetching, in case it's a range bound. + When we set the bit for the character, we translate it. */ + PATFETCH_RAW (c); + + /* If set, \ escapes characters when inside [...]. */ + if ((obscure_syntax & RE_AWK_CLASS_HACK) && c == '\\') + { + PATFETCH(c1); + if (ismbchar (c1)) { + unsigned char c2; + + PATFETCH_RAW (c2); + c1 = c1 << 8 | c2; + set_list_bits (c1, c1, (unsigned char *) b, translate); + continue; + } + SET_LIST_BIT (c1); + continue; + } + if (c == ']') + { + if (p == p0 + 1) + { + /* If this is an empty bracket expression. */ + if ((obscure_syntax & 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 (ismbchar (c)) { + unsigned char c2; + + PATFETCH_RAW (c2); + c = c << 8 | c2; + } + /* Get a range. */ + if (p[0] == '-' && p[1] != ']') + { + PATFETCH_RAW (c1); + /* Don't translate the range bounds while fetching them. */ + PATFETCH_RAW (c1); + if (ismbchar (c)) { + unsigned char c2; + + PATFETCH_RAW (c2); + c1 = c1 << 8 | c2; + } + + if ((obscure_syntax & RE_NO_EMPTY_RANGES) && c > c1) + goto invalid_pattern; + + if ((obscure_syntax & RE_NO_HYPHEN_RANGE_END) + && c1 == '-' && *p != ']') + goto invalid_pattern; + + set_list_bits (c, c1, (unsigned char *) b, translate); + } + else if ((obscure_syntax & RE_CHAR_CLASSES) + && c == '[' && p[0] == ':') + { + /* Longest valid character class word has six characters. */ + char str[CHAR_CLASS_MAX_LENGTH]; + PATFETCH_RAW (c); + c1 = 0; + /* If no ] at end. */ + if (p == pend) + goto invalid_pattern; + while (1) + { + /* Don't translate the ``character class'' characters. */ + PATFETCH_RAW (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + if (p == pend + || c == ']' /* End of the bracket expression. */ + || p[0] != ']' + || p + 1 == pend + || (strcmp (str, "alpha") != 0 + && strcmp (str, "upper") != 0 + && strcmp (str, "lower") != 0 + && strcmp (str, "digit") != 0 + && strcmp (str, "alnum") != 0 + && strcmp (str, "xdigit") != 0 + && strcmp (str, "space") != 0 + && strcmp (str, "print") != 0 + && strcmp (str, "punct") != 0 + && strcmp (str, "graph") != 0 + && strcmp (str, "cntrl") != 0)) + { + /* Undo the ending character, the letters, and leave + the leading : and [ (but set bits for them). */ + c1++; + while (c1--) + PATUNFETCH; +#if 1 /* The original was: */ + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); +#else /* I think this is the right way. */ + if (translate) { + SET_LIST_BIT (translate['[']); + SET_LIST_BIT (trasnlate[':']); + } + else { + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + } +#endif + } + else + { + /* The ] at the end of the character class. */ + PATFETCH (c); + if (c != ']') + goto invalid_pattern; + for (c = 0; c < (1 << BYTEWIDTH); c++) + { + if ((strcmp (str, "alpha") == 0 && isalpha (c)) + || (strcmp (str, "upper") == 0 && isupper (c)) + || (strcmp (str, "lower") == 0 && islower (c)) + || (strcmp (str, "digit") == 0 && isdigit (c)) + || (strcmp (str, "alnum") == 0 && isalnum (c)) + || (strcmp (str, "xdigit") == 0 && isxdigit (c)) + || (strcmp (str, "space") == 0 && isspace (c)) + || (strcmp (str, "print") == 0 && isprint (c)) + || (strcmp (str, "punct") == 0 && ispunct (c)) + || (strcmp (str, "graph") == 0 && isgraph (c)) + || (strcmp (str, "cntrl") == 0 && iscntrl (c))) + SET_LIST_BIT (c); + } + } + } + else if (translate && c < 1 << BYTEWIDTH) + SET_LIST_BIT (translate[c]); + else + set_list_bits (c, c, (unsigned char *) b, translate); + } + + /* 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) + 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; + break; + + case '(': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_open; + + case ')': + if (! (obscure_syntax & RE_NO_BK_PARENS)) + goto normal_char; + else + goto handle_close; + + case '\n': + if (! (obscure_syntax & RE_NEWLINE_OR)) + goto normal_char; + else + goto handle_bar; + + case '|': + if ((obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) + && (! laststart || p == pend)) + goto invalid_pattern; + else if (! (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_char; + else + goto handle_bar; + + case '{': + if (! ((obscure_syntax & RE_NO_BK_CURLY_BRACES) + && (obscure_syntax & RE_INTERVALS))) + goto normal_char; + else + goto handle_interval; + + case '\\': + if (p == pend) goto invalid_pattern; + PATFETCH_RAW (c); + switch (c) + { + case '(': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_open: + if (stackp == stacke) goto nesting_too_deep; + + /* Laststart should point to the start_memory that we are about + to push (unless the pattern has RE_NREGS or more ('s). */ + *stackp++ = b - bufp->buffer; + if (regnum < RE_NREGS) + { + BUFPUSH (start_memory); + BUFPUSH (regnum); + } + *stackp++ = fixup_jump ? fixup_jump - bufp->buffer + 1 : 0; + *stackp++ = regnum++; + *stackp++ = begalt - bufp->buffer; + fixup_jump = 0; + laststart = 0; + begalt = b; + break; + + case ')': + if (obscure_syntax & RE_NO_BK_PARENS) + goto normal_backsl; + handle_close: + if (stackp == stackb) goto unmatched_close; + begalt = *--stackp + bufp->buffer; + if (fixup_jump) + store_jump (fixup_jump, jump, b); + if (stackp[-1] < RE_NREGS) + { + BUFPUSH (stop_memory); + BUFPUSH (stackp[-1]); + } + stackp -= 2; + fixup_jump = *stackp ? *stackp + bufp->buffer - 1 : 0; + laststart = *--stackp + bufp->buffer; + break; + + case '|': + if ((obscure_syntax & RE_LIMITED_OPS) + || (obscure_syntax & RE_NO_BK_VBAR)) + goto normal_backsl; + handle_bar: + if (obscure_syntax & RE_LIMITED_OPS) + goto normal_char; + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (6); + 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; + b += 3; + + laststart = 0; + begalt = b; + break; + + case '{': + if (! (obscure_syntax & RE_INTERVALS) + /* Let \{ be a literal. */ + || ((obscure_syntax & RE_INTERVALS) + && (obscure_syntax & RE_NO_BK_CURLY_BRACES)) + /* If it's the string "\{". */ + || (p - 2 == pattern && p == pend)) + goto normal_backsl; + handle_interval: + beg_interval = p - 1; /* The {. */ + /* If there is no previous pattern, this isn't an interval. */ + if (!laststart) + { + if (obscure_syntax & RE_CONTEXTUAL_INVALID_OPS) + goto invalid_pattern; + else + goto normal_backsl; + } + /* 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 == start_memory + || (*laststart == exactn && laststart[1] == 1) + || (! (obscure_syntax & RE_NO_BK_REFS) + && *laststart == duplicate))) + { + if (obscure_syntax & RE_NO_BK_CURLY_BRACES) + goto normal_char; + + /* Posix extended syntax is handled in previous + statement; this is for Posix basic syntax. */ + if (obscure_syntax & RE_INTERVALS) + goto invalid_pattern; + + goto normal_backsl; + } + 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) + upper_bound = lower_bound; + if (! (obscure_syntax & RE_NO_BK_CURLY_BRACES)) + { + if (c != '\\') + goto invalid_pattern; + PATFETCH (c); + } + if (c != '}' || lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound + || ((obscure_syntax & RE_NO_BK_CURLY_BRACES) + && p != pend && *p == '{')) + { + if (obscure_syntax & RE_NO_BK_CURLY_BRACES) + goto unfetch_interval; + else + goto invalid_pattern; + } + + /* 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; + } + + /* Otherwise, after lower_bound number of succeeds, jump + to after the jump_n which will be inserted at the end + of the buffer, and insert that jump_n. */ + else + { /* Set to 5 if only one repetition is allowed and + hence no jump_n is inserted at the current end of + the buffer; then only space for the succeed_n is + needed. Otherwise, need space for both the + succeed_n and the jump_n. */ + + unsigned slots_needed = upper_bound == 1 ? 5 : 10; + + GET_BUFFER_SPACE (slots_needed); + /* Initialize the succeed_n to n, even though it will + be set by its attendant set_number_at, because + re_compile_fastmap will need to know it. Jump to + what the end of buffer will be after inserting + this succeed_n and possibly appending a jump_n. */ + insert_jump_n (succeed_n, laststart, b + slots_needed, + b, lower_bound); + b += 5; /* Just increment for the succeed_n here. */ + + /* More than one repetition is allowed, so put in at + the end of the buffer a backward jump from b to the + succeed_n we put in above. By the time we've gotten + to this jump when matching, we'll have matched once + already, so jump back only upper_bound - 1 times. */ + + if (upper_bound > 1) + { + store_jump_n (b, jump_n, laststart, upper_bound - 1); + b += 5; + /* When hit this when matching, reset the + preceding jump_n's n to upper_bound - 1. */ + BUFPUSH (set_number_at); + GET_BUFFER_SPACE (2); + STORE_NUMBER_AND_INCR (b, -5); + STORE_NUMBER_AND_INCR (b, upper_bound - 1); + } + /* When hit this when matching, set the succeed_n's n. */ + GET_BUFFER_SPACE (5); + insert_op_2 (set_number_at, laststart, b, 5, lower_bound); + b += 5; + } + pending_exact = 0; + beg_interval = 0; + break; + + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + if (beg_interval) + p = beg_interval; + else + { + fprintf (stderr, + "regex: no interval beginning to which to backtrack.\n"); + exit (1); + } + + beg_interval = 0; + PATFETCH (c); /* normal_char expects char in `c'. */ + goto normal_char; + break; + +#ifdef emacs + case '=': + BUFPUSH (at_dot); + break; + + case 's': + laststart = b; + BUFPUSH (syntaxspec); + PATFETCH (c); + BUFPUSH (syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + BUFPUSH (notsyntaxspec); + PATFETCH (c); + BUFPUSH (syntax_spec_code[c]); + break; +#endif /* emacs */ + +#ifdef RUBY + case 's': + case 'S': + case 'd': + case 'D': + while (b - bufp->buffer + > bufp->allocated - 9 - (1 << BYTEWIDTH) / BYTEWIDTH) + EXTEND_BUFFER; + + laststart = b; + if (c == 's' || c == 'd') { + BUFPUSH (charset); + } + else { + BUFPUSH (charset_not); + } + + BUFPUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + memset (b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); + if (c == 's' || c == 'S') { + SET_LIST_BIT (' '); + SET_LIST_BIT ('\t'); + SET_LIST_BIT ('\n'); + SET_LIST_BIT ('\r'); + SET_LIST_BIT ('\f'); + } + else { + char cc; + + for (cc = '0'; cc <= '9'; cc++) { + SET_LIST_BIT (cc); + } + } + + 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; + break; +#endif /* RUBY */ + + case 'w': + laststart = b; + BUFPUSH (wordchar); + break; + + case 'W': + laststart = b; + BUFPUSH (notwordchar); + break; +#ifndef RUBY + case '<': + BUFPUSH (wordbeg); + break; + + case '>': + BUFPUSH (wordend); + break; +#endif /* RUBY */ + case 'b': + BUFPUSH (wordbound); + break; + + case 'B': + BUFPUSH (notwordbound); + break; + + case '`': + BUFPUSH (begbuf); + break; + + case '\'': + BUFPUSH (endbuf); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (obscure_syntax & RE_NO_BK_REFS) + goto normal_char; + c1 = c - '0'; + if (c1 >= regnum) + { + if (obscure_syntax & RE_NO_EMPTY_BK_REF) + goto invalid_pattern; + else + goto normal_char; + } + /* Can't back reference to a subexpression if inside of it. */ + for (stackt = stackp - 2; stackt > stackb; stackt -= 4) + if (*stackt == c1) + goto normal_char; + laststart = b; + BUFPUSH (duplicate); + BUFPUSH (c1); + break; + + case '+': + case '?': + if (obscure_syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backsl; + break; + + default: + normal_backsl: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + if (translate && !ismbchar (c)) c = (unsigned char) translate[c]; + goto normal_char; + } + break; + + default: + normal_char: /* Expects the character in `c'. */ + c1 = 0; + if (ismbchar (c)) { + c1 = c; + PATFETCH_RAW (c); + } + if (!pending_exact || pending_exact + *pending_exact + 1 != b + || *pending_exact >= (c1 ? 0176 : 0177) + || *p == '*' || *p == '^' + || ((obscure_syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((obscure_syntax & RE_INTERVALS) + && ((obscure_syntax & RE_NO_BK_CURLY_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + laststart = b; + BUFPUSH (exactn); + pending_exact = b; + BUFPUSH (0); + } + if (c1) { + BUFPUSH (c1); + (*pending_exact)++; + } + BUFPUSH (c); + (*pending_exact)++; + } + } + + if (fixup_jump) + store_jump (fixup_jump, jump, b); + + if (stackp != stackb) goto unmatched_open; + + bufp->used = b - bufp->buffer; + return 0; + + invalid_pattern: + return "Invalid regular expression"; + + unmatched_open: + return "Unmatched \\("; + + unmatched_close: + return "Unmatched \\)"; + + end_of_pattern: + return "Premature end of regular expression"; + + nesting_too_deep: + return "Nesting too deep"; + + too_big: + return "Regular expression too big"; + + memory_exhausted: + return "Memory exhausted"; +} + + +/* Store a jump of the form <OPCODE> <relative address>. + Store in the location FROM a jump operation to jump to relative + address FROM - TO. OPCODE is the opcode to store. */ + +static void +store_jump (from, opcode, to) + char *from, *to; + int opcode; +{ + from[0] = (char)opcode; + STORE_NUMBER(from + 1, to - (from + 3)); +} + + +/* Open up space before char FROM, and insert there a jump to TO. + CURRENT_END gives the end of the storage not in use, so we know + how much data to copy up. OP is the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_jump (op, from, to, current_end) + int op; + char *from, *to, *current_end; +{ + register char *pfrom = current_end; /* Copy from here... */ + register char *pto = current_end + 3; /* ...to here. */ + + while (pfrom != from) + *--pto = *--pfrom; + store_jump (from, op, to); +} + + +/* Store a jump of the form <opcode> <relative address> <n> . + + Store in the location FROM a jump operation to jump to relative + address FROM - TO. OPCODE is the opcode to store, N is a number the + jump uses, say, to decide how many times to jump. + + If you call this function, you must zero out pending_exact. */ + +static void +store_jump_n (from, opcode, to, n) + char *from, *to; + int opcode; + unsigned n; +{ + from[0] = (char)opcode; + STORE_NUMBER (from + 1, to - (from + 3)); + STORE_NUMBER (from + 3, n); +} + + +/* Similar to insert_jump, but handles a jump which needs an extra + number to handle minimum and maximum cases. Open up space at + location FROM, and insert there a jump to TO. CURRENT_END gives the + end of the storage in use, so we know how much data to copy up. OP is + the opcode of the jump to insert. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_jump_n (op, from, to, current_end, n) + int op; + char *from, *to, *current_end; + unsigned n; +{ + register char *pfrom = current_end; /* Copy from here... */ + register char *pto = current_end + 5; /* ...to here. */ + + while (pfrom != from) + *--pto = *--pfrom; + store_jump_n (from, op, to, n); +} + + +/* Open up space at location THERE, and insert operation OP followed by + NUM_1 and NUM_2. CURRENT_END gives the end of the storage in use, so + we know how much data to copy up. + + If you call this function, you must zero out pending_exact. */ + +static void +insert_op_2 (op, there, current_end, num_1, num_2) + int op; + char *there, *current_end; + int num_1, num_2; +{ + register char *pfrom = current_end; /* Copy from here... */ + register char *pto = current_end + 5; /* ...to here. */ + + while (pfrom != there) + *--pto = *--pfrom; + + there[0] = (char)op; + STORE_NUMBER (there + 1, num_1); + STORE_NUMBER (there + 3, num_2); +} + + + +/* Given a pattern, compute a fastmap from it. The fastmap records + which of the (1 << BYTEWIDTH) possible characters can start a string + that matches the pattern. This fastmap is used by re_search to skip + quickly over totally implausible text. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as bufp->fastmap. + The other components of bufp describe the pattern to be used. */ + +void +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + 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; + +#ifndef NO_ALLOCA + unsigned char *stackb[NFAILURES]; + unsigned char **stackp = stackb; + +#else + unsigned char **stackb; + unsigned char **stackp; + stackb = (unsigned char **) xmalloc (NFAILURES * sizeof (unsigned char *)); + stackp = stackb; + +#endif /* NO_ALLOCA */ + memset (fastmap, 0, (1 << BYTEWIDTH)); + bufp->fastmap_accurate = 1; + bufp->can_be_null = 0; + + while (p) + { + is_a_succeed_n = 0; + if (p == pend) + { + bufp->can_be_null = 1; + break; + } +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + case exactn: +#if 0 /* The original was: */ + if (translate) + fastmap[translate[p[1]]] = 1; + else + fastmap[p[1]] = 1; +#else /* The compiled pattern has already been translated. */ + fastmap[p[1]] = 1; +#endif + break; + + case begline: + case before_dot: + case at_dot: + case after_dot: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + continue; + + case endline: + if (translate) + fastmap[translate['\n']] = 1; + else + fastmap['\n'] = 1; + + if (bufp->can_be_null != 1) + bufp->can_be_null = 2; + break; + + case jump_n: + case finalize_jump: + case maybe_finalize_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + /* Jump backward reached implies we just went through + the body of a loop and matched nothing. + Opcode jumped to should be an on_failure_jump. + Just treat it like an ordinary jump. + 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 != succeed_n) + continue; + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (stackp != stackb && *stackp == p) + stackp--; + continue; + + case on_failure_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + *++stackp = p + j; + if (is_a_succeed_n) + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + continue; + + case succeed_n: + is_a_succeed_n = 1; + /* Get to the number of times to succeed. */ + p += 2; + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + goto handle_on_failure_jump; + } + continue; + + case set_number_at: + p += 4; + continue; + + case start_memory: + case stop_memory: + p++; + continue; + + case duplicate: + bufp->can_be_null = 1; + fastmap['\n'] = 1; + case anychar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (j != '\n') + fastmap[j] = 1; + if (bufp->can_be_null) + { + FREE_AND_RETURN_VOID(stackb); + } + /* Don't return; check the alternative paths + so we can set can_be_null if appropriate. */ + break; + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + +#else /* not emacs */ + case syntaxspec: + case notsyntaxspec: + break; +#endif /* not emacs */ + + case charset: + /* NOTE: Charset for single-byte chars never contain + multi-byte char. See set_list_bits(). */ + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + { +#if 0 /* The original was: */ + if (translate) + fastmap[translate[j]] = 1; + else + fastmap[j] = 1; +#else /* The compiled pattern has already been translated. */ + fastmap[j] = 1; +#endif + } + { + unsigned short size; + unsigned char c, end; + + p += p[-1] + 2; + size = EXTRACT_UNSIGNED (&p[-2]); + for (j = 0; j < size; j++) + /* 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; + } + break; + + case charset_not: + /* S: set of all single-byte chars. + M: set of all first bytes that can start multi-byte chars. + s: any set of single-byte chars. + m: any set of first bytes that can start multi-byte chars. + + We assume S+M = U. + ___ _ _ + s+m = (S*s+M*m). */ + /* Chars beyond end of map must be allowed */ + /* NOTE: Charset_not for single-byte chars might contain + multi-byte chars. See set_list_bits(). */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + if (!ismbchar (j)) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + { + if (!ismbchar (j)) + fastmap[j] = 1; + } + { + unsigned short size; + unsigned char c, beg; + + p += p[-1] + 2; + size = EXTRACT_UNSIGNED (&p[-2]); + c = 0x8000; + for (j = 0; j < size; j++) { + 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; + } + } + break; + + case unused: /* pacify gcc -Wall */ + break; + } + + /* Get here means we have successfully found the possible starting + characters of one path of the pattern. We need not follow this + path any farther. Instead, look at the next alternative + remembered in the stack. */ + if (stackp != stackb) + p = *stackp--; + else + break; + } + FREE_AND_RETURN_VOID(stackb); +} + + + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (pbufp, string, size, startpos, range, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (pbufp, (char *) 0, 0, string, size, startpos, range, + regs, size); +} + + +/* Using the compiled pattern in PBUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. RANGE is the number of + places to try before giving up. If RANGE is negative, it searches + backwards, i.e., the starting positions tried are STARTPOS, STARTPOS + - 1, etc. STRING1 and STRING2 are of SIZE1 and SIZE2, respectively. + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire PBUFP->buffer and its contained + subexpressions. Do not consider matching one past the index MSTOP in + the virtual concatenation of STRING1 and STRING2. + + The value returned is the position in the strings at which the match + was found, or -1 if no match was found, or -2 if error (such as + failure stack overflow). */ + +int +re_search_2 (pbufp, string1, size1, string2, size2, startpos, range, + regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1, *string2; + int size1, size2; + int startpos; + register int range; + struct re_registers *regs; + int mstop; +{ + register char *fastmap = pbufp->fastmap; + register unsigned char *translate = (unsigned char *) pbufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + int val; + + /* Check for out-of-range starting position. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up range if it would eventually take startpos outside of the + virtual concatenation of string1 and string2. */ + if (endpos < -1) + range = -1 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* Update the fastmap now if not correct already. */ + if (fastmap && !pbufp->fastmap_accurate) + re_compile_fastmap (pbufp); + + /* If the search isn't to be a backwards one, don't waste time in a + long search for a pattern that says it is anchored. */ + if (pbufp->used > 0 && (enum regexpcode) pbufp->buffer[0] == begbuf + && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + while (1) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot possibly be the start of a match. Note, however, that + if the pattern can possibly match the null string, we must + test it at each starting point so that we take the first null + string we get. */ + + if (fastmap && startpos < total_size && pbufp->can_be_null != 1) + { + if (range > 0) /* Searching forwards. */ + { + register int lim = 0; + register unsigned char *p, c; + int irange = range; + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + p = ((unsigned char *) + &(startpos >= size1 ? string2 - size1 : string1)[startpos]); + + while (range > lim) { + c = *p++; + if (ismbchar (c)) { + if (fastmap[c]) + break; + p++; + range--; + } + else + if (fastmap[translate ? translate[c] : c]) + break; + range--; + } + startpos += irange - range; + } + else /* Searching backwards. */ + { + register unsigned char c; + + if (string1 == 0 || startpos >= size1) + c = string2[startpos - size1]; + else + c = string1[startpos]; + + c &= 0xff; + if (translate ? !fastmap[translate[c]] : !fastmap[c]) + goto advance; + } + } + + if (range >= 0 && startpos == total_size + && fastmap && pbufp->can_be_null == 0) + return -1; + + val = re_match_2 (pbufp, string1, size1, string2, size2, startpos, + regs, mstop); + if (val >= 0) + return startpos; + if (val == -2) + return -2; + +#ifndef NO_ALLOCA +#ifdef C_ALLOCA + alloca (0); +#endif /* C_ALLOCA */ + +#endif /* NO_ALLOCA */ + advance: + if (!range) + break; + else if (range > 0) { + const char *d = ((startpos >= size1 ? string2 - size1 : string1) + + startpos); + + if (ismbchar (*d)) { + range--, startpos++; + if (!range) + break; + } + range--, startpos++; + } + else { + range++, startpos--; + { + const char *s, *d, *p; + + if (startpos < size1) + s = string1, d = string1 + startpos; + else + s = string2, d = string2 + startpos - size1; + for (p = d; p-- > s && ismbchar(*p); ) + /* --p >= s would not work on 80[12]?86. + (when the offset of s equals 0 other than huge model.) */ + ; + if (!((d - p) & 1)) { + if (!range) + break; + range++, startpos--; + } + } + } + } + return -1; +} + + + +#ifndef emacs /* emacs never uses this. */ +int +re_match (pbufp, string, size, pos, regs) + struct re_pattern_buffer *pbufp; + char *string; + int size, pos; + struct re_registers *regs; +{ + return re_match_2 (pbufp, (char *) 0, 0, string, size, pos, regs, size); +} +#endif /* not emacs */ + + +/* The following are used for re_match_2, defined below: */ + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always pushed MAX_NUM_FAILURE_ITEMS each time we failed. */ + +int re_max_failures = 2000; + +/* Routine used by re_match_2. */ +/* static int memcmp_translate (); *//* already declared */ + + +/* Structure and accessing macros used in re_match_2: */ + +struct register_info +{ + unsigned is_active : 1; + unsigned matched_something : 1; +}; + +#define IS_ACTIVE(R) ((R).is_active) +#define MATCHED_SOMETHING(R) ((R).matched_something) + + +/* Macros used by re_match_2: */ + + +/* I.e., regstart, regend, and reg_info. */ + +#define NUM_REG_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 (RE_NREGS * NUM_REG_ITEMS + 2) + + +/* We push this many things on the stack whenever we fail. */ + +#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + 2) + + +/* 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) \ + { \ + 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 = RE_NREGS - 1; last_used_reg > 0; last_used_reg--)\ + if (regstart[last_used_reg] != (unsigned char *)(-1L)) \ + break; \ + \ + if (stacke - stackp < NUM_FAILURE_ITEMS) \ + { \ + unsigned char **stackx; \ + unsigned int len = stacke - stackb; \ + if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \ + { \ + FREE_AND_RETURN(stackb,(-2)); \ + } \ + \ + /* Roughly double the size of the stack. */ \ + stackx = DOUBLE_STACK(stackx,stackb,len); \ + /* Rearrange the pointers. */ \ + stackp = stackx + (stackp - stackb); \ + stackb = stackx; \ + stacke = stackb + 2 * len; \ + } \ + \ + /* Now push the info for each of those registers. */ \ + for (this_reg = 1; this_reg <= last_used_reg; this_reg++) \ + { \ + *stackp++ = regstart[this_reg]; \ + *stackp++ = regend[this_reg]; \ + *stackp++ = (unsigned char *) ®_info[this_reg]; \ + } \ + \ + /* Push how many registers we saved. */ \ + *stackp++ = (unsigned char *) last_used_reg; \ + \ + *stackp++ = pattern_place; \ + *stackp++ = string_place; \ + } + + +/* This pops what PUSH_FAILURE_POINT pushes. */ + +#define POP_FAILURE_POINT() \ + { \ + int temp; \ + stackp -= 2; /* Remove failure points. */ \ + temp = (int) *--stackp; /* How many regs pushed. */ \ + temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \ + stackp -= temp; /* Remove the register info. */ \ + } + + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Is true if there is a first string and if PTR is pointing anywhere + inside it or just past the end. */ + +#define IS_IN_FIRST_STRING(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ + +#define PREFETCH \ + while (d == dend) \ + { \ + /* end of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* end of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Call this when have matched something; it sets `matched' flags for the + registers corresponding to the subexpressions of which we currently + are inside. */ +#define SET_REGS_MATCHED \ + { unsigned this_reg; \ + for (this_reg = 0; this_reg < RE_NREGS; this_reg++) \ + { \ + if (IS_ACTIVE(reg_info[this_reg])) \ + MATCHED_SOMETHING(reg_info[this_reg]) = 1; \ + else \ + MATCHED_SOMETHING(reg_info[this_reg]) = 0; \ + } \ + } + +/* Test if at very beginning or at very end of the virtual concatenation + of string1 and string2. If there is only one string, we've put it in + string2. */ + +#define AT_STRINGS_BEG (d == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END (d == end2) + +#define AT_WORD_BOUNDARY \ + (AT_STRINGS_BEG || AT_STRINGS_END || IS_A_LETTER (d - 1) != IS_A_LETTER (d)) + +/* We have two special cases to check for: + 1) if we're past the end of string1, we have to look at the first + character in string2; + 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) == end1 ? *string2 : (d) == string2 - 1 ? *(end1 - 1) : *(d))\ + == Sword) + + +/* Match the pattern described by PBUFP against the virtual + concatenation of STRING1 and STRING2, which are of SIZE1 and SIZE2, + respectively. Start the match at index POS in the virtual + concatenation of STRING1 and STRING2. In REGS, return the indices of + the virtual concatenation of STRING1 and STRING2 that matched the + entire PBUFP->buffer and its contained subexpressions. Do not + consider matching one past the index MSTOP in the virtual + concatenation of STRING1 and STRING2. + + If pbufp->fastmap is nonzero, then it had better be up to date. + + The reason that the data to match are specified as two components + which are to be regarded as concatenated is so this function can be + used directly on the contents of an Emacs buffer. + + -1 is returned if there is no match. -2 is returned if there is an + error (such as match stack overflow). Otherwise the value is the + length of the substring which was matched. */ + +int +re_match_2 (pbufp, string1_arg, size1, string2_arg, size2, pos, regs, mstop) + struct re_pattern_buffer *pbufp; + char *string1_arg, *string2_arg; + int size1, size2; + int pos; + struct re_registers *regs; + int mstop; +{ + register unsigned char *p = (unsigned char *) pbufp->buffer; + + /* Pointer to beyond end of buffer. */ + register unsigned char *pend = p + pbufp->used; + + unsigned char *string1 = (unsigned char *) string1_arg; + unsigned char *string2 = (unsigned char *) string2_arg; + unsigned char *end1; /* Just past end of first string. */ + unsigned char *end2; /* Just past end of second string. */ + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + unsigned char *end_match_1, *end_match_2; + + register unsigned char *d, *dend; + register int mcnt; /* Multipurpose. */ + unsigned char *translate = (unsigned char *) pbufp->translate; + unsigned is_a_jump_n = 0; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to the + subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where to + resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is a + ``dummy''; if a failure happens and the failure point is a dummy, it + gets discarded and the next next one is tried. */ + +#ifndef NO_ALLOCA + unsigned char *initial_stack[MAX_NUM_FAILURE_ITEMS * NFAILURES]; +#endif + unsigned char **stackb; + unsigned char **stackp; + unsigned char **stacke; + + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ + + unsigned char *regstart[RE_NREGS]; + unsigned char *regend[RE_NREGS]; + + /* 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 + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ + + struct register_info reg_info[RE_NREGS]; + + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + + unsigned best_regs_set = 0; + unsigned char *best_regstart[RE_NREGS]; + unsigned char *best_regend[RE_NREGS]; + + /* Initialize the stack. */ +#ifdef NO_ALLOCA + stackb = (unsigned char **) xmalloc (MAX_NUM_FAILURE_ITEMS * NFAILURES * sizeof (char *)); +#else + stackb = initial_stack; +#endif + stackp = stackb; + stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES]; + +#ifdef DEBUG_REGEX + fprintf (stderr, "Entering re_match_2(%s%s)\n", string1_arg, string2_arg); +#endif + + /* Initialize subexpression text positions to -1 to mark ones that no + \( 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 < RE_NREGS; mcnt++) + { + regstart[mcnt] = regend[mcnt] = (unsigned char *) (-1L); + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + if (regs) + for (mcnt = 0; mcnt < RE_NREGS; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + + /* Set up pointers to ends of strings. + Don't allow the second string to be empty unless both are empty. */ + if (size2 == 0) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (mstop <= size1) + { + end_match_1 = string1 + mstop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + mstop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. `dend' + is the end of the input string that `d' points within. `d' is + advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal string2. */ + + if (size1 != 0 && pos <= size1) + d = string1 + pos, dend = end_match_1; + else + d = string2 + pos - size1, dend = end_match_2; + + + /* This loops over pattern commands. It exits by returning from the + function if match is complete, or it drops through if match fails + at this starting point in the input data. */ + + while (1) + { +#ifdef DEBUG_REGEX + fprintf (stderr, + "regex loop(%d): matching 0x%02d\n", + p - (unsigned char *) pbufp->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 != end_match_2) + { + if (stackp != stackb) + { + /* More failure points to try. */ + + unsigned in_same_string = + IS_IN_FIRST_STRING (best_regend[0]) + == MATCHING_IN_FIRST_STRING; + + /* If exceeds best match so far, save it. */ + if (! best_regs_set + || (in_same_string && d > best_regend[0]) + || (! in_same_string && ! MATCHING_IN_FIRST_STRING)) + { + best_regs_set = 1; + best_regend[0] = d; /* Never use regstart[0]. */ + + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. */ + d = best_regend[0]; + + for (mcnt = 0; mcnt < RE_NREGS; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } + + /* If caller wants register contents data back, convert it + to indices. */ + if (regs) + { + regs->start[0] = pos; + if (MATCHING_IN_FIRST_STRING) + regs->end[0] = d - string1; + else + regs->end[0] = d - string2 + size1; + for (mcnt = 1; mcnt < RE_NREGS; mcnt++) + { + if (regend[mcnt] == (unsigned char *)(-1L)) + { + regs->start[mcnt] = -1; + regs->end[mcnt] = -1; + continue; + } + if (IS_IN_FIRST_STRING (regstart[mcnt])) + regs->start[mcnt] = regstart[mcnt] - string1; + else + regs->start[mcnt] = regstart[mcnt] - string2 + size1; + + if (IS_IN_FIRST_STRING (regend[mcnt])) + regs->end[mcnt] = regend[mcnt] - string1; + else + regs->end[mcnt] = regend[mcnt] - string2 + size1; + } + } + FREE_AND_RETURN(stackb, + (d - pos - (MATCHING_IN_FIRST_STRING ? + string1 : + string2 - size1))); + } + + /* Otherwise match next pattern command. */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((enum regexpcode) *p++)) +#else + switch ((enum regexpcode) *p++) +#endif + { + + /* \( [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. */ + case start_memory: + regstart[*p] = d; + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + p++; + break; + + case stop_memory: + 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) + { + register unsigned char *p2 = p + 1; + mcnt = 0; + switch (*p2++) + { + case jump_n: + is_a_jump_n = 1; + 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; + break; + } + p2 += 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) + { + EXTRACT_NUMBER_AND_INCR (mcnt, p2); + PUSH_FAILURE_POINT (p2 + mcnt, d); + goto fail; + } + } + p++; + break; + + /* \<digit> has been turned into a `duplicate' command which is + followed by the numeric value of <digit> as the register number. */ + case duplicate: + { + int regno = *p++; /* Get which register to match against */ + register unsigned char *d2, *dend2; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((IS_IN_FIRST_STRING (regstart[regno]) + == IS_IN_FIRST_STRING (regend[regno])) + ? regend[regno] : end_match_1); + while (1) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + d2 = string2, dend2 = regend[regno]; /* end of string1 => advance to string2. */ + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH; + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? memcmp_translate (d, d2, mcnt, translate) + : memcmp ((char *)d, (char *)d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + case anychar: + PREFETCH; /* Fetch a data character. */ + /* Match anything but a newline, maybe even a null. */ + if (ismbchar (*d)) { + if (d + 1 == dend || d[1] == '\n' || d[1] == '\0') + goto fail; + SET_REGS_MATCHED; + d += 2; + break; + } + if ((translate ? translate[*d] : *d) == '\n' + || ((obscure_syntax & RE_DOT_NOT_NULL) + && (translate ? translate[*d] : *d) == '\000')) + goto fail; + SET_REGS_MATCHED; + d++; + break; + + case charset: + case charset_not: + { + int not; /* Nonzero for charset_not. */ + register int c; + if (*(p - 1) == (unsigned char) charset_not) + not = 1; + + PREFETCH; /* Fetch a data character. */ + + c = (unsigned char) *d; + if (ismbchar (c)) { + c <<= 8; + if (d + 1 != dend) + c |= (unsigned char) d[1]; + } + else if (translate) + c = (unsigned char) translate[c]; + + not = is_in_list (c, p); + + p += 1 + *p + 2 + EXTRACT_UNSIGNED (&p[1 + *p])*4; + + if (!not) goto fail; + SET_REGS_MATCHED; + d++; + if (d != dend && c >= 1 << BYTEWIDTH) + d++; + break; + } + + case begline: + if ((size1 != 0 && d == string1) + || (size1 == 0 && size2 != 0 && d == string2) + || (d && d[-1] == '\n') + || (size1 == 0 && size2 == 0)) + break; + else + goto fail; + + case endline: + if (d == end2 + || (d == end1 ? (size2 == 0 || *string2 == '\n') : *d == '\n')) + 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 + jump to the joining point. (Actually, each jump except for + the last one really jumps to the following jump, because + tensioning the jumps is a hassle.) */ + + /* The start of a stupid repeat has an on_failure_jump that points + past the end of the repeat text. This makes a failure point so + that on failure to match a repetition, matching restarts past + as many repetitions have been found with no way to fail and + look for another one. */ + + /* A smart repeat is similar but loops back to the on_failure_jump + so that each repetition makes another failure point. */ + + case on_failure_jump: + on_failure: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + PUSH_FAILURE_POINT (p + mcnt, d); + break; + + /* The end of a smart repeat has a maybe_finalize_jump back. + Change it either to a finalize_jump or an ordinary jump. */ + case maybe_finalize_jump: + 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. */ + if (p2 == pend) + p[-3] = (unsigned char) finalize_jump; + else if (*p2 == (unsigned char) exactn + || *p2 == (unsigned char) endline) + { + register int c = *p2 == (unsigned char) endline ? '\n' : p2[2]; + register unsigned char *p1 = p + mcnt; + /* p1[0] ... p1[2] are an on_failure_jump. + Examine what follows that. */ + if (p1[3] == (unsigned char) exactn && p1[5] != c) + p[-3] = (unsigned char) finalize_jump; + else if (p1[3] == (unsigned char) charset + || p1[3] == (unsigned char) charset_not) + { + if (ismbchar (c)) + c = c << 8 | p2[3]; + /* `is_in_list()' is TRUE if c would match */ + /* That means it is not safe to finalize. */ + if (!is_in_list (c, p1 + 4)) + p[-3] = (unsigned char) finalize_jump; + } + } + } + p -= 2; /* Point at relative address again. */ + if (p[-1] != (unsigned char) finalize_jump) + { + p[-1] = (unsigned char) jump; + goto nofinalize; + } + /* Note fall through. */ + + /* The end of a stupid repeat has a finalize_jump back to the + start, where another failure point will be made which will + point to after all the repetitions found so far. */ + + /* Take off failure points put on by matching on_failure_jump + because didn't fail. Also remove the register information + put on by the on_failure_jump. */ + case finalize_jump: + POP_FAILURE_POINT (); + /* Note fall through. */ + + /* Jump without taking off any failure points. */ + case jump: + nofinalize: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p += mcnt; + break; + + 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 + finalize_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for finalize_jump to pop. */ + PUSH_FAILURE_POINT (0, 0); + goto nofinalize; + + + /* Have to succeed matching what follows at least n times. Then + just handle like an on_failure_jump. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); + } + else if (mcnt == 0) + { + p[2] = unused; + p[3] = unused; + goto on_failure; + } + else + { + fprintf (stderr, "regex: the succeed_n's n is not set.\n"); + exit (1); + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER(p + 2, mcnt); + goto nofinalize; /* Do the jump without taking off + any failure points. */ + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + 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); + break; + } + + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case unused: + break; + + case wordbound: + if (AT_WORD_BOUNDARY) + break; + goto fail; + + case notwordbound: + if (AT_WORD_BOUNDARY) + goto fail; + break; + + case wordbeg: + if (IS_A_LETTER (d) && (AT_STRINGS_BEG || !IS_A_LETTER (d - 1))) + break; + goto fail; + + case wordend: + /* Have to check if AT_STRINGS_BEG before looking at d - 1. */ + if (!AT_STRINGS_BEG && IS_A_LETTER (d - 1) + && (!IS_A_LETTER (d) || AT_STRINGS_END)) + break; + goto fail; + +#ifdef emacs + case before_dot: + if (PTR_CHAR_POS (d) >= point) + goto fail; + break; + + case at_dot: + if (PTR_CHAR_POS (d) != point) + goto fail; + break; + + case after_dot: + if (PTR_CHAR_POS (d) <= point) + goto fail; + break; + + case wordchar: + mcnt = (int) Sword; + goto matchsyntax; + + case syntaxspec: + mcnt = *p++; + matchsyntax: + PREFETCH; + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; + SET_REGS_MATCHED; + break; + + case notwordchar: + mcnt = (int) Sword; + goto matchnotsyntax; + + case notsyntaxspec: + mcnt = *p++; + matchnotsyntax: + PREFETCH; + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; + SET_REGS_MATCHED; + break; + +#else /* not emacs */ + + case wordchar: + PREFETCH; + if (!IS_A_LETTER (d)) + goto fail; + d++; + SET_REGS_MATCHED; + break; + + case notwordchar: + PREFETCH; + if (IS_A_LETTER (d)) + goto fail; + d++; + SET_REGS_MATCHED; + break; + + case before_dot: + case at_dot: + case after_dot: + case syntaxspec: + case notsyntaxspec: + break; + +#endif /* not emacs */ + + case begbuf: + if (AT_STRINGS_BEG) + break; + goto fail; + + case endbuf: + if (AT_STRINGS_END) + break; + goto fail; + + case exactn: + /* Match the next few pattern characters exactly. + mcnt is how many characters to match. */ + mcnt = *p++; + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + unsigned char c; + + PREFETCH; + c = *d++; + if (ismbchar (c)) { + if (c != (unsigned char) *p++ + || !--mcnt /* �ѥ���������������ѥ��뤵 + ��Ƥ���¤�, ���Υ����å��� + ��Ĺ����ǰ�Τ���. */ + || d == dend + || (unsigned char) *d++ != (unsigned char) *p++) + goto fail; + continue; + } + if ((unsigned char) translate[c] != (unsigned char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { +#if 0 + /* this code suppose that multi-byte chars are not splited + in string1 and string2. If you want to check this with + speed cost, change `#if 0' here and next to `#if 1'. */ + unsigned char c; + +#endif + PREFETCH; +#if 0 + c = *d++; + if (ismbchar (c)) { + if (c != (unsigned char) *p++ + || !--mcnt + || d == dend) + goto fail; + c = *d++; + } + if (c != (unsigned char) *p++) goto fail; +#else + if (*d++ != *p++) goto fail; +#endif + } + while (--mcnt); + } + SET_REGS_MATCHED; + break; + } + continue; /* Successfully executed one pattern command; keep going. */ + + /* Jump here if any matching operation fails. */ + fail: + if (stackp != stackb) + /* A restart point is known. Restart there and pop it. */ + { + short last_used_reg, this_reg; + + /* If this failure point is from a dummy_failure_point, just + skip it. */ + if (!stackp[-2]) + { + POP_FAILURE_POINT (); + goto fail; + } + + d = *--stackp; + p = *--stackp; + if (d >= string1 && d <= end1) + dend = end_match_1; + /* Restore register info. */ + last_used_reg = (long) *--stackp; + + /* Make the ones that weren't saved -1 or 0 again. */ + for (this_reg = RE_NREGS - 1; this_reg > last_used_reg; this_reg--) + { + regend[this_reg] = (unsigned char *) (-1L); + regstart[this_reg] = (unsigned char *) (-1L); + IS_ACTIVE (reg_info[this_reg]) = 0; + MATCHED_SOMETHING (reg_info[this_reg]) = 0; + } + + /* And restore the rest from the stack. */ + for ( ; this_reg > 0; this_reg--) + { + reg_info[this_reg] = *(struct register_info *) *--stackp; + regend[this_reg] = *--stackp; + regstart[this_reg] = *--stackp; + } + } + else + break; /* Matching at this starting point really fails. */ + } + + if (best_regs_set) + goto restore_best_regs; + + FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */ +} + + +static int +memcmp_translate (s1, s2, len, translate) + 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; + } + else + if (translate[c] != translate[*p2++]) + return 1; + len--; + } + return 0; +} + + + +/* Entry points compatible with 4.2 BSD regex library. */ + +#if !defined(emacs) && !defined(GAWK) && !defined(RUBY) + +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + char *s; +{ + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + if (!(re_comp_buf.buffer = (char *) xmalloc (200))) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + if (!(re_comp_buf.fastmap = (char *) xmalloc (1 << BYTEWIDTH))) + return "Memory exhausted"; + } + return re_compile_pattern (s, strlen (s), &re_comp_buf); +} + +int +re_exec (s) + char *s; +{ + int len = strlen (s); + return 0 <= re_search (&re_comp_buf, s, len, 0, len, + (struct re_registers *) 0); +} +#endif /* not emacs && not GAWK && not RUBY */ + + + +#ifdef test + +#ifdef atarist +long _stksize = 2L; /* reserve memory for stack */ +#endif +#include <stdio.h> + +/* Indexed by a character, gives the upper case equivalent of the + character. */ + +char upcase[0400] = + { 000, 001, 002, 003, 004, 005, 006, 007, + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + 0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137, + 0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107, + 0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117, + 0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127, + 0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177, + 0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, + 0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, + 0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, + 0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, + 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, + 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, + 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, + 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, + 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, + 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, + 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, + 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, + 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, + 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, + 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, + 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377 + }; + +#ifdef canned + +#include "tests.h" + +typedef enum { extended_test, basic_test } test_type; + +/* Use this to run the tests we've thought of. */ + +void +main () +{ + test_type t = extended_test; + + if (t == basic_test) + { + printf ("Running basic tests:\n\n"); + test_posix_basic (); + } + else if (t == extended_test) + { + printf ("Running extended tests:\n\n"); + test_posix_extended (); + } +} + +#else /* not canned */ + +/* Use this to run interactive tests. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + char pat[80]; + struct re_pattern_buffer buf; + int i; + char c; + char fastmap[(1 << BYTEWIDTH)]; + + /* Allow a command argument to specify the style of syntax. */ + if (argc > 1) + obscure_syntax = atol (argv[1]); + + buf.allocated = 40; + buf.buffer = (char *) xmalloc (buf.allocated); + buf.fastmap = fastmap; + buf.translate = upcase; + + while (1) + { + gets (pat); + + if (*pat) + { + re_compile_pattern (pat, strlen(pat), &buf); + + for (i = 0; i < buf.used; i++) + printchar (buf.buffer[i]); + + putchar ('\n'); + + printf ("%d allocated, %d used.\n", buf.allocated, buf.used); + + re_compile_fastmap (&buf); + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (fastmap[i]) printchar (i); + putchar ('\n'); + } + + gets (pat); /* Now read the string to match against */ + + i = re_match (&buf, pat, strlen (pat), 0, 0); + printf ("Match value %d.\n", i); + } +} + +#endif + + +#ifdef NOTDEF +print_buf (bufp) + struct re_pattern_buffer *bufp; +{ + int i; + + printf ("buf is :\n----------------\n"); + for (i = 0; i < bufp->used; i++) + printchar (bufp->buffer[i]); + + printf ("\n%d allocated, %d used.\n", bufp->allocated, bufp->used); + + printf ("Allowed by fastmap: "); + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->fastmap[i]) + printchar (i); + printf ("\nAllowed by translate: "); + if (bufp->translate) + for (i = 0; i < (1 << BYTEWIDTH); i++) + if (bufp->translate[i]) + printchar (i); + printf ("\nfastmap is%s accurate\n", bufp->fastmap_accurate ? "" : "n't"); + printf ("can %s be null\n----------", bufp->can_be_null ? "" : "not"); +} +#endif /* NOTDEF */ + +printchar (c) + char c; +{ + if (c < 040 || c >= 0177) + { + putchar ('\\'); + putchar (((c >> 6) & 3) + '0'); + putchar (((c >> 3) & 7) + '0'); + putchar ((c & 7) + '0'); + } + else + putchar (c); +} + +error (string) + char *string; +{ + puts (string); + exit (1); +} +#endif /* test */ diff --git a/regex.h b/regex.h new file mode 100644 index 0000000000..8481bc84b3 --- /dev/null +++ b/regex.h @@ -0,0 +1,276 @@ +/* Definitions for data structures callers pass the regex library. + + Copyright (C) 1985, 1989-90 Free Software Foundation, Inc. + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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. */ +/* Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) + Last change: May 21, 1993 by t^2 */ + + +#ifndef __REGEXP_LIBRARY +#define __REGEXP_LIBRARY + +/* 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 +#define RE_NREGS 10 +#endif + +#define BYTEWIDTH 8 + + +/* Maximum number of duplicates an interval can allow. */ +#ifndef RE_DUP_MAX +#define RE_DUP_MAX ((1 << 15) - 1) +#endif + + +/* This defines the various regexp syntaxes. */ +extern long obscure_syntax; + + +/* The following bits are used in the obscure_syntax 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 not set, plain + or ? serves as an operator, and \+, \? are + literals. + If set, \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM (1L << 2) + +/* 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) + +/* 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) + + +/* 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) + +/* For multi-byte char support */ +#define RE_MBCTYPE_EUC (1L << 19) +#define RE_MBCTYPE_SJIS (1L << 20) +#define RE_MBCTYPE_MASK (RE_MBCTYPE_EUC | RE_MBCTYPE_SJIS) + +#undef ismbchar +#define ismbchar(c) \ + (obscure_syntax & RE_MBCTYPE_EUC \ + ? ((unsigned char) (c) >= 0x80) \ + : (obscure_syntax & RE_MBCTYPE_SJIS \ + ? (( 0x80 <= (unsigned char) (c) \ + && (unsigned char) (c) <= 0x9f) \ + || (0xe0 <= (unsigned char) (c))) \ + : 0)) + +/* 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 */ + 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 fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + 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 + + +/* Structure to store register contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + For i from 1 to RE_NREGS - 1, start[i] records the starting index in + the string of where the ith subexpression matched, and end[i] records + one after the ending index. start[0] and end[0] are analogous, for + the entire pattern. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + + + +#ifdef __STDC__ + +extern char *re_compile_pattern (char *, size_t, 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, + struct re_registers *); +extern int re_search_2 (struct re_pattern_buffer *, char *, int, + char *, int, int, int, + struct re_registers *, int); +extern int re_match (struct re_pattern_buffer *, char *, int, int, + struct re_registers *); +extern int re_match_2 (struct re_pattern_buffer *, char *, int, + char *, int, int, struct re_registers *, int); +extern long re_set_syntax (long syntax); + +#ifndef RUBY +/* 4.2 bsd compatibility. */ +extern char *re_comp (char *); +extern int re_exec (char *); +#endif + +#else /* !__STDC__ */ + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); +extern long re_set_syntax(); + +#ifndef RUBY +/* 4.2 bsd compatibility. */ +extern char *re_comp (); +extern int re_exec (); +#endif + +#endif /* __STDC__ */ + + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif + +#endif /* !__REGEXP_LIBRARY */ diff --git a/ruby.1 b/ruby.1 new file mode 100644 index 0000000000..df2e0aa6fa --- /dev/null +++ b/ruby.1 @@ -0,0 +1,212 @@ +.\"ruby.1 - -*- Nroff -*- +.\" $Author$ +.\" $Date$ +.\" created at: Tue Apr 12 01:45:04 GMT 1994 +.TH RUBY 1 "\*(RP" +.UC +.SH NAME +ruby \- ���֥������Ȼظ�������ץȸ��� +.SH "SYNOPSIS ����" +.B ruby +[ +.B options +] filename args +.SH DESCRIPTION +.IB Ruby +��, ��ڤʥ��֥������Ȼظ��ץ�����ߥ�¸����뤿��μ +�ε�ǽ����ĥ��֥������Ȼظ�������ץȸ���Ǥ���. �����߷פ� +���ܸ�§��, �ʲ����̤�Ǥ���. + +.IP ��ǽ�� +���֥������Ȼظ��ץ�����ߥȥ�����ץȥץ�����ߥΤ� +���ɬ�פʵ�ǽ��ʬ��������. �ä˥ƥ����Ƚ����ط��ε�ǽ��˭ +�٤˻���. �ޤ�, ���ʥ��֥������Ȼظ�����Ǥ���ʤ���, ɬ�� +�Ǥ���м�³�����ץ�����ߥ��ǽ�Ǥ���. +.IP ��ĥ�� +ɬ�פ˱������ưפ˵�ǽ���ĥ�Ǥ���. ���饹��ͳ���ɲäǤ��� +���Ȥ�����, C�ץ������Υ�ˤ�äƥ��ץ�ˤ���� +�뵡ǽ���ɲäǤ���. ����˥ץ�åȥե�����ˤ�äƤ�, ưŪ�� +���֥������ȥ����ɤ����뵡ǽ������. +.IP ����� +�����θ�§�����Τ�Ŭ�Ѥ����褦�ʰ�����Τ��������ͤ����. +����ˤ�äơ֥ѥ���γڤ����פϸ������������Τ�ʤ�. ������, +������Τ���Ȥ��䤹�������ˤ��뤳�ȤϤʤ�. +.PP +.IB Ruby +��sh��perl���ΤäƤ���ͤˤȤäƤξQ�ˤǤ���¤꽾�ä��Τ�, +�����θ�������̤��Ƥ���ͤˤȤäƤϽ�����(¿ʬ)�ưפ�����. +.SH OPTIONS +.IB ruby +�ϰʲ��ΰ���������դ���. +.TP 5 +.B \-a +`\-n'��`\-p'�ȤȤ���Ѥ���, �����ȥ��ץ�åȥ⡼�ɤ�ON�ˤ���. +�����ȥ��ץ�åȥ⡼�ɤǤϳƥ롼�פ���Ƭ��, +.nf +.ne 2 + + $F = $_.split + +.fi +���¹Ԥ����. `\-n'��`\-p'���ץ�����ꤵ��ʤ��¤�, ���� +���ץ����ϰ�̣������ʤ�. +.TP 5 +.B \-c +������ץȤ����������ؤΥ���ѥ���Τߤ�Ԥ�, �¹Ԥ��ʤ�. �� +��ѥ��뽪λ��, ʸˡ���顼��̵�����, "Syntax OK"�Ƚ��Ϥ���. +.TP 5 +.B \-e " script" +���ޥ�ɥ饤�饹����ץȤ���ꤹ��. \-e���ץ������դ� +�����ˤϰ������饹����ץȥե�����̾����ʤ�. +.TP 5 +.B \-F " ʸ����" +���ϥե�����ɥ��ѥ졼��(`$;')���ͤ�ʸ����˥��åȤ���. awk +��Ʊ̾�Υ��ץ�����Ʊ��Ư����. +.TP 5 +.B \-i " extension" +�����ǻ��ꤵ�줿�ե���������Ƥ��֤�������(in-place edit)�� +�Ȥ���ꤹ��. ���Υե�����ϳ�ĥ�Ҥ�Ĥ���������¸�����. +.nf +��: +.ne 2 + + % echo matz > /tmp/junk + % cat /tmp/junk + matz + % ruby -p -i.bak -e '$_.toupper' /tmp/junk + % cat /tmp/junk + MATZ + % cat /tmp/junk.bak + matz + +.fi +.TP 5 +.B \-I " directory" +�ե����������ɤ���ѥ������(�ɲ�)����. ���ꤵ�줿�ǥ��쥯 +�ȥ�� +.IB ruby +�������ѿ�$LOAD_PATH���ɲä����. +.TP 5 +.B \-d, \--debug +�ǥХå��⡼�ɤ�on�ˤ���. ���Υե饰�����åȤ����ȥ����ƥ� +�ѿ�$DEBUG�����åȤ����. +.TP 5 +.B \-l +`$\\'��`$/'��Ʊ���ͤ����ꤷ, print()�Ǥν��ϻ��˲��Ԥ��ղä� +��. �ޤ�, \-n�ޤ���\-p�ȤȤ���Ѥ������, ���Ϥ��줿�Ԥκ� +���ʸ����chop����. +.TP 5 +.B \-n +���Υե饰�����åȤ����ȥץ���������Τ� +.nf +.ne 2 + + while gets() + \.\.\. + end + +.fi +�ǰϤޤ�Ƥ���褦��ư���. +.TP 5 +.B \-p +\-n�ե饰��Ʊ������, �ƥ롼�פκǸ���ѿ�`$_'���ͤ���Ϥ���. +.nf +��: +.ne 2 + + % echo matz | ruby \-p \-e '$_.tr("a-z", "A-Z")' + MATZ + +.fi +.TP 5 +.B \-R ʸ����(�ޤ���8�ʿ�) +���ϥ쥳���ɥ��ѥ졼��(`$/')���ͤ�ʸ����˥��åȤ���. ʸ���� +�����٤ƿ���(0-7�ޤ�)���鹽������Ƥ�����ˤ�, ����8�ʿ��ǻ� +�ꤵ�줿�����ɤ���ʸ���ѥ졼���Ȥ���. + +���ξ��, \-R0��, �ѥ饰��ե⡼��, \-R777��(���Υ����ɤ�� +��ʸ����¸�ߤ��ʤ��Τ�)���ե��������٤��ɤ߹���⡼�ɤ��� +��Ǥ���. +.TP 5 +.B \-s +������ץ�̾��³��, \-�ǻϤޤ�������ᤷ��, Ʊ̾������ѿ� +���ͤ����ꤹ��. `\-\-'�ʤ�����ʹߤϲ���Ԥʤ�ʤ�. ������ +�������$ARGV������������. +.nf +��: +.ne 2 + + #! /usr/local/ruby -s + # -xyz���ץ����Ϳ�������"true"��ɽ������. + if $xyz then print("true\n") end + +.fi +.TP 5 +.B \-v, \--verbose +��Ĺ�⡼��. ��ư���˥С�������ֹ��ɽ����Ԥ�, �����ƥ��ѿ� +$VERBOSE�åȤ���. �����ѿ������åȤ���Ƥ����, �����Ĥ� +�Υ�åɤϼ¹Ի��˾�Ĺ�ʥ�å���������Ϥ���. \-v ���ץ��� +����������ꤵ��Ƥ���, ���ץ����ʳ��ΰ������ʤ����ˤϥС� +������ɽ��������, �¹Ԥ�λ����(ɸ�����Ϥ���Υ�����ץ� +���Ԥ��ʤ�). +.TP 5 +.B \--version +.IB ruby +�ΥС�������ɽ������. +.nf +ɽ����: +.ne 2 + + ruby - version 0.47 (11 Jul 94) + +.fi +.TP 5 +.B \-x +��å�������Υ�����ץȤ���Ф��Ƽ¹Ԥ���. #!�ǻϤޤ�, +"ruby"�Ȥ���ʸ�����ޤ�ԤޤǤ��ɤ����Ф�. ������ץȤν��� +��EOF(�ե�����ν���), ^D(����ȥ�����D), ^Z(����ȥ�����Z) +�ޤ���ʸ����"__END__"�ǻ��ꤹ��. +.TP 5 +.B \-X " directory" +������ץȼ¹����˻��ꤵ�줿�ǥ��쥯�ȥ�˰ܤ�. +.TP 5 +.B \-y, \--yydebug +����ѥ���ǥХå��⡼��. ����ѥ�����ι�ʸ���Ϥβ�����ɽ�� +����. ����ɽ�������˾�Ĺ�ʤΤ�, ����ѥ��餽�Τ�Τ�ǥХ� +������Ͱʳ���ɽ�������ʤ������ɤ��Ȼפ�. +.TP 5 +.B \-N, \-E, \-S +.IB ruby +�ν���������������ɤ���ꤹ��. N�ϴ�����������ʤ�. E��EUC, +S��SJIS��ɽ��. �ǥե���Ȥϴ������б�. + +.SH "BUG �Х�(���뤤�Ϸ���)" +.PP +�٤�. ñ��ʽ����ξ��perl��awk�ʤɤ�2,3�ܤμ¹Ի��֤�������. +¾�θ���Ȱۤʤ�, �������뵡ǽ�ΤۤȤ�ɤ���åɸƤӽ� +����𤹤뤳�Ȥ���������, ¾�θ���Ǥ�ؿ��ƤӽФ���¿���ʤ� +�褦�ʽ����Ǥϥ�åɥ���å����ʬ���� +.IB ruby +��ͭ���ˤʤ뤷, �ǡ�����¤��ʣ���ˤʤ��, ���֥������Ȼظ��� +���åȤ��褫����Τ�, �ޤ������뤫���Τ�ʤ�. +.PP +perl��국���̤�¿��. ����� +.IB ruby +����������ɵᤷ����̤Ǥ���. ����, ���η��, +.IB ruby +������ץȤ�perl����ɤߤ䤹���Ϥ���, �㴳�ε����̤������� +�䤹���Ȳ����������Ƥ���Ȼפä��ߤ���. +.PP +Sparc�ǥ���ѥ��뤵�줿 +.IB ruby +�ϥ��ƥ졼�����break��ɾ��������core dump���뤳�Ȥ�����. +�����setjmp()�˴�Ϣ����Х����Ȼפ��뤬, ¾�Υ������ƥ����� +�ǤϺƸ�����, �������ͤ��ߤ���Ƥ��ʤ�. ï��ʬ����ж����� +�ߤ���. +.PP +�ɥ�����Ȥ��Խ�ʬ. ɬ�פʾ�������뤿��ˤϥ��������ɤ�� +�ߤ���. +.PP +�ƥ��Ȥ��Խ�ʬ. �Х��ˤĤ������ä���, �Ǥ���м�ʬ��ľ����, +���ä����˶������ߤ���. ̵���ʤ��, ����ƥХ����Ƹ������ +������Τˤ��ƥ�ݡ��Ȥ����ߤ���. diff --git a/ruby.c b/ruby.c new file mode 100644 index 0000000000..5b98281bb7 --- /dev/null +++ b/ruby.c @@ -0,0 +1,374 @@ +/************************************************ + + ruby.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:37 $ + created at: Tue Aug 10 12:47:31 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "re.h" +#include <stdio.h> +#include <sys/file.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> + +#ifdef HAVE_GETOPT_LONG +#include "getopt.h" +#else +#include "missing/getopt.h" +#endif + +static struct option long_options[] = +{ + {"debug", 0, 0, 'd'}, + {"yydebug", 0, 0, 'y'}, + {"verbose", 0, 0, 'v'}, + {"version", 0, 0, 0}, + {0, 0, 0, 0} +}; + +int debug = 0; +int verbose = 0; +static int sflag = FALSE; + +char *inplace = Qnil; +char *strdup(); +char *strstr(); +char *index(); + +extern int yydebug; +extern int nerrs; + +int xflag = FALSE; + +#ifdef USE_DLN +char *rb_dln_argv0; +#endif + +static void load_stdin(); +void rb_load_file(); + +static int do_loop = FALSE, do_print = FALSE; +static int do_check = FALSE, do_line = FALSE; +static int do_split = FALSE; + +static char* +proc_options(argcp, argvp) + int *argcp; + char ***argvp; +{ + int argc = *argcp; + char **argv = *argvp; + extern VALUE rb_load_path; + extern long reg_syntax; + extern char *optarg; + extern int optind; + int c, i, j, script_given, version, opt_index; + extern VALUE RS, ORS, FS; + char *script; + char *src; + + version = FALSE; + script_given = FALSE; + script = Qnil; + + optind = 0; + while ((c = getopt_long(argc, argv, "+acde:F:i:I:lnpR:svxX:yNES", + long_options, &opt_index)) != EOF) { + switch (c) { + case 0: /* long options */ + if (strcmp(long_options[opt_index].name, "version") == 0) { + version = TRUE; + show_version(); + } + break; + + case 'p': + do_print = TRUE; + /* through */ + case 'n': + do_loop = TRUE; + break; + + case 'd': + debug = TRUE; + break; + + case 'y': + yydebug = 1; + break; + + case 'v': + version = verbose = TRUE; + show_version(); + break; + + case 'e': + script_given++; + if (script == 0) script = "-e"; + lex_setsrc("-e", optarg, strlen(optarg)); + yyparse(); + break; + + case 'i': + inplace = strdup(optarg); + break; + + case 'c': + do_check = TRUE; + break; + + case 'x': + xflag = TRUE; + break; + + case 'X': + if (chdir(optarg) < 0) + Fatal("Can't chdir to %s", optarg); + break; + + case 's': + sflag = TRUE; + break; + + case 'l': + do_line = TRUE; + ORS = RS; + break; + + case 'R': + { + char *p = optarg; + + while (*p) { + if (*p < '0' || '7' < *p) { + break; + } + p++; + } + if (*p) { + RS = str_new2(optarg); + } + else { + int i = strtoul(optarg, Qnil, 8); + + if (i == 0) RS = str_new(0, 0); + else if (i > 0xff) RS = Qnil; + else { + char c = i; + RS = str_new(&c, 1); + } + } + } + break; + + case 'F': + FS = str_new2(optarg); + break; + + case 'a': + do_split = TRUE; + break; + + case 'N': + reg_syntax &= ~RE_MBCTYPE_MASK; + re_set_syntax(reg_syntax); + break; + case 'E': + reg_syntax &= ~RE_MBCTYPE_MASK; + reg_syntax |= RE_MBCTYPE_EUC; + re_set_syntax(reg_syntax); + break; + case 'S': + reg_syntax &= ~RE_MBCTYPE_MASK; + reg_syntax |= RE_MBCTYPE_SJIS; + re_set_syntax(reg_syntax); + break; + + case 'I': + Fary_unshift(rb_load_path, str_new2(optarg)); + break; + + default: + break; + } + } + + if (argv[0] == Qnil) return Qnil; + + if (script_given == 0) { + if (argc == optind) { /* no more args */ + if (version == TRUE) exit(0); + script = "-"; + load_stdin(); + } + else { + script = argv[optind]; + rb_load_file(argv[optind]); + optind++; + } + } + + xflag = FALSE; + *argvp += optind; + *argcp -= optind; + + if (sflag) { + char *s; + VALUE v; + + argc = *argcp; argv = *argvp; + for (; argc > 0 && argv[0][0] == '-'; argc--,argv++) { + if (argv[0][1] == '-') { + argc--,argv++; + break; + } + argv[0][0] = '$'; + if (s = index(argv[0], '=')) { + *s++ = '\0'; + GC_LINK; + GC_PRO3(v, str_new2(s)); + rb_gvar_set2((*argvp)[0], v); + GC_UNLINK; + } + else { + rb_gvar_set2((*argvp)[0], TRUE); + } + } + *argcp = argc; *argvp = argv; + } + + return script; +} + +static void +readin(fd, fname) + int fd; + char *fname; +{ + struct stat st; + char *ptr, *p, *pend; + + if (fstat(fd, &st) < 0) rb_sys_fail(fname); + if (!S_ISREG(st.st_mode)) + Fail("script is not a regular file - %s", fname); + + p = ptr = ALLOC_N(char, st.st_size+1); + if (read(fd, ptr, st.st_size) != st.st_size) { + rb_sys_fail(fname); + } + p = ptr; + pend = p + st.st_size; + if (xflag) { + char *s = p; + + *pend = '\0'; + xflag = FALSE; + while (p < pend) { + while (s < pend && *s != '\n') s++; + if (*s != '\n') break; + *s = '\0'; + if (p[0] == '#' && p[1] == '!' && strstr(p, "ruby")) { + if (p = strstr(p, "ruby -")) { + int argc; char *argv[2]; char **argvp = argv; + argc = 2; argv[0] = Qnil; argv[1] = p + 5; + proc_options(&argc, &argvp); + } + xflag = TRUE; + p = s + 1; + goto start_read; + } + p = s + 1; + } + Fail("No Ruby script found in input"); + } + start_read: + lex_setsrc(fname, p, pend - p); + yyparse(); + free(ptr); +} + +void +rb_load_file(fname) + char *fname; +{ + int fd; + char *ptr; + + if (fname[0] == '\0') { + load_stdin(); + return; + } + + fd = open(fname, O_RDONLY, 0); + if (fd < 0) rb_sys_fail(fname); + readin(fd, fname); + close(fd); +} + +static void +load_stdin() +{ + char buf[32]; + FILE *f; + char c; + int fd; + + sprintf(buf, "/tmp/ruby-f%d", getpid()); + f = fopen(buf, "w"); + fd = open(buf, O_RDONLY, 0); + if (fd < 0) rb_sys_fail(buf); + unlink(buf); + while ((c = getchar()) != EOF) { + putc(c, f); + } + fclose(f); + + if (fd < 0) rb_sys_fail(buf); + + readin(fd, "-"); +} + +void +rb_main(argc, argv) /* real main() is in eval.c */ + int argc; + char **argv; +{ + char *script; + extern VALUE errat; + + rb_call_inits(); + + rb_define_variable("$@", &errat, Qnil, Qnil); + errat = str_new2(argv[0]); + rb_define_variable("$VERBOSE", &verbose, Qnil, Qnil); + rb_define_variable("$DEBUG", &debug, Qnil, Qnil); + +#ifdef USE_DLN + rb_dln_argv0 = argv[0]; +#endif + + script = proc_options(&argc, &argv); + if (do_check && nerrs == 0) { + printf("Syntax OK\n"); + exit(0); + } + if (do_print) { + yyappend_print(); + } + if (do_loop) { + yywhole_loop(do_line, do_split); + } + + if (nerrs == 0) { + TopLevel(script, argc, argv); + } + + exit(nerrs); +} diff --git a/ruby.h b/ruby.h new file mode 100644 index 0000000000..a454394f35 --- /dev/null +++ b/ruby.h @@ -0,0 +1,298 @@ +/************************************************ + + ruby.h - + + $Author: matz $ + $Date: 1994/06/27 15:48:38 $ + created at: Thu Jun 10 14:26:32 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#ifndef RUBY_H +#define RUBY_H + +#include "defines.h" + +#ifdef __STDC__ +#else +#define volatile +#define const +#endif + +#if defined(HAVE_ALLOCA_H) && !defined(__GNUC__) +#include <alloca.h> +#endif + +typedef unsigned int UINT; +typedef UINT VALUE; +typedef UINT ID; +typedef unsigned short USHORT; +#ifdef __STDC__ +# include <limits.h> +#else +# ifndef LONG_MAX +# define LONG_MAX ((long)((unsigned long)~0L>>1)) +# endif +# ifndef LONG_MIN +# if (0 != ~0) +# define LONG_MIN (-LONG_MAX-1) +# else +# define LONG_MIN (-LONG_MAX) +# endif +# endif +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +# define FIXNUM_MAX (LONG_MAX>>1) +# define FIXNUM_MIN RSHIFT((long)LONG_MIN,1) + +#define FIXNUM_FLAG 0x01 +#define INT2FIX(i) (VALUE)(((int)(i))<<1 | FIXNUM_FLAG) + +#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 FIX2UINT(f) ((unsigned int)(f)>>1) +#define FIXNUM_P(f) (((int)(f))&FIXNUM_FLAG) +#define POSFIXABLE(f) ((f) <= FIXNUM_MAX) +#define NEGFIXABLE(f) ((f) >= FIXNUM_MIN) +#define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f)) + +#define POINTER(p) (p) +#define NIL_P(p) ((p) == Qnil) + +#define TRUE INT2FIX(1) +#define FALSE Qnil + +extern VALUE C_Object; +extern VALUE C_Nil; +extern VALUE C_Fixnum; +extern VALUE C_Data; + +#define CLASS_OF(obj) (FIXNUM_P(obj)?C_Fixnum: NIL_P(obj)?C_Nil:\ + RBASIC(obj)->class) + +#define FL_SINGLE 0x10 +#define FL_MARK 0x20 +#define FL_LITERAL 0x40 + +#define FL_ABLE(x) (!(FIXNUM_P(x)||NIL_P(x))) +#define FL_TEST(x,f) (FL_ABLE(x)?(RBASIC(x)->flags&(f)):0) +#define FL_SET(x,f) if (FL_ABLE(x)) {RBASIC(x)->flags |= (f);} +#define FL_UNSET(x,f) if(FL_ABLE(x)){RBASIC(x)->flags &= ~(f);} + +#define T_NIL 0x0 +#define T_OBJECT 0x1 +#define T_CLASS 0x2 +#define T_ICLASS 0x3 +#define T_MODULE 0x4 +#define T_FLOAT 0x5 +#define T_STRING 0x6 +#define T_REGEXP 0x7 +#define T_ARRAY 0x8 +#define T_FIXNUM 0x9 +#define T_DICT 0xA +#define T_DATA 0xB +#define T_METHOD 0xC +#define T_STRUCT 0xD +#define T_BIGNUM 0xE + +#define T_MASK 0xF + +#define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) +#define TYPE(x) (FIXNUM_P(x)?T_FIXNUM:NIL_P(x)?T_NIL:BUILTIN_TYPE(x)) +#define Check_Type(x,t) {if (TYPE(x)!=(t)) WrongType(x,t);} +#define Need_Fixnum(x) {if (!FIXNUM_P(x)) (x) = num2fix(x);} +#define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):num2int(x)) +VALUE num2fix(); +int num2int(); + +#define NEWOBJ(obj,type) type *obj = (type*)newobj(sizeof(type)) +#define OBJSETUP(obj,c,t) {\ + RBASIC(obj)->class = (c);\ + RBASIC(obj)->flags |= (t);\ +} +#define CLONESETUP(obj1,obj2) \ + OBJSETUP(obj1,RBASIC(obj2)->class,RBASIC(obj2)->flags&T_MASK); + +struct RBasic { + UINT flags; + struct RBasic *next; + VALUE class; + struct st_table *iv_tbl; +}; + +struct RObject { + struct RBasic basic; +}; + +struct RClass { + struct RBasic basic; + struct st_table *m_tbl; + struct st_table *c_tbl; + struct RClass *super; +}; + +struct RFloat { + struct RBasic basic; + double value; +}; + +struct RString { + struct RBasic basic; + UINT len; + char *ptr; + struct RString *orig; +}; + +struct RArray { + struct RBasic basic; + UINT len, capa; + VALUE *ptr; +}; + +struct RRegexp { + struct RBasic basic; + struct Regexp *ptr; + UINT len; + char *str; +}; + +struct RDict { + struct RBasic basic; + struct st_table *tbl; +}; + +struct RData { + struct RBasic basic; + void (*dmark)(); + void (*dfree)(); + VALUE data[1]; +}; + +#define DATA_PTR(dta) &(RDATA(dta)->data[0]) + +#define Get_Data_Struct(obj, iv, type, sval) {\ + VALUE _data_;\ + _data_ = rb_iv_get(obj, iv);\ + Check_Type(_data_, T_DATA);\ + sval = (type*)DATA_PTR(_data_);\ +} + +#define Make_Data_Struct(obj, iv, type, mark, free, sval) {\ + struct RData *_new_;\ + _new_ = (struct RData*)newobj(sizeof(struct RData)+sizeof(type));\ + OBJSETUP(_new_, C_Data, T_DATA);\ + _new_->dmark = (void (*)())(mark);\ + _new_->dfree = (void (*)())(free);\ + sval = (type*)DATA_PTR(_new_);\ + bzero(sval, sizeof(type));\ + rb_iv_set(obj, iv, _new_);\ +} + +struct RMethod { + struct RBasic basic; + struct node *node; + struct RClass *origin; + ID id; + enum mth_scope { MTH_METHOD, MTH_FUNC, MTH_UNDEF } scope; +}; + +struct RStruct { + struct RBasic basic; + UINT len; + struct kv_pair { + ID key; + VALUE value; + } *tbl; + char *name; +}; + +struct RBignum { + struct RBasic basic; + char sign; + UINT len; + USHORT *digits; +}; + +#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 RFLOAT(obj) (R_CAST(RFloat)(obj)) +#define RSTRING(obj) (R_CAST(RString)(obj)) +#define RREGEXP(obj) (R_CAST(RRegexp)(obj)) +#define RARRAY(obj) (R_CAST(RArray)(obj)) +#define RDICT(obj) (R_CAST(RDict)(obj)) +#define RDATA(obj) (R_CAST(RData)(obj)) +#define RMETHOD(obj) (R_CAST(RMethod)(obj)) +#define RSTRUCT(obj) (R_CAST(RStruct)(obj)) +#define RBIGNUM(obj) (R_CAST(RBignum)(obj)) + +#define Qnil (VALUE)0 + +#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)) + +extern struct gc_list { + int n; + VALUE *varptr; + struct gc_list *next; +} *GC_List; + +#define GC_LINK { struct gc_list *_oldgc = GC_List; + +#define GC_PRO(var) {\ + struct gc_list *_tmp = (struct gc_list*)alloca(sizeof(struct gc_list));\ + _tmp->next = GC_List;\ + _tmp->varptr = (VALUE*)&(var);\ + _tmp->n = 1;\ + GC_List = _tmp;\ +} +#define GC_PRO2(var) GC_PRO3((var),Qnil) +#define GC_PRO3(var,init) {\ + (var) = (init);\ + GC_PRO(var);\ +} +#define GC_PRO4(var,nelt) {\ + GC_PRO(var[0]);\ + GC_List->n = nelt;\ +} + +#define GC_UNLINK GC_List = _oldgc; } + +VALUE rb_define_class(); +VALUE rb_define_module(); + +void rb_define_variable(); +void rb_define_const(); + +void rb_define_method(); +void rb_define_func(); +void rb_define_single_method(); +void rb_define_mfunc(); +void rb_undef_method(); +void rb_define_alias(); +void rb_define_attr(); + +ID rb_intern(); +char *rb_id2name(); + +VALUE rb_funcall(); +int rb_scan_args(); + +VALUE rb_yield(); + +extern int verbose, debug; + +#endif diff --git a/sample/Artistic b/sample/Artistic new file mode 100644 index 0000000000..fbf7989775 --- /dev/null +++ b/sample/Artistic @@ -0,0 +1,117 @@ + + + + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and 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 placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package 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, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard executables + non-standard names, and clearly documenting the differences in manual + pages (or equivalent), together with instructions on where to get + the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this Package. +You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whomever generated +them, and may be sold commercially, and may be aggregated with this +Package. + +7. C subroutines supplied by you and linked into this Package in order +to emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +9. THIS PACKAGE 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. + + The End diff --git a/sample/aset.rb b/sample/aset.rb new file mode 100644 index 0000000000..cfec649ac3 --- /dev/null +++ b/sample/aset.rb @@ -0,0 +1,3 @@ +ary = [0, 0, 4, 5] +ary[1, 0] = [7] +print(ary, "\n") diff --git a/sample/attr.rb b/sample/attr.rb new file mode 100644 index 0000000000..2db79f1ae5 --- /dev/null +++ b/sample/attr.rb @@ -0,0 +1,9 @@ +class Foo + attr("test", %TRUE) +end + +foo = Foo.new +foo.test = 10 +print(foo.test, "\n") +foo._inspect.print +print("\n") diff --git a/sample/biorhythm.rb b/sample/biorhythm.rb new file mode 100644 index 0000000000..3261c4377f --- /dev/null +++ b/sample/biorhythm.rb @@ -0,0 +1,201 @@ +#!/mp/free/bin/ruby +# +# biorhythm.rb - +# $Release Version: $ +# $Revision: 1.6 $ +# $Date: 1994/02/24 10:23:34 $ +# by Yasuo OHBA(STAFS Development Room) +# +# -- +# +# +# + +$RCS_ID="$Header: /var/ohba/RCS/biorhythm.rb,v 1.6 1994/02/24 10:23:34 ohba Exp ohba $" + +include Math +load("parsearg.rb") + +$wochentag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ] +monatstag1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +monatstag2 = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +def usage() + print("Usage:\n") + print("biorhythm.rb [options]\n") + print(" options...\n") + print(" -D YYYYMMDD(birthday) : ���٤� default �ͤ�Ȥ�. \n") + print(" --sdate | --date YYYYMMDD : system date �⤷���ϻ��ꤷ�����դ�Ȥ�.\n") + print(" --birthday YYYYMMDD : �������λ����. \n") + print(" -v | -g : Values or Graph �λ���. \n") + print(" --days DAYS : ���֤λ����(Graph �λ��Τ�ͭ��). \n") + print(" --help : help\n") +end +$USAGE = 'usage' + +def leapyear(y) + ta = 0 + if ((y % 4.0) == 0); ta = 1; end + if ((y % 100.0) == 0); ta = 0; end + if ((y % 400.0) == 0); ta = 1; end + return ta +end + +def bcalc(t, m, j) + ta = 0 + if (m <= 2) + ta = (m - 1) * 31 + else + ta = leapyear(j) + ta = ta + ((306 * m - 324) / 10.0).to_i + end + ta = ta + (j - 1) * 365 + ((j - 1) / 4.0).to_i + ta = ta - ((j - 1) / 100) + ((j - 1) / 400.0).to_i + ta = ta + t + return ta +end + +def printHeader(tg, mg, jg, gtag, tage) + print("\n") + print(" Biorhythm\n") + print(" =========\n") + print("\n") + printf("The birthday %04d.%02d.%02d is a %s\n", jg, mg, tg, $wochentag[gtag]) + printf("Age in days: [%d]\n", tage) +end + +def getPosition(z) + pi = 3.14159265 + $phys = (50.0 * (1.0 + sin((z / 23.0 - (z / 23)) * 360.0 * pi / 180.0))).to_i + $emot = (50.0 * (1.0 + sin((z / 28.0 - (z / 28)) * 360.0 * pi / 180.0))).to_i + $geist =(50.0 * (1.0 + sin((z / 33.0 - (z / 33)) * 360.0 * pi / 180.0))).to_i +end + +# +# main program +# +parseArgs(0, nil, "vg", "D:", "sdate", "date:", "birthday:", "days:") + +printf($stderr, "\n") +printf($stderr, "Biorhythm (c) 1987-1994 V3.0\n") +printf($stderr, "\n") +if ($OPT_D) + dtmp = Time.now.strftime("%Y%m%d") + jh = dtmp[0,4].to_i + mh = dtmp[4,2].to_i + th = dtmp[6,2].to_i + dtmp = $OPT_D + jg = dtmp[0,4].to_i + mg = dtmp[4,2].to_i + tg = dtmp[6,2].to_i + gtag = bcalc(tg, mg, jg) % 7 + ausgabeart = "g" +else + if ($OPT_birthday) + dtmp = $OPT_birthday + else + printf($stderr, "Birthday (YYYYMMDD) : ") + dtmp = $stdin.gets.chop + end + if (dtmp.length != 8) + printf($stderr, "BAD Input Birthday!!\n") + exit() + end + jg = dtmp[0,4].to_i + mg = dtmp[4,2].to_i + tg = dtmp[6,2].to_i + + gtag = bcalc(tg, mg, jg) % 7 + + if ($OPT_sdate) + dtmp = Time.now.strftime("%Y%m%d") + elsif ($OPT_date) + dtmp = $OPT_date + else + printf($stderr, "Date [<RETURN> for Systemdate] (YYYYMMDD) : ") + dtmp = $stdin.gets.chop + end + if (dtmp.length != 8) + dtmp = Time.now.strftime("%Y%m%d") + end + jh = dtmp[0,4].to_i + mh = dtmp[4,2].to_i + th = dtmp[6,2].to_i + + if ($OPT_v) + ausgabeart = "v" + elsif ($OPT_g) + ausgabeart = "g" + else + printf($stderr, "Values for today or Graph (v/g) [default g] : ") + ausgabeart = $stdin.gets.chop + end +end +if (ausgabeart == "v") + tag = bcalc(tg, mg, jg) + tah = bcalc(th, mh, jh) + tage = tah - tag + printHeader(tg, mg, jg, gtag, tage) + print("\n") + + getPosition(tage) + printf("Biorhythm: %04d.%02d.%02d\n", jh, mh, th) + printf("Physical: %d%%\n", $phys) + printf("Emotional: %d%%\n", $emot) + printf("Mental: %d%%\n", $geist) + print("\n") +else + if ($OPT_days) + ktage = $OPT_days.to_i + else + if ($OPT_D) + ktage = 9 + else + printf($stderr, "Graph for how many days [default 10] : ") + ktage = $stdin.gets.chop + if (ktage == "") + ktage = 9 + else + ktage = ktage.to_i - 1 + end + end + end + tag = bcalc(tg, mg, jg) + tah = bcalc(th, mh, jh) + tage = tah - tag + printHeader(tg, mg, jg, gtag, tage) + print(" P=physical, E=emotional, M=mental\n") + print(" -------------------------+-------------------------\n") + print(" Bad Condition | Good Condition\n") + print(" -------------------------+-------------------------\n") + + for z in tage..(tage + ktage) + getPosition(z) + + printf("%04d.%02d.%02d : ", jh, mh, th) + p = ($phys / 2.0 + 0.5).to_i + e = ($emot / 2.0 + 0.5).to_i + g = ($geist / 2.0 + 0.5).to_i + graph = "." * 51 + graph[25] = ?| + graph[p] = ?P + graph[e] = ?E + graph[g] = ?M + print(graph, "\n") + th = th + 1 + if (leapyear(jh) == 0) + $MONATSTAG = monatstag1 + else + $MONATSTAG = monatstag2 + end + if (th > $MONATSTAG[mh - 1]) + mh = mh + 1 + th = 1 + end + if (mh > 12) + jh = jh + 1 + mh = 1 + end + end + print(" -------------------------+-------------------------\n\n") +end diff --git a/sample/caller.rb b/sample/caller.rb new file mode 100644 index 0000000000..8988733377 --- /dev/null +++ b/sample/caller.rb @@ -0,0 +1,15 @@ +def test + for i in 1..2 + for j in 1..5 + print(j, ": ", caller(j).join(':'), "\n") + end + end +end + +def test2 + print(1, ": ", caller(1).join(':'), "\n") + test() +end + +test2() +caller() diff --git a/sample/case.rb b/sample/case.rb new file mode 100644 index 0000000000..f456f023d3 --- /dev/null +++ b/sample/case.rb @@ -0,0 +1,12 @@ + +case "t" +when /1/ + print(1, "\n") +when /t/ + print(3..5, "\n") +when /./ + print(2, "\n") +else + print("else\n") +end + diff --git a/sample/cat.rb b/sample/cat.rb new file mode 100644 index 0000000000..93f028906a --- /dev/null +++ b/sample/cat.rb @@ -0,0 +1,4 @@ +while gets() + if $. == 1 ... ~ /^\*/; print("--") end + printf("%5d: %s", $., $_) +end diff --git a/sample/cbreak.rb b/sample/cbreak.rb new file mode 100644 index 0000000000..4b4cb1d3e6 --- /dev/null +++ b/sample/cbreak.rb @@ -0,0 +1,34 @@ +%CBREAK = 0x00000002 +%ECHO = 0x00000008 +%TIOCGETP = 0x40067408 +%TIOCSETP = 0x80067409 + +def cbreak () + set_cbreak(%TRUE) +end + +def cooked () + set_cbreak(%FALSE) +end + +def set_cbreak (on) + tty = "\0" * 256 + $stdin.ioctl(%TIOCGETP, tty) + ttys = tty.unpack("C4 S") + if on + ttys[4] |= %CBREAK + ttys[4] &= ~%ECHO + else + ttys[4] &= ~%CBREAK + ttys[4] |= %ECHO + end + tty = ttys.pack("C4 S") + $stdin.ioctl(%TIOCSETP, tty) +end +cbreak(); + +print("this is echo line: "); +readline().print +cooked(); +print("this is non echo line: "); +readline().print diff --git a/sample/clnt.rb b/sample/clnt.rb new file mode 100644 index 0000000000..639e2a0daf --- /dev/null +++ b/sample/clnt.rb @@ -0,0 +1,12 @@ +host=(if $ARGV.length == 2; $ARGV.shift; else "localhost"; end) +print("Trying ", host, " ...") +$stdout.flush +s = TCPsocket.open(host, $ARGV.shift) +print(" done\n") +print("addr: ", s.addr.join(":"), "\n") +print("peer: ", s.peeraddr.join(":"), "\n") +while gets() + s.write($_) + print(s.gets) +end +s.close diff --git a/sample/clone.rb b/sample/clone.rb new file mode 100644 index 0000000000..6a752e8ab5 --- /dev/null +++ b/sample/clone.rb @@ -0,0 +1,12 @@ +foo = Object.new +def foo.test + print("test\n") +end +bar = foo.clone +def bar.test2 + print("test2\n") +end +bar.test2 +bar.test +foo.test +foo.test2 diff --git a/sample/const.rb b/sample/const.rb new file mode 100644 index 0000000000..d7629fe8e1 --- /dev/null +++ b/sample/const.rb @@ -0,0 +1,20 @@ +%test1 = 1 +%test2 = 2 + +module Const + %test3 = 3 + %test4 = 4 +end + +module Const2 + %test3 = 6 + %test4 = 8 +end + +include Const + +print(%test1,%test2,%test3,%test4,"\n") + +include Const2 + +print(%test1,%test2,%test3,%test4,"\n") diff --git a/sample/dbm.rb b/sample/dbm.rb new file mode 100644 index 0000000000..1f2886e026 --- /dev/null +++ b/sample/dbm.rb @@ -0,0 +1,6 @@ +# ruby +# + +d = Dbm.open("test") +for k in d.keys; print(k, "\n"); end +for v in d.values; print(v, "\n"); end diff --git a/sample/dir.rb b/sample/dir.rb new file mode 100644 index 0000000000..f4c3d17c11 --- /dev/null +++ b/sample/dir.rb @@ -0,0 +1,9 @@ +dirp = Dir.open(".") +dirp.rewind +for f in dirp + if (~/^\./ || ~/~$/ || ~/\.o/) + else + print(f, "\n") + end +end +dirp.close diff --git a/sample/evaldef.rb b/sample/evaldef.rb new file mode 100644 index 0000000000..c261b53068 --- /dev/null +++ b/sample/evaldef.rb @@ -0,0 +1,21 @@ +class foo + def foo + eval(" +def baz + print(\"bar\n\") +end") + end +end + +class bar:foo + def bar + baz() + end +end + +f = foo.new +b = bar.new + +b.foo +b.bar +f.baz diff --git a/sample/fib.awk b/sample/fib.awk new file mode 100644 index 0000000000..7ebe8930f5 --- /dev/null +++ b/sample/fib.awk @@ -0,0 +1,5 @@ + function fib(n) { + if ( n<2 ) return n; else return fib(n-2) + fib(n-1) + } + + BEGIN { print fib(20); } diff --git a/sample/fib.pl b/sample/fib.pl new file mode 100644 index 0000000000..c5593764aa --- /dev/null +++ b/sample/fib.pl @@ -0,0 +1,10 @@ + sub fib { + local($n)=@_; + if( $n<2 ){ + return $n; + } { + return &fib($n-2)+&fib($n-1) + } + } + + print &fib(20), "\n"; diff --git a/sample/fib.rb b/sample/fib.rb new file mode 100644 index 0000000000..c72f91f2f2 --- /dev/null +++ b/sample/fib.rb @@ -0,0 +1,8 @@ +def fib (n) + if n<2 + n + else + fib(n-2)+fib(n-1) + end +end +print(fib(20), "\n"); diff --git a/sample/freq.rb b/sample/freq.rb new file mode 100644 index 0000000000..7417e0b5a4 --- /dev/null +++ b/sample/freq.rb @@ -0,0 +1,13 @@ +# + +freq = {} +while gets() + while sub(/\w+/, '') + word = $& + freq[word] +=1 + end +end + +for word in freq.keys.sort + printf("%s -- %d\n", word, freq[word]) +end diff --git a/sample/fullpath.pl b/sample/fullpath.pl new file mode 100644 index 0000000000..a07b90edd4 --- /dev/null +++ b/sample/fullpath.pl @@ -0,0 +1,22 @@ +#! /usr/local/bin/perl +# convert ls-lR filename into fullpath. + +$path = shift; +if (!defined $path) { + $path = ""; +} +elsif ($path !~ /\/$/) { + $path .= "/" +} + +while (<>) { + if (/:$/) { + chop; chop; + $path = $_ . "/"; + } elsif (/^total/ || /^d/) { + next; + } elsif (/^(.*\d )(.+)$/) { + print $1, $path, $2, "\n"; + } +} + diff --git a/sample/fullpath.rb b/sample/fullpath.rb new file mode 100644 index 0000000000..b1d4b9c332 --- /dev/null +++ b/sample/fullpath.rb @@ -0,0 +1,24 @@ +#! /usr/local/bin/ruby +# convert ls-lR filename into fullpath. + +if $ARGV[0] =~ /-p/ + $ARGV.shift + path = $ARGV.shift +end + +if path == nil + path = "" +elsif path !~ /\/$/ + print(path, "/\n") + path += "/" +end + +while gets() + if /:$/ + path = $_.chop.chop + "/" + elsif /^total/ || /^d/ + elsif /^(.*\d )(.+)$/ + print($1, path, $2, "\n") + end +end + diff --git a/sample/gctest.rb b/sample/gctest.rb new file mode 100644 index 0000000000..6067393bbb --- /dev/null +++ b/sample/gctest.rb @@ -0,0 +1,69 @@ +def cons(car, cdr) + [car, cdr] +end + +def car(x) + if x == nil ; nil else x[0] end +end + +def cdr(x) + if x == nil ; nil else x[1] end +end + +def reverse1(x, y) + if x == nil ; y else reverse1(cdr(x), cons(car(x), y)) end +end + +def reverse(x) + reverse1(x, nil) +end + +def ints(low, up) + if low > up + nil + else + cons(low, ints(low+1, up)) + end +end + +def print_int_list(x) + if x == nil + print("NIL\n") + else + print(car(x)) + if nil != cdr(x) + print(", ") + print_int_list(cdr(x)) + else + print("\n") + end + end +end + +GC.threshold = 1000000 + +print("start\n") +print("threshold: ", GC.threshold, "\n"); + +a = ints(1, 100) +print_int_list(a) +b = ints(1, 50) +print_int_list(b) +print_int_list(reverse(a)) +print_int_list(reverse(b)) +for i in 1 .. 100 + b = reverse(reverse(b)) +# print(i, ": ") +# print_int_list(b) +end +print("a: ") +print_int_list(a) +print("b: ") +print_int_list(b) +print("reverse(a): ") +print_int_list(reverse(a)) +print("reverse(b): ") +print_int_list(reverse(b)) +a = b = nil +print("finish\n") +GC.start() diff --git a/sample/getopts.rb b/sample/getopts.rb new file mode 100644 index 0000000000..57a7db424f --- /dev/null +++ b/sample/getopts.rb @@ -0,0 +1,111 @@ +# +# getopts.rb - get options +# $Release Version: $ +# $Revision: 1.2 $ +# $Date: 1994/02/15 05:17:15 $ +# by Yasuo OHBA(STAFS Development Room) +# +# -- +# �I�v�V�����̉�͂���, $OPT_?? �ɒl���Z�b�g���܂�. +# �w��̂Ȃ��I�v�V�������w�肳�ꂽ���� nil ��Ԃ��܂�. +# ����I�������ꍇ��, �Z�b�g���ꂽ�I�v�V�����̐���Ԃ��܂�. +# +# getopts(single_opts, *opts) +# +# ex. sample [options] filename +# options ... +# -f -x --version --geometry 100x200 -d unix:0.0 +# �� +# getopts("fx", "version", "geometry:", "d:") +# +# ������: +# -f �� -x (= -fx) �̗l�Ȉꕶ���̃I�v�V�����̎w������܂�. +# �����ň������Ȃ��Ƃ��� nil �̎w�肪�K�v�ł�. +# �������ȍ~: +# �����O�l�[���̃I�v�V������, �����̔����I�v�V�����̎w������܂�. +# --version ��, --geometry 300x400 ��, -d host:0.0 ���ł�. +# �������w��� ":" ��K���t���Ă�������. +# +# �I�v�V�����̎w�肪�������ꍇ, �ϐ� $OPT_?? �� non-nil ��������, ���̃I +# �v�V�����̈������Z�b�g����܂�. +# -f -> $OPT_f = %TRUE +# --geometry 300x400 -> $OPT_geometry = 300x400 +# +# - �������� -- ��, ����ȍ~, �S�ăI�v�V�����̉�͂����܂���. +# + +$RCS_ID="$Header: /var/ohba/RCS/getopts.rb,v 1.2 1994/02/15 05:17:15 ohba Exp ohba $" + +def getopts(single_opts, *opts) + if (opts) + single_colon = "" + long_opts = [] + sc = 0 + for option in opts + if (option.length <= 2) + single_colon[sc, 0] = option[0, 1] + sc += 1 + else + long_opts.push(option) + end + end + end + + count = 0 + while ($ARGV.length != 0) + compare = nil + case $ARGV[0] + when /^-*$/ + $ARGV.shift + break + when /^--.*/ + compare = $ARGV[0][2, ($ARGV[0].length - 2)] + if (long_opts != "") + for option in long_opts + if (option[(option.length - 1), 1] == ":" && + option[0, (option.length - 1)] == compare) + if ($ARGV.length <= 1) + return nil + end + eval("$OPT_" + compare + " = " + '$ARGV[1]') + $ARGV.shift + count += 1 + break + elsif (option == compare) + eval("$OPT_" + compare + " = %TRUE") + count += 1 + break + end + end + end + when /^-.*/ + for index in 1..($ARGV[0].length - 1) + compare = $ARGV[0][index, 1] + if (single_opts && compare =~ "[" + single_opts + "]") + eval("$OPT_" + compare + " = %TRUE") + count += 1 + elsif (single_colon != "" && compare =~ "[" + single_colon + "]") + if ($ARGV[0][index..-1].length > 1) + eval("$OPT_" + compare + " = " + '$ARGV[0][(index + 1)..-1]') + count += 1 + elsif ($ARGV.length <= 1) + return nil + else + eval("$OPT_" + compare + " = " + '$ARGV[1]') + $ARGV.shift + count = count + 1 + end + break + end + end + else + break + end + + $ARGV.shift + if (!defined("$OPT_" + compare)) + return nil + end + end + return count +end diff --git a/sample/getopts.test b/sample/getopts.test new file mode 100755 index 0000000000..16f1bb06c7 --- /dev/null +++ b/sample/getopts.test @@ -0,0 +1,31 @@ +#! /mp/free/bin/ruby -- -*- ruby -*- + +load("parsearg.rb") + +def usage() + printf("Usage:\n") + printf("This is Getopt test program \n") +end + +$USAGE = 'usage' +parseArgs(0, !nil, "d", "x:", "y:", "version", "geometry:") +if ($OPT_d) + if ($OPT_x) + printf("x = %d\n", $OPT_x.atoi) + end + if ($OPT_y) + printf("y = %d\n", $OPT_y.atoi) + end + if ($OPT_geometry) + printf("geometry = %s\n", $OPT_geometry) + end +end + +if ($OPT_version) + printf("version 1.00\n") +end + +while ($ARGV.length != 0) + print ("other = ", $ARGV[0], "\n") + $ARGV.shift +end diff --git a/sample/hash.rb b/sample/hash.rb new file mode 100644 index 0000000000..126b17dfe4 --- /dev/null +++ b/sample/hash.rb @@ -0,0 +1,4 @@ +print(+-1.0.hash,"\n") +print(-1.0.hash,"\n") +print((-1.0).hash,"\n") +print(-(1.0.hash),"\n") diff --git a/sample/io.rb b/sample/io.rb new file mode 100644 index 0000000000..45d50d653a --- /dev/null +++ b/sample/io.rb @@ -0,0 +1,40 @@ +home = getenv("HOME") +print(home.sub("m", "&&"), home, "\n") +print(home.reverse, "\n") + +if File.s("io.rb") + print(File.s("io.rb"), ": io.rb\n") +end + +$/="f\n" +for i in "abc\n\ndef\nghi\n" + print("tt: ", i) +end + +printf("%s:(%d)%s\n", $0, $ARGV.length, $ARGV[0]) +passwd = open($ARGV[0], "r") +#printf("%s", do passwd.find using i; i =~ /\*/ end) + +n = 1 +for i in passwd #.grep(/^\*/) + printf("%6d: %s", n, i) + n = n + 1; +end + +fp = open("|-", "r") + +if fp == nil + for i in 1..5 + print(i, "\n") + end +else + for line in fp + print(line) + end +end + +def printUsage() + if $USAGE + apply($USAGE); + end +end diff --git a/sample/less.rb b/sample/less.rb new file mode 100755 index 0000000000..e818e7a2ba --- /dev/null +++ b/sample/less.rb @@ -0,0 +1,30 @@ +#! /mp/free/bin/ruby -- -*- ruby -*- +# +# less - +# $Release Version: $ +# $Revision: 1.1 $ +# $Date: 90/09/29 15:17:59 $ +# by Yasuo OHBA(STAFS Development Room) +# +# -- +# +# +# + +$RCS_ID="$Header: less,v 1.1 90/09/29 15:17:59 ohba Locked $" + +ZCAT = "/usr/local/bin/zcat" +LESS = "/usr/local/bin/less" + +FILE = $ARGV.pop +OPTION = (if $ARGV.length == 0; "" else $ARGV.join(" "); end) + +if FILE =~ /\.(Z|gz)$/ + exec(format("%s %s | %s %s", ZCAT, FILE, LESS, OPTION)) +elsif FILE == nil + exec(format("%s %s", LESS, OPTION)) +else + print(format("%s %s %s", LESS, OPTION, FILE), "\n") + exec(format("%s %s %s", LESS, OPTION, FILE)) +end +exit() diff --git a/sample/list.rb b/sample/list.rb new file mode 100644 index 0000000000..e0b5b383b0 --- /dev/null +++ b/sample/list.rb @@ -0,0 +1,81 @@ +# Linked list program +class MyElem + def MyElem.new(item) + super.init(item) + end + + def init(item) + @data = item + @next = nil + self + end + + def data + @data + end + + def next + @next + end + + def next=(new) + @next = new + end +end + +class MyList + def add_to_list(obj) + elt = MyElem.new(obj) + if @head + @tail.next = elt + else + @head = elt + end + @tail = elt + end + + def each + elt = @head + while elt + yield elt + elt = elt.next + end + end + + def to_s + str = "<MyList:\n"; + for elt in self + str += elt.data.to_s + "\n" + end + str += ">" + str + end +end + +class Point + def Point.new(x, y) + super.init(x, y) + end + + def init(x, y) + @x = x; @y = y + self + end + + def to_s + sprintf("%d@%d", @x, @y) + end +end + +list1 = MyList.new +list1.add_to_list(10) +list1.add_to_list(20) +list1.add_to_list(Point.new(2, 3)) +list1.add_to_list(Point.new(4, 5)) +list2 = MyList.new +list2.add_to_list(20) +list2.add_to_list(Point.new(4, 5)) +list2.add_to_list(list1) + +print("list1:\n", list1, "\n") +print("list2:\n", list2, "\n") diff --git a/sample/list2.rb b/sample/list2.rb new file mode 100644 index 0000000000..c2e9bca753 --- /dev/null +++ b/sample/list2.rb @@ -0,0 +1,20 @@ +# Linked list program -- short version +class Point + def Point.new(x, y) + super.init(x, y) + end + + def init(x, y) + @x = x; @y = y + self + end + + def to_s + sprintf("%d@%d", @x, @y) + end +end + +list1 = [10, 20, Point.new(2, 3), Point.new(4, 5)] +list2 = [20, Point.new(4, 5), list1] +print("list1:\n", list1.join("\n"), "\n") +print("list2:\n", list2.join("\n"), "\n") diff --git a/sample/math.rb b/sample/math.rb new file mode 100644 index 0000000000..83be1b9048 --- /dev/null +++ b/sample/math.rb @@ -0,0 +1,4 @@ +#load("lib/math.o") +include Math +sqrt(4) +print(Math.sqrt(257), "\n") diff --git a/sample/mpart.rb b/sample/mpart.rb new file mode 100755 index 0000000000..c0f705ef8e --- /dev/null +++ b/sample/mpart.rb @@ -0,0 +1,42 @@ +#! ./ruby + +lines = 1000 + +if ($ARGV[0] =~ /^-(\d+)$/ ) + lines = $1.to_i; + $ARGV.shift; +end + +basename = $ARGV[0] +extname = "part" + +part = 1 +line = 0 + +fline = 0 +for i in ifp = open(basename) + fline = fline + 1 +end +ifp.close + +parts = fline / lines + 1 + +for i in ifp = open(basename) + if line == 0 + ofp = open(sprintf("%s.%s%02d", basename, extname, part), "w") + printf(ofp, "%s part%02d/%02d\n", basename, part, parts) + ofp.write("BEGIN--cut here--cut here\n") + end + ofp.write(i) + line = line + 1 + if line >= lines + ofp.write("END--cut here--cut here\n") + ofp.close + part = part + 1 + line = 0 + end +end +ofp.write("END--cut here--cut here\n") +ofp.close + +ifp.close diff --git a/sample/newver.rb b/sample/newver.rb new file mode 100644 index 0000000000..bbf03aebc2 --- /dev/null +++ b/sample/newver.rb @@ -0,0 +1,13 @@ +#! /usr/local/bin/ruby + +f = open("version.h", "r") +f.gets() +f.close + +if $_ =~ /"(\d)\.(\d+)"/; + f = open("version.h", "w") + i = $2.to_i + 1 + printf("ruby version %d.%0d\n", $1, i) + printf(f, "#define RUBY_VERSION \"%d.%0d\"\n", $1, i) + f.close +end diff --git a/sample/occur.pl b/sample/occur.pl new file mode 100644 index 0000000000..1f5fcf27a4 --- /dev/null +++ b/sample/occur.pl @@ -0,0 +1,9 @@ +while (<>) { + for (split(/\W+/)) { + $freq{$_}++; + } +} + +for (sort keys %freq) { + print "$_ -- $freq{$_}\n"; +} diff --git a/sample/occur.rb b/sample/occur.rb new file mode 100644 index 0000000000..12e469d20a --- /dev/null +++ b/sample/occur.rb @@ -0,0 +1,10 @@ +freq = {} +while gets() + for word in $_.split(/\W+/) + freq[word] +=1 + end +end + +for word in freq.keys.sort + printf("%s -- %d\n", word, freq[word]) +end diff --git a/sample/occur2.rb b/sample/occur2.rb new file mode 100644 index 0000000000..6e0513707c --- /dev/null +++ b/sample/occur2.rb @@ -0,0 +1,14 @@ +freq = {} +while gets() + for word in $_.split(/\W+/) + protect + freq[word] = freq[word] + 1 + resque + freq[word] = 1 + end + end +end + +for word in freq.keys.sort + printf("%s -- %d\n", word, freq[word]) +end diff --git a/sample/opt_s.rb b/sample/opt_s.rb new file mode 100644 index 0000000000..4981119012 --- /dev/null +++ b/sample/opt_s.rb @@ -0,0 +1,8 @@ +#! ruby -s +if ($xyz) + print("xyz = TRUE\n") +end +if ($zzz) + print("zzz = ", $zzz, "\n") +end +print($ARGV.join(", "), "\n") diff --git a/sample/opt_x.rb b/sample/opt_x.rb new file mode 100644 index 0000000000..4fc9a25276 --- /dev/null +++ b/sample/opt_x.rb @@ -0,0 +1,8 @@ +this is a forwarding header +this is a header too. + #! ruby +this is a trailing +#! ./ruby -v +print("tt\n") +__END__ +this is a trailer diff --git a/sample/parsearg.rb b/sample/parsearg.rb new file mode 100644 index 0000000000..e7e2b7a7f3 --- /dev/null +++ b/sample/parsearg.rb @@ -0,0 +1,69 @@ +# +# parseargs.rb - parse arguments +# $Release Version: $ +# $Revision: 1.3 $ +# $Date: 1994/02/15 05:16:21 $ +# by Yasuo OHBA(STAFS Development Room) +# +# -- +# �����̉�͂���, $OPT_?? �ɒl���Z�b�g���܂�. +# ����I�������ꍇ��, �Z�b�g���ꂽ�I�v�V�����̐���Ԃ��܂�. +# +# parseArgs(argc, single_opts, *opts) +# +# ex. sample [options] filename +# options ... +# -f -x --version --geometry 100x200 -d unix:0.0 +# �� +# parseArgs(1, nil, "fx", "version", "geometry:", "d:") +# +# ������: +# �I�v�V�����ȊO�̍Œ�����̐� +# ������: +# �I�v�V�����̕K�v���c�K���K�v�Ȃ� %TRUE �����łȂ���� %FALSE. +# ��O����: +# -f �� -x (= -fx) �̗l�Ȉꕶ���̃I�v�V�����̎w������܂�. +# �����ň������Ȃ��Ƃ��� nil �̎w�肪�K�v�ł�. +# ��l�����ȍ~: +# �����O�l�[���̃I�v�V������, �����̔����I�v�V�����̎w������܂�. +# --version ��, --geometry 300x400 ��, -d host:0.0 ���ł�. +# �������w��� ":" ��K���t���Ă�������. +# +# �I�v�V�����̎w�肪�������ꍇ, �ϐ� $OPT_?? �� non-nil ��������, ���̃I +# �v�V�����̈������Z�b�g����܂�. +# -f -> $OPT_f = %TRUE +# --geometry 300x400 -> $OPT_geometry = 300x400 +# +# usage ���g�������ꍇ��, $USAGE �� usage() ���w�肵�܂�. +# def usage() +# �c +# end +# $USAGE = 'usage' +# usage ��, --help ���w�肳�ꂽ��, �Ԉ�����w����������ɕ\�����܂�. +# +# - �������� -- ��, ����ȍ~, �S�ăI�v�V�����̉�͂����܂���. +# + +$RCS_ID="$Header: /var/ohba/RCS/parseargs.rb,v 1.3 1994/02/15 05:16:21 ohba Exp ohba $" + +load("getopts.rb") + +def printUsageAndExit() + if $USAGE + apply($USAGE) + end + exit() +end + +def parseArgs(argc, nopt, single_opts, *opts) + if ((noOptions = getopts(single_opts, *opts)) == nil) + printUsageAndExit() + end + if (nopt && noOptions == 0) + printUsageAndExit() + end + if ($ARGV.length < argc) + printUsageAndExit() + end + return noOptions +end diff --git a/sample/perror.rb b/sample/perror.rb new file mode 100644 index 0000000000..9196525ee3 --- /dev/null +++ b/sample/perror.rb @@ -0,0 +1,7 @@ +if File._s("io.rb") + print(File._z("io.rb", "io.rb\n") +# print(File._s("io.rb"), ": io.rb\n") +end + +for i in 1..5 +end diff --git a/sample/rcs.awk b/sample/rcs.awk new file mode 100644 index 0000000000..08979285c9 --- /dev/null +++ b/sample/rcs.awk @@ -0,0 +1,33 @@ +BEGIN { + sw = 40.0; + dw = 78.0; + hdw = dw / 2.0; + w = 20.0; + h =1.0; + d = 0.2; + ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./"; + rnd = srand(); +} + +{ + xr = -hdw; y = h * 1.0; maxxl = -999; + s = ""; + while (xr < hdw) { + x = xr * (1 + y) - y * w / 2; + i = (x / (1 + h) + sw /2); + c = (0 < i && i < length($0)) ? substr($0, i, 1) : "0"; + y = h - d * c; + xl = xr - w * y / (1 + y); + if (xl < -hdw || xl >= hdw || xl <= maxxl) { + t = rand() * length(ss); + c = substr(ss, t, 1); + } + else { + c = substr(s, xl + hdw, 1); + maxxl = xl; + } + s = s c; + xr = xr + 1; + } + print s; +} diff --git a/sample/rcs.dat b/sample/rcs.dat new file mode 100644 index 0000000000..61c88bff89 --- /dev/null +++ b/sample/rcs.dat @@ -0,0 +1,17 @@ +0000000000000000220000000000000000 +0000000000000111221110000000000000 +0000000000111112222111110000000000 +0000000111111112222111111110000000 +0000111111111122222211111111110000 +0111111111111222222221111111111110 +2222222222222222222222222222222222 +1122222222222222222222222222222211 +0111122222222222222222222222211110 +0011111122222222222222222211111100 +0001111111222222222222221111111000 +0000111112222222222222222111110000 +0000011122222222112222222211100000 +0000001122222221111222222211000000 +0000000122221111111111222210000000 +0000000221111111111111111220000000 +0000000000000000000000000000000000 diff --git a/sample/rcs.rb b/sample/rcs.rb new file mode 100644 index 0000000000..b14742981d --- /dev/null +++ b/sample/rcs.rb @@ -0,0 +1,42 @@ +sw = 40.0 # ���̃p�^�[���̕� +dw = 78.0 # ��������� Random Character Streogram �̕� +hdw = dw / 2.0 +w = 20.0 # ����̕� +h =1.0 # ��ʂƊ�ʂ̋��� +d = 0.2 # �P�ʓ�����̕����オ��� +ss="abcdefghijklmnopqrstuvwxyz0123456789!#$%^&*()-=\\[];'`,./" +rnd = srand() + +while gets() +# print($_) + xr = -hdw; y = h * 1.0; maxxl = -999 + s = ""; + while xr < hdw + x = xr * (1 + y) - y * w / 2 + i = (x / (1 + h) + sw /2) + c = if (0 < i < $_.length); $_[i, 1].to_i else 0 end + y = h - d * c + xl = xr - w * y / (1 + y); + if xl < -hdw || xl >= hdw || xl <= maxxl + t = rand(ss.length) + c = ss[t, 1] + else + c = s[xl + hdw, 1] + maxxl = xl + end + s = s + c + xr = xr + 1 + end + print(s, "\n") +end + + + + + + + + + + + diff --git a/sample/reach.rb b/sample/reach.rb new file mode 100644 index 0000000000..25b340887d --- /dev/null +++ b/sample/reach.rb @@ -0,0 +1,5 @@ +for i in 1..10 + print("test\n") + break + print("test2\n") +end diff --git a/sample/resp.rb b/sample/resp.rb new file mode 100644 index 0000000000..84516b4c78 --- /dev/null +++ b/sample/resp.rb @@ -0,0 +1,2 @@ +undef kill +print(responds_to("kill"), "\n") diff --git a/sample/samp.rb b/sample/samp.rb new file mode 100644 index 0000000000..b4d818faba --- /dev/null +++ b/sample/samp.rb @@ -0,0 +1,12 @@ +�P�� = 0 +while gets() + printf("%3d: %s", $., $_) + while sub(/\w+/, '') + if $& != ""; + �P�� += 1 + end + end + if ($. >= 10); break; end +end +printf("line: %d\n", $.) +printf("word: %d\n", �P��) diff --git a/sample/split.rb b/sample/split.rb new file mode 100644 index 0000000000..737173635e --- /dev/null +++ b/sample/split.rb @@ -0,0 +1,12 @@ +print("1 byte string", "\n") +print("1 byte string".reverse, "\n") + +print("����ʸ����", "\n") +print("����ʸ����".reverse, "\n") + +print("1 byte string", "\n") +print("1 byte string".split(//).reverse.join(":"), "\n") +print("����ʸ����", "\n") +print("����ʸ����".split(//).reverse.join(":"), "\n") +print("���Ѥ�1byte�κ���", "\n") +print("���Ѥ�1byte�κ���".split(//).reverse.join(":"), "\n") diff --git a/sample/struct.rb b/sample/struct.rb new file mode 100644 index 0000000000..7c0690b627 --- /dev/null +++ b/sample/struct.rb @@ -0,0 +1,4 @@ +foo = Struct.new("test", "a1"::1, "a2"::2) +print(foo, "\n") +bar = foo.clone +print(bar.a1, "\n") diff --git a/sample/svr.rb b/sample/svr.rb new file mode 100644 index 0000000000..c00a03c8cf --- /dev/null +++ b/sample/svr.rb @@ -0,0 +1,23 @@ +gs = TCPserver.open(0) +printf("server port is on %d\n", gs.port) +socks = [gs] + +while %TRUE + nsock = select(socks); + if nsock == nil; continue end + for s in nsock[0] + if s == gs + socks.push(s.accept) + else + if s.eof + print(s, " is gone\n") + s.close + socks.delete(s) + else + if str = s.gets; + s.write(str) + end + end + end + end +end diff --git a/sample/system.rb b/sample/system.rb new file mode 100644 index 0000000000..c51626d2dc --- /dev/null +++ b/sample/system.rb @@ -0,0 +1 @@ +print(system2("echo foobar")) diff --git a/sample/t1.rb b/sample/t1.rb new file mode 100644 index 0000000000..98d3b529e9 --- /dev/null +++ b/sample/t1.rb @@ -0,0 +1,20 @@ +def test(a1, *a2) + while 1 + switch gets() + case nil + break + case /^-$/ + print("-\n") + return + case /^-help/ + print("-help\n") + break + end + end + print(a1, a2, "\n") +end + +print($ARGV, "\n") +print("in: ") +test(1) +print("end\n") diff --git a/sample/t2.rb b/sample/t2.rb new file mode 100644 index 0000000000..7f5b9df480 --- /dev/null +++ b/sample/t2.rb @@ -0,0 +1,24 @@ +#print("in Print\n") +def t2() end + +def println(*args) + for a in args + t2() + print(a) + end + print("\n") +end def + +def tt + for i in 1..10 + println("i:", i); + yield(i); + end +end + +test = +do tt() using i + if i == 3; break end + println("ttt: ", i); +end +#exit() diff --git a/sample/test.rb b/sample/test.rb new file mode 100644 index 0000000000..9c422cc94a --- /dev/null +++ b/sample/test.rb @@ -0,0 +1,5 @@ +index = 1 +for argument in $ARGV + printf("����%d:%s\n", index, argument) + index = index + 1 +end diff --git a/sample/trap.pl b/sample/trap.pl new file mode 100644 index 0000000000..ce022d4062 --- /dev/null +++ b/sample/trap.pl @@ -0,0 +1,6 @@ +$SIG{'INT'} = 'test'; + +while (<>) { + print; +} +sub test { print "C-c handled\n"; } diff --git a/sample/trap.rb b/sample/trap.rb new file mode 100644 index 0000000000..e552a0fddc --- /dev/null +++ b/sample/trap.rb @@ -0,0 +1,3 @@ +trap('print("C-c handled\n")', 'INT', 'HUP') +print("---\n") +while gets(); print($_) end diff --git a/sample/tt.rb b/sample/tt.rb new file mode 100644 index 0000000000..cb863e3527 --- /dev/null +++ b/sample/tt.rb @@ -0,0 +1,103 @@ +module Print + print("in Print\n") + def println(*args) + for a in args + print(a) + end + print("\n") + end def + + def println2(*args) + print(*args) + print("\n") + end def +end module + +module Print2 + def println(*args) + print("pr2: "); + super + end +end + +module Print3 + include Print2 + def println(*args) + print("pr3: "); + super + end +end + +include Print, Print2, Print3 + +println2("in TopLevel") + +print("a: ", $OPT_test, "\n") +printf("%10.5g: %*s -> 0x%x\n", 123345, -10, Print, Print.id); + +println("a+ matches aaa at ", "bccAAaaa" =~ /a+/) +ttt = "this is a ���� ����" +if offset = (ttt =~ /this ([^ ]*) (.*)/) + println("0 = ", $&); + println("1 = ", $1); + println("2 = ", $2); +end + +class Fib:Object + print("in Fib:Object\n") + + def Fib.test(*args) + println("in Fib.test") + + if args; println(*args) end + args = args.grep(/^c/) + super(*args) + end def + + def init + println("in Fib.init"); + end def + + def fib(n) + a =0; b = 1 + + while b <= n + c = a; a = b; b = c+b + end while + return b + end def +end + +def Object.test(*args) + println("in Object.test") + if args; println(*args) end +end + +Fib.test("abc", "def", "aaa", "ccc") +println("1:", 0x3fffffffa) +println("2:", 0x3ffffffa) +#println("3:", 0x40000000+0x40000000) + +fib = Fib.new + +fib.init +print(Fib, ":") + +#for i in 1 .. 100 +# fib.fib(90000) +#end + +println(fib.fib(9000)) + +def tt + for i in 1..10 + println("i:", i); + yield(i); + end +end + +test = do tt() using i + if i == 2; break end +end + +println([1,2,3,4].join(":")) diff --git a/socket.c b/socket.c new file mode 100644 index 0000000000..ce0f71d3d3 --- /dev/null +++ b/socket.c @@ -0,0 +1,738 @@ +/************************************************ + + socket.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:51 $ + created at: Thu Mar 31 12:21:29 JST 1994 + +************************************************/ + +#include "ruby.h" +#ifdef HAVE_SOCKET +#include "io.h" +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <sys/un.h> + +extern VALUE C_IO; +VALUE C_BasicSocket; +VALUE C_TCPsocket; +VALUE C_TCPserver; +VALUE C_UNIXsocket; +VALUE C_UNIXserver; +VALUE C_Socket; + +FILE *rb_fdopen(); +char *strdup(); + +static VALUE +sock_new(class, fd) + VALUE class; + int fd; +{ + VALUE sock = obj_alloc(class); + OpenFile *fp; + + GC_LINK; + GC_PRO(sock); + MakeOpenFile(sock, fp); + fp->f = rb_fdopen(fd, "r"); + setbuf(fp->f, NULL); + fp->f2 = rb_fdopen(fd, "w"); + fp->mode = FMODE_READWRITE|FMODE_SYNC; + GC_UNLINK; + + return sock; +} + +static VALUE +Fbsock_shutdown(sock, args) + VALUE sock, args; +{ + VALUE howto; + int how; + OpenFile *fptr; + + rb_scan_args(args, "01", &howto); + if (howto == Qnil) + how = 2; + else { + how = NUM2INT(howto); + if (how < 0 && how > 2) how = 2; + } + GetOpenFile(sock, fptr); + if (shutdown(fileno(fptr->f), how) == -1) + rb_sys_fail(Qnil); + return sock; +} + +static VALUE +Fbsock_setopt(sock, lev, optname, val) + VALUE sock, lev, optname; + struct RString *val; +{ + int level, option; + OpenFile *fptr; + + level = NUM2INT(lev); + option = NUM2INT(optname); + Check_Type(val, T_STRING); + + + GetOpenFile(sock, fptr); + if (setsockopt(fileno(fptr->f), level, option, val->ptr, val->len) < 0) + rb_sys_fail(fptr->path); + return sock; +} + +static VALUE +Fbsock_getopt(sock, lev, optname) + VALUE sock, lev, optname; +{ + int level, option, len; + struct RString *val; + OpenFile *fptr; + + level = NUM2INT(lev); + option = NUM2INT(optname); + len = 256; + val = (struct RString*)str_new(0, len); + Check_Type(val, T_STRING); + + GetOpenFile(sock, fptr); + if (getsockopt(fileno(fptr->f), level, option, val->ptr, &len) < 0) + rb_sys_fail(fptr->path); + val->len = len; + return (VALUE)val; +} + +static VALUE +Fbsock_getsockname(sock) + VALUE sock; +{ + char buf[1024]; + int len = sizeof buf; + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) + rb_sys_fail("getsockname(2)"); + return str_new(buf, len); +} + +static VALUE +Fbsock_getpeername(sock) + VALUE sock; +{ + char buf[1024]; + int len = sizeof buf; + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) + rb_sys_fail("getpeername(2)"); + return str_new(buf, len); +} + +static VALUE +open_inet(class, h, serv, server) + VALUE class, h, serv; + int server; +{ + char *host; + struct hostent *hostent, _hostent; + struct servent *servent, _servent; + struct protoent *protoent; + struct sockaddr_in sockaddr; + int fd, status; + int hostaddr, hostaddrPtr[2]; + int servport; + char *syscall; + VALUE sock; + + if (h) { + Check_Type(h, T_STRING); + host = RSTRING(h)->ptr; + hostent = gethostbyname(host); + if (hostent == NULL) { + hostaddr = inet_addr(host); + if (hostaddr == -1) { + if (server && !strlen(host)) + hostaddr = INADDR_ANY; + else + rb_sys_fail(host); + } + _hostent.h_addr_list = (char **)hostaddrPtr; + _hostent.h_addr_list[0] = (char *)&hostaddr; + _hostent.h_addr_list[1] = NULL; + _hostent.h_length = sizeof(hostaddr); + _hostent.h_addrtype = AF_INET; + hostent = &_hostent; + } + } + servent = NULL; + if (FIXNUM_P(serv)) { + servport = FIX2UINT(serv); + goto setup_servent; + } + Check_Type(serv, T_STRING); + servent = getservbyname(RSTRING(serv)->ptr, "tcp"); + if (servent == NULL) { + servport = strtol(RSTRING(serv)->ptr, Qnil, 0); + if (servport == -1) Fail("no such servce %s", RSTRING(serv)->ptr); + setup_servent: + _servent.s_port = servport; + _servent.s_proto = "tcp"; + servent = &_servent; + } + protoent = getprotobyname(servent->s_proto); + if (protoent == NULL) Fail("no such proto %s", servent->s_proto); + + fd = socket(PF_INET, SOCK_STREAM, protoent->p_proto); + + sockaddr.sin_family = AF_INET; + if (h == Qnil) { + sockaddr.sin_addr.s_addr = INADDR_ANY; + } + else { + memcpy((char *)&(sockaddr.sin_addr.s_addr), + (char *) hostent->h_addr_list[0], + (size_t) hostent->h_length); + } + sockaddr.sin_port = servent->s_port; + + if (server) { + status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "bind(2)"; + } + else { + status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "connect(2)"; + } + + if (status < 0) { + close (fd); + rb_sys_fail(syscall); + } + if (server) listen(fd, 5); + + /* create new instance */ + sock = sock_new(class, fd); + + return sock; +} + +static VALUE +Ftcp_sock_open(class, host, serv) + VALUE class, host, serv; +{ + Check_Type(host, T_STRING); + return open_inet(class, host, serv, 0); +} + +static VALUE +Ftcp_svr_open(class, args) + VALUE class, args; +{ + VALUE arg1, arg2; + + if (rb_scan_args(args, "11", &arg1, &arg2) == 2) + return open_inet(class, arg1, arg2, 1); + else + return open_inet(class, Qnil, arg1, 1); +} + +static VALUE +sock_accept(class, fd, sockaddr, len) + VALUE class; + int fd; + struct sockaddr *sockaddr; + int *len; +{ + int fd2; + + retry: + fd2 = accept(fd, sockaddr, len); + if (fd2 < 0) { + if (errno == EINTR) goto retry; + rb_sys_fail(Qnil); + } + return sock_new(class, fd2); +} + +static VALUE +Ftcp_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in from; + int fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(struct sockaddr_in); + return sock_accept(C_TCPsocket, fileno(fptr->f), + (struct sockaddr*)&from, &fromlen); +} + +static VALUE +open_unix(class, path, server) + VALUE class; + struct RString *path; + int server; +{ + struct sockaddr_un sockaddr; + int fd, status; + char *syscall; + VALUE sock; + OpenFile *fptr; + + Check_Type(path, T_STRING); + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) rb_sys_fail("socket(2)"); + + sockaddr.sun_family = AF_UNIX; + strncpy(sockaddr.sun_path, path->ptr, sizeof(sockaddr.sun_path)-1); + sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = '\0'; + + if (server) { + status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "bind(2)"; + } + else { + status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "connect(2)"; + } + + if (status < 0) { + close (fd); + rb_sys_fail(syscall); + } + + if (server) listen(fd, 5); + + GC_LINK; + GC_PRO3(sock, sock_new(class, fd)); + GetOpenFile(sock, fptr); + fptr->path = strdup(path->ptr); + GC_UNLINK; + + return sock; +} + +static VALUE +tcp_addr(sockaddr) + struct sockaddr_in *sockaddr; +{ + VALUE family, port, addr; + VALUE ary; + struct hostent *hostent; + + GC_LINK; + GC_PRO3(family, str_new2("AF_INET")); + hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr, + sizeof(sockaddr->sin_addr), + AF_INET); + if (hostent) { + addr = str_new2(hostent->h_name); + } + else { + char buf[16]; + char *a = (char*)&sockaddr->sin_addr; + sprintf(buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); + addr = str_new2(buf); + } + GC_PRO(addr); + port = INT2FIX(sockaddr->sin_port); + ary = ary_new3(3, family, port, addr); + GC_UNLINK; + return ary; +} + +static VALUE +Ftcp_addr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return tcp_addr(&addr); +} + +static VALUE +Ftcp_peeraddr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return tcp_addr(&addr); +} + +static VALUE +Funix_sock_open(sock, path) + VALUE sock, path; +{ + return open_unix(sock, path, 0); +} + +static VALUE +Funix_path(sock) + VALUE sock; +{ + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (fptr->path == Qnil) { + struct sockaddr_un addr; + int len = sizeof(addr); + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail(Qnil); + fptr->path = strdup(addr.sun_path); + } + return str_new2(fptr->path); +} + +static VALUE +Funix_svr_open(class, path) + VALUE class, path; +{ + return open_unix(class, path, 1); +} + +static VALUE +Funix_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un from; + int fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(struct sockaddr_un); + return sock_accept(C_UNIXsocket, fileno(fptr->f), + (struct sockaddr*)&from, &fromlen); +} + +static VALUE +unix_addr(sockaddr) + struct sockaddr_un *sockaddr; +{ + VALUE family, path; + VALUE ary; + + GC_LINK; + GC_PRO3(family, str_new2("AF_UNIX")); + GC_PRO3(path, str_new2(sockaddr->sun_path)); + ary = assoc_new(family, path); + GC_UNLINK; + return ary; +} + +static VALUE +Funix_addr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return unix_addr(&addr); +} + +static VALUE +Funix_peeraddr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return unix_addr(&addr); +} + +static void +setup_domain_and_type(domain, dv, type, tv) + VALUE domain, type; + int *dv, *tv; +{ + char *ptr; + + if (TYPE(domain) == T_STRING) { + ptr = RSTRING(domain)->ptr; + if (strcmp(ptr, "PF_UNIX") == 0) + *dv = PF_UNIX; + else if (strcmp(ptr, "PF_INET") == 0) + *dv = PF_INET; +#ifdef PF_IMPLINK + else if (strcmp(ptr, "PF_IMPLINK") == 0) + *dv = PF_IMPLINK; +#endif +#ifdef PF_AX25 + else if (strcmp(ptr, "PF_AX25") == 0) + *dv = PF_AX25; +#endif +#ifdef PF_IPX + else if (strcmp(ptr, "PF_IPX") == 0) + *dv = PF_IPX; +#endif + else + Fail("Unknown socket domain %s", ptr); + } + else { + *dv = NUM2INT(domain); + } + if (TYPE(type) == T_STRING) { + ptr = RSTRING(type)->ptr; + if (strcmp(ptr, "SOCK_STREAM") == 0) + *tv = SOCK_STREAM; + else if (strcmp(ptr, "SOCK_DGRAM") == 0) + *tv = SOCK_DGRAM; +#ifdef SOCK_RAW + else if (strcmp(ptr, "SOCK_RAW") == 0) + *tv = SOCK_RAW; +#endif +#ifdef SOCK_SEQPACKET + else if (strcmp(ptr, "SOCK_SEQPACKET") == 0) + *tv = SOCK_SEQPACKET; +#endif +#ifdef SOCK_RDM + else if (strcmp(ptr, "SOCK_RDM") == 0) + *tv = SOCK_RDM; +#endif +#ifdef SOCK_PACKET + else if (strcmp(ptr, "SOCK_PACKET") == 0) + *tv = SOCK_PACKET; +#endif + else + Fail("Unknown socket type %s", ptr); + } + else { + *tv = NUM2INT(type); + } +} + +static VALUE +Fsock_open(class, domain, type, protocol) + VALUE class, domain, type, protocol; +{ + int fd; + int d, t; + + setup_domain_and_type(domain, &d, type, &t); + fd = socket(d, t, NUM2INT(protocol)); + if (fd < 0) rb_sys_fail("socke(2)"); + return sock_new(class, fd); +} + +static VALUE +Fsock_socketpair(class, domain, type, protocol) + VALUE class, domain, type, protocol; +{ + int fd; + int d, t, sp[2]; + VALUE sock1, sock2, pair; + + setup_domain_and_type(domain, &d, type, &t); + if (socketpair(d, t, NUM2INT(protocol), sp) < 0) + rb_sys_fail("socketpair(2)"); + + GC_LINK; + GC_PRO3(sock1, sock_new(class, sp[0])); + GC_PRO3(sock2, sock_new(class, sp[1])); + pair = assoc_new(sock1, sock2); + GC_UNLINK; + + return pair; +} + +static VALUE +Fsock_connect(sock, addr) + VALUE sock; + struct RString *addr; +{ + OpenFile *fptr; + + Check_Type(addr, T_STRING); + str_modify(addr); + + GetOpenFile(sock, fptr); + if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) + rb_sys_fail("connect(2)"); + return sock; +} + +static VALUE +Fsock_bind(sock, addr) + VALUE sock; + struct RString *addr; +{ + OpenFile *fptr; + + Check_Type(addr, T_STRING); + str_modify(addr); + + GetOpenFile(sock, fptr); + if (bind(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) + rb_sys_fail("bind(2)"); + return sock; +} + +static VALUE +Fsock_listen(sock, log) + VALUE sock, log; +{ + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (listen(fileno(fptr->f), NUM2INT(log)) < 0) + rb_sys_fail("listen(2)"); + return sock; +} + +static VALUE +Fsock_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + VALUE addr, sock2; + int fd; + char buf[1024]; + int len = sizeof buf; + + GetOpenFile(sock, fptr); + if ((fd = accept(fileno(fptr->f), (struct sockaddr*)buf, &len)) < 0) + rb_sys_fail("listen(2)"); + + return sock_new(C_Socket, fd); +} + +static VALUE +Fsock_send(sock, args) + VALUE sock, args; +{ + struct RString *msg, *to; + VALUE flags; + OpenFile *fptr; + FILE *f; + int fd, n; + + rb_scan_args(args, "21", &msg, &flags, &to); + + Check_Type(msg, T_STRING); + + GetOpenFile(sock, fptr); + f = fptr->f2?fptr->f2:fptr->f; + fd = fileno(f); + if (to) { + Check_Type(to, T_STRING); + n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags), + (struct sockaddr*)to->ptr, to->len); + } + else { + n = send(fd, msg->ptr, msg->len, NUM2INT(flags)); + } + if (n < 0) { + rb_sys_fail("send(2)"); + } + return INT2FIX(n); +} + +static VALUE +Fsock_recv(sock, len, flags) + VALUE sock, len, flags; +{ + OpenFile *fptr; + FILE f; + struct RString *str; + char buf[1024]; + int fd, alen = sizeof buf; + VALUE addr, result; + + GC_LINK; + GC_PRO3(str, (struct RString*)str_new(0, NUM2INT(len))); + + GetOpenFile(sock, fptr); + fd = fileno(fptr->f); + if (recvfrom(fd, str->ptr, str->len, NUM2INT(flags), + (struct sockaddr*)buf, &alen) < 0) { + rb_sys_fail("recv(2)"); + } + GC_PRO3(addr, str_new(buf, alen)); + result = assoc_new(str, addr); + GC_UNLINK; + + return result; +} + +Init_Socket () +{ + C_BasicSocket = rb_define_class("BasicSocket", C_IO); + rb_undef_method(C_BasicSocket, "new"); + rb_define_method(C_BasicSocket, "shutdown", Fbsock_shutdown, -2); + rb_define_method(C_BasicSocket, "setopt", Fbsock_setopt, 3); + rb_define_method(C_BasicSocket, "getopt", Fbsock_getopt, 2); + rb_define_method(C_BasicSocket, "getsockname", Fbsock_getsockname, 0); + rb_define_method(C_BasicSocket, "getpeername", Fbsock_getpeername, 0); + + C_TCPsocket = rb_define_class("TCPsocket", C_BasicSocket); + rb_define_single_method(C_TCPsocket, "open", Ftcp_sock_open, 2); + rb_define_alias(C_TCPsocket, "new", "open"); + rb_define_method(C_TCPsocket, "addr", Ftcp_addr, 0); + rb_define_method(C_TCPsocket, "peeraddr", Ftcp_peeraddr, 0); + + C_TCPserver = rb_define_class("TCPserver", C_TCPsocket); + rb_define_single_method(C_TCPserver, "open", Ftcp_svr_open, -2); + rb_define_alias(C_TCPserver, "new", "open"); + rb_define_method(C_TCPserver, "accept", Ftcp_accept, 0); + + C_UNIXsocket = rb_define_class("UNIXsocket", C_BasicSocket); + rb_define_single_method(C_UNIXsocket, "open", Funix_sock_open, 1); + rb_define_alias(C_UNIXsocket, "new", "open"); + rb_define_method(C_UNIXsocket, "path", Funix_path, 0); + rb_define_method(C_UNIXsocket, "addr", Funix_addr, 0); + rb_define_method(C_UNIXsocket, "peeraddr", Funix_peeraddr, 0); + + C_UNIXserver = rb_define_class("UNIXserver", C_UNIXsocket); + rb_define_single_method(C_UNIXserver, "open", Funix_svr_open, 1); + rb_define_alias(C_UNIXserver, "new", "open"); + rb_define_single_method(C_UNIXserver, "new", Funix_svr_open, 1); + rb_define_method(C_UNIXserver, "accept", Funix_accept, 0); + + C_Socket = rb_define_class("Socket", C_BasicSocket); + rb_define_single_method(C_Socket, "open", Fsock_open, 3); + rb_define_alias(C_UNIXserver, "new", "open"); + + rb_define_method(C_Socket, "connect", Fsock_connect, 1); + rb_define_method(C_Socket, "bind", Fsock_bind, 1); + rb_define_method(C_Socket, "listen", Fsock_listen, 1); + rb_define_method(C_Socket, "accept", Fsock_accept, 0); + + rb_define_method(C_Socket, "send", Fsock_send, -2); + rb_define_method(C_Socket, "recv", Fsock_recv, 2); + + rb_define_single_method(C_Socket, "socketpair", Fsock_socketpair, 3); +} +#endif /* HAVE_SOCKET */ @@ -0,0 +1,3244 @@ +.\" spec - -*- Indented-Text -*- created at: Tue May 25 15:18:26 JST 1993 + +* �Ϥ����(�ʤ�Ruby��?) + +Ruby�ϡ�UNIX�Ǽ�ڤ˥��֥������Ȼظ��ץ�����ߥפ����Ȥ���˾�� +��¸����뤿������ޤ줿. ���Τ����ɬ�פ��Ȼפ�줿������: + + * ʸˡ�䵡ǽ��ñ��Ǥ���. + * ���֥������Ȼظ��ץ�����ߥݡ��Ȥ��뵡ǽ�� + ���ĸ���Ȥ����߷פ���Ƥ���. + * �����饦��ɥ����बû��(���ץ�Ǥ���). + * OS(UNIX)�ε�ǽ����ñ�����ѤǤ���. + * ������ץȸ���Ȥ��ƻȤ���. + * �����Ϥ�free�Ǥ���. + +�ʤɤǤ���. ���֥������Ȼظ�����Ȥ��ư���Ū�Ǥ���Smalltalk��C++�ʤɤ� +��ξ��ΰ������������ƤϤ��뤬, �ä˼�ڤʥץ�����ߥȤ������˷� +���Ƥ���, ���Ƥ���������ΤǤϤʤ��ä�. ����������ץȸ���Ǥ���Perl�� +Tcl�˥��֥������Ȼظ���ǽ���ɲä��������ƥ��¸�ߤ��뤬, �����ϡּ� +�ڤ˥ץ�����ߥפȤ����������������ƤϤ��Ƥ�, �դ˥��֥������Ȼظ� +��ǽ�����������������ä�. ��ä�, �����ξ�����������������߷� +����ɬ�פ�����ȹͤ���줿. ������Ƨ�ޤ����߷פ��줿Ruby����ħ��: + + * ���ץ�Ǥ���. + * ñ����㳰�ξ��ʤ�ʸˡ. + * ��ʬ�ʥ��֥������Ȼظ���ǽ�����. + * �Ǥ�������䤹��(�黻�ҷ����ʤ�). + * �����١������쥯��������. + * �㳰������ǽ������. + * ��ʬ�˶��Ϥʥ��饹���Ȥ߹��ޤ�Ƥ���. + * OS���������뵡ǽ�������. + * ��ĥ���䤹��. + +�ʤɤ�����. Ruby��sh��perl���ΤäƤ���ͤˤȤäƤξQ�ˤʤ뤿�����ä� +�Τ�, �����θ��줫��μ����ʰܹԤ���ǽ�Ǥ���Ȼפ���. �ץ�����ޤ� +Ruby�Υ��֥������Ȼظ���ǽ�ˤĤ��Ƴؤ٤�, ��궯�Ϥʤ��Ȥ�Ǥ���褦�� +�ʤ������. + +����C����ǥ��饹�Ҥ��뤳�Ȥ�Ruby�˶��Ϥˤ��뤳�Ȥ��Ǥ���. �� +����OS�Ǥ�Ruby��ưŪ�˥��֥������ȥե�������Ǥ��뤷, �����Ǥʤ� +�Ƥ�Ruby��ƥ���ѥ��뤷���Ȥ߹��ߥ��饹���ɲä���Τ��ưפǤ���. + +* Ruby�δ��� + +Ruby�δ���Ū����ʬ�����˾�����, ʸˡ���㳰�����ʤ��ΤǿȤˤĤ���Τ� +���ۤ����ʤ�������. + +** ������ + +������ץȸ���ν����ˤʤ餤, ʸ������ʳ���'#'��������ޤǤϥ����� +�ȸ��ʤ�. + +** ���ڤ국�� + +����ʸ��(���֤ȥ��ڡ���)����Ӳ���(\n)�����ڤ국��Ȥʤ�. ������, + + a + + b + +�Τ褦�˹Ԥ���(ʸ)������ǽ���, ���ιԤ�³�����Ȥ�����ʾ��ʳ��ϲ��� +��ʸ�ζ��ڤ�Ȥ���ǧ�������. + +** ���̻� + +����ե��٥åȤ�`_'�ǻϤޤ�, ����ե��٥å�, ����, `_'��Ǥ�դ��¤Ӥϼ� +�̻ҤǤ���. ���̻Ҥ�Ĺ�������¤Ϥʤ�. + +** ͽ��� + +ͽ���ϰʲ����̤�Ǥ��� + + break, case, class, continue, def, do, else, + elsif, end, ensure, for, func, if, in, + include, module, nil, protect, redo, resque, retry, + return, self, super, then, undef, unless, until, + using, when, while, yield, __END__ + +ͽ���ϥ��饹̾, ��å�̾, �ѿ�̾�ʤɤ��Ѥ��뤳�ȤϤǤ��ʤ�. + +** ��ƥ�� + +�ʲ��Υ�ƥ�뤬���� + + ʸ�����ƥ�� + + "..." # �Хå�����å���β�ᤢ�� + '...' # �Хå�����å���β��ʤ�(\\��\'�ϲ�᤹��) + + �Хå�����å��嵭ˡ + + \t ����(0x09) + \n ����ʸ��(0x0a) + \r ����ʸ��(0x0d) + \f ���ڡ���ʸ��(0x0c) + \b �Хå����ڡ���(0x08) + \a �٥�(0x07) + \e ����������(0x1b) + \nnn 8�ʿ�ɽ��(n��0-7) + \xnn 16�ʿ�ɽ��(n��0-9,a-f) + \^c ����ȥ�����ʸ��(c��ASCIIʸ��) + \C-c ����ȥ�����ʸ��(Ʊ��) + \M-c �ʸ��(c|0x80) + + ����ɽ����ƥ�� + + /.../ + + ����ɽ�� + + ^ ��Ƭ + $ ���� + . Ǥ�դ�1ʸ�� + \w �ѿ���. [0-9A-Za-z_]��Ʊ�� + \W ��ѿ��� + \s ����ʸ��. [ \t\n\r\f]��Ʊ�� + \S �����ʸ�� + \d ����. [0-9] ��Ʊ�� + \D ����� + \b �춭��ʸ��(ʸ�����饹��) + \B ��춭��ʸ�� + \b ����(0x08)(ʸ�����饹��) + [ ] ʸ�����饹���� + * ľ����ɽ����0��ʾ�η����֤� + + ľ����ɽ����1��ʾ�η����֤� + {m,n} m��n��η����֤� + ? 0�ޤ���1�� + | ���� + ( ) ����ɽ����ޤȤ�� + + ����¾�˥Хå�����å��嵭ˡ��ͭ���Ǥ���. + + ���ͥ�ƥ�� + + 123 ���� + -123 ����(���Ĥ���) + 1_234 ����(10�ʿ���`_'��ޤळ�Ȥ��Ǥ���) + 123.45 ��ư�������� + 1.2e-3 ��ư�������� + 0xffff 16������ + 0377 8������ + ?a ʸ��`a'�Υ�����(97) + ?\C-a ����ȥ�����a�Υ�����(1) + ?\M-a �a�Υ�����(225) + ?\M-\C-a �-����ȥ�����a�Υ�����(129) + + ?ɽ���Ǥ����ƤΥХå�����å��嵭ˡ��ͭ���Ǥ���. + +** ���롼�ԥ� + +���ϳ�̤ˤ�äƥ��롼�ԥ��뤳�Ȥ��Ǥ���. ���˳����ˤϼ����¤Ӥ� +��. �����¤ӤҤ�����, ���ȼ��ζ��ڤ�ˤϲ��Ԥ� ';' ���Ѥ���. +�����¤Ӥ��ͤϺǸ��ɾ�����������ͤǤ���. �Ĥޤ� + + (��; ��; ...) + +���ͤϺǸ��ɾ�����������ͤˤʤ�. + +** ��ƥ�� + +��Ҥο���, ʸ����, ����ɽ���γƥ�ƥ��ϼ��Ǥ���. + +** ���� + +���ϰʲ��η����Ǥ���. + + [ ��, ... ] + +���줾��μ���ɾ��������̤�ޤ�������֤�. ���Ǥ�0��������������뤿 +��ˤ϶������� + + [] + +���Ѥ���. + +** Ϣ������ + +Ϣ������Ȥ�Ǥ�դΥ��֥������Ȥ�(ź��)�Ȥ��ƻ��Ƥ�����Ǥ���. Ruby +�Ǥ�Ϣ�������Smalltalk���Ѹ��ڤ��Dict(����)�Ȥ�ƤФ��. �ܺ٤ϥ� +�饹Dict�ι�Ȥ��줿��. Ϣ���������������Ϣ�����ϰʲ��η����� +����. + + { ��=>��, ... } + +���줾��μ���ɾ��������̤����ͤȤ���Ϣ�����֥������Ȥ��֤�. +���Ǥ�0��Ϣ��������������뤿��ˤ϶���Ϣ������ + + {} + +���Ѥ���. + +** �ѿ����� + +�ѿ��ˤ�4���ढ�ä�, ���μ�����ѿ�̾�κǽ�ΰ�ʸ���Ƿ��ꤵ���. ���� +����Ƥ��ʤ��ѿ��Ȥ��������ͤ�nil�Ǥ���. + + ���饹�ѿ�(���) + + `%'�ǻϤޤ��ѿ��ϥ��饹�ѿ��Ǥ���, ���Υ��饹�����ƤΥ��֥��饹�� + �������黲�ȤǤ���. �����ѿ��ؤ������ϥȥåץ�٥�, ���ʤ� + ����åɤ�����Ǥ����٥�ǤΤ߲�ǽ�Ǥ���. �����ѿ��ϥ��饹�֤� + �ͤ���ͭ����, ������������ȥ�åɤ�����ͤ��ѹ����뤳�Ȥ��Ǥ��� + ���Τ�,����Ȥ����Ѥ�����. + + �������ѿ� + + `@'�ǻϤޤ��ѿ��ϥ������ѿ��Ǥ���, ���Υ��饹�ޤ��ϥ��֥��� + ���Υ�åɤ��黲�ȤǤ���. ���μ�̿�ϥ��֥������Ȥμ�̿��������. + + �������Х��ѿ� + + `$'�ǻϤޤ��ѿ��Υ������פϥ������Х�Ǥ���, ���μ�̿�ϥץ������ + �μ�̿��������. + + ���饹̾/�⥸�塼��̾/���������ѿ� + + ����ե��٥åȤޤ���`_'�ǻϤޤ��ѿ��ϼ��̻ҤȤ�ƤФ�, ������ + ���ѿ�, ���饹̾�ޤ��ϥ⥸�塼��̾�Ǥ���. + + ������֤Ǥϼ��̻Ҥϥ��饹/�⥸�塼��̾�Ȥߤʤ���뤬(�������륯�� + ����¸�ߤ��ʤ������ͤ�nil), �������κ��դ˸��줿���̻Ҥ�,���Υ� + ��������Ǥϥ��������ѿ��Ȥ��Ƹ��ʤ���, Ʊ̾�Υ��饹��⥸�塼��� + �������. ���ΰ�̣�Ǽ��̻Ҥؤ�����������Ȥ��Ƥ�Ư�������. + + Array # ���饹 Array + Array = 15 # ����. �ʸ�Array�ϥ��������ѿ� + print(Array, "\n") # `15'�����Ϥ���� + + ��������ϥ���ѥ�����˲�ᤵ��뤿��, ���̻Ҥؤ����������ºݤ˼� + �Ԥ���Ƥ�, ����ʤ��Ƥ�, �ʹߤΥ���������ǤϤ��μ��̻Ҥϥ������� + �ѿ��Ȥߤʤ����. + + Array # ���饹 Array + if %FALSE + Array = 15 # ���Υ����ɤϼ¹Ԥ���ʤ���, + # �ʹ�Array�ϥ��������ѿ��Ȥߤʤ����. + end + print(Array, "\n") # `nil'�����Ϥ���� + + ���Υ롼��ϰ츫ʣ������, ���饹/�⥸�塼��̾�ȥ��������ѿ�̾���� + ʣ���ʤ��¤�, ̤������Υ��������ѿ����ͤ�nil�Ǥ���ȹͤ��Ƥ⺹�� + �٤��Ϥʤ�. + + Ruby���Ȥ߹��ߴؿ�����ʸ���Υ���ե��٥åȤǻϤޤ�̾�����Ĥ��Ƥ���, + �桼���⥯�饹/�⥸�塼��̾�ˤ���ʸ���ǻϤޤ뼱�̻Ҥ�, ���������� + ��̾�ˤϾ�ʸ���ޤ���`_'�ǻϤޤ뼱�̻Ҥ�Ȥ����Ȥ��侩����. + + ���������ѿ��μ�̿�Ϥ��Υ�åɤ���λ����ޤ�(�ȥåץ�٥�Υ��� + �����ѿ��ϥץ������ν�λ�ޤ�)�Ǥ���. + +���˵����ѿ��ȸƤФ���ü���ѿ��Ȥ���self��nil������. self�ϸ��ߤΥ� +���åɤμ¹Լ��Τ�ؤ������ѿ��Ǥ���, nil��Nil���饹��ͣ��Υ����� +��(����ɽ��)��ؤ������ѿ��Ǥ���. �����ε����ѿ��������ˤ�äƤ����� +���ѹ����뤳�ȤϤǤ��ʤ�. �������ѿ��ؤ��������㳰��ȯ��������. + +** ��å������� + +���֥������Ȥ˥�å��������������Ū�ʹ�ʸ����å��������Ǥ���, ���δ� +�ܷ����ϰʲ����̤�Ǥ���. + + ��1.��å�̾(����...) + + ��1��ɾ�����������륪�֥������Ȥ�, ���̻Ҥǻ��ꤵ����� + �ɤ�ƤӽФ�. ���ֺǸ�ΰ�����'*'��³��(ñ���)���Ǥ�����, + ���μ���ɾ���������(����Ǥ���ɬ�פ�����)��Ÿ������, �����Ȥ� + ���ɲä���. + + ��������Ĥ�ʤ����ˤϳ�̤��ά�Ǥ���. + +��å�̾�Ȥ��Ƥ�Ǥ�դμ��̻Ҥ��Ѥ��뤳�Ȥ��Ǥ���. �ѿ�̾�Ȥϼ��̻Ҥ� +̾�����֤��㤦�Τǽ�ʣ���Ƥ��ʤ�. + +** �ؿ����� + +��å���������, �쥷���Ф�self�ξ��, �쥷���Ф��ά���ƴؿ������ǥ�� +�ɤ�ƤӽФ����Ȥ��Ǥ���. ���ξ�������1�Ĥ�ʤ����Ǥ��̤ξ�ά�Ϥ� +���ʤ�. + +�ؿ������Ǥ�`@'�ǻϤޤ�̾������ĥ�åɤ�ƤӽФ����Ȥ��Ǥ���. `@'�� +�Ϥޤ��åɤϴؿ������Ǥ����ƤӽФ����Ȥ��Ǥ��ʤ�����, �������륯�� +���ޤ���, ���Υ��֥��饹���餷���ƤФ�ʤ��Τ�, �ץ饤�١��ȥ�åɤ� +�ƤФ��. �ץ饤�١��ȥ�åɤ�C++�ˤ�����protected member function�� +��������. + +** �����ѡ����饹�Υ�åɸƤӽФ� + +��å����������ü�ʥ������Ȥ��ƥ����ѡ����饹�Υ�åɤθƤӽФ����� +��. ���η����ϥ�åɤ������������˥����ѡ����饹����������Ѥ��뤿 +��˻Ȥ�. + + super + + ���ߤΥ�åɤ�Ϳ����줿�����Τޤޥ����ѥ��饹��Ʊ̾�Υ�� + �ɤ�ƤӽФ�. + + super(����...) + + �����ȤȤ�˥����ѡ����饹��Ʊ̾�Υ�åɤ�ƤӽФ�. ���ֺǸ� + �ΰ�����`*'��³�������̾�Υ�åɸƤӽФ���Ʊ��. + +** �黻�� + +�ץ�����ߥ����ؤΤ���˰����Υ�åɸƤӽФ������湽¤�ϱ黻�ҷ� +����Ȥ�. Ruby�ˤϰʲ��ˤ�����黻�Ҥ�����. ��Τ�Τۤɷ���̤�����, +Ʊ����α黻�Ҥη���̤�Ʊ���Ǥ���. + + �� -(unary) +(unary) ! ~ + ** + * / % + + - + << >> + > >= < <= + <=> == != =~ !~ + & + | ^ + && + || + .. ... + :: + =(����) ��������(+=, -=, ..) + �� yield + +�ۤȤ�ɤα黻���ˤϥ�åɸƤӽФ��Ȥ��Ʋ�ᤵ���(���饹��˺���� +�Ǥ���)��, ����������Ǥ��ʤ��ü�ʤ�Τ�����. ������Ǥ��ʤ��ü�黻 +�Ҥ� + + &&(������), ||(������), =(����), ...(�ϰϻ���), + yield(�֥��å��ƤӽФ�) + +��5�ĤǤ���. + +��Ǥ������ü�黻�Ұʳ��α黻�ҷ����ϥ�åɸƤӽФ��ȸ��ʤ����. +ñ��黻��(+, -, !, ~)�� + + ��1."�黻��"() + +�Ȥ���������, 2��黻�Ҥ� + + ��1."�黻��"(��2) + +�Ȳ�ᤵ���. ¿��黻��(����λ��Ȥ�[])�ϱ黻�ҷ��������̤ʷ��Ȥ��� + + recv[arg..] + +��, + + recv."[]"(arg..) + +�Ȳ�ᤵ���. �������Ǥ�������Ʊ�ͤǤ���. + +** ��P + +if, unless, while, until�ξ��Ƚ�����μ�, ������ü�黻��`&&', `||', +`...'��ξ�դμ�, �̾�黻��`!'�α��դϾ�P�ȸƤФ��. ��P�Ǥ�ʸ�� +�������ɽ����ƥ��ϼ���$_=~��ƥ��פξ�ά�Ǥ���Ȥߤʤ����. ���� +�黻��`...'��ξ�դǤ�������ƥ�뤬��$.==��ƥ��פξ�ά�Ȳ�ᤵ���. + +����: �黻��`!'���ü�黻�ҤǤϤʤ��Τ�, �������Ԥʤ����˵���Ĥ� +�뤳��. + + ! ʸ�����ƥ�� + ! ����ɽ����ƥ�� + +�η��ǸƤӽФ�����åɤΰ�����, ��ƥ���ɽ�����֥������ȤǤϤʤ�. +`!'��åɤϺ�������ʤ������ɤ��Ȼפ�. + +** ���� + +�����ˤ��ѿ����Ф�������(��������)��, �ץ��������ñ�ˤ��뤿��Υ��� +���å������奬���Ȥ��Ƥ�����������. ���������ϰʲ��η����Ǥ���. + + �ѿ� = �� + +����ϼ���ɾ����, �ѿ����ͤȤ�����������. ���饹��⥸�塼��䵿���ѿ� +�ˤ������Ǥ��ʤ�. ���饹��⥸�塼���������ѹ����뤿��ˤ�classʸ, +moduleʸ���Ѥ���. �������ϱ黻�ҷ�����ȤäƤ��뤬, ��åɤǤϤʤ��� +�Ǻ�������뤳�ȤϤǤ��ʤ�. + +���å������奬���Ȥ��Ƥ��������ϰʲ��Τ�Τ�����. + + �������Ǥؤ����� + + ��1[��2,..] = ��n + + ��1��ɾ�����������륪�֥������Ȥ�, ��2���鼰n�ޤǤ�����Ȥ� + ��, "[]="�Ȥ�����åɤ�ƤӽФ�. + + °������ + + ��1.���̻� = ��2 + + ��1��ɾ�����������륪�֥������Ȥ��Ф���"���̻�="�Ȥ������ + �ɤ�, ��2������Ȥ��ƸƤӽФ�. + + �������� + + ��1 op= ��2 # ��1��������ǽ�Ǥʤ���Фʤ�ʤ�. + + ���η���������Ū�ˡּ�1 = ��1 op ��2�פ�Ÿ������, �¹Ԥ����. ���� + ���������ϥץ�����ޤΥ������餹��Ū�Τ����¸�ߤ�������Ǥ� + ��. op�Ȥ��ƻȤ���黻�Ҥ� + + +, -, *, /, %, **, &, |, ^, <<, >> + + ��11����Ǥ���. �黻�Ҥ�`='�δ֤˥��ڡ���������ƤϤ����ʤ�. + +*** ¿������ + +Ʊ����ʣ�����ѿ���������Ԥʤ����Ȥ��Ǥ���. ���η����ϰʲ����̤�Ǥ���. + + �ѿ�, [�ѿ�,...] = �� [, ��] + +���դμ�����Ĥ����ʤ�, ����, �����ͤ�����Ǥ�����ˤ���������Ǥ����� +�����ѿ������������. ����ʳ��ξ��ˤ�, ���줾��μ����ͤ��ѿ������� +�����. ���դ��ѿ��ο��ȱ��դ����Ǥο������ʤ����ˤ���ʤ��ѿ��ˤ� +nil����������, ;�ä����Ǥ�̵�뤵���. + + foo, bar = [1, 2] # foo = 1; bar = 2 + foo, bar = 1, 2 # foo = 1; bar = 2 + foo, bar = 1 # foo = 1; bar = nil + + foo, bar, baz = 1, 2 # foo = 1; bar = 2; baz = nil + foo, bar = 1, 2, 3 # foo = 1; bar = 2 + +** ���ʬ�� + + if ��1 [then] + ʸ1 + [ elsif ��2 [then] + ʸ2 ]... + [ else + ʸn ] + end [ if ] + + ���Ƚ��ʸ. else if �Ǥ�elif�Ǥ�ʤ�elsif��if��Ϣ³��Ԥʤ����Ȥ� + ���դ��뤳��. + + unless ��1 [then] + ʸ1 + [ else + ʸ2 ] + end [ unless ] + + ��1����(nil)���֤���, ��2��ɾ������㳰��ȯ����������ʸ1��ɾ�� + ����. + + ��1 && ��2 + + ��1��ɾ����, �����ͤ���(nil�ʳ�)�Ǥ����, ��2��ɾ������. + + ��1 || ��2 + + ��1��ɾ����, �����ͤ����Ǥ����, ��2��ɾ������. + + ��1 ... ��2 + + ��1�����ˤʤ�ޤǤϵ����֤�, ���θ�ϼ�2�������֤��ޤǤϿ����֤�. + ��2�����ˤʤ�о��֤ϵ������ + + case ��0 + [ when ��1 [, ��2]... + ʸ1 ]... + [ else + ʸn ] + end [ case ] + + ���ʬ��, C��switch����Pascal��case�˻��Ƥ���. break��æ�Ф��뤳 + �Ȥ�����ʸ�˷�³���뤳�Ȥ�ʤ��Τ�����. + + ���ΰ��פϡּ�n =~ ��0]�ǹԤʤ���. �Ĥޤ�, + + case expr0 + when expr1, expr2 + stmt1 + when expr3, expr4 + stmt2 + else + stmt3 + end + + �ϰʲ���ifʸ�������Ǥ���. + + _tmp = expr0 + if expr1 =~ _tmp || expr2 =~ _tmp + stmt1 + elsif expr3 =~ _tmp || expr4 =~ _tmp + stmt2 + else + stmt3 + end + +** �����֤� + + while �� + ʸ + end [ while ] + + ��郎���δ�, ʸ���֤��¹Ԥ���. + + until �� + ʸ + end [ until ] + ��1 until ��2 + + ������(nil)���֤���, ����ɾ������㳰��ȯ�������, ʸ���֤��� + �Ԥ���. + +** ���ƥ졼�� + +���ƥ졼���Ȥ����湽¤(�ä˥롼��)����ݲ��Τ�����Ѥ������åɤ� +���Ǥ���. ���ƥ졼���θƤӽФ��ϰʲ��ι�ʸ�ǹԤʤ���. + + do + ʸ1 + using �ѿ� + ʸ2 + end [ do ] + + ��ʸ2�פ�֥��å��Ȥ������ꤷ, ʸ1�Υ�åɤƥ졼���Ȥ���ɾ�� + ����. ʸ1�Υȥåץ�٥�Υ�åɤ��������ƥ졼���Ȥ��ƸƤӽФ���, + �쥷���Ф�ɽ������, �����μ��ϥ��ƥ졼���Ȥ��ƤϸƤӽФ���ʤ�. ʸ + 1��ʣ���μ�������гơ������ƥ졼���Ȥ��ƽ�˸ƤФ��. + +���ƥ졼�����yield value���¹Ԥ�����, �����ͤ�doʸ�ǻ��ꤵ�줿�ѿ� +����������֥��å����¹Ԥ����. �֥��å��μ¹Ԥ���λ����Ȥ����ͤ� +yield�����ͤȤ����֤����. �����åɤ����ƥ졼���Ȥ��ƸƤӽФ��줿 +���ɤ����ϴؿ�iterator_p()���Τ뤳�Ȥ��Ǥ���. ��ˤ�Enumerable�⥸�塼 +���grep��åɤΤ褦�˥��ƥ졼���Ȥ��ƸƤФ줿�������̤Υ�åɤȤ� +�ƸƤФ줿���Ȥ�ư��ۤʤ��åɤ⤢��. + + for �ѿ� in �� + ʸ + end [ for ] + + ���γ����Ǥ��Ф�ʸ��¹Ԥ���. ����ϰʲ���doʸ�������Ǥ���. + + do (��).each using �ѿ� + ʸ + end + + ��äƼ����ͤΥ��֥������Ȥ���å�each������ʤ����, for��¹� + ������㳰��ȯ������. + +** �㳰���� + +�������ͽ�����ʤ����֤�ȯ���������ˤ��㳰��ȯ������. Ruby�Ǥ��㳰���� +�����ª����, �ƻ�Ԥ�����, �������Ԥʤä��ꤹ�뤳�Ȥ��Ǥ���. + + protect + ʸ1 + [ resque + ʸ2 ] + [ ensure + ʸ3 ] + end [ protect ] + + ʸ1��¹Ԥ�, ���μ¹�����㳰��ȯ�������resque��ǻ��ꤵ�줿ʸ2�� + �¹Ԥ���. ����ensure�¸�ߤ������protectʸ��λ��������ɬ��(�� + �ェλ�������Ǥʤ�, �㳰, return, break, continue, redo�ʤɤˤ�� + æ�ФǤ�)ʸ3��¹Ԥ���. + +protect�ʳ���, unless�黻��, until�黻�Ҥϱ��դ��ͤ��������㳰��ȯ +���������, ���դ��ͤȤ��Ƶ���Ϳ����줿�ȸ��ʤ��Τ�, ���ۤ��㳰������ +�ԤʤäƤ��뤳�Ȥˤʤ�. + +** ���æ�� + + return [��] + + ��åɤμ¹Ԥ�λ����. + + continue + redo + break + + �嵭3�Ĥϥ롼����ǻȤ�. + + continue�Ϥ�äȤ���¦�Υ롼�פμ��η����֤���Ϥ��. redo�ϥ롼�� + �Υ롼���Υ����å���Ԥʤ鷺, ���ߤη����֤�����ľ��. break + �ϥ롼�פ�æ�Ф���. C�Ȱ㤤, break�Ϥ�äȤ���¦�Υ롼�פ�æ�Ф��� + ���Ѥ��������, case��ȴ������Ѥϻ����ʤ�. + + retry + + protectʸ��resque��ǻȤ�, protectʸ��Ϥᤫ��¹Ԥ���. �㳰������ + �ԤʤäƤ���ƻ�Ԥ���Τ˻Ȥ�. + + fail([��å�����]) * �����Kernel���饹�Υ�åɤǤ���. + + �㳰��ȯ��������. ��å�������Ϳ����줿���ˤ�ȯ�������������ե� + ����̾, ���ֹ��$@�˥�å�������$!�˥��åȤ���. + +** ���ƥ졼������ǤΥ֥��å��ƤӽФ� + + yield �� + + ���ƥ졼������ǥ֥��å��θƤӽФ���Ԥʤ�. yield��¹Ԥ������ + �ɤ����ƥ졼���Ȥ��ƸƤӽФ���Ƥ��ʤ����ˤ��㳰��ȯ������. + +** ���饹��� + +���饹��������빽ʸ�ϰʲ����̤�Ǥ���. + + class ���饹̾ [ : �����ѡ����饹̾ ] + ������� + end [ class ] + +�ͤ�nil. ���饹̾����ʸ���ǻϤޤ뼱�̻ҤǤ���. ���饹����Υͥ��ȤϤ� +���ʤ��Τ�¾�����ʸ��Ǥϥ��饹������Ǥ��ʤ�. + +** �⥸�塼����� + +�⥸�塼���������빽ʸ�ϰʲ����̤�Ǥ���. + + module ���饹̾ + ������� + end [ module ] + +�⥸�塼��̾����ʸ���ǻϤޤ뼱�̻ҤǤ���. ���饹Ʊ��, �⥸�塼������� +�ͥ��ȤǤ��ʤ�. + +** ���롼�� + +���饹�˥⥸�塼��롼�ɤ��빽ʸ�ϰʲ����̤�Ǥ���. + + include �⥸�塼��̾ [, �⥸�塼��̾...] + +���ߤ������Υ��饹�ޤ��ϥ⥸�塼��(�ȥåץ�٥�Ǥ�Object)�˻��ꤷ�� +�⥸�塼��롼�ɤ���. ����ˤ�ä�¿�ŷѾ��ߥ�졼�ȤǤ���. + +** ��å���� + +�̾�(�ðۥ�åɤǤʤ�)��å�����η����ϰʲ����̤�Ǥ���. �̾��� +������ϥͥ��ȤǤ��ʤ��Τ�, ��å����ʸ��Ǥϥ�å����ʸ��ƤӸ� +�ӽФ��ʤ�. + + def [func] ��å�̾ [ ( ���� [, ����...][, *���� ] ) ] + ������� + end [ def ] + +��å�̾�ϼ��̻Ҥޤ���ʸ����Ǥ���. �黻�Ҥκ��������ˤ�ʸ���� +�ǻ��ꤹ��. �������¤ӤκǸ��`*'��������, ���������¿��Ϳ����줿 +�°�����, �Ǹ�ΰ���������Ȥ���Ϳ������(��ʤ����ˤϥ��顼). + +�������`func'�����ꤵ�줿���ˤϤ��Υ�åɤϴؿ������Ǥ����ƤӽФ� +���Ȥ��Ǥ���ؿ�Ū��åɤˤʤ�. + +** �ðۥ�å���� + +��å�����ˤϤ⤦����ðۥ�åɤ����������. �����ϰʲ����̤�Ǥ� +��. + + def ��.��å�̾ [ ( ���� [, ����...][, *���� ] ) ] + ������� + end [ def ] + +���η����ϼ����ͤǤ��륪�֥������Ȥ��ðۥ�åɤ��������. �����ͤ� +(�ӥ�ȥ��饹�Ǥʤ�)�̾索�֥������Ȥ�, ���饹�ޤ��ϥ⥸�塼��Ǥ� +��ɬ�פ�����. �̾��å�����Ȥϰۤʤ�, ������ϥ�å�������Ǥ�� +���Ȥ��ƸƤӽФ����Ȥ��Ǥ���. + +�ðۥ�åɤ�����Υ��֥������Ȥˤ���°�����åɤǤ���. ��ä��̾� +�ϷѾ������ʤ���, �㳰�Ȥ��ƥ��饹���ðۥ�åɤϤ��Υ��֥��饹�ˤ�� +�������. �����ؤ���Х��饹���ðۥ�åɤ�¾�Υ��֥������Ȼظ������� +��ˤ����륯�饹��åɤ�Ư����. + +** ��åɤ���̾��� + +�ʲ��η����ǥ�åɤ���̾��Ĥ��뤳�Ȥ��Ǥ���. + + def ��å�̾1 ��å�̾2 + +��̾���դ���줿��åɤ�, ���λ����ǤΥ�å����������Ѥ�, ���Υ� +���åɤ����������Ƥ�, �Ť���åɤ��ƤӽФ��줿�Τ�����Ʊ��Ư���� +��. + +** ��å�������ä� + +��åɤ��������ä�����ˤ�undef���Ѥ���. + + undef ��å�̾ + +���̻Ҥޤ���ʸ����ǻ��ꤷ����åɤ��������ä�. + +def�ˤ����̾�����undef�ˤ��������ä���Ȥ��ȥ��饹�Υ��ե��� +�����ѥ��饹����Ω���ѹ����뤳�Ȥ��Ǥ���. ������, ��ʬ���Ȥ˥�å��� +�������äƤ���������դ��ʤ��ȴ�¸�Υ�åɤ�ư��ʤ��ʤ��ǽ���� +����. + +* Ruby���Ȥ߹��ߵ�ǽ + +Ruby�ץ�����ߥδ��ܤϥ��饹, �⥸�塼��Ȥ��Υ�åɤν����Ǥ���. +Ruby�ˤϽ����Ϥ��Τ�Τ˰ʲ��ε�ǽ���Ȥ߹��ޤ�Ƥ���. �饤�֥������ +�ɤ��뤳�Ȥˤ�äƵ�ǽ�������뤬, �����˴ؤ��ƤϤ��줾��Υ饤�֥�� +�Υɥ�����ȤȤ��Ƥ�餤����. + +��ü��`+'����ΤĤ�����åɤϴؿ���åɤǤ���. + +** �ؿ� + +Ruby�ˤϸ�̩�ʰ�̣�Ǥϴؿ��Ϥʤ���Kernel���饹�Υ�åɤΰ�����(���� +�饹����ؿ������ǸƤӽФ���Τ�), �ؿ�Ū���Ѥ�����. �ؿ�Ū���Ѥ��� +����åɤ�ʲ��ˤ�����. �����Υ�åɤ���������ݤˤϸߴ����� +�ͤ��ƹԤʤ��٤��Ǥ���. + + _exit(status) + + + �ץ������μ¹Ԥ�λ����. ����status��λ���ơ������Ȥ���. + exit()�Ȥϰ�ä�, �㳰�����ʤɤϰ��ڹԤʤ�ʤ�. fork()�θ�, �� + �ץ�������λ��������ʤɤ��Ѥ���. + + caller + + caller(level) + + + �����å��ե졼�फ����������, ��åɤθƤӽФ����Υե����� + ̾, ���ֹ�, ���������ǤȤ���������֤�. level��Ϳ����줿��� + �ϸ��ߤΥ����å��ե졼����level�ʾ�ξ�����֤�. + + eof() + + + ���ޥ�ɥ饤������Ϥ�EOF����ã���Ƥ�����, �����֤�. + + eval(expr) + + + expr�Ȥ���Ϳ����줿ʸ�����ruby�ץ������Ȥ��Ʋ��,�¹Ԥ���. + + exec(command) + + + ���¹Ԥ��Ƥ���ץ�������λ����, commandʸ����ǻ��ꤵ��� + �̥ץ�������ư����. + + exit([status]) + + + �ץ������μ¹Ԥ�λ����. status�Ȥ���������Ϳ����줿���, + �����ͤ�Ruby���ޥ�ɤν�λ���ơ������Ȥ���. �ǥե���Ȥ�0. + + fail([message]) + + + �㳰��ȯ��������. ��å�������Ϳ����줿���ˤϤ�����ƥ� + �ѿ�`$!'�˥��åȤ�, ȯ���������֤��ƥ��ѿ�`$@'�˥��åȤ���. + + fork() + + + fork�����ƥॳ�����¹Ԥ�, �ҥץ���������������. �ܺ٤� + fork(2)�ȤΤ���. �ƥץ�����¦�Ǥϻҥץ������Υץ�����id�� + �֤�, �ҥץ�����¦�Ǥ�nil���֤�. ���餫�θ����ǻҥץ��������� + ���˼��Ԥ������ˤ��㳰��ȯ������. + + format(format, ...) + + + �ե����ޥåȤȤ���Ϳ����줿ʸ�����C�����sprintf��Ʊ���褦�� + ��ᤷ, ������Ÿ������ʸ������֤�. ��å�sprintf()����̾. + + Ruby�ˤ�����format����Ҥγ�ĥ�ˤĤ��Ƥ�sprintf()�ι�Ȥ� + ����. + + getc() + + + ɸ�����Ϥ����ʸ�����Ф�. ����ͤ��ɤ߹����ʸ����ʸ�������� + (ASCII)��ɽ��Fixnum�Ǥ���. + + getenv(name) + + + name�˳�������Ķ��ѿ�����Ф�. + + gets(pattern, replace) + + + �����Ȥ���Ϳ����줿�ե�����(�ʤ����ɸ������)�������ɤ߹��� + ��, �ɤ߹��ߤ������������ˤϤ���ʸ������֤�. �ե�����ν���� + ��ã�������ˤ�nil���֤�. �Ԥζ��ڤ�ϥ����ƥ��ѿ�`$/'�ˤ�ä� + �ѹ��Ǥ���. �ɤ߹����ʸ����ϥ����ƥ��ѿ�`$_'�ˤ⥻�åȤ����. + + gsub() + + + �����ƥ��ѿ�`$_'�λؤ�ʸ������Ф����ִ���Ԥʤ�. ʸ������� + pattern�˥ޥå�������ʬ������replace���֤�������. String���饹 + ��gsub��åɤβ���ȤΤ���. + + iterator_p() + + + ��åɤ����ƥ졼���Ȥ��ƸƤӽФ��줿���˿�, �����Ǥʤ����˵� + ���֤��Ҹ�. + + kill(signal, pid...) + + + pid�ǻ��ꤵ�줿�ץ������˥����ʥ������. �����ʥ�ϥ����ʥ��� + �椫̾���ǻ��ꤹ��. ����ͤ���ĥ����ʥ�(���뤤�ϥ����ʥ�̾�� + ����`-')��Ϳ����ȥץ������ǤϤʤ��ץ��������롼�פ˥����ʥ�� + ����. + + load(file) + + + file������ɤ���. file������ɤ���ѥ��ϥ����ƥ��ѿ�$LOAD_PATH + �Ƿ��ꤵ���. + + open(file[, mode]) + + + file���ץ�, File���֥������Ȥ��֤�. �ե�����̾�ϥ����� + ��ե������. �ե�����̾��`|'�ǻϤޤ���ˤ�³��ʸ���� + �ޥ�ɤȤ��Ƶ�ư��, �ѥ��ץ饤�����������. + + ���ޥ��̾��"-"�Ǥ����, open()��Ruby�λҥץ�������������, �� + �λҥץ������ȤΥѥ��פ��֤�. + + mode�ϥե�����Υ��������⡼�ɤ���ꤹ��. ����ϰʲ��Τ����Τ� + ���줫��ʸ����Ǥ���. + + r �ɤ߹�������. open����ե�����Ϥ��餫����¸�ߤ��Ƥ��� + ɬ�פ�����. + + r+ �ɤ߽�ξ��. open����ե�����Ϥ��餫����¸�ߤ��Ƥ��� + ɬ�פ�����. + + w ��������. �ե����뤬¸�ߤ��Ƥ������, Ĺ����0�ˤ� + ��. ¸�ߤ��Ƥ��ʤ���п����˥ե�������������. + + w+ �ɤ߽�ξ��. �ɤ߹��ߤ��Ԥʤ��뤳�Ȱʳ���"w"��Ʊ��Ư�� + ��. + + a �ɲý�������. �ե�����Ϥ��餫����¸�ߤ��Ƥ���ɬ�� + ������. ���ߤϥե�����κǸ���ɲä����. + + a+ �ɤ߽�ξ��. �ե����뤬¸�ߤ��Ƥ��ʤ���п����˺����� + ��. �����������֤ϥե�����κǸ�˽���������. + + �⡼�ɤ���ά���줿���Υǥե���Ȥ�"r"�Ǥ���. + + print(arg1, ..., argn) + + �������˽��Ϥ���. ������Ϳ�����ʤ����ˤϥ쥷���Ф���Ϥ���. + ʸ����ʳ��Υ��֥������Ȥ������Ȥ���Ϳ����줿���ˤ�, ������ + �֥������Ȥ�to_s��åɤˤ�ä�ʸ������Ѵ����Ƥ�����Ϥ����. + �����ƥ��ѿ�`$;'(���ϥե�����ɥ��ѥ졼��)��nil�Ǥʤ��ͤ����� + �Ȥ���Ƥ�����ˤ�, �ư����δ֤ˤ���ʸ�������Ϥ���. �����ƥ� + �ѿ�`$\'(���ϥե�����ɥ��ѥ졼��)��nil �Ǥʤ��ͤ����åȤ���� + ������ˤ�, �Ǹ�ˤ������Ϥ���. + + printf([port, ]format, arg1, ..., argn) + + + C�����printf()��Ʊ��format�˽���������ʸ������Ѵ���, ���Ϥ� + ��. ��1������IO�Υ��֥��饹�Υ����Ǥ��ä����Ϥ��Υ� + �֥������Ȥ��Ф��ƽ��Ϥ�Ԥʤ�. �ǥե���Ȥ�$stdout�˽��Ϥ���. + + Ruby�ˤ�����format����Ҥγ�ĥ�ˤĤ��Ƥ�sprintf()�ι�Ȥ� + ����. + + rand(max) + + + 0����max��ۤ��ʤ��ϰϤ������������ȯ������. ����ͤ�Fixnum. + + require(file) + + file������ɤ���. load�Ȥ�ư��ΰ㤤��require�ϥ����ɤ����ե� + ����Υե�ѥ����ѿ�$LOAD_FILES�˳Ф��Ƥ���, ���˥����ɤ����ե� + ����Ϻƥ����ɤ��ʤ����Ǥ���. �ºݤ˥����ɤ������ˤ�%TRUE, �� + �˥����ɤ���Ƥ�����ˤ�%FALSE���֤�. + + select(reads[, writes[, execpts[, timeout]]]) + + + select(2)��¹Ԥ���. reads/writes/execpts�ˤ�IO(�ޤ��Ϥ��Υ��� + ���饹)�Υ����������Ϳ����. timeout��Fixnum / Float + / Time�Τ����줫�ǻ��ꤹ��. ����ͤ�timeout����Ω�������ˤ� + nil, �����Ǥʤ��Ȥ���3���Ǥ�������֤�, ���γ����Ǥ�����/����/ + �㳰�Ԥ��Υ��֥������Ȥ����ǤȤ��ƻ���. + + setenv(name, value) + + + name�ǻ��ꤵ���Ķ��ѿ���value�˥��åȤ���. + + sleep([sec]) + + + sec�ä����ץ������μ¹Ԥ���ߤ���. sec����ά���줿���, �ץ� + ������SIGALRM�������ʤ��¤�, �ʵפ˥���פ���. �ºݤ˥�� + �פ����ÿ����֤�. + + sprintf(format, ...) + + + formatʸ�����C�����sprintf��Ʊ���褦�˲�ᤷ, ������Ÿ������ + ʸ������֤�. ��å�format()����̾. + + + format����Ҥ�C�����sprintf()�������դ�����(������, Ruby�� + �� unsigned���ʤ��Τ�, %u�Ͻ���)�˲ä���, %b, %B, %O, %X��Ȥ� + ���Ȥ��Ǥ���. %b�Ͽ��ͤ�2��ɽ��, %B, %O, %X��, ���줾��, 2��, + 8 ��, 16�ʿ���ɽ����Ԥʤ���, ��ο��ν����κݤ�2�����ɽ���� + �Ϥʤ�, ����������ɽ������Ƭ��`-'��Ĥ�����Τ�ɽ������. + + srand([�����]) + + + ����ν���ͤ����ꤷ, �Ť�����ͤ��֤�. ����ͤ���ά���줿���� + ��time(3)���֤��ͤ�ǥե���ȤȤ���. + + sub() + + + �����ƥ��ѿ�`$_'�λؤ�ʸ������Ф����ִ���Ԥʤ�. ʸ������Ǻ� + ���pattern�˥ޥå�������ʬ��replace���֤�������. String���饹 + ��sub��åɤβ���ȤΤ���. + + system(command) + + + ���ޥ�ɤ�¹Ԥ�, ���ν�λ���ơ��������֤�. + + system2(command) + + + ���ޥ�ɤ�¹Ԥ�, ���ν��Ϥ�ʸ����Ȥ����֤�. + + trap(command, signal...) + + + signal�γ����ߤ������ä�����command��¹Ԥ���. signal�ϥ��� + �ʥ�̾�������ʥ���ֹ�. command�Ȥ���SIG_IGN�ޤ���IGNORE����� + �������ˤϤ��Υ����ʥ��̵�뤹��(��ǽ�ʤ��). SIG_DFL�ޤ��� + DEFAULT����ꤷ�����ϥǥե���Ȥ�ư���Ԥʤ�. + + wait() + + + �ҥץ���������λ����Τ��Ԥ�, ��λ�����ҥץ�������pid���֤�. + �ҥץ���������Ĥ�ʤ����nil���֤�. + + waitpid(pid, flags) + + + ����λҥץ������ν�λ���Ԥ�, ���Υץ���������λ�������˿����� + ��. �ҥץ�������¸�ߤ��ʤ���, �Υ�֥��å��⡼�ɤǻҥץ��� + �����ޤ���λ���Ƥ��ʤ����ˤ�nil���֤�. waitpid(2)��wait4(2)�� + ��������Ƥ��ʤ��ޥ���Ǥ�flags�Ϥ��Ĥ�nil�ޤ���0�Ǥʤ���Ф� + ��ʤ�. + +** �����ƥ��ѿ� + + $! ���顼��å�����. fail()�����ꤹ��. + + $@ ���顼��ȯ�����������Υե�����̾�ȹ��ֹ椬 + + "�ե�����:���ֹ�[:��å�̾(�����)]" + + �η����dz�Ǽ�����. + + $& �Ǹ�����������ѥ�����ޥå� + + $1..$9 �Ǹ�����������ѥ�����ޥå���n���ܤγ�̤˥ޥå����� + �ͤ���Ǽ�����. ���������̤��ʤ����nil�����äƤ���. + + $~ �Ǹ�Υޥå��˴ؤ������. ����åȤ����$&��$1..$9 + ���ͤ��Ѳ�����. + + $= �����ѿ����ͤ�nil�Ǥʤ���, �ѥ�����ޥå���ʸ������� + �Ӥǥ���ե��٥åȤ���ʸ����ʸ������̤��ʤ�. �ǥե��� + �Ȥ�nil(���̤���). + + $/ ���ϥ쥳���ɥ��ѥ졼��. �ե������ʸ������Ф���each�� + �Ԥʤ�����ʬ��ʸ������ꤹ��. $/�˶�ʸ����("")����ꤹ + �������ñ�̤����Ϥ�Ԥʤ�, nil����ꤹ������Τ���� + ���ɤ߹���. $/�ˤ�����ɽ���ϻȤ��ʤ�. �ǥե���Ȥ� + "\n". + + $\ ���ϥ쥳���ɥ��ѥ졼��. �����ѿ���ʸ�������ꤹ��� + write()��print()���٤˺Ǹ�ˤ���ʸ������ղä��ƽ��Ϥ� + ��. �ǥե���Ȥ�nil(�ʤˤ��ɲä��ʤ�). + + $, Array:join()�Υǥե���Ȥζ��ڤ�ʸ����. print()�γư� + ���δ֤˽��Ϥ����ʸ����. + + $; String:split()�Υǥե���Ȥζ��ڤ�ʸ��. + + $. �Ǹ���ɤ�����ϥե�����ι��ֹ�. + + $_ �Ǹ��gets()�ʤɤ��ɤ߹����ʸ����. + + $0 ruby������ץȤ�̾�� + + $* ruby������ץȤ�Ϳ����줿����. ruby���Ȥ��Ф�������� + ��������Ƥ���. + + $$ ���¹����ruby�ץ�������pid. + + $? �Ǹ�˼¹Ԥ����ҥץ�������status. + + $ARGV $*��Ʊ��. + + $ENV �Ķ��ѿ��˥�����������Ϣ������(EnvDict). �����ѿ����� + ���� `for'��Ԥʤ����ѿ�̾���ͤΥڥ���Ϳ����. + + $FILENAME �ؿ�gets()�Ǹ����ɤ߹�����Υե�����̾. + + $DEBUG `-d'�ե饰�ξ���(������) + + $LOAD_PATH �ե����������ɤ�����˸�������ǥ��쥯�ȥ�ؤΥѥ��� + �ޤ�����. ��ư���ˤϥǥե������(����ѥ�����˻��ꤹ + ��)�˲ä���, �Ķ��ѿ�RUBYLIB���ͤ�ruby��ư����-I���ץ��� + ��ǻ��ꤵ�줿�ͤ��ɲä����. + + $stdin ɸ������ + $stdout ɸ����� + $stderr ɸ�२�顼���� + + $VERBOSE `-v'�ե饰�ξ���(������) + + $VERSION ruby�ΥС�������ʸ���� + +** �����ƥ���� + + %TRUE 1(Fixnum) + %FALSE nil + + ���줾�쿿���ͤ�ɽ��. ���Ƚ�Ǥ�nil��, ����ʳ������Ƥ��ͤ� + ���Ȥ���Ƚ�Ǥ��뤿��, �����ͤ��֤���åɤ�%TRUE�ʳ����ͤ��� + ����Τ�¸�ߤ���Τ�, ��Ӥ��Ѥ���Τ�Ŭ�ڤǤʤ����Ȥ����դ��� + ���Ǥ���. �㤨�м��μ��Ͽ��ˤʤ�ʤ�. + + (2 < 3) == %TRUE + + ��å�"<"�Ͽ��λ������ͤ��֤��Τ�, ���ξ����ͤ�3�Ǥ���, �� + ��%TRUE����1�Ȥϰۤʤ�. %FALSE�˴ؤ��Ƥ�, ���Τ褦����������� + �ʤ�. + +** ���饹/�⥸�塼�� + +*** Array(���饹) + +������ź���Ȥ�������Υ��饹�Ǥ���. �����ϰ���Ū�ˤ�����``[...]''�� +�Ԥʤ���. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self[nth] + self[start..end] + self[start, length] + + ��������Ǥ˥�����������. �ǽ�η����Ǥ������nth���ܤ����Ǥ� + �֤�, 2���ܤη����Ǥ�start���ܤ����Ǥ���end���ܤ����Ǥ�ޤ��� + ʬ������֤�. 3���ܤη����Ǥ�start���ܤ���length�Ĥ����Ǥ�ޤ� + ��ʬ������֤�. + + self[nth] = val + self[start..end] = val + self[start, length] = val + + ��������Ǥ��ѹ�����. �ǽ�η����Ǥ������nth���ܤ����Ǥ�val�� + �ѹ�����. 2���ܤη�����start���ܤ����Ǥ���end���ܤ����ǤޤǤ� + val���ѹ�����. 3���ܤη����Ǥ�start���ܤ���length�Ĥ����Ǥ�val + ���ѹ�����. + + 2����, 3���ܤη����Ǥ�val������Ǥʤ���Фʤ�ʤ�. + + ��: + + ary = [1, 2, 3, 4, 5] + ary[0..2] = [0, 0] # ��������Ƥ� [0, 0, 4, 5] + ary[1, 0] = [7] # ��������Ƥ� [0, 7, 0, 6, 5] + + self + other + + �����Ϣ��. self��other��ξ������������Ƥ�Ҥ�������������� + �֤�. + + self * times + + ����η����֤�. + + self << obj + + obj��������������ɲä���. self���֤��Τ�C++Ū��Ϣ���Ǥ���. + + assoc(key) + + Ϣ�ۥꥹ��(2���Ǥ���������ǤȤ�������)����, ��1���Ǥ�key + ��������("=="����Ӥ���)������֤�. + + clear + + ������礭����0�ˤ���. + + delete(item) + + item�Ȱ��פ������Ǥ�������. + + delete_if + + ���Ǥ������륤�ƥ졼��. �֥��å���ɾ�������ͤ����λ�, �б��� + �����Ǥ�����������. + + each + + ����γ����Ǥ���Ϳ���륤�ƥ졼��. + + fill(val) + fill(val, start[, length]) + fill(val, start..end) + + ����(�λ��ꤵ�줿��ʬ)�����Ǥ��ͤ�val�����ꤹ��. 2�֤�η����� + length����ά���줿��������ν���ޤǤ�Ĺ����Ȥ�. ���ꤵ�줿�� + ʬ������������ϰϤ�ۤ�����ϼ�ưŪ�˳�ĥ�����. + + join([sep]) + + ��������Ǥ�Ϣ�뤷��ʸ������֤�. �����Ǥ�ʸ������Ѵ�����, �� + ��sep���Ϣ�뤵���. sep����ά���줿���ˤϥ����ƥ��ѿ�`$,' + ���ͤ��Ѥ�����. + + length + + �����Ĺ��(���ǿ�)���֤�. + + push(obj) + + obj��������������ɲä���. + + pack(template) + + ��������Ƥ�templateʸ����ˤ������ä�, 1�Ĥ�ʸ����˥ѥå��� + ��. �ѥå�����ʸ������֤�. �ƥ�ץ졼�ȤϷ�����ʸ����Ȥ���Ĺ + ��(��ά����1)���¤٤���ΤǤ���. Ĺ���Ȥ���`*'�����ꤵ�줿���� + �ֻĤ�Υǡ������ơפ�Ĺ����ɽ��. + + ������ʸ���ϰʲ��Τ�Τ�����. + + a ASCIIʸ����(nullʸ����ͤ��) + A ASCIIʸ����(���ڡ�����ͤ��) + b �ӥåȥ��ȥ��(���̥ӥåȤ����̥ӥå�) + B �ӥåȥ��ȥ��(��̥ӥåȤ��鲼�̥ӥå�) + h 16��ʸ����(���̥˥֥뤬��) + H 16��ʸ����(��̥˥֥뤬��) + c char + C unsigned char + s sort + S unsigned sort + i int + I unsigned int + l long + L unsigned int + n �ͥåȥ���Х��ȥ���������short + N �ͥåȥ���Х��ȥ���������long + f ñ������ư��������(�����¸) + d ��������ư��������(�����¸) + x �ʥ�Х��� + X 1�Х��ȸ��� + @ ���а��֤ؤΰ�ư + + pop + + ��������������Ǥ��������, ������֤�. + + rassoc(value) + + Ϣ�ۥꥹ��(2���Ǥ���������ǤȤ�������)����, ��2���Ǥ� + value��������("=="����Ӥ���)������֤�. + + shift + + �������Ƭ�����Ǥ��������, ������֤�. + + sort + + ��������Ƥ��Ȥ���. ���ƥ졼���Ȥ��ƸƤӽФ��줿���ϥ֥��� + ����ɾ�������ͤ����Ǥ��羮����ꤹ��. �礭��������, ���������� + 0, ������������. �̾�Υ�åɤȤ��ƸƤӽФ��줿���ϳ����� + ��`<=>'����Ӥ���. + + to_a + + ��ʬ���Ȥ��֤�. �о����Τ�����Ѱդ���Ƥ����åɤǤ��ޤ��� + �ʤ�. + + unshift(obj) + + obj���������Ƭ���ɲä���. + +*** Bignum(���饹) + +̵��¿��Ĺ�����Υ��饹. �黻�η�̤�����Fixnum���ϰ���Ǥ�����ˤϼ� +ưŪ�˥��饹��Fixnum���Ѵ������. ����Ū��Ruby�ץ������Ǥ�Fixnum�� +Bignum���Ѵ��ϰ��ۤΤ����˹Ԥ���Τ�, �ռ�����ɬ�פ�̵��. Float�Ȥ� +����˴ؤ��Ƥ�, Bignum��� Float������genericity���⤤�Τˤ�ؤ�餺, +Bignum������, �礭���ͤ�ɽ���Ǥ���Τ�, �Ѵ����˷�������������ǽ���� +����. + + +SuperClass: Integer + +Methods: + + self + other + self - other + self * other + self / other + self % other + self ** other + + ���ѱ黻. ���줾����, ��, ��, ��, ��;, �Ѿ���֤�. + + ~ self + self | other + self & other + self ^ other + + �ӥåȱ黻. ���줾��ӥå�ȿž, ������, ������, ��¾Ū�����¤� + �֤�. + + self << bits + self >> bits + + ���եȱ黻. ���줾��bits�ӥåȤ��������˥ӥåȥ��եȤ�Ԥʤ�. + + divmod(other) + + ���Ⱦ�;��2���Ǥ�������֤�. + +*** Class(���饹) + +���饹�Υ��饹. ��긷̩����������ȥ��饹���ðۥ�åɤ�Ѿ����뤿�� +��, ���줾�����饹�ȸƤФ��̾���Τʤ����饹�饹�Ȥ��ƻ���, +Class�Ϥ��Υ���饹�Υ��饹�Ǥ���(ʬ���ä�����?). ��, ���β��⤬���� +�Ǥ��ʤ��Ƥ�, Ruby��Ȥ����Ȥ˲��λپ��ʤ�. + +SuperClass: Module + +Methods: + + attr(name[, public]) + + ���Υ��饹�Υ������Ф���name�ǻ��ꤵ���°�����������. + �ܤ�����Module��attr��åɤι�ȤΤ���. + + new(...) + + ���饹�Υ�������������. ¿���ξ�礳�Υ�åɤϥ��֥� + �饹���ðۥ�åɤˤ�äƥ����С��饤�ɤ���, ���饹�ˤ�äư� + �����ۤʤ�. + +*** Comparable(�⥸�塼��) + + ��ӱ黻��������饹�Τ����Mixin. ���Υ⥸�塼��롼�ɤ��뤳 + �Ȥˤ�ä�, `<=>'��������������¾�α黻�ҤϤ�����������Ѥ��������� + ����. + +Methods: + + self > other + + self��other����礭���������֤�. + + self >= other + + self��other����礭�����������������֤�. + + self < other + + self��other��꾮�����������֤�. + + self <= other + + self��other��꾮�������������������֤�. + + between(min, max) + + self��min��max���ϰ���ˤ���������֤�. + +*** DBM(���饹) + +NDBM�ե�������������륯�饹. ����, �ǡ����Ȥ��ʸ����Ǥʤ���Ф� +��ʤ��Ȥ������¤�, �ǡ������ե��������¸�����Ȥ�����������Ƥ� +Dict���饹������Ʊ�ͤ˰������Ȥ��Ǥ���. NDBM�������Ƥ��ʤ������ƥ�Ǥ� +���Υ��饹�ؤΥ����������㳰��ȯ��������. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self [key] + + key���Ȥ����ͤ��֤�. + + self [key]= value + + key���Ȥ���, value���Ǽ����. value�Ȥ���nil����ꤹ���, + key���Ф�����ܤκ���Ȥʤ�. + + clear + + DBM�ե��������Ȥ���ˤ���. + + close + + DBM�ե��������������. �ʸ�������㳰��ȯ��������. + + delete(key) + + key���Ȥ����Ȥ�������. + + delete_if + + ���Ǥ������륤�ƥ졼��. [key, value]�Ȥ��������Ϳ����, �֥��� + ����ɾ�������ͤ����λ�, ����������ܤ�������. + + each + each_value + + ���Ƥ�value���Ф��Ʒ����֤����ƥ졼��. + + each_key + + ���Ƥ�key���Ф��Ʒ����֤����ƥ졼��. + + each_pair + + [key, value]�ʤ������Ϳ���륤�ƥ졼��. + + includes(key) + has_key(key) + + key���ǡ����١������¸�ߤ����, �����֤� + + has_value(value) + + value���ͤȤ����Ȥ��ǡ����١������¸�ߤ����, ���� + �֤� + + keys + + �ǡ����١������¸�ߤ��륭�����Ƥ�ޤ�������֤�. + + length + + �ǡ����١���������Ǥο����֤�. (����:���ߤμ¸��Ǥ����ǿ���� + ���뤿��˥ǡ����١�����������������Τ�, �빽�����Ȥ��⤤. �� + ��Ĥ��ƻȤ�����.) + + to_a + + �ǡ����١������key-value�ڥ������ǤȤ���������֤�. + + values + + �ǡ����١������¸�ߤ��������Ƥ�ޤ�������֤�. + +Single Methods: + + open(dbname[, mode]) + + dbname�ǻ��ꤷ���ǡ����١�����⡼�ɤ�mode�����ꤷ�ƥ����ץ� + ��. mode�ξ�ά�ͤ�0666�Ǥ���. mode�Ȥ���nil����ꤹ��ȥǡ��� + �١���������¸�ߤ��ʤ����ˤϿ����˥����ץ�, nil���֤�. + +*** Dict(���饹) + +���뤤��Ϣ������. Ǥ�դΥ��֥������Ȥ�ź���ȤǤ�������Υ��饹�Ǥ� +��. Hash�Ȥ���̾���Ǥ⥢�������Ǥ���. Ϣ�����֥������Ȥ������ϰ��� +Ū�ˤ�Ϣ������``{a=>b,..}'' �ǹԤʤ���. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self [key] + + key���Ȥ����ͤ��֤�. + + self [key]= value + + key���Ȥ���, value���Ǽ����. value�Ȥ���nil����ꤹ��Ȥ� + ��key���Ф�����ܤκ���Ȥʤ�. �Ĥޤ�, Dict���ͤȤ���nil����� + ���ȤϤǤ��ʤ�. + + clear + + Ϣ���������ˤ���. + + delete(key) + + key���Ȥ����Ȥ�������. + + delete_if + + ���Ǥ������륤�ƥ졼��. [key, value]�Ȥ��������Ϳ����, �֥��� + ����ɾ�������ͤ����λ�, ����������ܤ�������. + + each + each_value + + ���Ƥ�value���Ф��Ʒ����֤����ƥ졼��. + + each_key + + ���Ƥ�key���Ф��Ʒ����֤����ƥ졼��. + + each_pair + + [key, value]�ʤ������Ϳ���륤�ƥ졼��. + + includes(key) + has_key(key) + + key���������¸�ߤ����, �����֤� + + has_value(value) + + value���ͤȤ����Ȥ��������¸�ߤ����, �����֤� + + keys + + �������¸�ߤ��륭�����Ƥ�ޤ�������֤�. + + length + + ����������Ǥο����֤�. + + to_a + + �������key-value�ڥ������ǤȤ���������֤�. + + values + + �������¸�ߤ��������Ƥ�ޤ�������֤�. + +Single Methods: + + new + + ������(����)���֥������Ȥ��֤�. + +*** Directory(���饹) + +�ǥ��쥯�ȥ�������Ǥ����֤��ǥ��쥯�ȥꥹ�ȥ�����Τ���Υ��饹. +Dir�Ȥ���̾���Ǥ⥢�������Ǥ���. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + close + + �ǥ��쥯�ȥꥹ�ȥ�����������. �ʸ�������㳰��ȯ���� + ����. + + each + + �ǥ��쥯�ȥ���γ����Ǥ���Ϳ���륤�ƥ졼��. + + getwd + pwd + + �����ȥǥ��쥯�ȥ���֤�. + + rewind + + �ǥ��쥯�ȥꥹ�ȥ�����Ƭ�˥ꥻ�åȤ���. + + seek(pos) + + �ǥ��쥯�ȥꥹ�ȥ��ΰ��֤�pos�����ꤹ��. + + tell + + �ǥ��쥯�ȥꥹ�ȥ��θ��ߤΰ��֤��֤�. + +Single Methods: + + chdir(path) + + �����ȥǥ��쥯�ȥ��path���ѹ�����. + + chroot(path) + + �ץ������Υ롼�ȥǥ��쥯�ȥ���ѹ�����, Ʊ̾�Υ����ƥॳ����� + Ʊ��Ư����. �������ϼ¸�uid�������ѥ桼���Ǥ���������� + ���¤���Ƥ���. �롼�ȥǥ��쥯�ȥ���᤹(�롼�ȥǥ��쥯�� + ���������ѹ�����)��ˡ������Ƥ��ʤ�. + + mkdir(path[, mode]) + + mode�ǻ��ꤵ�줿�⡼�ɤ���ĥǥ��쥯�ȥ�path���������. �⡼�� + ��umask�ˤ�äƽ��������. mode�Υǥե�����ͤ�0777. + + open(path) + + path���Ф���ǥ��쥯�ȥꥹ�ȥ����ץ�. + + rmdir(path) + + path�ǻ��ꤵ�줿�ǥ��쥯�ȥ��������. �ǥ��쥯�ȥ�϶��Ǥ��� + ɬ�פ�����. + +*** Enumerable(�⥸�塼��) + +���Ǥ��Ф��뷫���֤���Ԥʤ����饹�Τ����Mixin. ���Υ⥸�塼��� +���롼�ɤ��뤿��ˤ�, ��å�`each'���������ɬ�פ�����. + +Methods: + + collect + + �����Ǥ��Ф��ƥ֥��å���ɾ��������̤����ƴޤ�������֤� + + find + + ���Ǥ��Ф��ƥ֥��å���ɾ�������ͤ����ˤʤä��ǽ�����Ǥ��֤�. + + find_all + + �����Ǥ��Ф��ƥ֥��å���ɾ�������ͤ����Ǥ��ä����Ǥ����ƴޤ��� + ����֤�. + + grep(pattern) + + ��pattern =~ ���ǡפ���Ω�������Ƥ����Ǥ�ޤ�������֤�. ���� + �졼���Ȥ����Ѥ���줿���Ͼ嵭�ξ�����Ω�������Ǥ��Ф��ƥ֥��� + ����¹Ԥ���. + + includes(val) + + val��`=='�δط��ˤ������Ǥ���Ļ�, �����֤�. + + index(val) + + val��`=='�δط��ˤ��륪�֥������Ȥ������ܤ˸��줿�����֤�. �� + �ֺǽ�����Ǥ�0�ˤʤ�. ���Ǥ�¸�ߤ��ʤ����ˤ�nil���֤�. ����� + �ʤ����饹���Ф��ƤϤ��ޤ��̣���ʤ�. + + min + + �Ǿ������Ǥ��֤�. �����Ǥ�`<=>'��åɤ���Ĥ��Ȥ���ۤΤ��� + �˲��ꤷ�Ƥ���. + + max + + ��������Ǥ��֤�. �����Ǥ�`<=>'��åɤ���Ĥ��Ȥ���ۤΤ��� + �˲��ꤷ�Ƥ���. + + reverse + + ���Ƥ����Ǥ�ս���¤٤�������֤�. + + sort + + ���Ƥ����Ǥ��Ȥ���������֤�. + +*** EnvDict(���饹) + +�Ķ��ѿ������뤿��Υ��饹. �����ƥ��ѿ�$ENV��ͣ��Υ����� +��������Ƥ���. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + [name] + + �Ķ��ѿ����ͤ��֤�. + + [name]= val + + �Ķ��ѿ����ͤ�val�����ꤹ��. val�Ȥ���nil����ꤷ�����ˤ�, + ��������Ķ��ѿ���������. + + delete(name) + + �Ķ��ѿ���������. + + each + + �Ķ��ѿ���̾�����ͤΥڥ���Ϳ���륤�ƥ졼��. + +*** Etc(�⥸�塼��) + +/etc�ǥ��쥯�ȥ�ʲ��ξ�������뤿��Υ⥸�塼��. ���饹�˥��롼�� +���ƻȤ����Ȥ�Ǥ���. + +Methods: +Single Methods: + + getlogin + + ��ʬ��login̾���֤�. ���줬���Ԥ�������getpwuid()���Ѥ���� + �ɤ�. + + getpwnam(name) + + /etc/passwd�ե�����(���뤤��DBM�ե������NIS�ǡ����١���)�� + ����, name��̾�������passwd����ȥ���֤�. ����ͤ�passwd��¤ + �Τǰʲ��Υ��Ф����. + + struct passwd + name # �桼��̾(ʸ����) + passwd # �ѥ����(ʸ����) + uid # �桼��ID(����) + gid # ���롼��ID(����) + gecos # gecos�ե������(ʸ����) + dir # �ۡ���ǥ��쥯�ȥ�(ʸ����) + shell # ����������(ʸ����) + # �ʹߤΥ��Фϥ����ƥ�ˤ�äƤϤʤ���Τ⤢�� + change # �ѥ�����ѹ�����(����) + quota # ��������(����) + age # ������(����) + class # �桼�������������饹(ʸ����) + comment # ������(ʸ����) + expire # ���������ͭ������(����) + end + + �ܺ٤�getpwnam(3)�ȤΤ���. + + getpwuid([uid]) + + uid��桼��ID�Ȥ���passwd����ȥ���֤�. ����ͤ�getpwnam()�� + Ʊ�ͤǤ���. �������ά�������ˤ�getuid()���ͤ��Ѥ���. �ܺ٤� + getpwuid(3)�ȤΤ���. + + getgrgid(gid) + + /etc/group�ե�����(���뤤�ϡ�getpwnam����)����, gid�롼 + ��ID�Ȥ��륰�롼�ץ���ȥ���֤�. ����ͤ�group��¤�Τǰʲ��� + ���Ф����. + + struct group + name # ���롼��̾(ʸ����) + passwd # ���롼�פΥѥ����(ʸ����) + gid # ���롼��ID(����) + mem # ���롼�ץ���̾������ + end + + �ܺ٤�getgrgid(3)�ȤΤ���. + + getgrnam(name) + + name�Ȥ���̾���Υ��롼�ץ���ȥ���֤�. ����ͤ�getgrgid()��Ʊ + �ͤǤ���. �ܺ٤�getgrnam(3)��. + + group + + ���ƤΥ��롼�ץ���ȥ���˥����������뤿��Υ��ƥ졼��. + + passwd + + ���Ƥ�passwd����ȥ���˥����������뤿��Υ��ƥ졼��. + +*** File(���饹) + +�ե����륢�������Τ���Υ��饹. �ؿ���å�open()�����������. �ޤ�, +���Υ��饹���ðۥ�åɤȤ���test�Υե�����ƥ��ȱ黻�������Υ�å� +���������Ƥ���. + +SuperClass: IO + +Methods: + + atime + + �ե�����κǽ���������������֤�. + + ctime + + �ե�����κǽ����ơ������ѹ�������֤�. + + chmod(mode) + + �ե�����Υѡ��ߥå������ѹ�����(cf chmod(2)). + + chmod(owner, group) + + �ե�����ν�ͭ�Ԥȥ��롼�פ��ѹ�����(cf chown(2)). nil��-1�� + ���ꤹ�뤳�Ȥˤ�äƽ�ͭ�Ԥ䥰�롼�פߤΤޤ��Ѥ��ʤ��Ǥ��� + ���Ȥ��Ǥ���. + + eof + + �ե�����ν�ü����ã�������˿����֤�. + + lstat + + �ե�����˴ؤ���Stat��¤�Τ��֤�. lstat�ϥե����뤬����ܥ�� + ����Ǥ���Х���Τ�Τ˴ؤ���Stat��¤�Τ��֤�. ��¤�� + �����ƤˤĤ��Ƥ�stat �ȤΤ���. + + mtime + + �ե�����κǽ�����������֤�. + + rewind + + �ե�����Υե�����ݥ��ΰ��֤���Ƭ�˰�ư����. + + path + + �ե�����Υѥ�̾���֤�. + + seek(offset, ptrname) + + �ե�����Υե�����ݥ��ΰ��֤�offset�˰�ư����. ptrname�� + 0, 1, 2�Τ����줫�Ǥ��ä�, ���줾��ե��������Ƭ, ���߰���, + �ե�����ν�ü�Τ����Τ����줫��������Ф�. + + stat() + + �ե�����˴ؤ���Stat��¤�Τ��֤�(Struct ��). + + struct stat + dev # �ե������¸�ߤ���ǥХ��� + ino # �ե������i-node�ֹ� + mode # �⡼�� + nlink # �ϡ��ɥ�ο� + uid # ��ͭ�ԤΥ桼��ID + gid # ��ͭ�ԤΥ��롼��ID + rdev # �ǥХ�����ID(���ڥ����ե�����Τ�) + size # �ե����륵����(byte��) + blksize # �ե����륷���ƥ�ˤ�����Ŭ�ڤʥ֥��å������� + blocks # �֥��å��� + atime # �ǽ������������� + mtime # �ǽ��������� + ctime # �ǽ������ѹ����� + end + + �ܺ٤�������fstat(2)�ȤΤ���. �����ƥ����������Ƥ��� + stat��¤�Τ˳���������Ф��ʤ�����0�����ꤵ��Ƥ���. + + tell + + �ե�����θ��ߤΥե�����ݥ��ΰ��֤��֤�. + + truncate(length) + + �ե�������ڤ�ΤƤƺ���length�Х��Ȥˤ���. �ե������write�⡼ + �ɤǥ����ץ�Ƥ��ʤ���Фʤ�ʤ�. + +Single Methods: + + atime(filename) + + filename�κǽ���������������֤�. + + b(filename) + + filename�Υե����뤬�֥��å����ڥ����ե�����Ǥ����, ������ + ��. + + c(filename) + + filename�Υե����뤬����饯�����ڥ����ե�����Ǥ����, ���� + �֤�. + + ctime(filename) + + filename�κǽ����ơ������ѹ�������֤�. + + chmod(mode, path, file...) + + �ե�����Υѡ��ߥå������ѹ�����(cf chmod(2)). + + chown(owner, group, file...) + + �ե�����ν�ͭ�Ԥȥ��롼�פ��ѹ�����(cf chown(2)). nil��-1��� + �ꤹ�뤳�Ȥˤ�äƽ�ͭ�Ԥ䥰�롼�פߤΤޤ��Ѥ��ʤ��Ǥ����� + �Ȥ��Ǥ���. + + executable(filename) + x(filename) + + filename�Υե����뤬�¹Բ�ǽ�λ�, �����֤�. + + exists(filename) + e(filename) + a(filename) + + filename�Υե����뤬¸�ߤ����, �����֤�. + + G(filename) + + filename�Υե������gid���¸����롼�פ�gid��Ʊ����, �����֤�. + + isdirectory(filename) + d(filename) + + filename���ǥ��쥯�ȥ�λ�, �����֤�. + + isfile(filename) + f(filename) + + filename�Υե����뤬�̾�ե�����λ�, �����֤�. + + islink(filename) + l(filename) + + filename�Υե����뤬����ܥ�å���Ǥ����, �����֤�. + + ispipe(filename) + p(filename) + + filename�Υե����뤬̾���Ĥ��ѥ���(FIFO)�Ǥ����, �����֤�. + + issocket(filename) + S(filename) + + filename�Υե����뤬�����åȤǤ����, �����֤�. + + link(old, new) + + old�ؤΥϡ��ɥ��new����������. link(2)��Ʊ�����¤�����. + + mtime(filename) + + filename�κǽ�����������֤�. + + owned(filename) + O(filename) + + filename�Υե������¸��桼������ͭ���Ƥ����, �����֤�. + + readable(filename) + r(filename) + + filename�Υե�������ɤߤȤ��ǽ�λ�, �����֤�. + + readlink(path) + + ����ܥ�å����path�����Ƥ�ʸ����Ȥ����֤�. + + rename(from, to) + + �ե�����̾from��to���ѹ�����. rename(2)����. ����to�Ȥ���̾�� + �Υե����뤬¸�ߤ�����ˤϤޤ����Υե����뤬��������. + + R(filename) + + filename�Υե�������uid/gid���ɤߤȤ��ǽ�λ�, �����֤�. + + setuid(filename) + u(filename) + + filename�Υե������setuid�ӥåȤ����åȤ���Ƥ����, �����֤�. + + setuid(filename) + g(filename) + + filename�Υե������setuid�ӥåȤ����åȤ���Ƥ����, �����֤�. + + size(filename) + s(filename) + + filename�Υե����뤬¸�ߤ����, �ե�������礭�����֤�. ¸�ߤ� + �ʤ�����nil���֤�. + + sticky(filename) + g(filename) + + filename�Υե������sticky�ӥåȤ����åȤ���Ƥ����, �����֤�. + + symlink(old, new) + + old�ؤΥ���ܥ�å����new����������. + + truncate(path, length) + + path�ǻ��ꤵ�줿�ե�������ڤ�ΤƤƺ���length�Х��Ȥˤ���. + + unlink(file...) + + �ե������������. �ǥ��쥯�ȥ�κ���ˤ�Dir.rmdir��Ȥ�����. + + utime(atime, mtime, file...) + + �ե�����Υ������������atime��, ���������mtime�����ꤹ��. + atime, mtime�Ͽ��ޤ���Time���饹�Υ����Ǥʤ���Фʤ�� + ��. + + writable(filename) + w(filename) + + filename�Υե����뤬��uid/gid�ǽ��߲�ǽ�λ�, �����֤�. + + W(filename) + + filename�Υե����뤬���߲�ǽ�λ�, �����֤�. + + z(filename) + + filename�Υե����뤬¸�ߤ�, �礭����0�Ǥ����, �����֤�. + +*** Fixnum(���饹) + +31bit�����Υ��饹. builtin class�Ǥ���. ���Υ��饹��pointer���¨�ͤ� +���뤿��call by value�ǸƤӽФ����������ħŪ�Ǥ���(¾�Υ��饹��call +by reference). �黻�η�̤�31bit��ۤ�����ˤϼ�ưŪ��Bignum(̵��¿ +��Ĺ����)�˳�ĥ�����. + +���ƥ졼��upto(), downto(), step()�Ϸ����֤��Τ�����Ѥ����, ���̤� +Range���饹���Ѥ������®�Ǥ���. + +SuperClass: Integer + +Methods: + + self + other + self - other + self * other + self / other + self % other + self ** other + + ���ѱ黻. ���줾����, ��, ��, ��, ��;, �Ѿ���֤�. + + ~ self + self | other + self & other + self ^ other + + �ӥåȱ黻. ���줾��ӥå�ȿž, ������, ������, ��¾Ū�����¤� + �֤�. + + self << bits + self >> bits + + ���եȱ黻. ���줾��bits�ӥåȤ��������˥ӥåȥ��եȤ�Ԥʤ�. + + self .. max + + �ϰϻ���. self ���� max�ޤǤ��ϰϥ��֥������Ȥ��֤�. + + downto(min) + + ���ƥ졼��. self����min�ޤDz������˷����֤�. + + id2name + + �����ͤ�ID���Ȥߤʤ���, ��������ʸ������֤�. ��������ʸ���� + ¸�ߤ��ʤ�����nil���֤�. + + step(max, step) + + ���ƥ졼��. self����max�ޤ�step�����Ѳ����ʤ���, �����֤�. + + to_f + + self��Float���Ѵ�������Τ��֤�. + + to_i + + self�Τޤ��֤�. + + upto(max) + + ���ƥ졼��. self����max�ޤǷ����֤�. + +*** Float(���饹) + + ��ư���������Υ��饹. + +SuperClass: Numeric + +Methods: + + self + other + self - other + self * other + self / other + self % other + self ** other + + ���ѱ黻. ���줾����, ��, ��, ��, ��;, �Ѿ���֤�. + + self == other + self > other + + ��ӱ黻. + + coerce(num) + + num��float���Ѵ�����. ��������������Float������Ǥ���¾�ο��� + Fixnum�����Ǥ���. + + to_f + + self�Τޤ��֤�. + + to_i + + float���������Ѵ�������̤��֤�. + +Single Methods: + + new(float) + + float��Ʊ���ͤ���Ŀ�����Float���֥������Ȥ��֤�. + +*** GC(�⥸�塼��) + +Ruby�Ȥ߹��ߤ�garbage collector�������Ԥʤ�����Υ⥸�塼��. ���Υ� +���塼��Υ�åɤ���Ѥ��뤳�Ȥˤ�ä�, ���Ū��GC��ߤ��, GC�ε� +���륿���ߥ����椷����Ǥ���. + +����gc�ϻϤޤ���ˤ��Υ⥸�塼���start_hook��åɤ�, ���ä����ˤ� +end_hook��åɤ�ƤӽФ�����, ������åɤ�������뤳�Ȥˤ�ä� +hook���뤳�Ȥ��Ǥ���. + +Methods: + + garbage_collect + + + GC�Ϥ���. ��GC.start�פ�Ʊ��. + +Single Methods: + + disable + + GC��ػߤ���. + + enable + + GC����Ĥ���. + + start + + GC�Ϥ���. + + threshold + + GC�γ��ϥ����ߥ���ꤹ�����ͤθ��ߤ��ͤ��֤�. + + threshold=(val) + + GC�����ͤ����ꤹ��. �Ť����ͤ��֤�. + + start_hook + end_hook + + GC�γ��ϻ�, ��λ���ˤ��줾��ƤФ��. �ǥե���ȤǤϲ��⤷�ʤ� + ��åɤ��������Ƥ���. + +*** Integer(���饹) + +�������饹. �ºݤϤ����礭���ˤ�ä�Fixnum��Bignum������ĤΥ��֥��饹 +�Ǽ¸�����Ƥ���. Integer�Ϥ����Υ����ѡ����饹�Ȥʤ���ݥ��饹�Ǥ� +��. Ruby�ǤϤۤȤ�ɤξ��, Fixnum��Bignum�ζ��̤�ɬ�פʤ�, ��ߤ��Ѵ� +�ϼ�ưŪ�˹Ԥʤ���. ������ӥå�����Ȥߤʤ����ˤ�, ̵�¤�Ĺ����� +�ĥӥå���ȹͤ��ƹ���ʤ�. + +SuperClass: Numeric + +Methods: + + self[idx] + + ������idx�ӥå��ܤ����åȤ���Ƥ����1, ���åȤ���Ƥ��ʤ���� + 0���֤�. + + chr + + ���ο����ɤȤ���ʸ��������ޤ�1ʸ����ʸ������֤�. ���̤� + Ĺ��1�ʾ��ʸ����ˤĤ���, ���δط��������Ω����. + + str[0].chr == str[0,1] + + ������ʸ�����ϰ���(0..255)�ˤʤ�����㳰��ȯ������. + + is_integer + + ���Ĥ���֤�. + +*** IO(���饹) + +�����ϤΤ���δ��ܥ��饹. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self << object + + object����Ϥ���. object��ʸ����Ǥʤ����ˤϥ�å�to_s���Ѥ� + ��ʸ������Ѵ�����. self������ͤȤ���Τ�, C++�Τ褦��`<<'�� + Ϣ����Ȥ���. + + ��: + + $stdout << 1 << " is a " << Fixnum + + close + + �����ϥݡ��Ȥ���������. �ʸ�Τ��Υ��֥������Ȥ��Ф������� + �����ϥ��顼�ˤʤ�. + + each + + ��Ԥ����ɤ߹���Ǥ��뤿��Υ��ƥ졼��. �Ԥζ��ڤ�ϥ����ƥ��� + ��`$/'�ˤ�ä��ѹ��Ǥ���. �ɤ߹����ʸ����ϥ����ƥ��ѿ�`$_'�� + �⥻�åȤ����. + + each_byte() + + ��ʸ�������ɤ߹���Ǥ��뤿��Υ��ƥ졼��. ʸ����ʸ�������ɤ�ɽ + ��Fixnum�Ǥ���. + + fileno + + IO���֥������Ȥ��ȤäƤ���ե�����ǥ�������ץ�(Fixnum)���֤�. + + flush + + �Хåե���ե�å��夹��. + + getc + + ����ɤ߹����, �ɤ߹��ߤ������������ˤϤ���ʸ������֤�. �ե� + ����ν������ã�������ˤ�nil���֤�. �ؿ�Ū��åɤ�getc()�� + $stdin.getc��Ʊ����̣�Ǥ���. + + gets + + ����ɤ߹����, �ɤ߹��ߤ������������ˤϤ���ʸ������֤�. �ե� + ����ν������ã�������ˤ�nil���֤�. + + isatty + + �����ϥݡ��Ȥ�tty�Ǥ����, �����֤�. + + puts(obj) + + obj����Ϥ���. ��self << obj�פ�Ʊ����̣�Ǥ���. + + read([length]) + + length�Х����ɤ߹����, ����ʸ������֤�. length����ά���줿�� + �ˤ�, ���ƤΥǡ������ɤ߹���. + + sync + + ���ߤν���Ʊ���⡼�ɤ��ͤ��֤�. Ʊ���⡼�ɤ����λ��Ͻ��ϴ� + ���θƽ���˥Хåե����ե�å��夵���. + + sync=(newstate) + + ����Ʊ���⡼�ɤ����ꤹ��. + + sysread(length) + + stdio���ͳ������read(2)���Ѥ������Ϥ�Ԥʤ�. ���Ϥ��줿�ǡ��� + ��ޤ�ʸ������֤�. �ե�����ν������ã�������ˤ�nil���֤�. + read(2)�������ˤ��ɬ��length�Х��Ȥ�ʸ�����ɤ߹��ޤ��櫓 + �ǤϤʤ�. gets()��getc()�ʤ�stdio���ͳ�����åɤȺ��Ѥ��� + ���ȤϥХåե����������ʤɤ�, �פ��ư��뤳�Ȥ�����. + + syswrite(str) + + stdio���ͳ������, wirte(2)���Ѥ��ƽ��Ϥ�Ԥʤ�. ���Υ�å� + �ϥХåե���ʤ�stdio�����Ƥ���뤳�Ȥϰ��ڹԤʤ�ʤ�. + print()��printf()��syswrite()���Ѥ���ΤϿ侩�Ǥ��ʤ�. + + write(str) + + str����Ϥ���. ���Ϥ����Х��ȿ����֤�. + +Single Methods: + + default + + print��printf�Υǥե���Ȥν�������֤�. ����ͤ�$stdout. + + default= + + �ǥե���Ȥν��������ꤹ��. + +*** Kernel(���饹) + +���ƤΥ��饹�δ��쥯�饹. Ruby�Ȥ߹��ߤ����Ƥδؿ�Ū��åɤϤ��Υ� +�饹���������Ƥ���. + +SuperClass: �ʤ� + +Methods: + + ! self + + ����. Non-nil�Υ��֥������Ȥξ���˵�(nil)���֤�. ���Υ�� + �ɤ�Nil���饹�ǤϺ�������쿿���֤�. + + equal(other) + self == other + + ���֥������Ȥΰ���Ƚ��. �쥷���ФȰ����ΰ��������פ����, ���� + �֤�. Kernel���饹������Ǥ������Υ��֥������Ȥ�Ʊ��λ������� + ��. "=="��åɤϳƥ��֥������Ȥ������˱����ƺ��������ɬ�פ� + ����. "=="��åɤ������������ˤ�, hash��åɤ⤽��˹�� + ���ƺ��������ɬ�פ�����. + + equal()��åɤ�"=="��åɤ���̾��, "=="������������Ǥ� + ���֥������Ȥ�Ʊ����Ƚ���Ԥʤ�������Ѥ�����. ��ä� + equal()��åɤϥ��֥��饹�Ǻ��������٤��ǤϤʤ�. + + self != other + + "=="������. ������"=="��åɤ�ƤӽФ��Ƥ���Τ�, ������Ϻ� + �������ɬ�פϤʤ�. + + self =~ other + + �ޥå�. �ǥե���Ȥ�"=="��Ʊ���Ǥ���. "=~"��case����Ӥˤ��Ѥ� + ����. + + !~ + + "=~"������. ������"=~"��åɤ�ƤӽФ��Ƥ���Τ�, ��������� + ɬ�פϤʤ�. + + self :: other + + self��other�����ǤȤ���Ĺ��2��������֤�. �������������Ȥ��� + ��̣�� [self, other]��Ʊ��Ư���뤬, ������������鷺���˸� + Ψ���ɤ�. ���α黻�Ҥϱ����Ǥ���Τ�, a::b::c �� (a::(b::c)) + �Ȳ�ᤵ���. + + is_nil + + ���֥������Ȥ�nil�Ǥ��뤫�ɤ���. Kernel���饹������ǤϿ����� + ��. Nil���饹�Ǻ��������Ƥ���. + + id + + �ƥ��֥������Ȥ��Ф��ư�դ�Fixnum���֤�. ��, Fixnum�ϼ�ʬ���Ȥ��� + ���Τ�, id�����פ��Ƥ�Ʊ�����֥������ȤǤ��뤳�Ȥ��ݾڤ���ʤ�. + �Ĥޤ�, + + obj1.id == obj2.id + + ����Ω���Ƥ�, �ɤ��餫��Fixnum�Ǥ����, obj1��obj2��Ʊ���Ǥ��� + �Ȥϸ¤�ʤ�. ������, ξ����Fixnum�Ǥʤ����Ȥ��ݾڤǤ����, 2 + �ĤΥ��֥������Ȥ�Ʊ��Ǥ��뤳�Ȥϳμ¤Ǥ���. + + hash + + ���֥������ȤΥϥå�����(Fixnum)���֤�. Dict���饹�ǥ����Ȥʤ� + ���֥������Ȥ��Ǽ����Τ��Ѥ����Ƥ���.��A == B�פ���Ω���� + ����ɬ����A.hash == B.hash�פ���Ω����ɬ�פ�����Τ�, "=="��� + ����������ˤϤ�����⤽��˹�碌�ƺ�������뤳��. + +*** Math(�⥸�塼��) + +��ư�������黻�ݡ��Ȥ��륯�饹. Math�⥸�塼���Ʊ������Υ�å� +���ðۥ�åɤȤ�ξ�����������Ƥ���Τ�, �ðۥ�åɤ�ƤӽФ��ƻ� +���Ȥ�����, ���饹�˥��롼�ɤ��ƻȤ��Ȥ����Ȥ�ξ�����Ǥ���. + + ��: + + pi = Math.atan2(1, 1) * 4; + include Math + pi2 = atan2(1, 1) + +Methods: +Single Methods: + + atan2(x, y) + + �С�-�Ф��ϰϤ�X/Y�Υ�����������Ȥ��֤�. + + cos(x) + sin(x) + tan(x) + + �饸�����ɽ���줿x�λ��Ѵؿ����ͤ��֤�. + + exp(x) + + x�λؿ��ؿ����ͤ��֤�. + + log(x) + + x�μ����п����֤�. + + log10(x) + + x�ξ����п����֤�. + + sqrt(x) + + x��ʿ�������֤�. x���ͤ���Ǥ�����ˤ��㳰��ȯ��������. + + cbrt(x) + + x��Ω�������֤�. + +*** Module(���饹) + +�⥸�塼��Υ��饹. + +SuperClass: Object + +Methods: + + attr(name[, public]) + + + ���Υ⥸�塼��롼�ɤ������饹�Υ������Ф��� + name�ǻ��ꤵ���°�����ղä�, °�����Ф��륢��������åɤ��� + ������. attr("attr")�ϰʲ��˼��������ɤȤۤ�Ʊ���Ǥ���. + + def attr; @attr; end + + ��ά��ǽ����2����public��Ϳ������, ���Ĥ����ͤ�nil�Ǥʤ����� + ��, ����°���ˤ�°�������åɤ��Ѱդ���, ��������������ǽ�� + �ʤ�. attr("attr", %TRUE)�ϰʲ��Υ����ɤȤۤ�Ʊ���Ǥ���. + + def attr; @attr; end + def attr=(val); @attr = val; end + + °�����������åɤ��������뤳�Ȥˤ�ä�, ������������ư + ����ѹ��Ǥ���. �㤨�� + + attr("test", %TRUE) + def test=(val) + print("test was ", @test, "\n") + print("and now is ", @test = val, "\n") + end + + �Τ褦���������°�����ͤ�ɽ������褦�ʤ��Ȥ���ǽ�Ǥ���. attr + �ϥ���������åɤ����Ǥ��������Ƥ������, �ǥե���ȤΥ� + ��������åɤ�������ʤ�. + + to_s + + �⥸�塼���ʸ����ɽ�����֤�. �⥸�塼��ξ���ʸ����ɽ���ϥ� + ���塼��̾�Ǥ���. + +*** Nil(���饹) + +����ɽ�����֥�������nil�Υ��饹. ���ѿ�(����)nil��Nil���饹��ͣ��Υ� +���Ǥ���. nil���饹����ӥ�åɤ�����դ��뤬, �������Ӥ� +Ϣ����Ԥʤ�����Ǥ���. ��Ӥ�Ϣ���Ȥ� + + 10 < a < 13 + +�Τ褦�ʤ�ΤǤ���. ��ӱ黻�ҥ�åɤϼ��Ԥ�����nil���֤�, �������� +���ϱ��դΥ��֥������Ȥ��֤��Τ�, nil����ӱ黻�Ҥ˵����֤����Ȥˤ�� +��Ϣ������Ω����. + +SuperClass: Kernel + +Methods: + + self + other + + other������, ��ư��������, ʸ����, ����Τ����줫�Ǥ��ä����, + other���֤�. ̤������ΰ������Ф��뼫�������������ʤ褦���Ѱ� + ���줿��åɤǤ���. + + foo # �ͤ�nil + foo += 1 # foo��1�ˤʤ�. + + self > other + self >= other + self < other + self <= other + + ���Ϣ���Τ���Υ�å�. ����nil���֤�. + + ! self + + ��˿����֤�. + + is_nil + + ��˿����֤�. + +*** Numeric(���饹) + +�����̤�������ɽ����ݥ��饹. + +SuperClass: Object + +Included Modules: Comparable + +Methods: + + + self + + ���֥�������self���Τ�Τ��֤� + + - self + + ��0 - self�פ��ͤ��֤�. ���֥��饹�Ǥ���ΨŪ�˺��������뤳 + �Ȥ����Ԥ����. + + abs + + �����ͤ��֤�. + + divmod(other) + + ���Ⱦ�;��2���Ǥ�������֤�. + +*** Object(���饹) + +���Ƥ��̾說�饹�Υ����ѥ��饹. ���Υ��饹�Υ��֥��饹�Ǥʤ����饹�� +Kernel��Nil�����Ǥ���. + +SuperClass: Kernel + +Methods: + + is_member_of(class) + + ���֥�������self�����饹class�Υ����Ǥ����,�����֤�. + + is_kind_of(class) + + ���֥�������self�����饹class�����Υ��֥��饹�Υ����� + �����, �����֤�. + + clone + + ���֥������Ȥ�ʣ������. Fixnum�ʳ��Υ��饹�ξ��, ���餯�� + ��obj.eqaul(obj.clone)�פϵ��Ǥ��뤬, ¿���ξ���obj == + obj.clone�פϿ��Ǥ���. + + to_s + + ���֥������Ȥ�ʸ����ɽ�����֤�. ���Υ�åɤ�����Ū��print() + ��format()��åɤ��Ѥ����Ƥ���. + + to_a + + ���֥������Ȥ�������Ѵ�����. �����ͥ륯�饹���������Ƥ���� + �ե���Ȥ�, ���Υ��֥������ȼ��Ȥ�ޤ�1���Ǥ�������֤�. + +*** Process(�⥸�塼��) + +�ץ������˴ؤ�������Ԥʤ�����Υ⥸�塼��. Math�⥸�塼���Ʊ�ͤ��� +�ƤΥ�åɤ��ðۥ�åɤȤ��Ƥ��̾�Υ�åɤȤ��Ƥ�Ȥ���. +Process�ϥץ��������֥������ȤΥ��饹�ǤϤʤ���, �ץ��������Υ�� +�ɤ�ޤȤ��ΤǤ��뤳�Ȥ����դ��뤳��. + +Methods: +Single Methods: + + euid + + �ץ������θ��ߤμ¸�UID���֤�. + + euid=(uid) + + �ץ������θ��ߤμ¸�UID��uid�˥��åȤ���. + + getpgrp([pid]) + + pid�ǻ��ꤵ�줿�ץ����������߽�°���Ƥ���ץ��������롼�פ�id + ���֤�. pid���ά��������pid��0��Ϳ�������ϸ��¹Ԥ��Ƥ���� + ���������оݤˤ���. + + getpriority(which, who) + + which��who�ǻ��ꤵ���ץ�����, �ץ��������롼��, �桼���θ��� + ��ͥ���̤��֤�. �ܺ٤�getpriority(2)��. Process�⥸�塼 + ��Ǥ�which�Ȥ��ƻ���Ǥ������%PRIO_PROCESS, %PRIO_PGRP, + %PRIO_USER���������Ƥ���. + + pid + + �ץ������Υץ�����ID���֤�. ����ϥ����ƥ��ѿ�`$$'���ͤ�Ʊ���� + ����. + + ppid + + �ƥץ������Υץ������Υץ�����ID���֤�. UNIX�Ǥ�ľ�ܤοƥץ��� + ������λ�������, �ƥץ�������pid��1(init��pid)�ˤʤ�. + + setpgrp(pid, pgrp) + + pid�ǻ��ꤵ�줿�ץ������Υץ��������롼�פ�pgrp�ˤ���. pid��0 + ��Ϳ����ȸ��¹���Υץ��������оݤˤ���. + + setpriority(which, who, prio) + + which��who�ǻ��ꤵ���ץ�����, �ץ��������롼��, �桼���θ��� + ��ͥ���̤�prio�����ꤹ��. �ܺ٤�setpriority(2)�ȤΤ���. + + uid + + �ץ������θ��ߤμ�UID���֤�. + + uid= + + �ץ������θ��ߤμ�UID��uid�˥��åȤ���. + +*** Range(���饹) + +�ϰϥ��֥������ȤΥ��饹. �ϰϥ��֥������Ȥ�`..'�黻�Ҥˤ�ä���������, +����Ū�ˤϰʲ��Τ褦�ʻȤ����� + + for i in 1..5 + ... + end + +������, ���ξ��ϰʲ�������®��. + + do 1.upto(5) + ... + end + +�ϰϥ��֥������Ȥ���������`..'�黻�Ҥ�ξ�դ�Comparable��ޤ९�饹�Υ� +���Ǥ���в��Ǥ��ʤ�. �ϰϤϻ����Ƚ�����ޤळ�Ȥ����դ��� +����. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self =~ other + + self��other��Ʊ�����饹���Ф����ϰϥ��֥������Ȥ�, �����ϰ��� + ��other�������(start <= other <= end),�����֤�. �����caseʸ + ���ϰϻ��ꤹ����������Ǥ���. �㤨�� + + case i + when 1, 3..5 + ... + end case + + �Τ褦�ʥ����ɤ���Ȥ��Ǥ���. + + each + + �ϰ����¸�ߤ��륪�֥������Ȥ�Ϳ���륤�ƥ졼��. ���forʸ�Τ� + ����Ѥ�����. + + end + + �ϰϤν������֤� + + start + + �ϰϤλ������֤�. + +*** Socket(���饹) + +SuperClass: BasicSocket + +�����åȤ��Τ�Τ��Ф��륷���ƥॳ�����٥�Υ������������륯�饹. +Perl�Υ����åȤ��Ф��륢��������Ʊ��٥�ε�ǽ�����Ƥ���. ���Υ��� +���Ǥϥ����åȥ��ɥ쥹��pack���줿ʸ�����, ���ꤹ��. UDP�����åȤϤ� +�Υ��饹��Ȥä����Ѥ���. + +Methods: + + accept + + ��������³������դ���, ��������³���Ф��륽���åȤ��֤�. + accept(2)��. + + bind(addr) + + bind(2)��Ʊ��Ư����. addr��pack���줿�����åȥ��ɥ쥹��¤ + �ΤǤ���. + + connect(addr) + + connect(2)��Ʊ��Ư����. addr��pack���줿�����åȥ��ɥ쥹�� + ¤�ΤǤ���. + + listen(backlog) + + listen(2)��Ʊ��Ư����. + + recv(len, flags) + send(mesg, flags[, to]) + sysread(len) + +Single Methods: + + open(domain, type, protocol) + new(domain, type, protocol) + + �����������åȤ���������. domain, type, protocol�ϥ��롼�� + �ե�������������Ƥ�������ͤǻ��ꤹ��. domain��type�˴ؤ��� + ��, ʸ����ǻ���Ǥ��뤬, ���٤ƤС����Ƥ����ݾڤϤʤ�. + + socketpair(domain, type, protocol) + + �����åȤΥڥ���������, 2���Ǥ�����Ȥ����֤�. �����λ���� + open��Ʊ���Ǥ���. + +*** Regexp(���饹) + +����ɽ���Υ��饹. ����ɽ���Υ�ƥ���/.../�Ȥ���������ɽ����, ưŪ�� +�������뤿��ˤ� + + Regexp.compile(ʸ����) + +�Ȥ���. ������, String���饹��`=~'��Ϥ�Ȥ���¿���Υ�åɤ�����ɽ�� +���ؤ���ʸ����Ϳ����줿���ˤ�����Ū������ɽ������������Τ�, ���� +�����Ȥ��������Ȼפ����ʳ�������Ū�������������Ȼפ����ȤϾ��ʤ��� +����. + +SuperClass: Object + +Methods: + + + self =~ string + + ����ɽ����ʸ����˥ޥå��������, �ޥå��������֤��֤�. �ޥå� + ���ʤ�����nil���֤�. + + ~ self + + ��$_ =~ self�פ�Ʊ��. + +Single Methods: + + complie(string) + + ʸ���������ɽ�����Ѵ��������֥������Ȥ��֤�. + +*** BasicSocket(���饹) + +�����åȤ�ɽ����ݥ��饹. ����Ū�ʥ����å����ϥ��֥��饹����������. +�㤨�Х����ͥåȥɥᥤ��ξ���TCPsocket���Ѥ���. + +SuperClass: IO + +Methods: + + getopt(level, optname) + + �����åȤΥ��ץ������������. getsockopt(2)�ȤΤ���. �� + ���������ץ��������Ƥ�ޤ�ʸ������֤�. + + getpeername + + ��³�������Υ����åȤξ��������. �ѥå����줿sockaddr��¤�� + ��٥��˥���פ���ʸ�����֤����. getpeername(2)�ȤΤ���. + + getsockname + + �����åȤξ��������. �ѥå����줿sockaddr��¤�Τ�٥��˥���� + ����ʸ�����֤����. getsockname(2)�ȤΤ���. + + setopt(level, optname, optval) + + �����åȤΥ��ץ��������ꤹ��. setsockopt(2)�ȤΤ���. + + shutdown(how) + + �����åȤΰʹߤ���³��λ������. how��0�Ǥ����, �ʹߤμ�����, + how��1�Ǥ������, �ʹߤ����������ݤ����. how��2�λ��ˤ�, ���� + �ʹߤ�����, �����Ȥ�˵��ݤ����. + +*** String(���饹) + +ʸ���饹. Ruby��ʸ����ϥ̥륿���ߥ͡��ȤǤϤʤ��Τ�, �Х��ʥ�ǡ� +���ⰷ����. ���äƤɤ��餫�Ȥ�����ñ�ʤ�ʸ����Ȥ������Х�����Ǥ���. +���λ��ۤ˴�Ť���, ����ɽ���˴ؤ����åɰʳ���2byte�Ϥ�ʸ����ռ� +���Ƥ��ʤ�. ����Ϻ�Ԥμ�ȴ���ǤϤʤ��տ�Ū�ˤ������Ƥ���ΤǤ���(�� +���Ƥ���). + +SuperClass: Object + +Included Modules: Comparable, Enumerable + +Methods: + + self + other + + ʸ�����Ϣ��. Ϣ�뤵�줿ʸ������֤�. + + self * times + + ʸ����η����֤�. �㤨�� + + "x" * 4 == "xxxx" + + �Ǥ���. + + self == other + self > other + + ʸ��������. �����ƥ��ѿ�$=��nil�Ǥʤ����ˤ���ʸ����ʸ����� + �̤�������Ӥ�Ԥʤ�. + + self =~ other + + ʸ����Υޥå�. other������ɽ����ʸ����. other��ʸ����ξ��� + ��ưŪ������ɽ�����Ѵ������. �ޥå��������ϥޥå���������, + ���ʤ��ä�����nil���֤�. + + ~ self + + ��$_ =~ self�פ�Ʊ��. + + self[nth] + self[beg..end] + self[beg,len] + + ���Ƥμ��Ф�. 1���ܤη����Ǥ�nth�Х����ܤΥǡ�����Fixnum�Ȥ� + ���֤�. 2���ܤη����Ǥ�beg�Х����ܤ���end�Х����ܤޤǤ���ʬʸ + ������֤�(ξü��ޤ�). 3���ܤη����Ǥ�beg�Х����ܤ���len�Х� + ��ʬ����ʬʸ������֤�. + + self[nth] = val + self[beg..end] = val + self[beg,len] = val + + ���Ƥι���. 1���ܤη����Ǥ�nth�Х����ܤΥǡ�����val (����)���� + ������. 2���ܤη�����beg�Х����ܤ���end�Х����ܤޤǤ���ʬʸ�� + ���val�Ȥ���Ϳ����줿ʸ������֤�������. 3���ܤη�����beg�� + �����ܤ���len�Х���ʬ����ʬʸ�����val�Ȥ���Ϳ����줿ʸ����� + �֤�������. + + chop + + ʸ����κǸ�ΥХ��Ȥ��ڤ���Ȥ�. + + crypt(salt) + + crypt(3)���Ѥ��ưŹ沽����ʸ������֤�. salt��2�Х��Ȱʾ��Ĺ + ����Ǥ�դ�ʸ����Ǥ���. + + delete(str) + + ʸ����Τ���, str�˴ޤޤ��ʸ����������. ʸ����λ����tr�� + Ʊ�ͤǤ���, a-b��a����b�ޤǤ��ϰϤ�, ��Ƭ��^��ʸ���������(�� + �ޤ�Ƥʤ���Τ����)���̣����. + + each + + ʸ����1�Ԥ����ɤ߹���Ǥ��륤�ƥ졼��. + + each_byte + + ʸ����Τ��줾��ΥХ��ȤˤĤ��Ʒ����֤����ƥ졼��. + + gsub(pattern, replace) + + ʸ�������pattern�˥ޥå�������ʬ������replace���֤�������. �� + ��ʸ����replace���&��\0�ϥޥå�����ʸ�����, \1..\9��n���ܤ� + ��̤����Ƥ��֤���������. + + hex + + ʸ�����16�ʿ���ɽ��ʸ����Ȳ�ᤷ��, �������Ѵ�����. + + index(substr[, pos]) + + substr���ǽ�˽и�������֤��֤�. pos��Ϳ����Ȥ��ΰ��֤��鸡 + ���Ϥ���. ���Ĥ���ʤ����ˤ�nil���֤�. + + intern + + ʸ����˰�դ��б������������֤�. ʸ����ϥʥ�ʸ����ޤ�ǤϤ� + ��ʤ�. + + lcfirst + + ʸ������κǽ��ʸ����(���줬����ե��٥åȤǤ����), ��ʸ���� + �Ѵ�����. + + length + + ʸ�����Ĺ��(�Х��ȿ�)���֤�. + + next + + �ּ��Ρ�ʸ������֤�. ����ʸ����ȤϿ����Ͽ����Ȥ���,��ʸ���� + ��ʸ���Ȥ������ä�, ��夬��ν������Ԥʤ�줿�ԤǤ���. + + "aa".next == "ab" + "99".next == "100" + "a9".next == "b0" + + ���Υ�åɤ�Range:each���Ѥ����Ƥ���Τ�, �ʲ��Τ褦�ʽ��� + ����ǽ�Ǥ���. + + for i in "a" .. "ba" + print(i, "\n"); + end + + �����a, b, c, .. aa, .. az, ba�ޤǤ�ƹԤ˽��Ϥ���. + + + �����դ��ʤ���Ф����ʤ��Τ�, ���ν�λȽ����羮�ط��ǤϤʤ� + `=='��Ƚ�ꤵ��Ƥ��뤿��, `..'�黻�Ҥκ��դ��ͤ�³��ʸ����˱� + �դ�ʸ���ޤޤ�Ƥ��ʤ�, �ʲ�����Τ褦�ʾ���̵�¥롼�פ� + �٤äƤ��ޤ�. + + for i in "0" .. "1a" + print(i, "\n"); + end + + ��ԤϤ������Ȥˤ�ä���Ǥ��ƨ��Ƥ褦�Ȥ��Ƥ���ȹͤ���� + �⤤�뤫�⤷��ʤ�. ���ο�¬��������. + + oct + + ʸ�����8�ʿ���ɽ��ʸ����Ȳ�ᤷ��, �������Ѵ�����. 8�ʿ��� + �����/[0-7]+/�Ǥ���, ������������ƤϤޤ�ʤ�ʸ������Ф��Ƥ� + 0���֤�. perl�Ȥϰ�ä�ʸ����0x����ϤޤäƤ��뤫��Ȥ��ä� + 16�ʿ����ȸ��ʤ��Ƥ��줿��Ϥ��ʤ�. ������8�ʿ��ǤϤʤ��Τ�0 + ���֤�. + + reverse + + ʸ����γƥХ��Ȥ�ս���¤٤�ʸ������֤�. ʸ����2�Х��Ȥ� + ���������ʸ����ޤ�Ǥ��Ƥ⤪�����ʤ��˥Х���ñ�̤�ȿž����. + split��2�Х���ʸ��������Τ�, 2�Х���ʸ����ޤ�ʸ�����ʸ + ��ñ�̤�ȿž����ˤ� + + "����ʸ����".split(//).reverse.join("") + + �Ȥ���Ф褤. + + rindex(substr[, pos]) + + ʸ����substr���Ǹ�˽и�������֤��֤�. pos��Ϳ����Ȥ��ΰ��� + �Ǹ�����λ����. ���Ĥ���ʤ����ˤ�nil���֤�. index�Ȥ������ + ��1)ʸ������������鸡������. 2)substr�Ȥ�������ɽ��������դ� + �ʤ�. ��2���Ǥ���. + + split([sep[, limit]]) + + ʸ�����sep�ǻ��ꤵ�줿�ѥ�����ˤ�ä�, �ե�����ɤ�ʬ�䤹��. + sep����ά���줿���Υǥե���Ȥϥ����ƥ��ѿ�`$;'���ͤ��Ѥ���� + ��. limit�����ꤵ�줿���ˤϺ���limit�ĤΥե�����ɤ�ʬ�䤹��. + split()��ʬ�䤵�줿ʸ�����ޤ�������֤�. sep�ǻ��ꤵ�줿�ѥ��� + ��ʸ����ȥޥå��������ʸ����1ʸ�����Ĥ�ʬ�䤵���. + + squeeze([str]) + + ʸ����Τ���, str�˴ޤޤ��ʸ����Ϣ³���Ƥ������, ��ʸ���˰� + �̤���. str����ά���줿���, ���٤Ƥ�ʸ�����оݤȤ���. ʸ���� + �λ����tr��Ʊ�ͤǤ���, `a-b'��a����b�ޤǤ��ϰϤ�, ��Ƭ��`^'�� + ʸ���������(�ޤޤ�Ƥʤ���Τ����)���̣����. + + strip + + ʸ���������ζ���������. + + sub(pattern, replace) + + ʸ�������pattern�˥ޥå�������ʬ��replace���֤�������. �ִ�ʸ + ����replace���&��\0�ϥޥå�����ʸ�����, \1..\9��n���ܤγ�� + �����Ƥ��֤���������. sub()��gsub()�Ȱۤʤ�, �ǽ�Υޥå��� + �����ִ�����. + + to_f + + ʸ�����Float���Ѵ�����. + + to_i + + ʸ�����10�ʿ���ɽ��ʸ����Ȳ�ᤷ��, �������Ѵ�����. + + toupper + uc + + ʸ������Υ���ե��٥åȤ�������ʸ�����֤�������. ����ʸ���� + ��������뤳�Ȥ�����. tr("a-z", "A-Z")��꾯��®��. + + tolower + lc + + ʸ������Υ���ե��٥åȤ����ƾ�ʸ�����֤�������. ����ʸ���� + ��������뤳�Ȥ�����. tr("A-Z", "a-z")��꾯��®��. + + tr(search, replace) + + ʸ��������searchʸ����˴ޤޤ��ʸ����¸�ߤ����, replaceʸ + ������б�����ʸ�����֤�������. replaceʸ����ά���줿��� + �϶�ʸ����Ϳ����줿�ȸ��ʤ�. replaceʸ����searchʸ����� + ���û������replaceʸ����κǸ��ʸ���������֤���Ƥ���ȸ��� + ��. searchʸ���������û�����ˤ��б�����ʸ���Τʤ�replace���� + ñ��̵�뤵���(BSD��tr��ư��). + + searchʸ����, replaceʸ�������`a-b'�Ȥ������������줿���, �� + ��a����b�ޤǤ��ϰϤ�ʸ����ASCII�ξ���ǻ��ꤷ�����Ȥˤʤ�. �� + ��, searchʸ����κǽ��ʸ����`^'�Ǥ�����, ³��ʸ�����*�ޤ� + ��ʤ�*ʸ�����ִ����оݤˤʤ�. + + tr(1)�ε�ǽ�Τ���, ʸ���������뵡ǽ, Ϣ³����ʸ���̤��� + ��ǽ���̤Υ�åɤ�ʬ�䤵��Ƥ���. �����ε�ǽ�ˤĤ��Ƥ� + delete, squeeze�ȤΤ���. + + ���ؤΤ���, str.tr(src,repl).squeeze(repl)�����������å� + tr_s(src,repl) ������Ƥ���. + + ucfirst + + ʸ������κǽ��ʸ����(���줬����ե��٥åȤǤ����), ��ʸ���� + �Ѵ�����. + + unpack(template) + + ʸ�����templateʸ����ˤ������äƥ���ѥå���, ���������Ǥ� + �ޤ�������֤�. templateʸ�����Array���饹��pack��åɤȤ� + ��Ʊ�ͤǤ���. + + a ASCIIʸ����(��³����nullʸ���䥹�ڡ�����Ĥ�) + A ASCIIʸ����(��³����nullʸ���䥹�ڡ�������) + b �ӥåȥ��ȥ��(���̥ӥåȤ����̥ӥå�) + B �ӥåȥ��ȥ��(��̥ӥåȤ��鲼�̥ӥå�) + h 16��ʸ����(���̥˥֥뤬��) + H 16��ʸ����(��̥˥֥뤬��) + c char + C unsigned char + s sort + S unsigned sort + i int + I unsigned int + l long + L unsigned int + n �ͥåȥ���Х��ȥ���������short + N �ͥåȥ���Х��ȥ���������long + f ñ������ư��������(�����¸) + d ��������ư��������(�����¸) + x 1�Х����ɤ����Ф� + X 1�Х��ȸ��� + @ ���а��֤ؤΰ�ư + +Single Methods: + + new(string) + + string��Ʊ�����Ƥ���Ŀ�����ʸ������֤�. + +*** Struct(���饹) + +��¤�Υ��饹. ʣ���Υǡ�����ޤȤ������Ѥ�����(��: Time::times). +�ǡ�����ޤȤ����ˤ����饹���Ѥ����뤳�Ȥ⤢�뤬(��: select), +��¤�Τ�Ȥ��٤����ϰʲ��Τ褦�ʾ��Ǥ���. + + (1) ���Ǥο���¿�� + + �ʹ֤����٤��ưפ˰����복ǰ�ο���7�ĤޤǤǤ���Ȥ������⤬����. + ���β���˽�����, �ǡ�����4�İʾ�ξ���������Ѥ������, ���� + ��*2(�Ĥޤꥪ�ե��åȤȤ��ΰ�̣)��7��ۤ���. ��ä�, ���Τ褦�� + ���ˤϹ�¤�Τ�Ȥä��������䤹���Ȼפ���. + + (2) Ʊ�������̤���������ʤ� + + ��¤�Τ��������㴳���������Ȥ��⤤�Τ�, ®�٤�����ˤʤ��� + �ˤ�, (Ʊ�������̤������������ʤ�)�Ϲ�¤�Τλ��Ѥ�Ŭ�ڤǤʤ� + ��ǽ��������. + +�ƹ�¤�Τˤϥ���̾��Ʊ̾�ΰ����Τʤ���åɤ��������Ƥ���. + +�ܥɥ���������, ��¤�Τ�ɽ�����뤿��ˤϰʲ��η�����Ȥ�. + + struct ��¤��̾ + ���� ... + end + +������, �ץ��������Ǥ��η����ǹ�¤�Τ���������櫓�ǤϤʤ�. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self[idx] + + idx�����λ���idx���ܤ����Ǥ��֤�. idx��ʸ����λ���idx��Ʊ��̾ + ���Υ��Ф����Ǥ��֤�. + + values + + ��¤�ΤΥ��Ф��ͤ����Ǥ˻���������֤�. �㤨�аʲ��Υ����ɤ� + ��ʬ��passwd����ȥ����Ϥ��뤳�Ȥ��Ǥ���. + + print(Etc.getpwuid().values.join(":"), "\n") + + ���ν��Ϥ�`grep "$USER" /etc/passwd'�ν��Ϥ�;ʬ�ʥե�����ɤ� + ���Ĥ�(�����ƥ�ˤ�äưۤʤ�)������ʳ���Ʊ���Ǥ���. + +Single Methods: + + new(name, member::value...) + + name�Ȥ���̾������Ĺ�¤�Τ���������. member�Ϲ�¤�ΤΥ��Ф� + ɽ��ʸ����Ǥ���, value�Ϥ����ͤǤ���. �������줿��¤�Τϥ�� + �Фǻ��ꤵ�줿̾�����ðۥ�åɤ��������Ƥ���, ���Υ�å� + �ˤ�äƥ��Ф����Ƥ����뤳�Ȥ��Ǥ���. + +*** TCPserver(���饹) + +TCP/IP���ȥ���³�Υ�����¦�Υ����åȤΥ��饹. ���Υ��饹�ˤ�ä� +��ñ�˥����åȤ����Ѥ��������ФΥץ�����ߥ��Ǥ���. �㤨��echo���� +�Фϰʲ��Τ褦�ˤʤ�. + + gs = TCPserver.open(4444) + socks = [gs] + + while %TRUE + nsock = select(socks); + if nsock == nil; continue end + for s in nsock[0] + if s == gs + socks.push(s.accept) + else + if s.eof + s.close + socks.delete(s) + else + str = s.gets + s.write(str) + end + end + end + end + +SuperClass: TCPsocket + +Methods: + + accept + + ���饤����Ȥ������³�������դ�, ��³����TCPsocket�Υ��� + �������֤�. + +Single Methods: + + new([host, ]service) + open([host, ]service) + + service��/etc/services(�ޤ���NIS)����Ͽ����Ƥ��륵���ӥ�̾�� + �ݡ����ֹ�ǻ��ꤹ��. host����ꤷ�����ϻ��ꤷ���ۥ��Ȥ������ + ³����������դ���. ��ά�������ƤΥۥ��Ȥ������³�������� + ����. + +*** TCPsocket + +�����ͥåȥɥᥤ��Υ��ȥ������åȤΥ��饹. �̾��IO���饹�� +���֥��饹��Ʊ�ͤ������Ϥ��Ǥ���. ���Υ��饹�ˤ�äƥ����åȤ��Ѥ����� +�饤����Ȥ��ñ�˵��ҤǤ���. �桼�������ϤΤޤޥ����Ф�ž������� +�������ϰʲ��Τ褦�ˤʤ�. + + s = TCPsocket("localhost", 4444) + while gets() + s.write($_) + print(s.read) + end + +SuperClass: BasicSocket + +Methods: + + addr + + �����åȤ���³�����ɽ��������֤�. ��������γ����Ǥ���1���� + ��ʸ���� "AF_INET", ��2���Ǥ�port�ֹ�, ��3���Ǥ��ۥ��Ȥ�ɽ��ʸ + ����Ǥ���. + + peeraddr + + ��³����襽���åȤξ����ɽ��������֤�. ��������γ����Ǥ� + addr��åɤ��֤������Ʊ���Ǥ���. + +Single Methods: + + open(host, service) + new(host, service) + + host�ǻ��ꤷ���ۥ��Ȥ�service�ǻ��ꤷ���ݡ��Ȥ���³���������� + �Ȥ��֤�. host�ϥۥ���̾, �ޤ��ϥ����ͥåȥ��ɥ쥹��ʸ + ����, service��/etc/services(�ޤ���NIS)����Ͽ����Ƥ��륵���� + ��̾���ݡ����ֹ�Ǥ���. + +*** Time(���饹) + +���֤�ɽ�����饹. �羮��Ӥʤɤ��Ǥ���. Time.now�Ǹ��ߤλ��֤����뤳�� +���Ǥ���. �ޤ��ե�����Υ����ॹ����פ������åɤ�����ͤ⤳�Υ��� +���Υ����Ǥ���. + +SuperClass: Object + +Included Modules: Comparable + +Methods: + + self == other + self > other + + other��Time�Υ���������. ������Ϳ����줿�� + ��ˤ�1970ǯ 1�� 1�� 00:00:00 GMT������ÿ��Ǥ���� + ���ƻ���Ȥ���Ӥ�Ԥʤ�. + + asctime + ctime + to_s + + �����date(1)������ʸ������Ѵ�����. + + gmtime + + �����ॾ����ν�����Ԥʤ�ʤ�GMT�Ǥλ��������. ���Υ�å� + ������Ȥä�Time���饹�Υ�����, �ʸ�λ����Ѵ���GMT�� + �Ԥʤ�. gmtime�ϼ�ʬ���Ȥ��֤�. + + ����ɥ�λ����ɽ������ˤ� + + print(Time.now.gmtime, "\n") + + �Ȥ���Ф褤. + + localtime + + �����ॾ����ν�����Ԥʤä����������(�ǥե����). localtime + �⼫ʬ���Ȥ��֤�. + + to_i + tv_sec + + 1970ǯ 1�� 1�� 00:00:00 GMT�������ޤǤ��ÿ����������֤�. �� + ���second����ʬ�Ǥ⤢��. + + sec + min + hour + mday + year + wday + yday + zone + isdst + + ����Ū���ݻ����Ƥ���tm��¤�Τ����Ƥ��֤�. zone�ʳ����������֤�. + zone�ϥ����ॾ�����ɽ��ʸ������֤�. (cf localtime(3)) + + strftime(format) + + �����formatʸ����˽��ä�ʸ������Ѵ�������̤��֤�. format + ʸ����Ȥ��ƻ���Ǥ����Τ� �ʲ����̤�Ǥ���. + + %A ������̾��(Sunday, Monday,...) + %a �����ξ�ά̾(Sun, Mon,...) + %B ���̾��(January, February,...) + %b ��ξ�ά̾(Jan, Feb,...) + %c ����ɽ��(cf ctime(3)) + %d ���ʿ��Ǥ���(01-31) + %H 24�������λ�(00-23) + %I 12�������λ�(01-12) + %j ǯ����̻���(001-366) + %M ʬ(00-59) + %m ���ɽ������(01-12) + %p �����ޤ��ϸ��(AM,PM) + %S ��(00-61) + %U ����ɽ������. �ǽ������������1���� + �Ϥޤ�(00-53) + %W ����ɽ������. �ǽ�η���������1���� + �Ϥޤ�(00-53) + %w ������ɽ������. ��������0(0-6) + %X ����(��: 15:01:06) + %x ����(��: Fri Jan 14 1994) + %Y �����ɽ������ + %y ����β�2��(00-99) + %Z �����ॾ���� + %% %���� + + usec + tv_usec + + �����micro second����ʬ���֤�. + +Single Methods: + + now + + ���ߤλ����ɽ��Time���饹�Υ�������������. + + at(time) + + time��Ʊ�������ɽ��Time���饹�Υ�������������. time�� + Time���饹�Υ��������뤤�Ͽ�(����/��ư��������)�Ǥ���, + ���ξ���1970ǯ 1�� 1�� 00:00:00 GMT������ÿ��Ǥ���Ȥ��ƻ� + ��������. + + times + + ���ߤΥץ������Ȥ��λҥץ������������桼��/�����ƥ�CPU���� + ����ѻ���¤�ΤȤ����֤�(Struct��). + + struct tms + utime # �ץ������Υ桼������ + stime # �ץ������Υ����ƥ���� + cutime # �ҥץ������Υ桼������ + cstime # �ҥץ������Υ����ƥ���� + end + + ���֤�ñ�̤��äǤ���, ��ư����������Ϳ������. �ܺ٤� + times(3C)�ȤΤ���. + +*** UNIXserver + +UNIX���ȥ���³�Υ�����¦�Υ����åȤΥ��饹. + +SuperClass: UNIXsocket + +Methods: + + accept + + ���饤����Ȥ������³�������դ�, ��³����UNIXsocket�Υ��� + �������֤�. + +*** UNIXsocket + +UNIX�ɥᥤ��Υ��ȥ������åȤΥ��饹. �̾��IO���饹�Υ��֥��饹 +��Ʊ�ͤ������Ϥ��Ǥ���. + +SuperClass: BasicSocket + +Methods: + + addr + + �����åȤ���³�����ɽ��������֤�. ��������γ����Ǥ���1���� + ��ʸ���� "AF_UNIX", ��2���Ǥ�path�Ǥ���. + + path + + UNIX�����åȤΥѥ����֤�. + + peeraddr + + ��³����襽���åȤξ����ɽ��������֤�. ��������γ����Ǥ� + addr��åɤ��֤������Ʊ���Ǥ���. + +Single Methods: + + open(path) + new(path) + + path�ǻ��ꤷ���ѥ�̾���Ѥ�����³���������åȤ��֤�. + +------------------------------------------------------- +Local variables: +fill-column: 70 +end: diff --git a/sprintf.c b/sprintf.c new file mode 100644 index 0000000000..e63798be5e --- /dev/null +++ b/sprintf.c @@ -0,0 +1,431 @@ +/************************************************ + + sprintf.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:40 $ + created at: Fri Oct 15 10:39:26 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include <ctype.h> + +static void fmt_setup(); + +VALUE +Fsprintf(argc, argv) + int argc; + VALUE *argv; +{ + struct RString *fmt; + char *buf, *p, *end; + int i, blen, bsiz; + VALUE result; + +#define FNONE 0 +#define FSHARP 1 +#define FMINUS 2 +#define FPLUS 4 +#define FZERO 8 +#define FWIDTH 16 +#define FPREC 32 + + int width, prec, flags = FNONE; + VALUE str; + + GC_LINK; + GC_PRO2(str); + +#define CHECK(l) {\ + while (blen + (l) >= bsiz) {\ + REALLOC_N(buf, char, bsiz*2);\ + bsiz*=2;\ + }\ +} + +#define PUSH(s, l) { \ + CHECK(l);\ + memmove(&buf[blen], s, l);\ + blen += (l);\ +} + +#define GETARG() \ + ((argc == 1)?Fail("too few argument."):(argc--, argv++, argv[0])) + + fmt = (struct RString*)GETARG(); + Check_Type(fmt, T_STRING); + + blen = 0; + bsiz = 120; + buf = ALLOC_N(char, bsiz); + end = fmt->ptr + fmt->len; + + for (p = fmt->ptr; p < end; p++) { + char *t; + + for (t = p; t < end && *t != '%'; t++) ; + CHECK(t - p); + PUSH(p, t - p); + if (t >= end) { + /* end of fmt string */ + goto sprint_exit; + } + p = t + 1; /* skip `%' */ + + retry: + switch (*p) { + default: + if (isprint(*p)) + Fail("malformed format string - %%%c", *p); + else + Fail("malformed format string"); + break; + + case ' ': + p++; + goto retry; + + case '#': + flags |= FSHARP; + p++; + goto retry; + + case '+': + flags |= FPLUS; + p++; + goto retry; + + case '-': + flags |= FMINUS; + p++; + goto retry; + + case '0': + flags |= FZERO; + p++; + goto retry; + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + flags |= FWIDTH; + width = 0; + for (p; p < end && isdigit(*p); p++) { + width = 10 * width + (*p - '0'); + } + if (p >= end) { + Fail("malformed format string - %%[0-9]"); + } + goto retry; + + case '*': + if (flags & FWIDTH) { + Fail("width given twice"); + } + + flags |= FWIDTH; + width = GETARG(); + width = NUM2INT(width); + if (width < 0) { + flags |= FMINUS; + width = - width; + } + p++; + goto retry; + + case '.': + if (flags & FPREC) { + Fail("precision given twice"); + } + + prec = 0; + p++; + if (*p == '0') flags |= FZERO; + if (*p == '*') { + prec = GETARG(); + prec = NUM2INT(prec); + if (prec > 0) + flags |= FPREC; + p++; + goto retry; + } + + for (p; p < end && isdigit(*p); p++) { + prec = 10 * prec + (*p - '0'); + } + if (p >= end) { + Fail("malformed format string - %%.[0-9]"); + } + if (prec > 0) + flags |= FPREC; + goto retry; + + case '%': + PUSH("%", 1); + break; + + case 'c': + { + VALUE val = GETARG(); + char c; + + c = NUM2INT(val) & 0xff; + PUSH(&c, 1); + } + break; + + case 's': + { + VALUE arg = GETARG(); + int len; + char fbuf[32]; +#define MIN(a,b) ((a)<(b)?(a):(b)) + + str = obj_as_string(arg); + fmt_setup(fbuf, 's', flags, width, prec); + if (flags&FPREC) { + CHECK(prec); + } + else if ((flags&FWIDTH) && width > RSTRING(str)->len) { + CHECK(width); + } + else { + CHECK(RSTRING(str)->len); + } + sprintf(&buf[blen], fbuf, RSTRING(str)->ptr); + blen += strlen(&buf[blen]); + } + break; + + case 'b': + case 'B': + case 'o': + case 'x': + { + VALUE val = GETARG(); + char fbuf[32], *s, *t, *end; + int v, base; + + GC_LINK; + GC_PRO(val); + bin_retry: + switch (TYPE(val)) { + case T_FIXNUM: + v = FIX2INT(val); + val = int2big(v); + break; + case T_FLOAT: + v = RFLOAT(val)->value; + val = int2big(v); + break; + case T_STRING: + val = str2inum(RSTRING(val)->ptr, 0); + goto bin_retry; + case T_BIGNUM: + val = Fbig_clone(val); + break; + default: + WrongType(val, T_FIXNUM); + break; + } + if (*p == 'x') base = 16; + else if (*p == 'o') base = 8; + else if (*p == 'b' || *p == 'B') base = 2; + if (*p != 'B' && !RBIGNUM(val)->sign) big_2comp(val); + val = big2str(val, base); + fmt_setup(fbuf, 's', flags, width, prec); + + s = t = RSTRING(val)->ptr; + end = s + RSTRING(val)->len; + if (*s == '-' && *p != 'B') { + s++; t++; + if (base == 16) { + while (t<end && *t == 'f') t++; + if (*t == 'e') { + *t = '2'; + } + else if (*t == 'd') { + *t = '5'; + } + else if (*t == 'c') { + *t = '4'; + } + else if (*t < '8') { + *--t = '1'; + } + } + if (base == 8) { + while (t<end && *t == '7') t++; + if (*t == '6') { + *t = '2'; + } + else if (*t < '4') { + *--t = '1'; + } + } + if (base == 2) { + while (t<end && *t == '1') t++; + t--; + } + while (t<end) *s++ = *t++; + *s = '\0'; + } + s = RSTRING(val)->ptr; + if (flags&FPREC) { + CHECK(prec); + } + else if ((flags&FWIDTH) && width > end - s) { + CHECK(width); + } + else { + CHECK(s - end); + } + sprintf(&buf[blen], fbuf, s); + blen += strlen(&buf[blen]); + obj_free(val); + GC_UNLINK; + } + break; + + case 'd': + case 'D': + case 'O': + case 'X': + { + VALUE val = GETARG(); + char fbuf[32], c = *p; + int bignum = 0, base; + int v; + + if (c == 'D') c = 'd'; + GC_LINK; + GC_PRO(val); + 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: + WrongType(val, T_FIXNUM); + break; + } + + if (bignum) { + fmt_setup(fbuf, 's', flags, width, prec); + + if (flags&FPREC) { + CHECK(prec); + } + else if ((flags&FWIDTH) && width > RSTRING(val)->len) { + CHECK(width); + } + else { + CHECK(RSTRING(val)->len); + } + sprintf(&buf[blen], fbuf, RSTRING(val)->ptr); + blen += strlen(&buf[blen]); + } + else { + fmt_setup(fbuf, c, flags, width, prec); + + CHECK(11); + if (v < 0 && (c == 'X' || c == 'O')) { + v = -v; + PUSH("-", 1); + } + sprintf(&buf[blen], fbuf, v); + blen += strlen(&buf[blen]); + } + GC_UNLINK; + } + break; + + case 'f': + case 'g': + case 'e': + { + VALUE val = GETARG(); + double fval; + char fbuf[32]; + double big2dbl(); + double atof(); + + switch (TYPE(val)) { + case T_FIXNUM: + fval = FIX2INT(val); + break; + case T_FLOAT: + fval = RFLOAT(val)->value; + break; + case T_BIGNUM: + fval = big2dbl(val); + break; + case T_STRING: + fval = atof(RSTRING(val)->ptr); + break; + default: + WrongType(val, T_FLOAT); + break; + } + + fmt_setup(fbuf, *p, flags, width, prec); + + CHECK(22); + sprintf(&buf[blen], fbuf, fval); + blen += strlen(&buf[blen]); + } + break; + } + flags = FNONE; + } + + sprint_exit: + GC_UNLINK; + if (verbose && argc > 1) { + Fail("too many argument for format string"); + } + result = str_new(buf, blen); + free(buf); + + return result; +} + +static void +fmt_setup(buf, c, flags, width, prec) + char *buf, c; + int flags, width, prec; +{ + *buf++ = '%'; + if (flags & FSHARP) *buf++ = '#'; + if (flags & FPLUS) *buf++ = '+'; + if (flags & FMINUS) *buf++ = '-'; + if (flags & FZERO) *buf++ = '0'; + + if (flags & FWIDTH) { + sprintf(buf, "%d", width); + buf += strlen(buf); + } + + if (flags & FPREC) { + sprintf(buf, ".%d", prec); + buf += strlen(buf); + } + + *buf++ = c; + *buf = '\0'; +} @@ -0,0 +1,365 @@ +/* This is a general purpose hash table package written by Peter Moore @ UCB. */ + +static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; +#ifndef lint +static char *rcsid = "$Header: /work/cvsroot/ruby/st.c,v 1.2 1994/06/27 15:48:41 matz Exp $"; +#endif + +#include <stdio.h> +#include "st.h" + +extern void *xmalloc(); +static 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)) + + /* + * DEFAULT_MAX_DENSITY is the default for the largest we allow the + * average number of items per bin before increasing the number of + * bins + * + * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins + * allocated initially + * + * DEFAULT_GROW_FACTOR is the amount the hash table is expanded after + * the density has reached max_density + */ + +#define EQUAL(func, x, y) \ + ((func == ST_NUMCMP) ? ((x) == (y)) : ((*func)((x), (y)) == 0)) + +/*#define do_hash(key, table) (*table->hash)(key, table->num_bins)*/ + +#define do_hash(key, table)\ + ((table->hash == ST_PTRHASH) ? (((int) (key) >> 2) % table->num_bins) :\ + (table->hash == ST_NUMHASH) ? ((int) (key) % table->num_bins) :\ + (*table->hash)((key), table->num_bins)) + +st_table *st_init_table_with_params(compare, hash, size, density, grow_factor, + reorder_flag) +int (*compare)(); +int (*hash)(); +int size; +int density; +double grow_factor; +int reorder_flag; +{ + st_table *tbl; + + tbl = alloc(st_table); + tbl->compare = compare; + tbl->hash = hash; + tbl->num_entries = 0; + tbl->max_density = density; + tbl->grow_factor = grow_factor; + tbl->reorder_flag = reorder_flag; + tbl->num_bins = size; + tbl->bins = + (st_table_entry **) Calloc((unsigned)size, sizeof(st_table_entry *)); + return tbl; +} + +st_table *st_init_table(compare, hash) +int (*compare)(); +int (*hash)(); +{ + return st_init_table_with_params(compare, hash, ST_DEFAULT_INIT_TABLE_SIZE, + ST_DEFAULT_MAX_DENSITY, + ST_DEFAULT_GROW_FACTOR, + ST_DEFAULT_REORDER_FLAG); +} + +st_free_table(table) +st_table *table; +{ + register st_table_entry *ptr, *next; + int i; + + for(i = 0; i < table->num_bins ; i++) { + ptr = table->bins[i]; + while (ptr != nil(st_table_entry)) { + next = ptr->next; + free((char *) ptr); + ptr = next; + } + } + free((char *) table->bins); + free((char *) table); +} + +#define PTR_NOT_EQUAL(table, ptr, key)\ +(ptr != nil(st_table_entry) && !EQUAL(table->compare, 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)) {\ + ptr = ptr->next;\ + }\ + if (ptr->next != nil(st_table_entry) && (table)->reorder_flag) {\ + st_table_entry *_tmp = (ptr)->next;\ + (ptr)->next = (ptr)->next->next;\ + _tmp->next = (table)->bins[hash_val];\ + (table)->bins[hash_val] = _tmp;\ + ptr = _tmp;\ + } else {\ + ptr = ptr->next;\ + }\ +} + +st_lookup(table, key, value) +st_table *table; +register char *key; +char **value; +{ + int hash_val; + register st_table_entry *ptr; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, ptr, hash_val); + + if (ptr == nil(st_table_entry)) { + return 0; + } else { + if (value != nil(char *)) *value = ptr->record; + return 1; + } +} + +#define ADD_DIRECT(table, key, value, hash_val, tbl)\ +{\ + if (table->num_entries/table->num_bins > table->max_density) {\ + rehash(table);\ + hash_val = do_hash(key,table);\ + }\ + \ + tbl = alloc(st_table_entry);\ + \ + tbl->key = key;\ + tbl->record = value;\ + tbl->next = table->bins[hash_val];\ + table->bins[hash_val] = tbl;\ + table->num_entries++;\ +} + +st_insert(table, key, value) +register st_table *table; +register char *key; +char *value; +{ + int hash_val; + st_table_entry *tbl; + register st_table_entry *ptr; + + hash_val = do_hash(key, table); + + FIND_ENTRY(table, ptr, hash_val); + + if (ptr == nil(st_table_entry)) { + ADD_DIRECT(table,key,value,hash_val,tbl); + return 0; + } else { + ptr->record = value; + return 1; + } +} + +st_add_direct(table, key, value) +st_table *table; +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); +} + +st_find_or_add(table, key, slot) +st_table *table; +char *key; +char ***slot; +{ + int hash_val; + st_table_entry *tbl, *ptr; + + 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; + } +} + +static 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 = table->grow_factor*old_num_bins; + + if (table->num_bins%2 == 0) { + table->num_bins += 1; + } + + table->num_entries = 0; + table->bins = + (st_table_entry **) Calloc((unsigned) table->num_bins, + sizeof(st_table_entry *)); + + for(i = 0; i < old_num_bins ; i++) { + ptr = old_bins[i]; + while (ptr != nil(st_table_entry)) { + next = ptr->next; + hash_val = do_hash(ptr->key, table); + ptr->next = table->bins[hash_val]; + table->bins[hash_val] = ptr; + table->num_entries++; + ptr = next; + } + } + free((char *) old_bins); +} + +st_table *st_copy(old_table) +st_table *old_table; +{ + st_table *new_table; + st_table_entry *ptr, *tbl; + int i, num_bins = old_table->num_bins; + + new_table = alloc(st_table); + if (new_table == nil(st_table)) { + return nil(st_table); + } + + *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); + } + + for(i = 0; i < num_bins ; i++) { + new_table->bins[i] = nil(st_table_entry); + ptr = old_table->bins[i]; + while (ptr != nil(st_table_entry)) { + tbl = alloc(st_table_entry); + if (tbl == nil(st_table_entry)) { + free((char *) new_table->bins); + free((char *) new_table); + return nil(st_table); + } + *tbl = *ptr; + tbl->next = new_table->bins[i]; + new_table->bins[i] = tbl; + ptr = ptr->next; + } + } + return new_table; +} + +st_delete(table, key, value) +register st_table *table; +register char **key; +char **value; +{ + int hash_val; + st_table_entry *tmp; + register st_table_entry *ptr; + + hash_val = do_hash(*key, table); + + ptr = table->bins[hash_val]; + + if (ptr == nil(st_table_entry)) { + if (value != nil(char *)) *value = nil(char); + return 0; + } + + if (EQUAL(table->compare, *key, ptr->key)) { + table->bins[hash_val] = ptr->next; + table->num_entries--; + if (value != nil(char *)) *value = ptr->record; + *key = ptr->key; + free((char *) ptr); + return 1; + } + + for(; ptr->next != nil(st_table_entry); ptr = ptr->next) { + if (EQUAL(table->compare, ptr->next->key, *key)) { + tmp = ptr->next; + ptr->next = ptr->next->next; + table->num_entries--; + if (value != nil(char *)) *value = tmp->record; + *key = tmp->key; + free((char *) tmp); + return 1; + } + } + + return 0; +} + +st_foreach(table, func, arg) +st_table *table; +enum st_retval (*func)(); +char *arg; +{ + st_table_entry *ptr, *last, *tmp; + enum st_retval retval; + 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);) { + retval = (*func)(ptr->key, ptr->record, arg); + switch (retval) { + case ST_CONTINUE: + last = ptr; + ptr = ptr->next; + break; + case ST_STOP: + return; + case ST_DELETE: + tmp = ptr; + if (last == nil(st_table_entry)) { + table->bins[i] = ptr->next; + } else { + last->next = ptr->next; + } + ptr = ptr->next; + free((char *) tmp); + } + } + } +} + +st_strhash(string, modulus) +register char *string; +int modulus; +{ + register int val = 0; + register int c; + + while ((c = *string++) != '\0') { + val = val*997 + c; + } + + return ((val < 0) ? -val : val)%modulus; +} @@ -0,0 +1,57 @@ +/* This is a general purpose hash table package written by Peter Moore @ UCB. */ + +/* @(#) st.h 5.1 89/12/14 */ + +#ifndef ST_INCLUDED + +#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_table { + int (*compare)(); + int (*hash)(); + int num_bins; + int num_entries; + int max_density; + int reorder_flag; + double grow_factor; + st_table_entry **bins; +}; + +#define st_is_member(table,key) st_lookup(table,key,(char **) 0) + +enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE}; + +int st_delete(), st_insert(), st_foreach(), st_free_table(); +int st_lookup(), st_find_or_add(), st_add_direct(); +st_table *st_init_table(), *st_init_table_with_params(); +st_table *st_copy(); + +#define ST_NUMCMP ((int (*)()) 0) +#define ST_NUMHASH ((int (*)()) -2) + +#define ST_PTRCMP ((int (*)()) 0) +#define ST_PTRHASH ((int (*)()) -1) + +#define st_numcmp ST_NUMCMP +#define st_numhash ST_NUMHASH +#define st_ptrcmp ST_PTRCMP +#define st_ptrhash ST_PTRHASH + +#define ST_DEFAULT_MAX_DENSITY 5 +#define ST_DEFAULT_INIT_TABLE_SIZE 11 +#define ST_DEFAULT_GROW_FACTOR 2.0 +#define ST_DEFAULT_REORDER_FLAG 0 + +int st_strhash(); + +#endif ST_INCLUDED diff --git a/string.c b/string.c new file mode 100644 index 0000000000..57198e4e87 --- /dev/null +++ b/string.c @@ -0,0 +1,1552 @@ +/************************************************ + + string.c - + + $Author: matz $ + $Date: 1994/06/27 15:48:44 $ + created at: Mon Aug 9 17:12:58 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "re.h" + +#include <stdio.h> +#include <ctype.h> + +VALUE C_String; + +#define STRLEN(s) RSTRING(s)->len + +VALUE +str_new(ptr, len) + char *ptr; + UINT len; +{ + NEWOBJ(str, struct RString); + OBJSETUP(str, C_String, T_STRING); + + str->len = len; + str->ptr = ALLOC_N(char,len+1); + if (ptr) { + memmove(str->ptr, ptr, len); + } + str->ptr[len] = '\0'; + str->orig = Qnil; + return (VALUE)str; +} + +VALUE +str_new2(ptr) + char *ptr; +{ + return str_new(ptr, strlen(ptr)); +} + +VALUE +str_new3(str) + struct RString *str; +{ + NEWOBJ(str2, struct RString); + OBJSETUP(str2, C_String, T_STRING); + + str2->len = str->len; + str2->ptr = str->ptr; + str2->orig = str; + + return (VALUE)str2; +} + +#define as_str(str) (struct RString*)obj_as_string(str) + +static ID pr_str = Qnil; + +VALUE +obj_as_string(obj) + VALUE obj; +{ + VALUE str; + + if (TYPE(obj) == T_STRING) { + return obj; + } + str = rb_funcall(obj, pr_str, 0); + if (TYPE(str) != T_STRING) + return Fkrn_to_s(obj); + return str; +} + +VALUE +Fstr_clone(str) + struct RString *str; +{ + VALUE obj; + + if (str->orig) + obj = str_new3(str->orig); + else + obj = str_new(str->ptr, str->len); + CLONESETUP(obj, str); + return obj; +} + +static VALUE +Fstr_new(class, str) + VALUE class; + struct RString *str; +{ + Check_Type(str, T_STRING); + { + NEWOBJ(str2, struct RString); + OBJSETUP(str2, class, T_STRING); + + str2->len = str->len; + str2->ptr = ALLOC_N(char, str->len+1); + if (str2->ptr) { + memmove(str2->ptr, str->ptr, str->len); + } + str2->ptr[str->len] = '\0'; + str2->orig = Qnil; + return (VALUE)str2; + } +} + +static VALUE +Fstr_length(str) + struct RString *str; +{ + return INT2FIX(str->len); +} + +VALUE +Fstr_plus(str1, str2) + struct RString *str1, *str2; +{ + struct RString *str3; + + GC_LINK; + GC_PRO3(str2, as_str(str2)); + str3 = (struct RString*)str_new(0, str1->len+str2->len); + memcpy(str3->ptr, str1->ptr, str1->len); + memcpy(str3->ptr+str1->len, str2->ptr, str2->len); + str3->ptr[str3->len] = '\0'; + GC_UNLINK; + + return (VALUE)str3; +} + +VALUE +Fstr_times(str, times) + struct RString *str; + VALUE times; +{ + struct RString *str2; + int i; + + times = NUM2INT(times); + + str2 = (struct RString*)str_new(0, str->len*times); + for (i=0; i<times; i++) { + memmove(str2->ptr+(i*str->len), str->ptr, str->len); + } + str2->ptr[str2->len] = '\0'; + + return (VALUE)str2; +} + +extern VALUE C_Range; + +static VALUE +Fstr_dot2(left, right) + VALUE left, right; +{ + extern VALUE C_Range; + VALUE str; + + Check_Type(right, T_STRING); + str = range_new(C_Range, left, right); + return str; +} + +VALUE +str_substr(str, start, len) + struct RString *str; + int start, len; +{ + struct RString *str2; + + if (start < 0) { + start = str->len + start; + } + if (str->len <= start) { + Fail("index %d out of range [0..%d]", start, str->len-1); + } + if (len < 0) { + Fail("Negative length %d", len); + } + + str2 = (struct RString*)str_new(str->ptr+start, len); + + return (VALUE)str2; +} + +VALUE +str_subseq(str, beg, end) + struct RString *str; + int beg, end; +{ + int len; + + if (beg < 0) { + beg = str->len + beg; + if (beg < 0) beg = 0; + } + if (end < 0) { + end = str->len + end; + if (end < 0) end = 0; + } + + if (beg > end) { + int tmp; + + if (verbose) { + Warning("start %d is bigger than end %d", beg, end); + } + tmp = beg; beg = end; end = tmp; + } + + if (beg >= str->len) { + return str_new(0, 0); + } + if (str->len < end) { + end = str->len; + } + + len = end - beg + 1; + if (len < 0) { + Fail("end %d too small(size %d)", end, str->len); + } + + return str_substr(str, beg, len); +} + +extern VALUE ignorecase; + +void +str_modify(str) + struct RString *str; +{ + if (str->orig == Qnil) return; + str->ptr = ALLOC_N(char, str->len+1); + if (str->ptr) { + memcpy(str->ptr, str->orig->ptr, str->len+1); + } + str->orig = Qnil; +} + +VALUE +str_grow(str, len) + struct RString *str; + UINT len; +{ + str_modify(str); + if (len > 0) { + REALLOC_N(str->ptr, char, len + 1); + str->len = len; + str->ptr[len] = '\0'; /* sentinel */ + } + return (VALUE)str; +} + +VALUE +str_cat(str, ptr, len) + struct RString *str; + char *ptr; + UINT len; +{ + str_modify(str); + + if (len > 0) { + REALLOC_N(str->ptr, char, str->len + len + 1); + if (ptr) + memmove(str->ptr + str->len, ptr, len); + str->len += len; + str->ptr[str->len] = '\0'; /* sentinel */ + } + return (VALUE)str; +} + +static VALUE +Fstr_concat(str1, str2) + struct RString *str1, *str2; +{ + str2 = as_str(str2); + str_cat(str1, str2->ptr, str2->len); + return (VALUE)str1; +} + +static char +str_next(s) + char *s; +{ + char c = *s; + + /* control code */ + if (c < ' ') return 0; + + /* numerics */ + if ('0' <= c && c < '9') (*s)++; + else if (c == '9') { + *s = '0'; + return '1'; + } + /* small alphabets */ + else if ('a' <= c && c < 'z') (*s)++; + else if (c == 'z') { + return *s = 'a'; + } + /* capital alphabets */ + else if ('A' <= c && c < 'Z') (*s)++; + else if (c == 'Z') { + return *s = 'A'; + } + return 0; +} + +static VALUE +Fstr_next(orig) + struct RString *orig; +{ + struct RString *str, *str2; + char *sbeg, *s; + char c = -1; + + GC_LINK; + GC_PRO3(str, (struct RString*)str_new(orig->ptr, orig->len)); + + sbeg = str->ptr; s = sbeg + str->len - 1; + + while (sbeg <= s) { + if (isalnum(*s) && (c = str_next(s)) == Qnil) break; + s--; + } + if (s < sbeg && c != -1) { + GC_PRO3(str2, (struct RString*)str_new(0, str->len+1)); + str2->ptr[0] = c; + memmove(str2->ptr+1, str->ptr, str->len); + obj_free(str); + str = str2; + } + GC_UNLINK; + + return (VALUE)str; +} + +static +str_hash(str) + struct RString *str; +{ + int len = str->len; + unsigned char *p = (unsigned char*)str->ptr; + int key = 0; + + if (ignorecase) { + while (len--) { + key = key*65599 + *p; + } + } + else { + while (len--) { + key = key*65599 + toupper(*p); + } + } + return key; +} + +static VALUE +Fstr_hash(str) + VALUE str; +{ + int key = str_hash(str); + return INT2FIX(key); +} + +#define min(a,b) (((a)>(b))?(b):(a)) + +int +str_cmp(str1, str2) + struct RString *str1, *str2; +{ + UINT len; + int retval; + + if (ignorecase != Qnil) { + return str_cicmp(str1, str2); + } + + len = min(str1->len, str2->len); + retval = memcmp(str1->ptr, str2->ptr, len); + if (retval == 0) { + return str1->ptr[len] - str2->ptr[len]; + } + return retval; +} + +static VALUE +Fstr_equal(str1, str2) + struct RString *str1, *str2; +{ + if (TYPE(str2) != T_STRING) + return FALSE; + + if (str1->len == str2->len + && str_cmp(str1, str2) == 0) { + return TRUE; + } + return FALSE; +} + +static VALUE +Fstr_cmp(str1, str2) + VALUE str1, str2; +{ + int result; + + Check_Type(str2, T_STRING); + result = str_cmp(str1, str2); + return INT2FIX(result); +} + +Regexp * make_regexp(); +VALUE Freg_match(); + +static VALUE +Fstr_match(this, other) + struct RString *this, *other; +{ + VALUE reg; + int start; + + switch (TYPE(other)) { + case T_REGEXP: + return Freg_match(other, this); + case T_STRING: + reg = re_regcomp(other); + start = research(reg, this, 0, ignorecase); + if (start == -1) { + return FALSE; + } + return INT2FIX(start); + default: + Fail("type mismatch"); + break; + } +} + +static VALUE +Fstr_match2(str) + struct RString *str; +{ + extern VALUE rb_lastline; + VALUE reg; + int start; + + if (TYPE(rb_lastline) != T_STRING) + Fail("$_ is not a string"); + + reg = re_regcomp(str); + start = research(reg, rb_lastline, 0, ignorecase); + if (start == -1) { + return Qnil; + } + return INT2FIX(start); +} + +static int +str_index(str, sub, offset) + struct RString *str, *sub; + int offset; +{ + char *s, *e, *p; + int len; + + if (str->len - offset < sub->len) return -1; + s = str->ptr+offset; + p = sub->ptr; + len = sub->len; + e = s + str->len - len + 1; + while (s < e) { + if (*s == *(sub->ptr) && memcmp(s, p, len) == 0) { + return (s-(str->ptr)); + } + s++; + } + return -1; +} + +static VALUE +Fstr_index(str, args) + struct RString *str; + VALUE args; +{ + struct RString *sub; + VALUE initpos; + int pos; + + if (rb_scan_args(args, "11", &sub, &initpos) == 2) { + pos = NUM2INT(initpos); + } + else { + pos = 0; + } + + switch (TYPE(sub)) { + case T_REGEXP: + pos = research(sub, str, pos, ignorecase); + break; + + case T_STRING: + pos = str_index(str, sub, pos); + break; + + default: + Fail("Type mismatch: %s given", rb_class2name(CLASS_OF(sub))); + } + + if (pos == -1) return Qnil; + return INT2FIX(pos); +} + +static VALUE +Fstr_rindex(str, args) + struct RString *str; + VALUE args; +{ + struct RString *sub; + VALUE initpos; + int pos, len; + char *s, *sbeg, *t; + + if (rb_scan_args(args, "11", &sub, &initpos) == 2) { + pos = NUM2INT(initpos); + if (pos >= str->len) pos = str->len; + } + else { + pos = str->len; + } + + Check_Type(sub, T_STRING); + if (pos > str->len) return Qnil; /* substring longer than string */ + sbeg = str->ptr; s = s + pos - sub->len; + t = sub->ptr; + len = sub->len; + while (sbeg <= s) { + if (*s == *t && memcmp(s, t, len) == 0) { + return INT2FIX(s - sbeg); + } + s--; + } + return Qnil; +} + +static VALUE +Fstr_aref_internal(str, indx) + struct RString *str; + VALUE indx; +{ + int idx; + + switch (TYPE(indx)) { + case T_FIXNUM: + idx = FIX2UINT(indx); + + if (idx < 0) { + idx = str->len + idx; + } + if (idx < 0 || str->len <= idx) { + Fail("index %d out of range [0..%d]", idx, str->len-1); + } + return (VALUE)INT2FIX(str->ptr[idx] & 0xff); + + case T_REGEXP: + if (Fstr_index(str, indx)) + return re_last_match(0); + return Qnil; + + case T_STRING: + if (str_index(str, indx, 0)) return indx; + return Qnil; + + default: + /* check if indx is Range */ + if (obj_is_kind_of(indx, C_Range)) { + int beg, end; + + beg = rb_iv_get(indx, "start"); beg = NUM2INT(beg); + end = rb_iv_get(indx, "end"); end = NUM2INT(end); + if (beg > end) { + int tmp; + + if (verbose) { + Warning("start %d is bigger than end %d", beg, end); + } + tmp = beg; beg = end; end = tmp; + } + + return str_subseq(str, beg, end); + } + Fail("Invalid index for string"); + } +} + +static VALUE +Fstr_aref(str, args) + struct RString *str; + VALUE args; +{ + VALUE arg1, arg2; + + if (rb_scan_args(args, "11", &arg1, &arg2) == 2) { + return str_substr(str, NUM2INT(arg1), NUM2INT(arg2)); + } + return Fstr_aref_internal(str, arg1); +} + +static void +str_replace(str, beg, len, val) + struct RString *str, *val; + int beg, len; +{ + if (len < val->len) { + /* expand string */ + REALLOC_N(str->ptr, char, str->len+val->len-len+1); + } + + memmove(str->ptr+beg+val->len, str->ptr+beg+len, str->len-(beg+len)); + memmove(str->ptr+beg, val->ptr, val->len); + str->len += val->len - len; + str->ptr[str->len] = '\0'; +} + +static void +str_replace2(str, beg, end, val) + struct RString *str, *val; + int beg, end; +{ + int len; + + if (beg < 0) { + beg = str->len + beg; + } + if (str->len <= beg) { + Fail("start %d too big", beg); + } + if (end < 0) { + end = str->len + end; + } + if (end < 0 || str->len <= end) { + Fail("end %d too big", end); + } + len = end - beg + 1; /* length of substring */ + if (len < 0) { + Fail("end %d too small", end); + } + + str_replace(str, beg, len, val); +} + +static VALUE +str_sub(str, pat, val, once) + struct RString *str; + struct RRegexp *pat; + VALUE val; + int once; +{ + VALUE sub; + int beg, end, offset, n; + + GC_LINK; + GC_PRO2(sub); + for (offset=0, n=0; + (beg=research(pat, str, offset, ignorecase)) >= 0; + offset=RREGEXP(pat)->ptr->regs.start[0]+STRLEN(val)) { + end = RREGEXP(pat)->ptr->regs.end[0]-1; + sub = re_regsub(val); + str_replace2(str, beg, end, sub); + n++; + if (once) break; + } + GC_UNLINK; + if (n == 0) return Qnil; + return INT2FIX(n); +} + +static VALUE +Fstr_aset_internal(str, indx, val) + struct RString *str; + VALUE indx, val; +{ + int idx, beg, end, offset; + + switch (TYPE(indx)) { + case T_FIXNUM: + idx = NUM2INT(indx); + if (idx < 0) { + idx = str->len + idx; + } + if (idx < 0 || str->len <= idx) { + Fail("index %d out of range [0..%d]", idx, str->len-1); + } + str->ptr[idx] = FIX2UINT(val) & 0xff; + return val; + + case T_REGEXP: + str_sub(str, indx, val, 0); + 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); + } + if (offset == 0) Fail("Not a substring"); + return val; + + default: + /* check if indx is Range */ + if (obj_is_kind_of(indx, C_Range)) { + Check_Type(val, T_STRING); + + beg = rb_iv_get(indx, "start"); beg = NUM2INT(beg); + end = rb_iv_get(indx, "end"); end = NUM2INT(end); + if (beg > end) { + int tmp; + + if (verbose) { + Warning("start %d is bigger than end %d", beg, end); + } + tmp = beg; beg = end; end = tmp; + } + + str_replace2(str, beg, end, val); + return val; + } + Fail("Invalid index for string"); + } +} + +static VALUE +Fstr_aset(str, args) + struct RString *str; + VALUE args; +{ + VALUE arg1, arg2, arg3; + + str_modify(str); + + if (rb_scan_args(args, "21", &arg1, &arg2, &arg3) == 3) { + int beg, len; + + Check_Type(arg3, T_STRING); + + beg = NUM2INT(arg1); + if (beg < 0) { + beg = str->len + beg; + if (beg < 0) Fail("start %d too small", beg); + } + len = NUM2INT(arg2); + if (len < 0) Fail("length %d too small", len); + if (beg + len > str->len) { + len = str->len - beg; + } + str_replace(str, beg, len, arg3); + return arg3; + } + return Fstr_aset_internal(str, arg1, arg2); +} + +static VALUE +Fstr_sub_internal(str, pat, val, once) + VALUE str, pat, val; + int once; +{ + VALUE reg, result; + + Check_Type(val, T_STRING); + str_modify(str); + + switch (TYPE(pat)) { + case T_REGEXP: + return str_sub(str, pat, val, once); + + case T_STRING: + reg = re_regcomp(pat); + result = str_sub(str, reg, val, once); + return result; + + default: + /* type failed */ + Check_Type(pat, T_REGEXP); + } + return Qnil; /* not reached */ +} + +static VALUE +Fstr_sub(str, pat, val) + VALUE str, pat, val; +{ + return Fstr_sub_internal(str, pat, val, 1); +} + +static VALUE +Fstr_gsub(str, pat, val) + VALUE str, pat, val; +{ + return Fstr_sub_internal(str, pat, val, 0); +} + +extern VALUE rb_lastline; + +static VALUE +Fsub(obj, pat, val) + VALUE obj, pat, val; +{ + Check_Type(rb_lastline, T_STRING); + return Fstr_sub_internal(rb_lastline, pat, val, 1); +} + +static VALUE +Fgsub(obj, pat, val) + VALUE obj, pat, val; +{ + Check_Type(rb_lastline, T_STRING); + return Fstr_sub_internal(rb_lastline, pat, val, 0); +} + +static VALUE +Fstr_reverse(str) + struct RString *str; +{ + VALUE obj = str_new(0, str->len); + char *s, *e, *p; + + s = str->ptr; e = s + str->len - 1; + p = RSTRING(obj)->ptr; + + while (e >= s) { + *p++ = *e--; + } + + return obj; +} + +static VALUE +Fstr_to_i(str) + struct RString *str; +{ + return str2inum(str->ptr, 10); +} + +static VALUE +Fstr_to_f(str) + struct RString *str; +{ + double atof(); + double f = atof(str->ptr); + + return float_new(f); +} + +static VALUE +Fstr_to_s(str) + VALUE str; +{ + return str; +} + +static VALUE +Fstr_inspect(str) + struct RString *str; +{ + char buf[160]; + char *p, *pend; + char *b, *bend; + +#define CHECK(n) if (b+n > bend) break; + + p = str->ptr; pend = p + str->len; + b = buf; bend = b + sizeof buf - (str->len>150?4:2); + *b++ = '"'; + while (p < pend) { + char c = *p++; + if (isprint(c)) { + CHECK(1); + *b++ = c; + } + else if (ismbchar(c)) { + CHECK(2); + *b++ = c; + *b++ = *p++; + } + else if (c == '\n') { + CHECK(2); + *b++ = '\\'; + *b++ = 'n'; + } + else if (c == '\r') { + CHECK(2); + *b++ = '\\'; + *b++ = 'r'; + } + else if (c == '\t') { + CHECK(2); + *b++ = '\\'; + *b++ = 't'; + } + else if (c == '\f') { + CHECK(2); + *b++ = '\\'; + *b++ = 'f'; + } + else if (c == '\13') { + CHECK(2); + *b++ = '\\'; + *b++ = 'v'; + } + else if (c == '\a') { + CHECK(2); + *b++ = '\\'; + *b++ = 'a'; + } + else if (c == 033) { + CHECK(2); + *b++ = '\\'; + *b++ = 'e'; + } + else if (iscntrl(c)) { + CHECK(2); + *b++ = '^'; + *b++ = c; + } + else { + CHECK(1); + *b++ = c; + } + } + *b++ = '"'; + if (p < pend) { + bend = buf + sizeof buf; + while (b < bend) { + *b++ = '.'; + } + } + return str_new(buf, b - buf); +} + +static VALUE +Fstr_toupper(str) + struct RString *str; +{ + char *s; + int i; + + str_modify(str); + s = str->ptr; + for (i=0; i < str->len; i++) { + if (islower(*s)) { + *s = toupper(*s); + } + *s++; + } + + return (VALUE)str; +} + +static VALUE +Fstr_tolower(str) + struct RString *str; +{ + char *s; + int i; + + str_modify(str); + s = str->ptr; + for (i=0; i < str->len; i++) { + if (isupper(*s)) { + *s = tolower(*s); + } + *s++; + } + + return (VALUE)str; +} + +static VALUE +Fstr_ucfirst(str) + struct RString *str; +{ + char *s, *send; + int i; + + str_modify(str); + s = str->ptr; send = s + str->len; + if (islower(*s)) + *s = toupper(*s); + return (VALUE)str; +} + +static VALUE +Fstr_lcfirst(str) + struct RString *str; +{ + char *s, *send; + int i; + + str_modify(str); + s = str->ptr; send = s + str->len; + if (isupper(*s)) + *s = tolower(*s); + return (VALUE)str; +} + +struct tr { + int last, max; + char *p, *pend; +} trsrc, trrepl; + +static +trnext(t) + struct tr *t; +{ + while (t->p < t->pend) { + if (t->max) { + if (++t->last < t->max) + return t->last; + t->last = t->max = 0; + } + else if (t->last && *t->p == '-') { + t->p++; + t->max = *t->p; + if (t->p == t->pend) { + t->p--; + return '-'; + } + else if (t->max < t->last) { + t->last = t->max - 1; + return '-'; + } + continue; + } + return t->last = *t->p++; + } + return -1; +} + +static VALUE +Fstr_tr(str, src, repl) + struct RString *str, *src, *repl; +{ + struct tr trsrc, trrepl; + char trans[256]; + int cflag = 0; + int i, c, save; + char *s, *send, *t; + + Check_Type(src, T_STRING); + trsrc.p = src->ptr; trsrc.pend = trsrc.p + src->len; + if (src->len > 2 && src->ptr[0] == '^') { + cflag++; + trsrc.p++; + } + Check_Type(repl, T_STRING); + trrepl.p = repl->ptr; trrepl.pend = trrepl.p + repl->len; + trsrc.last = trrepl.last = trsrc.max = trrepl.max = 0; + + for (i=0; i<256; i++) { + trans[i] = cflag ? 1 : 0; + } + + while ((c = trnext(&trsrc)) >= 0) { + trans[c & 0xff] = cflag ? 0 : 1; + } + + c = 0; + for (i=0; i<256; i++) { + if (trans[i] == 0) { + trans[i] = i; + } + else { + c = trnext(&trrepl); + if (c == -1) { + trans[i] = trrepl.last; + } + else { + trans[i] = c; + } + } + } + + str_modify(str); + + t = s = str->ptr; send = s + str->len; + while (s < send) { + c = *s++ & 0xff; + c = trans[c] & 0xff; + *t++ = c; + } + *t = '\0'; + str->len = t - str->ptr; + + return (VALUE)str; +} + +static void +tr_setup_table(str, table) + struct RString *str; + char table[256]; +{ + struct tr tr; + int i, cflag = 0; + char c; + + tr.p = str->ptr; tr.pend = tr.p + str->len; + tr.last = tr.max = 0; + if (str->len > 2 && str->ptr[0] == '^') { + cflag++; + tr.p++; + } + + for (i=0; i<256; i++) { + table[i] = cflag ? 1 : 0; + } + while ((c = trnext(&tr)) >= 0) { + table[c & 0xff] = cflag ? 0 : 1; + } +} + +static VALUE +Fstr_delete(str1, str2) + struct RString *str1, *str2; +{ + char *s, *send, *t; + char squeez[256]; + + Check_Type(str2, T_STRING); + tr_setup_table(str2, squeez); + + str_modify(str1); + + s = t = str1->ptr; + send = s + str1->len; + while (s < send) { + if (!squeez[*s & 0xff]) { + *t++ = *s; + } + s++; + } + *t = '\0'; + str1->len = t - str1->ptr; + + return (VALUE)str1; +} + +static VALUE +tr_squeeze(str1, str2) + struct RString *str1, *str2; +{ + char squeez[256]; + char *s, *send, *t; + char c, save; + + if (str2) { + tr_setup_table(str2, squeez); + } + else { + int i; + + for (i=0; i<256; i++) { + squeez[i] = 1; + } + } + + str_modify(str1); + + s = t = str1->ptr; + send = s + str1->len; + save = -1; + while (s < send) { + c = *s++ & 0xff; + if (c != save || !squeez[c & 0xff]) { + *t++ = save = c; + } + } + *t = '\0'; + str1->len = t - str1->ptr; + + return (VALUE)str1; +} + +static VALUE +Fstr_squeeze(str1, args) + VALUE str1; + VALUE *args; +{ + VALUE str2; + + rb_scan_args(args, "01", &str2); + if (str2) { + Check_Type(str2, T_STRING); + } + return tr_squeeze(str1, str2); +} + +static VALUE +Fstr_tr_s(str, src, repl) + VALUE str, src, repl; +{ + Check_Type(src, T_STRING); + Check_Type(repl, T_STRING); + Fstr_tr(str, src, repl); + tr_squeeze(str, repl); + return str; +} + +static VALUE +Fstr_split(str, args) + struct RString *str; + VALUE args; +{ + extern VALUE FS; + struct RRegexp *spat; + VALUE limit; + char char_sep = 0; + int beg, end, lim, i; + VALUE result, tmp; + + rb_scan_args(args, "02", &spat, &limit); + if (limit) { + lim = NUM2INT(limit); + i = 1; + } + + if (spat == Qnil) { + if (FS) { + spat = (struct RRegexp*)FS; + goto fs_set; + } + char_sep = ' '; + } + else { + switch (TYPE(spat)) { + case T_STRING: + fs_set: + if (STRLEN(spat) == 1) { + char_sep = RSTRING(spat)->ptr[0]; + } + else { + spat = (struct RRegexp*)re_regcomp(spat); + } + break; + case T_REGEXP: + break; + default: + Fail("split(): bad separator"); + } + } + + GC_LINK; + GC_PRO(spat); + GC_PRO3(result, ary_new()); + + beg = 0; + if (char_sep != 0) { + char *ptr = str->ptr; + int len = 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)) { + beg++; + } + else { + end = beg+1; + skip = 0; + } + } + else { + if (isspace(*ptr)) { + Fary_push(result, str_substr(str, beg, end-beg)); + if (limit && lim <= ++i) break; + skip = 1; + beg = end + 1; + } + else { + end++; + } + } + } + } + else { + for (end = beg = 0; ptr<eptr; ptr++) { + if (*ptr == char_sep) { + Fary_push(result, str_substr(str, beg, end-beg)); + if (limit && lim <= ++i) break; + beg = end + 1; + } + end++; + } + } + } + else { + int start = beg; + int last_null = 0; + int idx; + +#define LMATCH spat->ptr->regs.start +#define RMATCH spat->ptr->regs.end + + while ((end = research(spat, str, start, ignorecase)) >= 0) { + if (start == end && LMATCH[0] == RMATCH[0]) { + if (last_null == 1) { + if (ismbchar(str->ptr[beg])) + Fary_push(result, str_substr(str, beg, 2)); + else + Fary_push(result, str_substr(str, beg, 1)); + beg = start; + if (limit && lim <= ++i) break; + } + else { + start += ismbchar(str->ptr[start])?2:1; + last_null = 1; + continue; + } + } + else { + Fary_push(result, str_substr(str, beg, end-beg)); + beg = start = RMATCH[0]; + if (limit && lim <= ++i) break; + } + last_null = 0; + + for (idx=1; idx < 10; idx++) { + if (LMATCH[idx] == -1) break; + if (LMATCH[idx] == RMATCH[idx]) + tmp = str_new(0, 0); + else + tmp = str_subseq(str, LMATCH[idx], RMATCH[idx]-1); + Fary_push(result, tmp); + if (limit && lim <= ++i) break; + } + + } + } + if (str->len > beg) { + Fary_push(result, str_subseq(str, beg, -1)); + } + else if (str->len == beg) { + Fary_push(result, str_new(0, 0)); + } + + GC_UNLINK; + return result; +} + +static VALUE +Fstr_each(str) + struct RString* str; +{ + extern VALUE RS; + int newline; + int rslen; + char *p = str->ptr, *pend = p + str->len, *s; + + if (RS == Qnil) { + rb_yield(str); + return (VALUE)str; + } + + rslen = RSTRING(RS)->len; + if (rslen == 0) { + newline = '\n'; + } + else { + newline = RSTRING(RS)->ptr[rslen-1]; + } + + for (s = p, p += rslen; p < pend; p++) { + if (rslen == 0 && *p == '\n') { + if (*(p+1) != '\n') continue; + while (*p == '\n') p++; + p--; + } + if (*p == newline && + (rslen <= 1 || + memcmp(RSTRING(RS)->ptr, p-rslen+1, rslen) == 0)) { + rb_lastline = str_new(s, p - s + 1); + rb_yield(rb_lastline); + s = p + 1; + } + } + + if (s != pend) { + rb_lastline = str_new(s, p - s); + rb_yield(rb_lastline); + } + + return (VALUE)str; +} + +static VALUE +Fstr_each_byte(str) + struct RString* str; +{ + int i; + + for (i=0; str->len; i++) { + rb_yield(str->ptr[i] & 0xff); + } + return (VALUE)str; +} + +static VALUE +Fstr_chop(str) + struct RString *str; +{ + int result; + + str_modify(str); + + str->len--; + str->ptr[str->len] = '\0'; + + return (VALUE)str; +} + +static VALUE +Fstr_strip(str) + struct RString *str; +{ + char *s, *t, *e; + + s = str->ptr; + e = t = s + str->len; + /* remove spaces at head */ + while (s < t && isspace(*s)) s++; + + /* remove trailing spaces */ + t--; + while (s <= t && isspace(*t)) t--; + t++; + + if (s > str->ptr || t < e) { + str_modify(str); + return str_new(s, t-s); + } + return (VALUE)str; +} + +static VALUE +Fstr_hex(str) + struct RString *str; +{ + return str2inum(str->ptr, 16); +} + +static VALUE +Fstr_oct(str) + struct RString *str; +{ + return str2inum(str->ptr, 8); +} + +static VALUE +Fstr_crypt(str, salt) + struct RString *str, *salt; +{ + Check_Type(salt, T_STRING); + if (salt->len < 2) + Fail("salt too short(need 2 byte)"); + return str_new2(crypt(str->ptr, salt->ptr)); +} + +static VALUE +Fstr_intern(str) + struct RString *str; +{ + if (strlen(str->ptr) != str->len) + Fail("string contains `\0'"); + + return rb_intern(str->ptr)|FIXNUM_FLAG; +} + +extern VALUE C_Kernel; +extern VALUE M_Comparable; +extern VALUE M_Enumerable; + +Init_String() +{ + C_String = rb_define_class("String", C_Object); + rb_include_module(C_String, M_Comparable); + rb_include_module(C_String, M_Enumerable); + rb_define_single_method(C_String, "new", Fstr_new, 1); + rb_define_method(C_String, "clone", Fstr_clone, 0); + rb_define_method(C_String, "<=>", Fstr_cmp, 1); + rb_define_method(C_String, "==", Fstr_equal, 1); + rb_define_method(C_String, "hash", Fstr_hash, 0); + rb_define_method(C_String, "+", Fstr_plus, 1); + rb_define_method(C_String, "*", Fstr_times, 1); + rb_define_method(C_String, "..", Fstr_dot2, 1); + rb_define_method(C_String, "[]", Fstr_aref, -2); + rb_define_method(C_String, "[]=", Fstr_aset, -2); + rb_define_method(C_String, "length", Fstr_length, 0); + rb_define_method(C_String, "=~", Fstr_match, 1); + rb_define_method(C_String, "~", Fstr_match2, 0); + rb_define_method(C_String, "next", Fstr_next, 0); + rb_define_method(C_String, "index", Fstr_index, -2); + rb_define_method(C_String, "rindex", Fstr_rindex, -2); + + rb_define_method(C_String, "to_i", Fstr_to_i, 0); + rb_define_method(C_String, "to_f", Fstr_to_f, 0); + rb_define_method(C_String, "to_s", Fstr_to_s, 0); + rb_define_method(C_String, "_inspect", Fstr_inspect, 0); + + rb_define_method(C_String, "toupper", Fstr_toupper, 0); + rb_define_alias(C_String, "uc", "toupper"); + rb_define_method(C_String, "tolower", Fstr_tolower, 0); + rb_define_alias(C_String, "lc", "tolower"); + rb_define_method(C_String, "ucfirst", Fstr_ucfirst, 0); + rb_define_method(C_String, "lcfirst", Fstr_lcfirst, 0); + rb_define_method(C_String, "hex", Fstr_hex, 0); + rb_define_method(C_String, "oct", Fstr_oct, 0); + rb_define_method(C_String, "split", Fstr_split, -2); + rb_define_method(C_String, "reverse", Fstr_reverse, 0); + rb_define_method(C_String, "concat", Fstr_concat, 1); + rb_define_method(C_String, "crypt", Fstr_crypt, 1); + rb_define_method(C_String, "intern", Fstr_intern, 0); + + rb_define_method(C_String, "sub", Fstr_sub, 2); + rb_define_method(C_String, "gsub", Fstr_gsub, 2); + rb_define_method(C_String, "chop", Fstr_chop, 0); + rb_define_method(C_String, "strip", Fstr_strip, 0); + + rb_define_method(C_String, "tr", Fstr_tr, 2); + rb_define_method(C_String, "tr_s", Fstr_tr_s, 2); + rb_define_method(C_String, "delete", Fstr_delete, 1); + rb_define_method(C_String, "squeeze", Fstr_squeeze, -2); + + rb_define_method(C_String, "each", Fstr_each, 0); + rb_define_method(C_String, "each_byte", Fstr_each_byte, 0); + + rb_define_func(C_Kernel, "sub", Fsub, 2); + rb_define_func(C_Kernel, "gsub", Fgsub, 2); + + pr_str = rb_intern("to_s"); +} diff --git a/struct.c b/struct.c new file mode 100644 index 0000000000..658925109d --- /dev/null +++ b/struct.c @@ -0,0 +1,274 @@ +/************************************************ + + struct.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:51 $ + created at: Tue Mar 22 18:44:30 JST 1994 + +************************************************/ + +#include "ruby.h" +#include "env.h" + +VALUE C_Struct; +extern VALUE M_Enumerable; + +char *strdup(); + +static VALUE +struct_alloc(class, name) + VALUE class; + char *name; +{ + NEWOBJ(st, struct RStruct); + OBJSETUP(st, class, T_STRUCT); + + if (name) st->name = strdup(name); + else st->name = Qnil; + st->len = 0; + st->tbl = Qnil; + + return (VALUE)st; +} + +static VALUE +struct_find(s, id) + struct RStruct *s; + ID id; +{ + struct kv_pair *t, *tend; + + t = s->tbl; + tend = t + s->len; + while (t < tend) { + if (t->key == id) return t->value; + t++; + } + Fail("struct %s has no member %s", s->name, rb_id2name(id)); +} + +static VALUE +Fstruct_access(s) + struct RStruct *s; +{ + return struct_find(s, the_env->last_func); +} + +static VALUE +struct_add(s, mem, val) + struct RStruct *s; + char *mem; + VALUE val; +{ + int pos = s->len; + + s->len++; + if (s->tbl == Qnil) { + s->tbl = ALLOC_N(struct kv_pair, 1); + } + else { + REALLOC_N(s->tbl, struct kv_pair, s->len); + } + + s->tbl[pos].key = rb_intern(mem); + s->tbl[pos].value = val; + rb_define_single_method(s, mem, Fstruct_access, 0); +} + +#include <varargs.h> + +VALUE +struct_new(name, va_alist) + char *name; + va_dcl +{ + VALUE st; + va_list args; + char *mem; + + GC_LINK; + GC_PRO3(st, struct_alloc(C_Struct,name)); + va_start(args); + + while (mem = va_arg(args, char*)) { + struct_add(st, mem, va_arg(args, VALUE)); + } + + va_end(vargs); + GC_UNLINK; + + return st; +} + +#define ASSOC_KEY(a) RARRAY(a)->ptr[0] +#define ASSOC_VAL(a) RARRAY(a)->ptr[1] + +static VALUE +Fstruct_new(class, args) + VALUE class, args; +{ + VALUE name, st; + struct RArray *tbl; + int i, max; + + rb_scan_args(args, "1*", &name, &tbl); + Check_Type(name, T_STRING); + + GC_LINK; + GC_PRO(tbl); + GC_PRO3(st, struct_alloc(class, RSTRING(name)->ptr)); + + for (i=0, max=tbl->len; i<max; i++) { + VALUE assoc = tbl->ptr[i]; + + Check_Type(assoc, T_ARRAY); + if (RARRAY(assoc)->len != 2) { + Fail("args must be pairs"); + } + Check_Type(ASSOC_KEY(assoc), T_STRING); + struct_add(st, RSTRING(ASSOC_KEY(assoc))->ptr, ASSOC_VAL(assoc)); + } + + GC_UNLINK; + + return st; +} + +static VALUE +Fstruct_each(s) + struct RStruct *s; +{ + struct kv_pair *t, *tend; + + t = s->tbl; + tend = t + s->len; + while (t < tend) { + rb_yield(t->value); + t++; + } +} + +static VALUE +Fstruct_values(s) + struct RStruct *s; +{ + VALUE ary; + struct kv_pair *t, *tend; + + GC_LINK; + GC_PRO3(ary, ary_new()); + t = s->tbl; + tend = t + s->len; + while (t < tend) { + Fary_push(ary, t->value); + t++; + } + GC_UNLINK; + return ary; +} + +static VALUE +Fstruct_aref(s, idx) + struct RStruct *s; + VALUE idx; +{ + struct RArray *ary; + int i; + + if (TYPE(idx) == T_STRING) + return struct_find(rb_intern(RSTRING(idx)->ptr)); + + i = NUM2INT(idx); + if (s->len <= i) + Fail("offset %d too large for struct(size:%d)", i, s->len); + return s->tbl[i].value; +} + +#define HDR "struct " + +static VALUE +Fstruct_to_s(s) + struct RStruct *s; +{ + char *buf; + + buf = (char*)alloca(strlen(s->name) + sizeof(HDR) + 1); + sprintf(buf, "%s%s", HDR, s->name); + return str_new2(buf); +} + +static VALUE +Fstruct_inspect(s) + struct RStruct *s; +{ + VALUE str, str2; + char buf[256], *p; + int i; + ID inspect = rb_intern("_inspect"); + + GC_LINK; + sprintf(buf, "#<%s%s: ", HDR, s->name); + GC_PRO3(str, str_new2(buf)); + GC_PRO2(str2); + for (i=0; i<s->len; i++) { + if (i > 0) { + str_cat(str, ", ", 2); + } + p = rb_id2name(s->tbl[i].key); + str_cat(str, p, strlen(p)); + str_cat(str, "=", 1); + str2 = rb_funcall(s->tbl[i].value, inspect, 0, Qnil); + str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); + } + str_cat(str, ">", 1); + GC_UNLINK; + + return str; +} + +static VALUE +Fstruct_to_a(s) + struct RStruct *s; +{ + VALUE ary; + int i; + + ary = ary_new2(s->len); + for (i=0; i<s->len; i++) { + Fary_push(ary, s->tbl[i].value); + } + + return ary; +} + +static VALUE +Fstruct_clone(s) + struct RStruct *s; +{ + struct RStruct *st = (struct RStruct*)struct_alloc(s->name); + + CLONESETUP(st, s); + st->len = s->len; + st->tbl = ALLOC_N(struct kv_pair, s->len); + memcpy(st->tbl, s->tbl, sizeof(struct kv_pair) * st->len); + RBASIC(st)->class = single_class_clone(RBASIC(s)->class); + return (VALUE)st; +} + +Init_Struct() +{ + C_Struct = rb_define_class("Struct", C_Object); + rb_include_module(C_Struct, M_Enumerable); + + rb_define_single_method(C_Struct, "new", Fstruct_new, -2); + rb_define_method(C_Struct, "clone", Fstruct_clone, 0); + + rb_define_method(C_Struct, "to_s", Fstruct_to_s, 0); + rb_define_method(C_Struct, "_inspect", Fstruct_inspect, 0); + rb_define_method(C_Struct, "to_a", Fstruct_to_a, 0); + + rb_define_method(C_Struct, "each", Fstruct_each, 0); + rb_define_method(C_Struct, "values", Fstruct_values, 0); + rb_define_method(C_Struct, "[]", Fstruct_aref, 1); +} diff --git a/time.c b/time.c new file mode 100644 index 0000000000..05f477cd5c --- /dev/null +++ b/time.c @@ -0,0 +1,562 @@ +/************************************************ + + time.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:51 $ + created at: Tue Dec 28 14:31:59 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include <sys/types.h> +#include <sys/time.h> +#include <sys/times.h> + +static VALUE C_Time; +extern VALUE M_Comparable; + +struct time_object { + struct timeval tv; + struct tm tm; +#ifndef HAVE_TM_ZONE + int gmt; +#endif + int tm_got; +}; + +#define GetTimeval(obj, tobj) \ + Get_Data_Struct(obj, "tv", struct time_object, tobj) +#define MakeTimeval(obj,tobj) {\ + Make_Data_Struct(obj, "tv", struct time_object, Qnil, Qnil, tobj);\ + tobj->tm_got=0;\ +} + +static VALUE +Ftime_now(class) + VALUE class; +{ + VALUE obj = obj_alloc(class); + struct time_object *tobj; + + GC_LINK; + GC_PRO(obj); + MakeTimeval(obj, tobj); + + if (gettimeofday(&(tobj->tv), 0) == -1) { + rb_sys_fail("gettimeofday"); + } + GC_UNLINK; + + return obj; +} + +static VALUE +time_new_internal(class, sec, usec) + int sec, usec; +{ + VALUE obj = obj_alloc(class); + struct time_object *tobj; + + GC_LINK; + GC_PRO(obj); + MakeTimeval(obj, tobj); + tobj->tv.tv_sec = sec; + tobj->tv.tv_usec =usec; + GC_UNLINK; + + return obj; +} + +VALUE +time_new(sec, usec) + int sec, usec; +{ + return time_new_internal(C_Time, sec, usec); +} + +struct timeval* +time_timeval(time) + VALUE time; +{ + struct time_object *tobj; + static struct timeval t, *tp; + + switch (TYPE(time)) { + case T_FIXNUM: + t.tv_sec = FIX2UINT(time); + if (t.tv_sec < 0) + Fail("time must be positive"); + t.tv_usec = 0; + tp = &t; + break; + + case T_FLOAT: + { + double floor(); + double seconds, microseconds; + + if (RFLOAT(time)->value < 0.0) + Fail("time must be positive"); + seconds = floor(RFLOAT(time)->value); + microseconds = (RFLOAT(time)->value - seconds) * 1000000.0; + t.tv_sec = seconds; + t.tv_usec = microseconds; + tp = &t; + } + break; + + default: + if (!obj_is_kind_of(time, C_Time)) { + Fail("Can't convert %s into Time", rb_class2name(CLASS_OF(time))); + } + GetTimeval(time, tobj); + tp = &(tobj->tv); + break; + } + return tp; +} + +static VALUE +Ftime_at(class, time) + VALUE class, time; +{ + VALUE obj; + int sec, usec; + struct time_object *tobj; + struct timeval *tp; + + tp = time_timeval(time); + return time_new_internal(class, tp->tv_sec, tp->tv_usec); + +} +static VALUE +Ftime_to_i(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + return int2inum(tobj->tv.tv_sec); +} + +static VALUE +Ftime_usec(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + return INT2FIX(tobj->tv.tv_usec); +} + +static VALUE +Ftime_cmp(time1, time2) + VALUE time1, time2; +{ + struct time_object *tobj1, *tobj2; + int i; + + GetTimeval(time1, tobj1); + if (obj_is_member_of(time2, C_Time)) { + GetTimeval(time2, tobj2); + if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) { + if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return INT2FIX(0); + if (tobj1->tv.tv_usec > tobj2->tv.tv_usec) return INT2FIX(1); + return FIX2INT(-1); + } + if (tobj1->tv.tv_sec > tobj2->tv.tv_sec) return INT2FIX(1); + return FIX2INT(-1); + } + i = NUM2INT(time2); + if (tobj1->tv.tv_sec == i) return INT2FIX(0); + if (tobj1->tv.tv_sec > i) return INT2FIX(1); + return FIX2INT(-1); +} + +static VALUE +Ftime_hash(time) + VALUE time; +{ + struct time_object *tobj; + int hash; + + GetTimeval(time, tobj); + hash = tobj->tv.tv_sec ^ tobj->tv.tv_usec; + return INT2FIX(hash); +} + +static VALUE +Ftime_localtime(time) + VALUE time; +{ + struct time_object *tobj; + struct tm *tm_tmp; + + GetTimeval(time, tobj); + tm_tmp = localtime(&tobj->tv.tv_sec); + tobj->tm = *tm_tmp; + tobj->tm_got = 1; +#ifndef HAVE_TM_ZONE + tobj->gmt = 0; +#endif + return time; +} + +static VALUE +Ftime_gmtime(time) + VALUE time; +{ + struct time_object *tobj; + struct tm *tm_tmp; + + GetTimeval(time, tobj); + tm_tmp = gmtime(&tobj->tv.tv_sec); + tobj->tm = *tm_tmp; + tobj->tm_got = 1; +#ifndef HAVE_TM_ZONE + tobj->gmt = 1; +#endif + return time; +} + +static VALUE +Ftime_asctime(time) + VALUE time; +{ + struct time_object *tobj; + char *ct; + char buf[32]; + int len; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } +#ifndef HAVE_TM_ZONE + if (tobj->gmt == 1) + len = strftime(buf, 32, "%a %b %d %H:%M:%S GMT %Y", &(tobj->tm)); + else +#endif + { + len = strftime(buf, 32, "%a %b %d %H:%M:%S %Z %Y", &(tobj->tm)); + } + return str_new(buf, len); +} + +static VALUE +Ftime_coerce(time1, time2) + VALUE time1, time2; +{ + return time_new(CLASS_OF(time1), NUM2INT(time2), 0); +} + +static VALUE +Ftime_plus(time1, time2) + VALUE time1, time2; +{ + struct time_object *tobj1, *tobj2; + int sec, usec; + + GetTimeval(time1, tobj1); + if (obj_is_member_of(time2, C_Time)) { + GetTimeval(time2, tobj2); + sec = tobj1->tv.tv_sec + tobj2->tv.tv_sec; + usec = tobj1->tv.tv_usec + tobj2->tv.tv_usec; + } + else { + sec = tobj1->tv.tv_sec + NUM2INT(time2); + usec = tobj1->tv.tv_usec; + if (usec >= 1000000) { + sec++; + usec -= 1000000; + } + } + return time_new(sec, usec); +} + +static VALUE +Ftime_minus(time1, time2) + VALUE time1, time2; +{ + struct time_object *tobj1, *tobj2; + int sec, usec; + + GetTimeval(time1, tobj1); + if (obj_is_member_of(time2, C_Time)) { + GetTimeval(time2, tobj2); + sec = tobj1->tv.tv_sec - tobj2->tv.tv_sec; + usec = tobj1->tv.tv_usec - tobj2->tv.tv_usec; + if (usec < 0) { + sec--; + usec += 1000000; + } + } + else { + sec = tobj1->tv.tv_sec - NUM2INT(time2); + usec = tobj1->tv.tv_usec; + } + return time_new(sec, usec); +} + +static VALUE +Ftime_sec(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_sec); +} + +static VALUE +Ftime_min(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_min); +} + +static VALUE +Ftime_hour(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_hour); +} + +static VALUE +Ftime_mday(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_mday); +} + +static VALUE +Ftime_mon(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_mon); +} + +static VALUE +Ftime_year(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_year); +} + +static VALUE +Ftime_wday(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_wday); +} + +static VALUE +Ftime_yday(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_yday); +} + +static VALUE +Ftime_isdst(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + return INT2FIX(tobj->tm.tm_isdst); +} + +static VALUE +Ftime_zone(time) + VALUE time; +{ + struct time_object *tobj; + char buf[10]; + int len; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + + len = strftime(buf, 10, "%Z", &(tobj->tm)); + return str_new(buf, len); +} + +static VALUE +Ftime_to_a(time) + VALUE time; +{ + struct time_object *tobj; + struct tm *tm; + char buf[10]; + VALUE ary; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_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; +} + +static VALUE +Ftime_strftime(time, format) + VALUE time, format; +{ + struct time_object *tobj; + char buf[100]; + int len; + + Check_Type(format, T_STRING); + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + Ftime_localtime(time); + } + if (strlen(RSTRING(format)->ptr) < RSTRING(format)->len) { + /* Ruby string contains \0. */ + VALUE str; + int l, total = 0; + char *p = RSTRING(format)->ptr, *pe = p + RSTRING(format)->len; + + GC_LINK; + GC_PRO3(str, str_new(0, 0)); + while (p < pe) { + len = strftime(buf, 100, p, &(tobj->tm)); + str_cat(str, buf, len); + l = strlen(p); + p += l + 1; + } + GC_UNLINK; + return str; + } + len = strftime(buf, 100, RSTRING(format)->ptr, &(tobj->tm)); + return str_new(buf, len); +} + +static VALUE +Ftime_times(obj) + VALUE obj; +{ + struct tms buf; + VALUE t1, t2, t3, t4, tm; + + if (times(&buf) == -1) rb_sys_fail(Qnil); + GC_LINK; + GC_PRO3(t1, float_new((double)buf.tms_utime / 60.0)); + GC_PRO3(t2, float_new((double)buf.tms_stime / 60.0)); + GC_PRO3(t3, float_new((double)buf.tms_cutime / 60.0)); + GC_PRO3(t4, float_new((double)buf.tms_cstime / 60.0)); + + tm = struct_new("tms", + "utime", t1, "stime", t2, + "cutime", t3, "cstime", t4, + Qnil); + GC_UNLINK; + + return tm; +} + +Init_Time() +{ + C_Time = rb_define_class("Time", C_Object); + rb_include_module(C_Time, M_Comparable); + + rb_define_single_method(C_Time, "now", Ftime_now, 0); + rb_define_single_method(C_Time, "new", Ftime_now, 0); + rb_define_single_method(C_Time, "at", Ftime_at, 1); + + rb_define_single_method(C_Time, "times", Ftime_times, 0); + + rb_define_method(C_Time, "to_i", Ftime_to_i, 0); + rb_define_method(C_Time, "<=>", Ftime_cmp, 1); + rb_define_method(C_Time, "hash", Ftime_hash, 0); + + rb_define_method(C_Time, "localtime", Ftime_localtime, 0); + rb_define_method(C_Time, "gmtime", Ftime_gmtime, 0); + rb_define_method(C_Time, "ctime", Ftime_asctime, 0); + rb_define_method(C_Time, "asctime", Ftime_asctime, 0); + rb_define_method(C_Time, "to_s", Ftime_asctime, 0); + rb_define_method(C_Time, "_inspect", Ftime_asctime, 0); + rb_define_method(C_Time, "to_a", Ftime_to_a, 0); + rb_define_method(C_Time, "coerce", Ftime_coerce, 1); + + rb_define_method(C_Time, "+", Ftime_plus, 1); + rb_define_method(C_Time, "-", Ftime_minus, 1); + + rb_define_method(C_Time, "sec", Ftime_sec, 0); + rb_define_method(C_Time, "min", Ftime_min, 0); + rb_define_method(C_Time, "hour", Ftime_hour, 0); + rb_define_method(C_Time, "mday", Ftime_mday, 0); + rb_define_method(C_Time, "year", Ftime_year, 0); + rb_define_method(C_Time, "wday", Ftime_wday, 0); + rb_define_method(C_Time, "yday", Ftime_yday, 0); + rb_define_method(C_Time, "isdst", Ftime_isdst, 0); + + rb_define_method(C_Time, "tv_sec", Ftime_to_i, 0); + rb_define_method(C_Time, "tv_usec", Ftime_usec, 0); + rb_define_method(C_Time, "usec", Ftime_usec, 0); + + rb_define_method(C_Time, "strftime", Ftime_strftime, 1); +} diff --git a/variable.c b/variable.c new file mode 100644 index 0000000000..27b5630170 --- /dev/null +++ b/variable.c @@ -0,0 +1,416 @@ +/************************************************ + + variable.c - + + $Author: matz $ + $Date: 1994/06/17 14:23:51 $ + created at: Tue Apr 19 23:55:15 JST 1994 + +************************************************/ + +#include "ruby.h" +#include "env.h" +#include "node.h" +#include "ident.h" +#include "st.h" + +st_table *rb_global_tbl; +st_table *rb_class_tbl; +#define global_tbl rb_global_tbl +#define class_tbl rb_class_tbl +#define instance_tbl (RBASIC(Qself)->iv_tbl) + +st_table *new_idhash() +{ + return st_init_table(ST_NUMCMP, ST_NUMHASH); +} + +void +Init_var_tables() +{ + global_tbl = new_idhash(); + class_tbl = new_idhash(); +} + +void +rb_name_class(class, id) + VALUE class; + ID id; +{ + VALUE body; + + if (st_lookup(class_tbl, id, &body)) { + Bug("%s %s already exists", + TYPE(body)==T_CLASS?"class":"module", rb_id2name(id)); + } + st_add_direct(class_tbl, id, class); +} + +struct global_entry { + enum { GLOBAL_VAL, GLOBAL_VAR, GLOBAL_UNDEF } mode; + ID id; + union { + VALUE val; + VALUE *var; + } v; + VALUE (*get_hook)(); + VALUE (*set_hook)(); +}; + +static mark_global_entry(key, entry) + ID key; + struct global_entry *entry; +{ + switch (entry->mode) { + case GLOBAL_VAL: + mark(entry->v.val); /* normal global value */ + break; + case GLOBAL_VAR: + if (entry->v.var) + mark(*entry->v.var); /* c variable pointer */ + break; + default: + break; + } + return ST_CONTINUE; +} + +mark_global_tbl() +{ + st_foreach(global_tbl, mark_global_entry, 0); +} + +struct global_entry* +rb_global_entry(id) + ID id; +{ + struct global_entry *entry; + + if (!st_lookup(global_tbl, id, &entry)) { + entry = ALLOC(struct global_entry); + st_insert(global_tbl, id, entry); + entry->id = id; + entry->mode = GLOBAL_UNDEF; + entry->v.var = Qnil; + entry->get_hook = entry->set_hook = Qnil; + } + return entry; +} + +void +rb_define_variable(name, var, get_hook, set_hook) + char *name; + VALUE *var; + VALUE (*get_hook)(); + VALUE (*set_hook)(); +{ + struct global_entry *entry; + ID id; + + if (name[0] == '$') id = rb_intern(name); + else { + char *buf = (char*)alloca(strlen(name)+2); + buf[0] = '$'; + strcpy(buf+1, name); + id = rb_intern(buf); + } + + if (!st_lookup(global_tbl, id, &entry)) { + entry = rb_global_entry(id); + } + entry->mode = GLOBAL_VAR; + entry->v.var = var; + entry->get_hook = get_hook; + entry->set_hook = set_hook; +} + +void +rb_define_varhook(name, get_hook, set_hook) + char *name; + VALUE (*get_hook)(); + VALUE (*set_hook)(); +{ + struct global_entry *entry; + ID id; + + if (name[0] == '$') id = rb_intern(name); + else { + char *buf = (char*)alloca(strlen(name)+2); + buf[0] = '$'; + strcpy(buf+1, name); + id = rb_intern(buf); + } + + if (!st_lookup(global_tbl, id, &entry)) { + entry = ALLOC(struct global_entry); + entry->id = id; + entry->mode = GLOBAL_VAL; + st_insert(global_tbl, id, entry); + } + else if (entry->mode == GLOBAL_UNDEF) { + entry->mode = GLOBAL_VAL; + } + entry->v.val = Qnil; + entry->get_hook = get_hook; + entry->set_hook = set_hook; +} + +VALUE +rb_readonly_hook(val, id) + VALUE val; + ID id; +{ + Fail("Can't set variable %s", rb_id2name(id)); + /* not reached */ +} + +VALUE +rb_id2class(id) + ID id; +{ + VALUE class; + + if (st_lookup(class_tbl, id, &class)) + return class; + return Qnil; +} + +VALUE +rb_gvar_get(entry) + struct global_entry *entry; +{ + VALUE val; + + if (entry->get_hook) + val = (*entry->get_hook)(entry->id); + switch (entry->mode) { + case GLOBAL_VAL: + return entry->v.val; + + case GLOBAL_VAR: + if (entry->v.var == Qnil) return val; + return *entry->v.var; + + default: + break; + } + return Qnil; +} + +rb_ivar_get_1(obj, id) + struct RBasic *obj; + ID id; +{ + VALUE val; + + if (obj->iv_tbl == Qnil) + return Qnil; + if (st_lookup(obj->iv_tbl, id, &val)) + return val; + return Qnil; +} + +VALUE +rb_ivar_get(id) + ID id; +{ + return rb_ivar_get_1(Qself, id); +} + +VALUE +rb_mvar_get(id) + ID id; +{ + VALUE val; + + if (st_lookup(class_tbl, id, &val)) return val; + return Qnil; +} + +VALUE +rb_const_get(id) + ID id; +{ + struct RClass *class = (struct RClass*)CLASS_OF(Qself); + VALUE value; + + while (class) { + if (class->c_tbl && st_lookup(class->c_tbl, id, &value)) { + return value; + } + class = class->super; + } + Fail("Uninitialized constant %s", rb_id2name(id)); + /* not reached */ +} + +VALUE +rb_gvar_set(entry, val) + struct global_entry *entry; + VALUE val; +{ + if (entry->set_hook) + (*entry->set_hook)(val, entry->id); + + if (entry->mode == GLOBAL_VAR && entry->v.var != Qnil) + return *entry->v.var = val; + else { + if (entry->mode == GLOBAL_UNDEF) + entry->mode = GLOBAL_VAL; + return entry->v.val = val; + } +} + +VALUE +rb_gvar_set2(name, val) + char *name; + VALUE val; +{ + struct global_entry *entry; + ID id; + + id = rb_intern(name); + if (!st_lookup(global_tbl, id, &entry)) { + entry = rb_global_entry(id); + } + rb_gvar_set(entry, val); + + return val; +} + +rb_ivar_set_1(obj, id, val) + struct RBasic *obj; + ID id; + VALUE val; +{ + if (obj->iv_tbl == Qnil) obj->iv_tbl = new_idhash(); + st_insert(obj->iv_tbl, id, val); + return val; +} + +VALUE +rb_ivar_set(id, val) + ID id; + VALUE val; +{ + return rb_ivar_set_1(Qself, id, val); +} + +static VALUE +const_bound(id) + ID id; +{ + struct RClass *class = (struct RClass*)CLASS_OF(Qself); + + while (class) { + if (class->c_tbl && st_lookup(class->c_tbl, id, Qnil)) { + return TRUE; + } + class = class->super; + } + return FALSE; +} + +static void +rb_const_set_1(class, id, val) + struct RClass *class; + ID id; + VALUE val; +{ + if (const_bound(id)) + Fail("already initialized constnant"); + + if (class->c_tbl == Qnil) + class->c_tbl = new_idhash(); + + st_insert(class->c_tbl, id, val); +} + +VALUE +rb_const_set(id, val) + ID id; + VALUE val; +{ + rb_const_set_1(the_class, id, val); + return val; +} + +void +rb_define_const(class, name, val) + struct RClass *class; + char *name; + VALUE val; +{ + rb_const_set_1(class, rb_intern(name), val); +} + +VALUE +rb_iv_get(obj, name) + VALUE obj; + char *name; +{ + ID id = rb_intern(name); + + return rb_ivar_get_1(obj, id); +} + +VALUE +rb_iv_set(obj, name, val) + VALUE obj; + char *name; + VALUE val; +{ + ID id = rb_intern(name); + + return rb_ivar_set_1(obj, id, val); +} + +VALUE +Fdefined(obj, name) + VALUE obj; + struct RString *name; +{ + ID id; + struct global_entry *entry; + + if (FIXNUM_P(name)) { + id = FIX2INT(name); + } + else { + Check_Type(name, T_STRING); + id = rb_intern(name->ptr); + } + + if (id == rb_intern("nil") || id == rb_intern("self")) return TRUE; + + switch (id & ID_SCOPE_MASK) { + case ID_GLOBAL: + if (st_lookup(global_tbl, id, &entry) && entry->mode != GLOBAL_UNDEF) + return TRUE; + break; + + case ID_INSTANCE: + if (TYPE(Qself) != T_OBJECT || instance_tbl == Qnil) break; + if (st_lookup(instance_tbl, id, Qnil)) return TRUE; + break; + + case ID_CONST: + return const_bound(id); + break; + + default: + { + int i, max; + + if (the_env->local_tbl) { + for (i=1, max=the_env->local_tbl[0]+1; i<max; i++) { + if (the_env->local_tbl[i] == id) return TRUE; + } + } + } + if (st_lookup(class_tbl, id, Qnil)) return TRUE; + break; + } + return FALSE; +} + diff --git a/version.c b/version.c new file mode 100644 index 0000000000..b671b46139 --- /dev/null +++ b/version.c @@ -0,0 +1,31 @@ +/************************************************ + + version.c - + + $Author: matz $ + $Revision: 1.1.1.1 $ + $Date: 1994/06/17 14:23:51 $ + created at: Thu Sep 30 20:08:01 JST 1993 + + Copyright (C) 1994 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" +#include "version.h" +#include <stdio.h> + +static VALUE rb_version; + +VALUE rb_readonly_hook(); + +Init_version() +{ + rb_version = str_new2(RUBY_VERSION); + rb_define_variable("$VERSION", &rb_version, Qnil, rb_readonly_hook); +} + +show_version() +{ + printf("ruby - version %s (%s)\n", RUBY_VERSION, VERSION_DATE); +} diff --git a/version.h b/version.h new file mode 100644 index 0000000000..f158e8a8ad --- /dev/null +++ b/version.h @@ -0,0 +1,2 @@ +#define RUBY_VERSION "0.49" +#define VERSION_DATE "18 Jul 94" |