@@@ tvec setvar
[mLib] / test / tvec-timeout.c
index d9a614b..a1800db 100644 (file)
@@ -77,177 +77,73 @@ void tvec_timeoutsetup(struct tvec_state *tv, const struct tvec_env *env,
   if (subenv && subenv->setup) subenv->setup(tv, subenv, tc, tc->subctx);
 }
 
-/* --- @tvec_timeoutset@ --- *
+/* --- @tvec_timeoutfindvar@, @setvar@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test vector state
  *             @const char *var@ = variable name to set
+ *             @const union tvec_regval *rv@ = register value
+ *             @void **ctx_out@ = where to put the @setvar@ context
  *             @void *ctx@ = context pointer
  *
- * Returns:    %$+1$% on success, %$0$% if the variable name was not
- *             recognized, or %$-1$% on any other error.
+ * Returns:    @tvec_timeoutfindvar@ returns a pointer to the variable
+ *             definition, or null; @setvar@ returns zero on success or
+ *             %$-1$% on error.
  *
- * Use:                Set a special variable.  The following special variables are
- *             supported.
+ * Use:                Find a definition for a special variable.  The following
+ *             special variables are supported.
  *
- *               * %|@timeout|% is the number of seconds (or other unit) to
- *                 wait before giving up and killing the test process.  The
- *                 string may also include a keyword %|REAL|%, %|VIRTUAL|%,
- *                 or %|PROF|% to select the timer.
+ *               * %|@timeout|% is the duration to wait before killing the
+ *                 process.
+ *
+ *               * %|@timer|% is the timer to use to measure the duration.
  *
  *             Unrecognized variables are passed to the subordinate
  *             environment, if there is one.
  */
 
