- 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