summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2017-07-03 13:24:42 (GMT)
committersebres <sebres@users.sourceforge.net>2017-07-03 13:24:42 (GMT)
commit0e11ffaa99da39ffd0a3eac314a1f9f848641b83 (patch)
tree56a4396103e194aeb006a124ac3f5bdec84e7dbb
parent5daa7f610ab6e2ea43bca023cb3cfe96811b48b4 (diff)
downloadtcl-0e11ffaa99da39ffd0a3eac314a1f9f848641b83.zip
tcl-0e11ffaa99da39ffd0a3eac314a1f9f848641b83.tar.gz
tcl-0e11ffaa99da39ffd0a3eac314a1f9f848641b83.tar.bz2
interim commit: try to extend "vwait" with same options as "update"
-rw-r--r--generic/tclEvent.c166
-rw-r--r--tests/event.test16
2 files changed, 121 insertions, 61 deletions
diff --git a/generic/tclEvent.c b/generic/tclEvent.c
index d18836b..6413d10 100644
--- a/generic/tclEvent.c
+++ b/generic/tclEvent.c
@@ -1298,6 +1298,61 @@ TclInThreadExit(void)
return tsdPtr->inExit;
}
}
+
+
+static int
+GetEventFlagsFromOpts(
+ Tcl_Interp *interp, /* Used for error reporting if not NULL. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *CONST objv[], /* Arguments containing the option to lookup. */
+ int *flagsPtr) /* Input and resulting flags. */
+{
+ int i, optionIndex, result = TCL_ERROR;
+ int flags = *flagsPtr; /* default flags */
+ static CONST char *updateOptions[] = {
+ "-idle", "-noidle", /* new options */
+ "-timer", "-notimer",
+ "-file", "-nofile",
+ "-window", "-nowindow",
+ "-async", "-noasync",
+ "-nowait", "-wait",
+ "idletasks", /* backwards compat. */
+ NULL};
+ static CONST struct {
+ int mask;
+ int flags;
+ } *updateFlag, updateFlags[] = {
+ {0, TCL_IDLE_EVENTS}, {TCL_IDLE_EVENTS, 0}, /* -idle, -noidle */
+ {0, TCL_TIMER_EVENTS}, {TCL_TIMER_EVENTS, 0}, /* -timer, -notimer */
+ {0, TCL_FILE_EVENTS}, {TCL_FILE_EVENTS, 0}, /* -file, -nofile */
+ {0, TCL_WINDOW_EVENTS}, {TCL_WINDOW_EVENTS, 0}, /* -window, -nowindow */
+ {0, TCL_ASYNC_EVENTS}, {TCL_ASYNC_EVENTS, 0}, /* -async, -noasync */
+ {0, TCL_DONT_WAIT}, {TCL_DONT_WAIT, 0}, /* -nowait, -wait */
+ {TCL_ALL_EVENTS,
+ TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS}, /* idletasks */
+ {0, 0} /* dummy / place holder */
+ };
+
+ for (i = 0; i < objc; i++) {
+ if (Tcl_GetIndexFromObj(interp, objv[i], updateOptions,
+ "option", 0, &optionIndex) != TCL_OK) {
+ goto done;
+ }
+ updateFlag = &updateFlags[optionIndex];
+ /* pure positive option and still default,
+ * reset all events (only this flag) */
+ if (!updateFlag->mask && flags == *flagsPtr) {
+ flags &= ~TCL_ALL_EVENTS;
+ }
+ flags &= ~updateFlag->mask;
+ flags |= updateFlag->flags;
+ }
+ result = TCL_OK;
+
+ done:
+ *flagsPtr = flags;
+ return result;
+}
static void
VwaitTimeOutProc(
@@ -1332,57 +1387,90 @@ Tcl_VwaitObjCmd(
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
- int done, foundEvent, flags = TCL_ALL_EVENTS;
+ int done = 0, foundEvent;
+ int flags = TCL_ALL_EVENTS; /* default flags */
char *nameString;
+ int opti = 1, /* start option index (and index of varname later) */
+ optc = objc - 2; /* options count without cmd and varname */
TimerEntry *timerEvent = NULL;
+ Tcl_WideInt ms = -1;
- if (objc < 2 || objc > 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "name ?timeout?");
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "?options? name ?timeout?");
return TCL_ERROR;
}
+ /* if arguments available - wrap options to flags */
+ if (objc >= 3) {
+ /* first try to recognize options up to the possible end, thereby
+ * we assume that varname is not integer, try to get numeric timeout,
+ * (just assume precidence of option fewer as timeout)
+ */
+ if (Tcl_GetWideIntFromObj(NULL, objv[objc-1], &ms) == TCL_OK) {
+ objc--;
+ optc--;
+ }
+
+ /* now try to parse options (if available) */
+ if ( optc > 0
+ && GetEventFlagsFromOpts(interp, optc, objv+1, &flags) != TCL_OK
+ ) {
+ return TCL_ERROR;
+ }
+ /* opti points to varname */
+ opti += optc;
+ }
+
+ done = 0;
+
/* if timeout specified - create timer event or no-wait by 0ms */
- if (objc == 3) {
- Tcl_Time wakeup;
- Tcl_WideInt ms;
- if (Tcl_GetWideIntFromObj(interp, objv[2], &ms) != TCL_OK) {
- return TCL_ERROR;
- }
- if (ms > 0) {
+ if (ms != -1) {
+ Tcl_Time wakeup;
+
+ if (ms > 0) {
Tcl_GetTime(&wakeup);
wakeup.sec += (long)(ms / 1000);
wakeup.usec += ((long)(ms % 1000)) * 1000;
if (wakeup.usec > 1000000) {
- wakeup.sec++;
- wakeup.usec -= 1000000;
+ wakeup.sec++;
+ wakeup.usec -= 1000000;
}
timerEvent = TclCreateAbsoluteTimerHandlerEx(&wakeup, VwaitTimeOutProc, NULL, 0);
timerEvent->clientData = &done;
} else if (ms == 0) {
flags |= TCL_DONT_WAIT;
- } else {
- /* infinite vait */
- objc = 2;
}
}
- nameString = Tcl_GetString(objv[1]);
+ nameString = Tcl_GetString(objv[opti]);
if (Tcl_TraceVar(interp, nameString,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, (ClientData) &done) != TCL_OK) {
+
+ /* if timeout-timer and no timeout fired, cancel timer event */
+ if (timerEvent && done != -1) {
+ TclDeleteTimerEntry(timerEvent);
+ }
return TCL_ERROR;
};
- done = 0;
do {
if ((foundEvent = Tcl_DoOneEvent(flags)) == 0) {
- /* no wait, no error - just stop waiting (no more events) */
- if (flags |= TCL_DONT_WAIT) {
+ /*
+ * If don't wait flag set - no error, and two cases:
+ * option -nowait for vwait means - we don't wait for events
+ * if no timeout (0) - just stop waiting (no more events)
+ */
+ if (flags & TCL_DONT_WAIT) {
foundEvent = 1;
+ if (ms != 0) {
+ goto checkLimit; /* continue waiting */
+ }
done = -2;
}
break;
}
+ checkLimit:
if (Tcl_LimitExceeded(interp)) {
foundEvent = -1;
break;
@@ -1399,7 +1487,7 @@ Tcl_VwaitObjCmd(
}
/* if timeout specified (and no errors) */
- if (objc == 3 && foundEvent > 0) {
+ if (ms != -1 && foundEvent > 0) {
Tcl_Obj *objPtr;
/* done - true, timeout false */
@@ -1468,42 +1556,14 @@ Tcl_UpdateObjCmd(
int objc, /* Number of arguments. */
Tcl_Obj *CONST objv[]) /* Argument objects. */
{
- int i, optionIndex;
- static CONST defUpdateFlags = TCL_ALL_EVENTS|TCL_DONT_WAIT;
- int flags = defUpdateFlags;
- static CONST char *updateOptions[] = {"idletasks", /* backwards compat. */
- "-nowait", "-wait", /* new options */
- "-idle", "-noidle", "-timer", "-notimer",
- "-file", "-nofile", "-window", "-nowindow",
- "-async", "-noasync",
- NULL};
- static CONST struct {
- int minus;
- int plus;
- } *updateFlag, updateFlags[] = {
- {TCL_ALL_EVENTS,
- TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS}, /* idletasks */
- {0, TCL_DONT_WAIT}, {TCL_DONT_WAIT, 0}, /* -nowait, -wait */
- {0, TCL_IDLE_EVENTS}, {TCL_IDLE_EVENTS, 0}, /* -idle, -noidle */
- {0, TCL_TIMER_EVENTS}, {TCL_TIMER_EVENTS, 0}, /* -file, -nofile */
- {0, TCL_FILE_EVENTS}, {TCL_FILE_EVENTS, 0}, /* -file, -nofile */
- {0, TCL_WINDOW_EVENTS}, {TCL_WINDOW_EVENTS, 0}, /* -window, -nowindow */
- {0, TCL_ASYNC_EVENTS}, {TCL_ASYNC_EVENTS, 0}, /* -async, -noasync */
- {0, 0} /* dummy / place holder */
- };
+ int flags = TCL_ALL_EVENTS|TCL_DONT_WAIT; /* default flags */
- for (i = 1; i < objc; i++) {
- if (Tcl_GetIndexFromObj(interp, objv[i], updateOptions,
- "option", 0, &optionIndex) != TCL_OK) {
+ /* if arguments available - wrap options to flags */
+ if (objc > 1) {
+ int i = 1;
+ if (GetEventFlagsFromOpts(interp, objc-1, objv+1, &flags) != TCL_OK) {
return TCL_ERROR;
}
- updateFlag = &updateFlags[optionIndex];
- /* pure positive option and still default - reset all events */
- if (flags == defUpdateFlags && !updateFlag->minus) {
- flags &= ~TCL_ALL_EVENTS;
- }
- flags &= ~updateFlag->minus;
- flags |= updateFlag->plus;
}
while (Tcl_DoOneEvent(flags) != 0) {
diff --git a/tests/event.test b/tests/event.test
index cf65ae17..cce486a 100644
--- a/tests/event.test
+++ b/tests/event.test
@@ -488,10 +488,10 @@ test event-10.1 {Tcl_Exit procedure} {stdio} {
test event-11.1 {Tcl_VwaitCmd procedure} {
list [catch {vwait} msg] $msg
-} {1 {wrong # args: should be "vwait name ?timeout?"}}
+} {1 {wrong # args: should be "vwait ?options? name ?timeout?"}}
test event-11.2 {Tcl_VwaitCmd procedure} {
list [catch {vwait a b} msg] $msg
-} {1 {expected integer but got "b"}}
+} {1 {bad option "a": must be -idle, -noidle, -timer, -notimer, -file, -nofile, -window, -nowindow, -async, -noasync, -nowait, -wait, or idletasks}}
test event-11.3 {Tcl_VwaitCmd procedure} {
catch {unset x}
set x 1
@@ -568,15 +568,15 @@ test event-11.4.1 {vwait with timeout} {} {
set x {}
# success cases:
after 0 {lappend z 0}
- after 20 {lappend x 1}
- after 30 {lappend x 2}
- after 100 {lappend x 3}
+ after 100 {lappend x 1}
+ after 100 {lappend x 2}
+ after 500 {lappend x 3}
after 1000 {lappend x "error-too-slow"}
vwait x 0; # no-wait
lappend z $x; # 0 {} - (x still empty)
- vwait x 50; # wait up-to 50ms
+ vwait x 200; # wait up-to 200ms
lappend z $x; # 0 {} {1 2}
- vwait x -1; # wait without timeout
+ vwait x -1; # infinite wait
lappend z $x; # 0 {} {1 2} {1 2 3}
foreach i [after info] {
after cancel $i
@@ -696,7 +696,7 @@ test event-11.7 {Bug 16828b3744} {
test event-12.2 {Tcl_UpdateCmd procedure} {
list [catch {update bogus} msg] $msg
-} {1 {bad option "bogus": must be idletasks, -nowait, -wait, -idle, -noidle, -timer, -notimer, -file, -nofile, -window, -nowindow, -async, or -noasync}}
+} {1 {bad option "bogus": must be -idle, -noidle, -timer, -notimer, -file, -nofile, -window, -nowindow, -async, -noasync, -nowait, -wait, or idletasks}}
test event-12.3 {Tcl_UpdateCmd procedure} {
foreach i [after info] {
after cancel $i