summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--C-IF135
-rw-r--r--CVS/Entries51
-rw-r--r--CVS/Repository1
-rw-r--r--ChangeLog788
-rw-r--r--FAQ65
-rw-r--r--Makefile202
-rw-r--r--Makefile.in186
-rw-r--r--ToDo6
-rw-r--r--array.c805
-rw-r--r--bignum.c1121
-rw-r--r--bring57
-rw-r--r--class.c387
-rw-r--r--compar.c99
-rwxr-xr-xconfig.status72
-rw-r--r--configure.in63
-rw-r--r--dbm.c401
-rw-r--r--defines.h36
-rw-r--r--dict.c517
-rw-r--r--dir.c257
-rw-r--r--dln.c1088
-rw-r--r--dln.h33
-rw-r--r--enum.c332
-rw-r--r--env.h40
-rw-r--r--error.c165
-rw-r--r--etc.c220
-rw-r--r--eval.c1858
-rw-r--r--file.c1059
-rw-r--r--gc.c490
-rw-r--r--ident.h25
-rw-r--r--inits.c50
-rw-r--r--io.c1221
-rw-r--r--io.h47
-rw-r--r--math.c125
-rw-r--r--methods.c145
-rw-r--r--missing.c67
-rw-r--r--missing/CVS/Entries9
-rw-r--r--missing/CVS/Repository1
-rw-r--r--missing/getopt.c662
-rw-r--r--missing/getopt.h128
-rw-r--r--missing/getopt1.c162
-rw-r--r--missing/memmove.c24
-rw-r--r--missing/mkdir.c103
-rw-r--r--missing/strerror.c19
-rw-r--r--missing/strftime.c781
-rw-r--r--missing/strstr.c73
-rw-r--r--missing/strtol.c84
-rw-r--r--missing/strtoul.c184
-rwxr-xr-xnewver.rb14
-rw-r--r--node.h216
-rw-r--r--numeric.c962
-rw-r--r--object.c458
-rw-r--r--pack.c849
-rw-r--r--parse.y2585
-rw-r--r--process.c849
-rw-r--r--random.c80
-rw-r--r--range.c149
-rw-r--r--re.c442
-rw-r--r--re.h28
-rw-r--r--regex.c3237
-rw-r--r--regex.h276
-rw-r--r--ruby.1212
-rw-r--r--ruby.c374
-rw-r--r--ruby.h298
-rw-r--r--sample/Artistic117
-rw-r--r--sample/aset.rb3
-rw-r--r--sample/attr.rb9
-rw-r--r--sample/biorhythm.rb201
-rw-r--r--sample/caller.rb15
-rw-r--r--sample/case.rb12
-rw-r--r--sample/cat.rb4
-rw-r--r--sample/cbreak.rb34
-rw-r--r--sample/clnt.rb12
-rw-r--r--sample/clone.rb12
-rw-r--r--sample/const.rb20
-rw-r--r--sample/dbm.rb6
-rw-r--r--sample/dir.rb9
-rw-r--r--sample/evaldef.rb21
-rw-r--r--sample/fib.awk5
-rw-r--r--sample/fib.pl10
-rw-r--r--sample/fib.rb8
-rw-r--r--sample/freq.rb13
-rw-r--r--sample/fullpath.pl22
-rw-r--r--sample/fullpath.rb24
-rw-r--r--sample/gctest.rb69
-rw-r--r--sample/getopts.rb111
-rwxr-xr-xsample/getopts.test31
-rw-r--r--sample/hash.rb4
-rw-r--r--sample/io.rb40
-rwxr-xr-xsample/less.rb30
-rw-r--r--sample/list.rb81
-rw-r--r--sample/list2.rb20
-rw-r--r--sample/math.rb4
-rwxr-xr-xsample/mpart.rb42
-rw-r--r--sample/newver.rb13
-rw-r--r--sample/occur.pl9
-rw-r--r--sample/occur.rb10
-rw-r--r--sample/occur2.rb14
-rw-r--r--sample/opt_s.rb8
-rw-r--r--sample/opt_x.rb8
-rw-r--r--sample/parsearg.rb69
-rw-r--r--sample/perror.rb7
-rw-r--r--sample/rcs.awk33
-rw-r--r--sample/rcs.dat17
-rw-r--r--sample/rcs.rb42
-rw-r--r--sample/reach.rb5
-rw-r--r--sample/resp.rb2
-rw-r--r--sample/samp.rb12
-rw-r--r--sample/split.rb12
-rw-r--r--sample/struct.rb4
-rw-r--r--sample/svr.rb23
-rw-r--r--sample/system.rb1
-rw-r--r--sample/t1.rb20
-rw-r--r--sample/t2.rb24
-rw-r--r--sample/test.rb5
-rw-r--r--sample/trap.pl6
-rw-r--r--sample/trap.rb3
-rw-r--r--sample/tt.rb103
-rw-r--r--socket.c738
-rw-r--r--spec3244
-rw-r--r--sprintf.c431
-rw-r--r--st.c365
-rw-r--r--st.h57
-rw-r--r--string.c1552
-rw-r--r--struct.c274
-rw-r--r--time.c562
-rw-r--r--variable.c416
-rw-r--r--version.c31
-rw-r--r--version.h2
128 files changed, 34584 insertions, 0 deletions
diff --git a/C-IF b/C-IF
new file mode 100644
index 0000000000..df4dffc3f6
--- /dev/null
+++ b/C-IF
@@ -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.
diff --git a/FAQ b/FAQ
new file mode 100644
index 0000000000..eaa9c86056
--- /dev/null
+++ b/FAQ
@@ -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
diff --git a/ToDo b/ToDo
new file mode 100644
index 0000000000..b909816583
--- /dev/null
+++ b/ToDo
@@ -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);
+}
diff --git a/bring b/bring
new file mode 100644
index 0000000000..771cd04542
--- /dev/null
+++ b/bring
@@ -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)
diff --git a/dbm.c b/dbm.c
new file mode 100644
index 0000000000..f3946f7163
--- /dev/null
+++ b/dbm.c
@@ -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);
+}
diff --git a/dir.c b/dir.c
new file mode 100644
index 0000000000..bf62e302de
--- /dev/null
+++ b/dir.c
@@ -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");
+}
diff --git a/dln.c b/dln.c
new file mode 100644
index 0000000000..766297e2ae
--- /dev/null
+++ b/dln.c
@@ -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 */
diff --git a/dln.h b/dln.h
new file mode 100644
index 0000000000..0589954e73
--- /dev/null
+++ b/dln.h
@@ -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("<=>");
+}
diff --git a/env.h b/env.h
new file mode 100644
index 0000000000..09ff31d13f
--- /dev/null
+++ b/env.h
@@ -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]);
+}
diff --git a/etc.c b/etc.c
new file mode 100644
index 0000000000..311f6eb137
--- /dev/null
+++ b/etc.c
@@ -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 = &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);
+}
diff --git a/gc.c b/gc.c
new file mode 100644
index 0000000000..5f30206f09
--- /dev/null
+++ b/gc.c
@@ -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();
+}
diff --git a/io.c b/io.c
new file mode 100644
index 0000000000..b3ed236474
--- /dev/null
+++ b/io.c
@@ -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();
+}
diff --git a/io.h b/io.h
new file mode 100644
index 0000000000..f325de3c3c
--- /dev/null
+++ b/io.h
@@ -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>
+
+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");
+}
diff --git a/re.c b/re.c
new file mode 100644
index 0000000000..ac7047833c
--- /dev/null
+++ b/re.c
@@ -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(&reg_cache);
+}
diff --git a/re.h b/re.h
new file mode 100644
index 0000000000..e483080fc5
--- /dev/null
+++ b/re.h
@@ -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 *) &reg_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 */
diff --git a/spec b/spec
new file mode 100644
index 0000000000..2171e958aa
--- /dev/null
+++ b/spec
@@ -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';
+}
diff --git a/st.c b/st.c
new file mode 100644
index 0000000000..fcae526853
--- /dev/null
+++ b/st.c
@@ -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;
+}
diff --git a/st.h b/st.h
new file mode 100644
index 0000000000..04ac5c1088
--- /dev/null
+++ b/st.h
@@ -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"