summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Doc/Zsh/params.yo6
-rw-r--r--Src/builtin.c48
-rw-r--r--Src/params.c56
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 <pws@csr.com>
+
+ * 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 <clint@zsh.org>
* 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) <S>)(
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");