-int tvec_timeoutset(struct tvec_state *tv, const char *var, void *ctx)
+static int setvar(struct tvec_state *tv, const char *var,
+                 const union tvec_regval *rv, void *ctx)
+{
+  struct tvec_timeoutctx *tc = ctx;
+
+  if (STRCMP(var, ==, "@timeout")) {
+    if (tc->f&TVTF_SETTMO) return (tvec_dupreg(tv, var));
+    tc->t = rv->f; tc->f |= TVTF_SETTMO;
+  } else if (STRCMP(var, ==, "@timer")) {
+    if (tc->f&TVTF_SETTMR) return (tvec_dupreg(tv, var));
+    tc->timer = rv->i; tc->f |= TVTF_SETTMR;
+  } else assert(!"unknown var");
+  return (0);
+}
+
+static const struct tvec_vardef timeout_var =
+  { sizeof(struct tvec_reg), setvar,
+    { "@timeout", -1, &tvty_duration, 0 } };
+
+static const struct tvec_iassoc timer_assocs[] = {
+  { "REAL",    ITIMER_REAL },
+  { "VIRTUAL", ITIMER_VIRTUAL },
+  { "PROF",    ITIMER_PROF },
+  TVEC_ENDENUM
+};
+static const struct tvec_ienuminfo timer_enum =
+  { "interval-timer", timer_assocs, &tvrange_int };
+static const struct tvec_vardef timer_var =
+  { sizeof(struct tvec_reg), setvar,
+    { "@timer", -1, &tvty_ienum, 0, { &timer_enum } } };
+
+const struct tvec_vardef *tvec_timeoutfindvar
+  (struct tvec_state *tv, const char *var, void **ctx_out, void *ctx)
 {
   struct tvec_timeoutctx *tc = ctx;
   const struct tvec_timeoutenv *te = tc->te;
   const struct tvec_env *subenv = te->env;
-  dstr d = DSTR_INIT;
-  double t = 0.0; unsigned tmr = 0;
-  const char *p; char *q; size_t pos;
-  int rc;
-  unsigned f = 0;
-#define f_time 1u
-#define f_timer 2u
-#define f_all (f_time | f_timer)
 
-  if (STRCMP(var, ==, "@timeout")) {
-    /* Parse a timeout specification. */
-
-    /* If we've already set one then report an error. */
-    if (tc->f&TVTF_SETTMO) { rc = tvec_dupreg(tv, var); goto end; }
-
-    for (;;) {
-      /* Continue until we run out of things. */
-
-      /* Read the next word. */
-      DRESET(&d); if (tvec_readword(tv, &d, ";", 0)) break;
-    timeout_primed:
-
-      /* Start parsing the word. */
-      p = d.buf;
-
-      /* Check for timer tokens. */
-      if (!(f&f_timer) && STRCMP(p, ==, "REAL"))
-       { tmr = ITIMER_REAL; f |= f_timer;  }
-      else if (!(f&f_timer) && STRCMP(p, ==, "VIRTUAL"))
-       { tmr = ITIMER_VIRTUAL; f |= f_timer; }
-      else if (!(f&f_timer) && STRCMP(p, ==, "PROF"))
-       { tmr = ITIMER_PROF; f |= f_timer; }
-
-      /* Otherwise, check for durations. */
-      else if (!(f&f_time)) {
-
-       /* Skip leading stuff that isn't digits.  This is a hedge against
-        * @strtod@ interpreting something unhelpful like a NaN.
-        */
-       if (*p == '+' || *p == '-') p++;
-       if (*p == '.') p++;
-       if (!ISDIGIT(*p)) {
-         tvec_syntax(tv, *d.buf, "floating-point number");
-         rc = -1; goto end;
-       }
-
-       /* Parse the number and check that it's reasonable. */
-       errno = 0; t = strtod(p, &q); f |= f_time;
-       if (errno) {
-         tvec_error(tv, "invalid floating-point number `%s': %s",
-                    d.buf, strerror(errno));
-         rc = -1; goto end;
-       }
-       if (t < 0) {
-         tvec_error(tv, "invalid duration `%s': %s",
-                    d.buf, strerror(errno));
-         rc = -1; goto end;
-       }
-
-       /* We're now on the lookout for units.  If there's nothing here then
-        * fetch the next word.
-        */
-       if (!*q) {
-         tvec_skipspc(tv); pos = d.len;
-         if (!tvec_readword(tv, &d, ";", 0)) pos++;
-         q = d.buf + pos;
-       }
-
-       /* Match various units. */
-       if (!*q || STRCMP(q, ==, "s") || STRCMP(q, ==, "sec"))
-         /* nothing to do */;
-
-       else if (STRCMP(q, ==, "ds")) t *= 1e-1;
-       else if (STRCMP(q, ==, "cs")) t *= 1e-2;
-       else if (STRCMP(q, ==, "ms")) t *= 1e-3;
-       else if (STRCMP(q, ==, "us") || STRCMP(q, ==, "µs")) t *= 1e-6;
-       else if (STRCMP(q, ==, "ns")) t *= 1e-9;
-       else if (STRCMP(q, ==, "ps")) t *= 1e-12;
-       else if (STRCMP(q, ==, "fs")) t *= 1e-15;
-       else if (STRCMP(q, ==, "as")) t *= 1e-18;
-       else if (STRCMP(q, ==, "zs")) t *= 1e-21;
-       else if (STRCMP(q, ==, "ys")) t *= 1e-24;
-
-       else if (STRCMP(q, ==, "das")) t *= 1e+1;
-       else if (STRCMP(q, ==, "hs")) t *= 1e+2;
-       else if (STRCMP(q, ==, "ks")) t *= 1e+3;
-       else if (STRCMP(q, ==, "Ms")) t *= 1e+6;
-       else if (STRCMP(q, ==, "Gs")) t *= 1e+9;
-       else if (STRCMP(q, ==, "Ts")) t *= 1e+12;
-       else if (STRCMP(q, ==, "Ps")) t *= 1e+15;
-       else if (STRCMP(q, ==, "Es")) t *= 1e+18;
-       else if (STRCMP(q, ==, "Zs")) t *= 1e+21;
-       else if (STRCMP(q, ==, "Ys")) t *= 1e+24;
-
-       else if (STRCMP(q, ==, "m") || STRCMP(q, ==, "min")) t *= 60;
-       else if (STRCMP(q, ==, "h") || STRCMP(q, ==, "hr")) t *= 3600;
-       else if (STRCMP(q, ==, "d") || STRCMP(q, ==, "dy")) t *= 86400;
-       else if (STRCMP(q, ==, "y") || STRCMP(q, ==, "yr")) t *= 31557600;
-
-       /* Not a unit specification after all.  If we've already selected a
-        * timer, then this is just junk so report the error.  Otherwise, we
-        * snarfed the next token too early, so move it to the start of the
-        * buffer and go round again.
-        */
-       else {
-         if (f&f_timer)
-           { rc = tvec_syntax(tv, *q, "end-of-line"); goto end; }
-         pos = q - d.buf; d.len -= pos;
-         memmove(d.buf, q, d.len + 1);
-         goto timeout_primed;
-       }
-      }
-
-      /* If we've read all that we need to, then stop. */
-      if (!(~f&f_all)) break;
-    }
-
-    /* If we didn't get anything, that's a problem. */
-    if (!f) {
-      rc = tvec_syntax(tv, fgetc(tv->fp), "timeout or timer keyword");
-      goto end;
-    }
-
-    /* Make sure there's nothing else on the line. */
-    rc = tvec_flushtoeol(tv, 0); if (rc) goto end;
-    if (f&f_time) tc->t = t;
-    if (f&f_timer) tc->timer = tmr;
-    tc->f |= TVTF_SETTMO;
-    rc = 1;
-
-  } else if (subenv && subenv->set)
-    /* Not one of ours: pass it on to the sub-environment. */
-    rc = subenv->set(tv, var, tc->subctx);
-  else
-    /* No subenvironment.  Report the error. */
-    rc = 0;
-
-  /* Done. */
-end:
-  dstr_destroy(&d);
-  return (rc);
-
-#undef f_time
-#undef f_timer
-#undef f_all
+  if (STRCMP(var, ==, "@timeout")) { *ctx_out = tc; return (&timeout_var); }
+  else if (STRCMP(var, ==, "@timer")) { *ctx_out = tc; return (&timer_var); }
+  else if (subenv && subenv->findvar)
+    return (subenv->findvar(tv, var, ctx_out, tc->subctx));
+  else return (0);
 }
 
 /* --- @tvec_timeoutbefore@ --- *
@@ -267,7 +163,6 @@ void tvec_timeoutbefore(struct tvec_state *tv, void *ctx)
   const struct tvec_timeoutenv *te = tc->te;
   const struct tvec_env *subenv = te->env;
 
-  /* Just call the subsidiary environment. */
   if (subenv && subenv->before) subenv->before(tv, tc->subctx);
 }