From 7bfc0f1b5c3f4f02193d7b5e1d631b224e054f8b Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 29 Oct 2002 10:31:12 +0000 Subject: 17868: Allow $SECONDS to become floating point. --- ChangeLog | 7 +++++++ Doc/Zsh/params.yo | 6 ++++++ Src/builtin.c | 48 ++++++++++++++++++++++++++++++++++++++--------- Src/params.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8bc841d84..610b0c88e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2002-10-29 Peter Stephenson + + * 17868: Src/builtin.c, Src/params.c, Doc/Zsh/params.yo: + Can `typeset -F SECONDS' to get better accuracy. Try to + catch all cases when converting or creating local copy + (but I missed at least one --- next patch). + 2002-10-18 Clint Adams * unposted: Completion/Debian/Command/_apt: add showsrc part missing diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index f45a9eb39..889ab3f85 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -589,6 +589,12 @@ The number of seconds since shell invocation. If this parameter is assigned a value, then the value returned upon reference will be the value that was assigned plus the number of seconds since the assignment. + +Unlike other special parameters, the type of the tt(SECONDS) parameter can +be changed using the tt(typeset) command. Only integer and one of the +floating point types are allowed. For example, `tt(typeset -F SECONDS)' +causes the value to be reported as a floating point number. The precision +is six decimal places, although not all places may be useful. ) vindex(SHLVL) item(tt(SHLVL) )( diff --git a/Src/builtin.c b/Src/builtin.c index d36b697bc..9f1c2dcb6 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1653,6 +1653,13 @@ getasg(char *s) return &asg; } +/* for new special parameters */ +enum { + NS_NONE, + NS_NORMAL, + NS_SECONDS +}; + /* function to set a single parameter */ /**/ @@ -1661,7 +1668,7 @@ typeset_single(char *cname, char *pname, Param pm, int func, int on, int off, int roff, char *value, Param altpm, Options ops, int auxlen) { - int usepm, tc, keeplocal = 0, newspecial = 0; + int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly; char *subscript; /* @@ -1694,14 +1701,15 @@ typeset_single(char *cname, char *pname, Param pm, int func, * local. It can be applied either to the special or in the * typeset/local statement for the local variable. */ - newspecial = (pm->flags & PM_SPECIAL) - && !(on & PM_HIDE) && !(pm->flags & PM_HIDE & ~off); + if ((pm->flags & PM_SPECIAL) + && !(on & PM_HIDE) && !(pm->flags & PM_HIDE & ~off)) + newspecial = NS_NORMAL; usepm = 0; } /* attempting a type conversion, or making a tied colonarray? */ tc = 0; - if (usepm || newspecial) { + if (usepm || newspecial != NS_NONE) { int chflags = ((off & pm->flags) | (on & ~pm->flags)) & (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED| PM_ARRAY|PM_TIED|PM_AUTOLOAD); @@ -1716,11 +1724,31 @@ typeset_single(char *cname, char *pname, Param pm, int func, * with a special or a parameter which isn't loaded yet (which * may be special when it is loaded; we can't tell yet). */ - if (tc || ((usepm || newspecial) && (off & pm->flags & PM_READONLY))) { + if ((readonly = + ((usepm || newspecial != NS_NONE) && + (off & pm->flags & PM_READONLY))) || + tc) { if (pm->flags & PM_SPECIAL) { - zerrnam(cname, "%s: can't change type of a special parameter", - pname, 0); - return NULL; + int err = 1; + if (!readonly && !strcmp(pname, "SECONDS")) + { + if (newspecial != NS_NONE) + { + newspecial = NS_SECONDS; + err = 0; /* and continue */ + tc = 0; /* but don't do a normal conversion */ + } else if (!setsecondstype(pm, on, off)) { + if (value && !setsparam(pname, ztrdup(value))) + return NULL; + return pm; + } + } + if (err) + { + zerrnam(cname, "%s: can't change type of a special parameter", + pname, 0); + return NULL; + } } else if (pm->flags & PM_AUTOLOAD) { zerrnam(cname, "%s: can't change type of autoloaded parameter", pname, 0); @@ -1820,7 +1848,7 @@ typeset_single(char *cname, char *pname, Param pm, int func, unsetparam_pm(pm, 0, 1); } - if (newspecial) { + if (newspecial != NS_NONE) { Param tpm, pm2; if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { zerrnam(cname, "%s: restricted", pname, 0); @@ -1866,6 +1894,8 @@ typeset_single(char *cname, char *pname, Param pm, int func, * because we've checked for unpleasant surprises above. */ pm->flags = (PM_TYPE(pm->flags) | on | PM_SPECIAL) & ~off; + if (newspecial == NS_SECONDS) + setsecondstype(pm, on, off); /* * Final tweak: if we've turned on one of the flags with * numbers, we should use the appropriate integer. diff --git a/Src/params.c b/Src/params.c index 0b3a065ba..0d796871f 100644 --- a/Src/params.c +++ b/Src/params.c @@ -141,7 +141,7 @@ IPDEF1("EGID", egidgetfn, egidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("HISTSIZE", histsizegetfn, histsizesetfn, PM_RESTRICTED), IPDEF1("RANDOM", randomgetfn, randomsetfn, 0), IPDEF1("SAVEHIST", savehistsizegetfn, savehistsizesetfn, PM_RESTRICTED), -IPDEF1("SECONDS", secondsgetfn, secondssetfn, 0), +IPDEF1("SECONDS", intsecondsgetfn, intsecondssetfn, 0), IPDEF1("UID", uidgetfn, uidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("EUID", euidgetfn, euidsetfn, PM_DONTIMPORT | PM_RESTRICTED), IPDEF1("TTYIDLE", ttyidlegetfn, nullintsetfn, PM_READONLY), @@ -2670,7 +2670,7 @@ randomsetfn(Param pm, zlong v) /**/ zlong -secondsgetfn(Param pm) +intsecondsgetfn(Param pm) { return time(NULL) - shtimer.tv_sec; } @@ -2679,12 +2679,60 @@ secondsgetfn(Param pm) /**/ void -secondssetfn(Param pm, zlong x) +intsecondssetfn(Param pm, zlong x) { shtimer.tv_sec = time(NULL) - x; shtimer.tv_usec = 0; } +/**/ +double +floatsecondsgetfn(Param pm) +{ + struct timeval now; + struct timezone dummy_tz; + + gettimeofday(&now, &dummy_tz); + + return (double)(now.tv_sec - shtimer.tv_sec) + + (double)(now.tv_usec - shtimer.tv_usec) / 1000000.0; +} + +/**/ +void +floatsecondssetfn(Param pm, double x) +{ + struct timeval now; + struct timezone dummy_tz; + + gettimeofday(&now, &dummy_tz); + shtimer.tv_sec = now.tv_sec - (int)x; + shtimer.tv_usec = now.tv_usec - (int)((x - (double)(int)x) * 1000000.0); +} + +/**/ +int +setsecondstype(Param pm, int on, int off) +{ + int newflags = (pm->flags | on) & ~off; + int tp = PM_TYPE(newflags); + /* Only one of the numeric types is allowed. */ + if (tp == PM_EFLOAT || tp == PM_FFLOAT) + { + pm->gets.ffn = floatsecondsgetfn; + pm->sets.ffn = floatsecondssetfn; + } + else if (tp == PM_INTEGER) + { + pm->gets.ifn = intsecondsgetfn; + pm->sets.ifn = intsecondssetfn; + } + else + return 1; + pm->flags = newflags; + return 0; +} + /* Function to get value for special parameter `USERNAME' */ /**/ @@ -3435,6 +3483,8 @@ scanendscope(HashNode hn, int flags) */ Param tpm = pm->old; + if (!strcmp(pm->nam, "SECONDS")) + setsecondstype(pm, PM_TYPE(tpm->flags), PM_TYPE(pm->flags)); DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) || !(tpm->flags & PM_SPECIAL), "BUG: in restoring scope of special parameter"); -- cgit 1.4.1