summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-09-25 07:07:43 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2002-09-25 07:07:43 +0000
commitf33958990a43b8a20ad7ed7eb1d30ec211b46f85 (patch)
treef962530dd96d7c293cba9d8f4bd6318d688c33f2
parentd65fac5daa6838c9c56c6b6dd2f3127fe229d4e8 (diff)
* eval.c (ruby_run): should set toplevel visibility again here.
* eval.c (rb_eval): should not rely on ruby_class == rb_cObject check. Besides allow implicit publicity for attribute set methods. * parse.y (primary): need not to check class_nest, just set whether method is an attrset or not. * string.c (rb_str_each_line): p might be at the top of the string. * variable.c (rb_path2class): should not use rb_eval_string(). * parse.y (str_extend): expression substitution can contain string terminator again. * parse.y (yylex): the warning message "invalid character syntax" was never issued. * file.c (rb_find_file): $LOAD_PATH must not be empty. * file.c (rb_find_file_ext): ditto. * range.c (range_eq): class check should be based on range.class, instead of Range to work with Range.dup. * range.c (range_eql): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_6@2888 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog43
-rw-r--r--class.c2
-rw-r--r--configure.in2
-rw-r--r--error.c2
-rw-r--r--eval.c18
-rw-r--r--ext/tcltklib/tcltklib.c484
-rw-r--r--file.c15
-rw-r--r--lib/uri/mailto.rb10
-rw-r--r--object.c4
-rw-r--r--parse.y46
-rw-r--r--range.c4
-rw-r--r--string.c2
-rw-r--r--variable.c37
-rw-r--r--version.h4
14 files changed, 545 insertions, 128 deletions
diff --git a/ChangeLog b/ChangeLog
index e8a7292090..88f9523df7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Mon Sep 23 02:46:29 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (ruby_run): should set toplevel visibility again here.
+
+ * eval.c (rb_eval): should not rely on ruby_class == rb_cObject
+ check. Besides allow implicit publicity for attribute set
+ methods.
+
+ * parse.y (primary): need not to check class_nest, just set
+ whether method is an attrset or not.
+
+Sun Sep 22 17:08:11 2002 Tanaka Akira <akr@m17n.org>
+
+ * string.c (rb_str_each_line): p might be at the top of the
+ string.
+
Sun Sep 22 15:31:33 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
* lib/mkmf.rb: some backports.
@@ -97,6 +113,15 @@ Fri Sep 6 05:11:48 2002 Minero Aoki <aamine@loveruby.net>
* intern.h (rb_gc_mark_parser): added.
+Thu Sep 5 18:32:32 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * variable.c (rb_path2class): should not use rb_eval_string().
+
+Thu Sep 5 15:33:16 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (str_extend): expression substitution can contain string
+ terminator again.
+
Thu Sep 5 13:09:22 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
* eval.c (rb_eval): overriding false constant with class/module
@@ -108,6 +133,11 @@ Thu Sep 5 13:09:22 2002 Nobuyoshi Nakada <nobu.nokada@softhome.net>
* ruby.c (require_libraries): not clear source file.
[ruby-dev:18074]
+Wed Sep 4 05:10:16 2002 Koji Arai <jca02266@nifty.ne.jp>
+
+ * parse.y (yylex): the warning message "invalid
+ character syntax" was never issued.
+
Tue Sep 3 00:22:43 2002 Minero Aoki <aamine@loveruby.net>
* gc.c (gc_sweep): does reclaim nodes in also compile time, if we
@@ -119,6 +149,19 @@ Tue Sep 3 00:22:43 2002 Minero Aoki <aamine@loveruby.net>
* intern.h (ruby_parser_stack_on_heap): added.
+Tue Aug 27 15:03:35 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * file.c (rb_find_file): $LOAD_PATH must not be empty.
+
+ * file.c (rb_find_file_ext): ditto.
+
+Tue Aug 27 02:35:21 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * range.c (range_eq): class check should be based on range.class,
+ instead of Range to work with Range.dup.
+
+ * range.c (range_eql): ditto.
+
Sun Aug 25 20:10:32 2002 Wakou Aoyama <wakou@ruby-lang.org>
* lib/cgi.rb (CGI#form): fix ruby-bugs-ja:PR#280, add default action.
diff --git a/class.c b/class.c
index 15f060d4e9..60b64ac884 100644
--- a/class.c
+++ b/class.c
@@ -643,7 +643,7 @@ rb_singleton_class(obj)
klass = RBASIC(obj)->klass;
}
else {
- klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
+ klass = rb_make_metaclass(obj, CLASS_OF(obj));
}
if (OBJ_TAINTED(obj)) {
OBJ_TAINT(klass);
diff --git a/configure.in b/configure.in
index 9d064249e5..543965ba2a 100644
--- a/configure.in
+++ b/configure.in
@@ -913,7 +913,7 @@ case "$target_os" in
CFLAGS="$CFLAGS -pipe -no-precomp"
;;
darwin*)
- CFLAGS="$CFLAGS -pipe -no-precomp"
+ CFLAGS="$CFLAGS -pipe"
;;
os2_emx)
CFLAGS="$CFLAGS -DOS2"
diff --git a/error.c b/error.c
index 73d0026314..7e9e4a91ba 100644
--- a/error.c
+++ b/error.c
@@ -469,7 +469,9 @@ static VALUE *syserr_list;
#endif
#if !defined(NT) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(sys_nerr)
+# if !defined(__APPLE__) || (__APPLE_CC__ < 1151)
extern int sys_nerr;
+# endif
#endif
static VALUE
diff --git a/eval.c b/eval.c
index 449b13d3c8..21b3fa20f2 100644
--- a/eval.c
+++ b/eval.c
@@ -1216,6 +1216,8 @@ ruby_run()
Init_stack(&tmp);
PUSH_TAG(PROT_NONE);
PUSH_ITER(ITER_NOT);
+ /* default visibility is private at toplevel */
+ SCOPE_SET(SCOPE_PRIVATE);
if ((state = EXEC_TAG()) == 0) {
eval_node(ruby_top_self, ruby_eval_tree);
}
@@ -2995,15 +2997,15 @@ rb_eval(self, n)
}
}
- if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) {
+ if (node->nd_noex == NOEX_PUBLIC) {
+ noex = NOEX_PUBLIC; /* means is is an attrset */
+ }
+ else if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) {
noex = NOEX_PRIVATE;
}
else if (SCOPE_TEST(SCOPE_PROTECTED)) {
noex = NOEX_PROTECTED;
}
- else if (ruby_class == rb_cObject) {
- noex = node->nd_noex;
- }
else {
noex = NOEX_PUBLIC;
}
@@ -3159,8 +3161,8 @@ rb_eval(self, n)
}
else {
module = rb_define_module_id(node->nd_cname);
- rb_const_set(ruby_class, node->nd_cname, module);
rb_set_class_path(module,ruby_class,rb_id2name(node->nd_cname));
+ rb_const_set(ruby_class, node->nd_cname, module);
}
if (ruby_wrapper) {
rb_extend_object(module, ruby_wrapper);
@@ -7946,7 +7948,7 @@ void
rb_thread_wait_for(time)
struct timeval time;
{
- double date;
+ double limit;
if (rb_thread_critical ||
curr_thread == curr_thread->next ||
@@ -7986,9 +7988,9 @@ rb_thread_wait_for(time)
}
}
- date = timeofday() + (double)time.tv_sec + (double)time.tv_usec*1e-6;
+ limit = timeofday() + (double)time.tv_sec + (double)time.tv_usec*1e-6;
curr_thread->status = THREAD_STOPPED;
- curr_thread->delay = date;
+ curr_thread->delay = limit;
curr_thread->wait_for = WAIT_TIME;
rb_thread_schedule();
}
diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c
index 7818f0e0bc..0972f9ec9d 100644
--- a/ext/tcltklib/tcltklib.c
+++ b/ext/tcltklib/tcltklib.c
@@ -48,20 +48,44 @@ int *tclDummyMathPtr = (int *) matherr;
/*---- module TclTkLib ----*/
struct invoke_queue {
+ Tcl_Event ev;
int argc;
VALUE *argv;
VALUE obj;
int done;
- VALUE result;
+ int safe_level;
+ VALUE *result;
VALUE thread;
- struct invoke_queue *next;
};
-static struct invoke_queue *iqueue;
static VALUE main_thread;
+static VALUE eventloop_thread;
+static VALUE watchdog_thread;
+Tcl_Interp *current_interp;
+
+/*
+ * 'event_loop_max' is a maximum events which the eventloop processes in one
+ * term of thread scheduling. 'no_event_tick' is the count-up value when
+ * there are no event for processing.
+ * 'timer_tick' is a limit of one term of thread scheduling.
+ * If 'timer_tick' == 0, then not use the timer for thread scheduling.
+ */
+static int tick_counter;
+#define DEFAULT_EVENT_LOOP_MAX 800
+#define DEFAULT_NO_EVENT_TICK 10
+#define DEFAULT_TIMER_TICK 0
+static int event_loop_max = DEFAULT_EVENT_LOOP_MAX;
+static int no_event_tick = DEFAULT_NO_EVENT_TICK;
+static int timer_tick = DEFAULT_TIMER_TICK;
+
+#if TCL_MAJOR_VERSION >= 8
+static int ip_ruby _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*));
+#else
+static int ip_ruby _((ClientData, Tcl_Interp *, int, char **));
+#endif
/* Tk_ThreadTimer */
-static Tcl_TimerToken timer_token;
+static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL;
/* timer callback */
static void _timer_for_tcl _((ClientData));
@@ -73,44 +97,265 @@ _timer_for_tcl(clientData)
VALUE thread;
Tk_DeleteTimerHandler(timer_token);
- timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0);
-
- CHECK_INTS;
- q = iqueue;
- while (q) {
- tmp = q;
- q = q->next;
- if (!tmp->done) {
- tmp->done = 1;
- tmp->result = ip_invoke_real(tmp->argc, tmp->argv, tmp->obj);
- thread = tmp->thread;
- tmp = tmp->next;
- rb_thread_run(thread);
+ if (timer_tick > 0) {
+ timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl,
+ (ClientData)0);
+ } else {
+ timer_token = (Tcl_TimerToken)NULL;
+ }
+
+ /* rb_thread_schedule(); */
+ timer_tick += event_loop_max;
+}
+
+static VALUE
+set_eventloop_tick(self, tick)
+ VALUE self;
+ VALUE tick;
+{
+ int ttick = NUM2INT(tick);
+
+ if (ttick < 0) {
+ rb_raise(rb_eArgError, "timer-tick parameter must be 0 or plus number");
+ }
+
+ /* delete old timer callback */
+ Tk_DeleteTimerHandler(timer_token);
+
+ timer_tick = ttick;
+ if (timer_tick > 0) {
+ /* start timer callback */
+ timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl,
+ (ClientData)0);
+ } else {
+ timer_token = (Tcl_TimerToken)NULL;
+ }
+
+ return tick;
+}
+
+static VALUE
+get_eventloop_tick(self)
+ VALUE self;
+{
+ return INT2NUM(timer_tick);
+}
+
+static VALUE
+set_eventloop_weight(self, loop_max, no_event)
+ VALUE self;
+ VALUE loop_max;
+ VALUE no_event;
+{
+ int lpmax = NUM2INT(loop_max);
+ int no_ev = NUM2INT(no_event);
+
+ if (lpmax <= 0 || no_ev <= 0) {
+ rb_raise(rb_eArgError, "weight parameters must be plus number");
+ }
+
+ event_loop_max = lpmax;
+ no_event_tick = no_ev;
+
+ return rb_ary_new3(2, loop_max, no_event);
+}
+
+static VALUE
+get_eventloop_weight(self)
+ VALUE self;
+{
+ return rb_ary_new3(2, INT2NUM(event_loop_max), INT2NUM(no_event_tick));
+}
+
+VALUE
+lib_mainloop_core(check_root_widget)
+ VALUE check_root_widget;
+{
+ VALUE current = eventloop_thread;
+ int check = (check_root_widget == Qtrue);
+
+ Tk_DeleteTimerHandler(timer_token);
+ if (timer_tick > 0) {
+ timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl,
+ (ClientData)0);
+ } else {
+ timer_token = (Tcl_TimerToken)NULL;
+ }
+
+ for(;;) {
+ tick_counter = 0;
+ while(tick_counter < event_loop_max) {
+ if (Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT)) {
+ tick_counter++;
+ } else {
+ tick_counter += no_event_tick;
+ }
+ if (watchdog_thread != 0 && eventloop_thread != current) {
+ return Qnil;
}
+ }
+ if (check && Tk_GetNumMainWindows() == 0) {
+ break;
+ }
+ rb_thread_schedule();
+ }
+ return Qnil;
+}
+
+VALUE
+lib_mainloop_ensure(parent_evloop)
+ VALUE parent_evloop;
+{
+ Tk_DeleteTimerHandler(timer_token);
+ timer_token = (Tcl_TimerToken)NULL;
+ DUMP2("mainloop-ensure: current-thread : %lx\n", rb_thread_current());
+ DUMP2("mainloop-ensure: eventloop-thread : %lx\n", eventloop_thread);
+ if (eventloop_thread == rb_thread_current()) {
+ DUMP2("tcltklib: eventloop-thread -> %lx\n", parent_evloop);
+ eventloop_thread = parent_evloop;
}
- rb_thread_schedule();
+ return Qnil;
+}
+
+static VALUE
+lib_mainloop_launcher(check_rootwidget)
+ VALUE check_rootwidget;
+{
+ VALUE parent_evloop = eventloop_thread;
+
+ eventloop_thread = rb_thread_current();
+
+ if (ruby_debug) {
+ fprintf(stderr, "tcltklib: eventloop-thread : %lx -> %lx\n",
+ parent_evloop, eventloop_thread);
+ }
+
+ return rb_ensure(lib_mainloop_core, check_rootwidget,
+ lib_mainloop_ensure, parent_evloop);
}
/* execute Tk_MainLoop */
static VALUE
-lib_mainloop(self)
+lib_mainloop(argc, argv, self)
+ int argc;
+ VALUE *argv;
VALUE self;
{
- timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0);
- DUMP1("start Tk_Mainloop");
- Tk_MainLoop();
- DUMP1("stop Tk_Mainloop");
- Tk_DeleteTimerHandler(timer_token);
+ VALUE check_rootwidget;
+
+ if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) {
+ check_rootwidget = Qtrue;
+ } else if (RTEST(check_rootwidget)) {
+ check_rootwidget = Qtrue;
+ } else {
+ check_rootwidget = Qfalse;
+ }
+
+ return lib_mainloop_launcher(check_rootwidget);
+}
+
+VALUE
+lib_watchdog_core(check_rootwidget)
+ VALUE check_rootwidget;
+{
+ VALUE current = eventloop_thread;
+ VALUE evloop;
+ int check = (check_rootwidget == Qtrue);
+ ID stop = rb_intern("stop?");
+
+ /* check other watchdog thread */
+ if (watchdog_thread != 0) {
+ if (rb_funcall(watchdog_thread, stop, 0) == Qtrue) {
+ rb_funcall(watchdog_thread, rb_intern("kill"), 0);
+ } else {
+ return Qnil;
+ }
+ }
+ watchdog_thread = rb_thread_current();
+
+ /* watchdog start */
+ do {
+ if (eventloop_thread == 0
+ || rb_funcall(eventloop_thread, stop, 0) == Qtrue) {
+ /* start new eventloop thread */
+ DUMP2("eventloop thread %lx is sleeping or dead", eventloop_thread);
+ evloop = rb_thread_create(lib_mainloop_launcher,
+ (void*)&check_rootwidget);
+ DUMP2("create new eventloop thread %lx", evloop);
+ rb_thread_run(evloop);
+ } else {
+ rb_thread_schedule();
+ }
+ } while(!check || Tk_GetNumMainWindows() != 0);
return Qnil;
}
+VALUE
+lib_watchdog_ensure(arg)
+ VALUE arg;
+{
+ eventloop_thread = 0; /* stop eventloops */
+ return Qnil;
+}
+
+static VALUE
+lib_mainloop_watchdog(argc, argv, self)
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE check_rootwidget;
+
+ if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) {
+ check_rootwidget = Qtrue;
+ } else if (RTEST(check_rootwidget)) {
+ check_rootwidget = Qtrue;
+ } else {
+ check_rootwidget = Qfalse;
+ }
+
+ return rb_ensure(lib_watchdog_core, check_rootwidget,
+ lib_watchdog_ensure, Qnil);
+}
+
+static VALUE
+lib_do_one_event(argc, argv, self)
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE obj, vflags;
+ int flags;
+
+ if (rb_scan_args(argc, argv, "01", &vflags) == 0) {
+ flags = 0;
+ } else {
+ Check_Type(vflags, T_FIXNUM);
+ flags = FIX2INT(vflags);
+ }
+ return INT2NUM(Tcl_DoOneEvent(flags));
+}
+
/*---- class TclTkIp ----*/
struct tcltkip {
Tcl_Interp *ip; /* the interpreter */
int return_value; /* return value */
};
+static struct tcltkip *
+get_ip(self)
+ VALUE self;
+{
+ struct tcltkip *ptr;
+
+ Data_Get_Struct(self, struct tcltkip, ptr);
+ if (ptr == 0) {
+ rb_raise(rb_eTypeError, "uninitialized TclTkIp");
+ }
+ return ptr;
+}
+
/* Tcl command `ruby' */
static VALUE
ip_eval_rescue(failed, einfo)
@@ -126,10 +371,7 @@ static VALUE
lib_restart(self)
VALUE self;
{
- struct tcltkip *ptr; /* tcltkip data struct */
-
- /* get the data struct */
- Data_Get_Struct(self, struct tcltkip, ptr);
+ struct tcltkip *ptr = get_ip(self);
/* destroy the root wdiget */
ptr->return_value = Tcl_Eval(ptr->ip, "destroy .");
@@ -185,7 +427,9 @@ ip_ruby(clientData, interp, argc, argv)
DUMP2("rb_eval_string(%s)", arg);
old_trapflg = rb_trap_immediate;
rb_trap_immediate = 0;
- res = rb_rescue(rb_eval_string, (VALUE)arg, ip_eval_rescue, (VALUE)&failed);
+ res = rb_rescue2(rb_eval_string, (VALUE)arg,
+ ip_eval_rescue, (VALUE)&failed,
+ rb_eStandardError, rb_eScriptError, 0);
rb_trap_immediate = old_trapflg;
Tcl_ResetResult(interp);
@@ -221,8 +465,10 @@ ip_free(ptr)
struct tcltkip *ptr;
{
DUMP1("Tcl_DeleteInterp");
- Tcl_DeleteInterp(ptr->ip);
- free(ptr);
+ if (ptr) {
+ Tcl_DeleteInterp(ptr->ip);
+ free(ptr);
+ }
}
/* create and initialize interpreter */
@@ -276,10 +522,7 @@ ip_eval(self, str)
{
char *s;
char *buf; /* Tcl_Eval requires re-writable string region */
- struct tcltkip *ptr; /* tcltkip data struct */
-
- /* get the data struct */
- Data_Get_Struct(self, struct tcltkip, ptr);
+ struct tcltkip *ptr = get_ip(self);
/* call Tcl_Eval() */
s = STR2CSTR(str);
@@ -310,7 +553,7 @@ ip_toUTF8(self, str, encodename)
struct tcltkip *ptr;
char *buf;
- Data_Get_Struct(self,struct tcltkip, ptr);
+ ptr = get_ip(self);
interp = ptr->ip;
encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename));
@@ -341,7 +584,7 @@ ip_fromUTF8(self, str, encodename)
struct tcltkip *ptr;
char *buf;
- Data_Get_Struct(self,struct tcltkip, ptr);
+ ptr = get_ip(self);
interp = ptr->ip;
encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename));
@@ -367,10 +610,11 @@ ip_invoke_real(argc, argv, obj)
VALUE *argv;
VALUE obj;
{
+ VALUE v;
struct tcltkip *ptr; /* tcltkip data struct */
int i;
Tcl_CmdInfo info;
- char *cmd;
+ char *cmd, *s;
char **av = (char **)NULL;
#if TCL_MAJOR_VERSION >= 8
Tcl_Obj **ov = (Tcl_Obj **)NULL;
@@ -378,10 +622,11 @@ ip_invoke_real(argc, argv, obj)
#endif
/* get the data struct */
- Data_Get_Struct(obj, struct tcltkip, ptr);
+ ptr = get_ip(obj);
/* get the command name string */
- cmd = STR2CSTR(argv[0]);
+ v = argv[0];
+ cmd = STR2CSTR(v);
/* map from the command name to a C procedure */
if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) {
@@ -394,8 +639,9 @@ ip_invoke_real(argc, argv, obj)
/* object interface */
ov = (Tcl_Obj **)ALLOCA_N(Tcl_Obj *, argc+1);
for (i = 0; i < argc; ++i) {
- char *s = STR2CSTR(argv[i]);
- ov[i] = Tcl_NewStringObj(s, strlen(s));
+ v = argv[i];
+ s = STR2CSTR(v);
+ ov[i] = Tcl_NewStringObj(s, RSTRING(v)->len);
Tcl_IncrRefCount(ov[i]);
}
ov[argc] = (Tcl_Obj *)NULL;
@@ -406,8 +652,8 @@ ip_invoke_real(argc, argv, obj)
/* string interface */
av = (char **)ALLOCA_N(char *, argc+1);
for (i = 0; i < argc; ++i) {
- char *s = STR2CSTR(argv[i]);
-
+ v = argv[i];
+ s = STR2CSTR(v);
av[i] = ALLOCA_N(char, strlen(s)+1);
strcpy(av[i], s);
}
@@ -435,8 +681,9 @@ ip_invoke_real(argc, argv, obj)
else
#endif
{
- ptr->return_value = (*info.proc)(info.clientData,
- ptr->ip, argc, av);
+ TRAP_BEG;
+ ptr->return_value = (*info.proc)(info.clientData, ptr->ip, argc, av);
+ TRAP_END;
}
if (ptr->return_value == TCL_ERROR) {
@@ -447,48 +694,104 @@ ip_invoke_real(argc, argv, obj)
return rb_str_new2(ptr->ip->result);
}
+VALUE
+ivq_safelevel_handler(arg, ivq)
+ VALUE arg;
+ VALUE ivq;
+{
+ struct invoke_queue *q;
+
+ Data_Get_Struct(ivq, struct invoke_queue, q);
+ DUMP2("(safe-level handler) $SAFE = %d", q->safe_level);
+ rb_set_safe_level(q->safe_level);
+ return ip_invoke_real(q->argc, q->argv, q->obj);
+}
+
+int invoke_queue_handler _((Tcl_Event *, int));
+int
+invoke_queue_handler(evPtr, flags)
+ Tcl_Event *evPtr;
+ int flags;
+{
+ struct invoke_queue *tmp, *q = (struct invoke_queue *)evPtr;
+
+ DUMP1("do_invoke_queue_handler");
+ DUMP2("invoke queue_thread : %lx", rb_thread_current());
+ DUMP2("added by thread : %lx", q->thread);
+
+ if (q->done) {
+ /* processed by another event-loop */
+ return 0;
+ }
+
+ /* process it */
+ q->done = 1;
+
+ /* check safe-level */
+ if (rb_safe_level() != q->safe_level) {
+ *(q->result) = rb_funcall(rb_proc_new(ivq_safelevel_handler,
+ Data_Wrap_Struct(rb_cData,0,0,q)),
+ rb_intern("call"), 0);
+ } else {
+ *(q->result) = ip_invoke_real(q->argc, q->argv, q->obj);
+ }
+
+ /* back to caller */
+ rb_thread_run(q->thread);
+
+ /* end of handler : remove it */
+ return 1;
+}
+
static VALUE
ip_invoke(argc, argv, obj)
int argc;
VALUE *argv;
VALUE obj;
{
- struct invoke_queue *tmp, *p;
- VALUE result = rb_thread_current();
+ struct invoke_queue *tmp;
+ VALUE current = rb_thread_current();
+ VALUE result;
+ VALUE *alloc_argv, *alloc_result;
+ Tcl_QueuePosition position;
- if (result == main_thread) {
- return ip_invoke_real(argc, argv, obj);
+ if (eventloop_thread == 0 || current == eventloop_thread) {
+ DUMP2("invoke from current eventloop %lx", current);
+ return ip_invoke_real(argc, argv, obj);
}
- tmp = ALLOC(struct invoke_queue);
+
+ DUMP2("invoke from thread %lx (NOT current eventloop)", current);
+
+ /* allocate memory (protected from Tcl_ServiceEvent) */
+ alloc_argv = ALLOC_N(VALUE,argc);
+ MEMCPY(alloc_argv, argv, VALUE, argc);
+ alloc_result = ALLOC(VALUE);
+
+ /* allocate memory (freed by Tcl_ServiceEvent */
+ tmp = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue));
+
+ /* construct event data */
+ tmp->done = 0;
tmp->obj = obj;
tmp->argc = argc;
- tmp->argv = ALLOC_N(VALUE, argc);
- MEMCPY(tmp->argv, argv, VALUE, argc);
- tmp->thread = result;
- tmp->done = 0;
+ tmp->argv = alloc_argv;
+ tmp->result = alloc_result;
+ tmp->thread = current;
+ tmp->safe_level = rb_safe_level();
+ tmp->ev.proc = invoke_queue_handler;
+ position = TCL_QUEUE_TAIL;
- tmp->next = iqueue;
- iqueue = tmp;
+ /* add the handler to Tcl event queue */
+ Tcl_QueueEvent(&tmp->ev, position);
+ /* wait for the handler to be processed */
rb_thread_stop();
- result = tmp->result;
- if (iqueue == tmp) {
- iqueue = tmp->next;
- free(tmp->argv);
- free(tmp);
- return result;
- }
- p = iqueue;
- while (p->next) {
- if (p->next == tmp) {
- p->next = tmp->next;
- free(tmp->argv);
- free(tmp);
- break;
- }
- p = p->next;
- }
+ /* get result & free allocated memory */
+ result = *alloc_result;
+ free(alloc_argv);
+ free(alloc_result);
+
return result;
}
@@ -500,7 +803,7 @@ ip_retval(self)
struct tcltkip *ptr; /* tcltkip data struct */
/* get the data strcut */
- Data_Get_Struct(self, struct tcltkip, ptr);
+ ptr = get_ip(self);
return (INT2FIX(ptr->return_value));
}
@@ -521,6 +824,8 @@ Init_tcltklib()
VALUE lib = rb_define_module("TclTkLib");
VALUE ip = rb_define_class("TclTkIp", rb_cObject);
+ VALUE ev_flag = rb_define_module_under(lib, "EventFlag");
+
#if defined USE_TCL_STUBS && defined USE_TK_STUBS
extern int ruby_tcltk_stubs();
int ret = ruby_tcltk_stubs();
@@ -528,10 +833,26 @@ Init_tcltklib()
rb_raise(rb_eLoadError, "tcltklib: tcltk_stubs init error(%d)", ret);
#endif
+ rb_define_const(ev_flag, "WINDOW", INT2FIX(TCL_WINDOW_EVENTS));
+ rb_define_const(ev_flag, "FILE", INT2FIX(TCL_FILE_EVENTS));
+ rb_define_const(ev_flag, "TIMER", INT2FIX(TCL_TIMER_EVENTS));
+ rb_define_const(ev_flag, "IDLE", INT2FIX(TCL_IDLE_EVENTS));
+ rb_define_const(ev_flag, "ALL", INT2FIX(TCL_ALL_EVENTS));
+ rb_define_const(ev_flag, "DONT_WAIT", INT2FIX(TCL_DONT_WAIT));
+
eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError);
eTkCallbackContinue = rb_define_class("TkCallbackContinue",rb_eStandardError);
- rb_define_module_function(lib, "mainloop", lib_mainloop, 0);
+ rb_define_module_function(lib, "mainloop", lib_mainloop, -1);
+ rb_define_module_function(lib, "mainloop_watchdog",
+ lib_mainloop_watchdog, -1);
+ rb_define_module_function(lib, "do_one_event", lib_do_one_event, -1);
+ rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1);
+ rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0);
+ rb_define_module_function(lib, "set_eventloop_weight",
+ set_eventloop_weight, 2);
+ rb_define_module_function(lib, "get_eventloop_weight",
+ get_eventloop_weight, 0);
rb_define_singleton_method(ip, "new", ip_new, 0);
rb_define_method(ip, "_eval", ip_eval, 1);
@@ -539,10 +860,19 @@ Init_tcltklib()
rb_define_method(ip, "_fromUTF8",ip_fromUTF8,2);
rb_define_method(ip, "_invoke", ip_invoke, -1);
rb_define_method(ip, "_return_value", ip_retval, 0);
- rb_define_method(ip, "mainloop", lib_mainloop, 0);
+ rb_define_method(ip, "mainloop", lib_mainloop, -1);
+ rb_define_method(ip, "mainloop_watchdog", lib_mainloop_watchdog, -1);
+ rb_define_method(ip, "do_one_event", lib_do_one_event, -1);
+ rb_define_method(ip, "set_eventloop_tick", set_eventloop_tick, 1);
+ rb_define_method(ip, "get_eventloop_tick", get_eventloop_tick, 0);
+ rb_define_method(ip, "set_eventloop_weight", set_eventloop_weight, 2);
+ rb_define_method(ip, "get_eventloop_weight", get_eventloop_weight, 0);
rb_define_method(ip, "restart", lib_restart, 0);
main_thread = rb_thread_current();
+ eventloop_thread = 0;
+ watchdog_thread = 0;
+
#ifdef __MACOS__
_macinit();
#endif
diff --git a/file.c b/file.c
index 3243f41c4c..9a0789b5f6 100644
--- a/file.c
+++ b/file.c
@@ -2198,6 +2198,7 @@ rb_find_file_ext(filep, ext)
VALUE str = RARRAY(rb_load_path)->ptr[i];
Check_SafeStr(str);
+ if (RSTRING(str)->len == 0) return 0;
path = RSTRING(str)->ptr;
for (j=0; ext[j]; j++) {
fname = rb_str_dup(*filep);
@@ -2262,15 +2263,23 @@ rb_find_file(path)
}
}
tmp = rb_ary_join(tmp, rb_str_new2(PATH_SEP));
- lpath = STR2CSTR(tmp);
- if (rb_safe_level() >= 2 && !rb_path_check(lpath)) {
- rb_raise(rb_eSecurityError, "loading from unsafe path %s", lpath);
+ if (RSTRING(tmp)->len == 0) {
+ lpath = 0;
+ }
+ else {
+ lpath = STR2CSTR(tmp);
+ if (rb_safe_level() >= 2 && !rb_path_check(lpath)) {
+ rb_raise(rb_eSecurityError, "loading from unsafe path %s", lpath);
+ }
}
}
else {
lpath = 0;
}
+ if (!lpath) {
+ return 0; /* no path, no load */
+ }
f = dln_find_file(f, lpath);
if (file_load_ok(f)) {
return rb_str_new2(f);
diff --git a/lib/uri/mailto.rb b/lib/uri/mailto.rb
index bf6b954903..0a378b5c51 100644
--- a/lib/uri/mailto.rb
+++ b/lib/uri/mailto.rb
@@ -46,17 +46,19 @@ module URI
# hname = *urlc
# hvalue = *urlc
# header = hname "=" hvalue
- HEADER_REGEXP = "(?:[^?=&]*=[^?=&]*)".freeze
+ header_pattern = "(?:[^?=&]*=[^?=&]*)"
+ HEADER_REGEXP = /#{header_pattern}/
# headers = "?" header *( "&" header )
# to = #mailbox
# mailtoURL = "mailto:" [ to ] [ headers ]
- MAILBOX_REGEXP = "(?:[^(),%?=&]|#{PATTERN::ESCAPED})".freeze
+ mailbox_pattern = "(?:[^(),%?=&]|#{PATTERN::ESCAPED})"
+ MAILBOX_REGEXP = /#{mailbox_pattern}/
MAILTO_REGEXP = Regexp.new("
\\A
- (#{MAILBOX_REGEXP}*?) (?# 1: to)
+ (#{mailbox_pattern}*?) (?# 1: to)
(?:
\\?
- (#{HEADER_REGEXP}(?:\\&#{HEADER_REGEXP})*) (?# 2: headers)
+ (#{header_pattern}(?:\\&#{header_pattern})*) (?# 2: headers)
)?
\\z
", Regexp::EXTENDED, 'N').freeze
diff --git a/object.c b/object.c
index afaab4cbbb..73264b3e55 100644
--- a/object.c
+++ b/object.c
@@ -114,8 +114,8 @@ rb_obj_dup(obj)
VALUE dup;
dup = rb_funcall(obj, clone, 0, 0);
- if (TYPE(dup) != TYPE(obj)) {
- rb_raise(rb_eTypeError, "dupulicated object must be same type");
+ if (TYPE(dup) != TYPE(obj) || rb_obj_class(dup) != rb_obj_class(obj)) {
+ rb_raise(rb_eTypeError, "dupulicated object must be same class");
}
if (!SPECIAL_CONST_P(dup)) {
OBJSETUP(dup, rb_obj_class(obj), BUILTIN_TYPE(obj));
diff --git a/parse.y b/parse.y
index 10b8ab5ec4..7670c26119 100644
--- a/parse.y
+++ b/parse.y
@@ -1362,8 +1362,7 @@ primary : literal
}
if ($8) $5 = NEW_ENSURE($5, $8);
- /* NOEX_PRIVATE for toplevel */
- $$ = NEW_DEFN($2, $4, $5, class_nest?NOEX_PUBLIC:NOEX_PRIVATE);
+ $$ = NEW_DEFN($2, $4, $5, NOEX_PRIVATE);
if (is_attrset_id($2)) $$->nd_noex = NOEX_PUBLIC;
fixpos($$, $4);
local_pop();
@@ -3154,22 +3153,22 @@ yylex()
}
if (ISSPACE(c)){
if (lex_state != EXPR_ARG){
- int c = 0;
+ int c2 = 0;
switch (c) {
case ' ':
- c = 's';
+ c2 = 's';
break;
case '\n':
- c = 'n';
+ c2 = 'n';
break;
case '\t':
- c = 't';
+ c2 = 't';
break;
case '\v':
- c = 'v';
+ c2 = 'v';
break;
}
- if (c) {
+ if (c2) {
rb_warn("invalid character syntax; use ?\\%c", c);
}
}
@@ -4066,13 +4065,13 @@ str_extend(list, term, paren)
case '{':
if (c == '{') brace = '}';
- brace_nest = 0;
+ brace_nest = 1;
do {
loop_again:
c = nextc();
switch (c) {
case -1:
- if (brace_nest > 0) {
+ if (brace_nest > 1) {
yyerror("bad substitution in string");
newtok();
return list;
@@ -4080,8 +4079,8 @@ str_extend(list, term, paren)
return (NODE*)-1;
case '}':
if (c == brace) {
- if (brace_nest == 0) break;
brace_nest--;
+ if (brace_nest == 0) break;
}
tokadd(c);
goto loop_again;
@@ -4099,6 +4098,22 @@ str_extend(list, term, paren)
case '{':
if (brace != -1) brace_nest++;
default:
+ /* within brace */
+ if (brace_nest > 0) {
+ if (ismbchar(c)) {
+ int i, len = mbclen(c)-1;
+
+ for (i = 0; i < len; i++) {
+ tokadd(c);
+ c = nextc();
+ }
+ }
+ else {
+ tokadd(c);
+ }
+ break;
+ }
+ /* out of brace */
if (c == paren) paren_nest++;
else if (c == term && (!paren || paren_nest-- == 0)) {
pushback(c);
@@ -4109,14 +4124,7 @@ str_extend(list, term, paren)
newtok();
return list;
}
- else if (ismbchar(c)) {
- int i, len = mbclen(c)-1;
-
- for (i = 0; i < len; i++) {
- tokadd(c);
- c = nextc();
- }
- }
+ break;
case '\n':
tokadd(c);
break;
diff --git a/range.c b/range.c
index 8e3019df7b..6988e2e512 100644
--- a/range.c
+++ b/range.c
@@ -90,7 +90,7 @@ static VALUE
range_eq(range, obj)
VALUE range, obj;
{
- if (!rb_obj_is_kind_of(obj, rb_cRange)) return Qfalse;
+ if (!rb_obj_is_kind_of(obj, rb_obj_class(range))) return Qfalse;
if (!rb_equal(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
return Qfalse;
@@ -140,7 +140,7 @@ range_eql(range, obj)
VALUE range, obj;
{
if (range == obj) return Qtrue;
- if (!rb_obj_is_kind_of(obj, rb_cRange)) return Qfalse;
+ if (!rb_obj_is_kind_of(obj, rb_obj_class(range))) return Qfalse;
if (!rb_eql(rb_ivar_get(range, id_beg), rb_ivar_get(obj, id_beg)))
return Qfalse;
diff --git a/string.c b/string.c
index 803cf9ae70..ccf2cdcde6 100644
--- a/string.c
+++ b/string.c
@@ -2354,7 +2354,7 @@ rb_str_each_line(argc, argv, str)
if (*++p != '\n') continue;
while (*p == '\n') p++;
}
- if (p[-1] == newline &&
+ if (RSTRING(str)->ptr < p && p[-1] == newline &&
(rslen <= 1 ||
rb_memcmp(RSTRING(rs)->ptr, p-rslen, rslen) == 0)) {
line = rb_str_new(s, p - s);
diff --git a/variable.c b/variable.c
index 29dc1edb8a..95c03cd3fc 100644
--- a/variable.c
+++ b/variable.c
@@ -221,19 +221,40 @@ VALUE
rb_path2class(path)
const char *path;
{
- VALUE c;
+ const char *pbeg, *p;
+ ID id;
+ VALUE c = rb_cObject;
if (path[0] == '#') {
rb_raise(rb_eArgError, "can't retrieve anonymous class %s", path);
}
- c = rb_eval_string(path);
- switch (TYPE(c)) {
- case T_MODULE:
- case T_CLASS:
- break;
- default:
- rb_raise(rb_eTypeError, "class path %s does not point class", path);
+ pbeg = p = path;
+ while (*p) {
+ VALUE str;
+
+ while (*p && *p != ':') p++;
+ str = rb_str_new(pbeg, p-pbeg);
+ id = rb_intern(RSTRING(str)->ptr);
+ if (p[0] == ':') {
+ if (p[1] != ':') goto undefined_class;
+ p += 2;
+ pbeg = p;
+ }
+ if (!rb_const_defined(c, id)) {
+ undefined_class:
+ rb_raise(rb_eArgError, "undefined class/module %s", rb_id2name(id));
+ rb_raise(rb_eArgError, "undefined class/module %s", path);
+ }
+ c = rb_const_get_at(c, id);
+ switch (TYPE(c)) {
+ case T_MODULE:
+ case T_CLASS:
+ break;
+ default:
+ rb_raise(rb_eTypeError, "%s does not refer class/module %d", path, TYPE(c));
+ }
}
+
return c;
}
diff --git a/version.h b/version.h
index f904c0989e..1063690adb 100644
--- a/version.h
+++ b/version.h
@@ -1,4 +1,4 @@
#define RUBY_VERSION "1.6.7"
-#define RUBY_RELEASE_DATE "2002-09-22"
+#define RUBY_RELEASE_DATE "2002-09-25"
#define RUBY_VERSION_CODE 167
-#define RUBY_RELEASE_CODE 20020922
+#define RUBY_RELEASE_CODE 20020925