diff options
| author | Paul Eggert | 2014-11-16 20:38:15 -0800 |
|---|---|---|
| committer | Paul Eggert | 2014-11-16 20:41:22 -0800 |
| commit | 0921dbc3ab4dcc6b291ef45e46a24b322bbcb885 (patch) | |
| tree | 0e320978c7d30af415bb7de6e0b8f6735a3ca3d1 /src/editfns.c | |
| parent | 058f56d24f776bdc25bcac86fe1f8969a78374e9 (diff) | |
| download | emacs-0921dbc3ab4dcc6b291ef45e46a24b322bbcb885.tar.gz emacs-0921dbc3ab4dcc6b291ef45e46a24b322bbcb885.zip | |
Improve time stamp handling, and be more consistent about it.
This implements a suggestion made in:
http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00587.html
Among other things, this means timer.el no longer needs to
autoload the time-date module.
* doc/lispref/os.texi (Time of Day, Time Conversion, Time Parsing)
(Processor Run Time, Time Calculations):
Document the new behavior, plus be clearer about the old behavior.
(Idle Timers): Take advantage of new functionality.
* etc/NEWS: Document the changes.
* lisp/allout-widgets.el (allout-elapsed-time-seconds): Doc fix.
* lisp/arc-mode.el (archive-ar-summarize):
* lisp/calendar/time-date.el (seconds-to-time, days-to-time, time-since):
* lisp/emacs-lisp/timer.el (timer-relative-time, timer-event-handler)
(run-at-time, with-timeout-suspend, with-timeout-unsuspend):
* lisp/net/tramp.el (tramp-time-less-p, tramp-time-subtract):
* lisp/proced.el (proced-time-lessp):
* lisp/timezone.el (timezone-time-from-absolute):
* lisp/type-break.el (type-break-schedule, type-break-time-sum):
Simplify by using new functionality.
* lisp/calendar/cal-dst.el (calendar-next-time-zone-transition):
Do not return time values in obsolete and undocumented (HI . LO)
format; use (HI LO) instead.
* lisp/calendar/time-date.el (with-decoded-time-value):
Treat 'nil' as current time. This is mostly for XEmacs.
(encode-time-value, with-decoded-time-value): Obsolete.
(time-add, time-subtract, time-less-p): Use no-op autoloads, for
XEmacs. Define only if XEmacs, as they're now C builtins in Emacs.
* lisp/ldefs-boot.el: Update to match new time-date.el
* lisp/proced.el: Do not require time-date.
* src/editfns.c (invalid_time): New function.
Use it instead of 'error ("Invalid time specification")'.
(time_add, time_subtract, time_arith, Ftime_add, Ftime_less_p)
(decode_float_time, lisp_to_timespec, lisp_time_struct):
New functions.
(make_time_tail, make_time): Remove. All uses changed to use
new functions or plain list4i.
(disassemble_lisp_time): Return effective length if successful.
Check that LOW is an integer, if it's combined with other components.
(decode_time_components): Decode into struct lisp_time, not
struct timespec, so that we can support a wide set of times
regardless of whether time_t is signed. Decode plain numbers
as seconds since the Epoch, and nil as the current time.
(lisp_time_argument, lisp_seconds_argument, Ffloat_time):
Reimplement in terms of new functions.
(Fencode_time): Just use list2i.
(syms_of_editfns): Add time-add, time-subtract, time-less-p.
* src/keyboard.c (decode_timer): Don't allow the new formats (floating
point or nil) in timers.
* src/systime.h (LO_TIME_BITS): New constant. Use it everywhere in
place of the magic number '16'.
(struct lisp_time): New type.
(decode_time_components): Use it.
(lisp_to_timespec): New decl.
Diffstat (limited to 'src/editfns.c')
| -rw-r--r-- | src/editfns.c | 364 |
1 files changed, 269 insertions, 95 deletions
diff --git a/src/editfns.c b/src/editfns.c index 376d8e3a0ea..0a07886934c 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -64,6 +64,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 64 | extern Lisp_Object w32_get_internal_run_time (void); | 64 | extern Lisp_Object w32_get_internal_run_time (void); |
| 65 | #endif | 65 | #endif |
| 66 | 66 | ||
| 67 | static struct lisp_time lisp_time_struct (Lisp_Object, int *); | ||
| 67 | static void set_time_zone_rule (char const *); | 68 | static void set_time_zone_rule (char const *); |
| 68 | static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, | 69 | static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, |
| 69 | bool, struct tm *); | 70 | bool, struct tm *); |
| @@ -1392,6 +1393,12 @@ time_overflow (void) | |||
| 1392 | error ("Specified time is not representable"); | 1393 | error ("Specified time is not representable"); |
| 1393 | } | 1394 | } |
| 1394 | 1395 | ||
| 1396 | static void | ||
| 1397 | invalid_time (void) | ||
| 1398 | { | ||
| 1399 | error ("Invalid time specification"); | ||
| 1400 | } | ||
| 1401 | |||
| 1395 | /* A substitute for mktime_z on platforms that lack it. It's not | 1402 | /* A substitute for mktime_z on platforms that lack it. It's not |
| 1396 | thread-safe, but should be good enough for Emacs in typical use. */ | 1403 | thread-safe, but should be good enough for Emacs in typical use. */ |
| 1397 | #ifndef HAVE_TZALLOC | 1404 | #ifndef HAVE_TZALLOC |
| @@ -1420,26 +1427,26 @@ mktime_z (timezone_t tz, struct tm *tm) | |||
| 1420 | static EMACS_INT | 1427 | static EMACS_INT |
| 1421 | hi_time (time_t t) | 1428 | hi_time (time_t t) |
| 1422 | { | 1429 | { |
| 1423 | time_t hi = t >> 16; | 1430 | time_t hi = t >> LO_TIME_BITS; |
| 1424 | 1431 | ||
| 1425 | /* Check for overflow, helping the compiler for common cases where | 1432 | /* Check for overflow, helping the compiler for common cases where |
| 1426 | no runtime check is needed, and taking care not to convert | 1433 | no runtime check is needed, and taking care not to convert |
| 1427 | negative numbers to unsigned before comparing them. */ | 1434 | negative numbers to unsigned before comparing them. */ |
| 1428 | if (! ((! TYPE_SIGNED (time_t) | 1435 | if (! ((! TYPE_SIGNED (time_t) |
| 1429 | || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> 16 | 1436 | || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> LO_TIME_BITS |
| 1430 | || MOST_NEGATIVE_FIXNUM <= hi) | 1437 | || MOST_NEGATIVE_FIXNUM <= hi) |
| 1431 | && (TIME_T_MAX >> 16 <= MOST_POSITIVE_FIXNUM | 1438 | && (TIME_T_MAX >> LO_TIME_BITS <= MOST_POSITIVE_FIXNUM |
| 1432 | || hi <= MOST_POSITIVE_FIXNUM))) | 1439 | || hi <= MOST_POSITIVE_FIXNUM))) |
| 1433 | time_overflow (); | 1440 | time_overflow (); |
| 1434 | 1441 | ||
| 1435 | return hi; | 1442 | return hi; |
| 1436 | } | 1443 | } |
| 1437 | 1444 | ||
| 1438 | /* Return the bottom 16 bits of the time T. */ | 1445 | /* Return the bottom bits of the time T. */ |
| 1439 | static int | 1446 | static int |
| 1440 | lo_time (time_t t) | 1447 | lo_time (time_t t) |
| 1441 | { | 1448 | { |
| 1442 | return t & ((1 << 16) - 1); | 1449 | return t & ((1 << LO_TIME_BITS) - 1); |
| 1443 | } | 1450 | } |
| 1444 | 1451 | ||
| 1445 | DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, | 1452 | DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, |
| @@ -1453,6 +1460,96 @@ picosecond counts. */) | |||
| 1453 | return make_lisp_time (current_timespec ()); | 1460 | return make_lisp_time (current_timespec ()); |
| 1454 | } | 1461 | } |
| 1455 | 1462 | ||
| 1463 | static struct lisp_time | ||
| 1464 | time_add (struct lisp_time ta, struct lisp_time tb) | ||
| 1465 | { | ||
| 1466 | EMACS_INT hi = ta.hi + tb.hi; | ||
| 1467 | int lo = ta.lo + tb.lo; | ||
| 1468 | int us = ta.us + tb.us; | ||
| 1469 | int ps = ta.ps + tb.ps; | ||
| 1470 | us += (1000000 <= ps); | ||
| 1471 | ps -= (1000000 <= ps) * 1000000; | ||
| 1472 | lo += (1000000 <= us); | ||
| 1473 | us -= (1000000 <= us) * 1000000; | ||
| 1474 | hi += (1 << LO_TIME_BITS <= lo); | ||
| 1475 | lo -= (1 << LO_TIME_BITS <= lo) << LO_TIME_BITS; | ||
| 1476 | return (struct lisp_time) { hi, lo, us, ps }; | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | static struct lisp_time | ||
| 1480 | time_subtract (struct lisp_time ta, struct lisp_time tb) | ||
| 1481 | { | ||
| 1482 | EMACS_INT hi = ta.hi - tb.hi; | ||
| 1483 | int lo = ta.lo - tb.lo; | ||
| 1484 | int us = ta.us - tb.us; | ||
| 1485 | int ps = ta.ps - tb.ps; | ||
| 1486 | us -= (ps < 0); | ||
| 1487 | ps += (ps < 0) * 1000000; | ||
| 1488 | lo -= (us < 0); | ||
| 1489 | us += (us < 0) * 1000000; | ||
| 1490 | hi -= (lo < 0); | ||
| 1491 | lo += (lo < 0) << LO_TIME_BITS; | ||
| 1492 | return (struct lisp_time) { hi, lo, us, ps }; | ||
| 1493 | } | ||
| 1494 | |||
| 1495 | static Lisp_Object | ||
| 1496 | time_arith (Lisp_Object a, Lisp_Object b, | ||
| 1497 | struct lisp_time (*op) (struct lisp_time, struct lisp_time)) | ||
| 1498 | { | ||
| 1499 | int alen, blen; | ||
| 1500 | struct lisp_time ta = lisp_time_struct (a, &alen); | ||
| 1501 | struct lisp_time tb = lisp_time_struct (b, &blen); | ||
| 1502 | struct lisp_time t = op (ta, tb); | ||
| 1503 | if (! (MOST_NEGATIVE_FIXNUM <= t.hi && t.hi <= MOST_POSITIVE_FIXNUM)) | ||
| 1504 | time_overflow (); | ||
| 1505 | Lisp_Object val = Qnil; | ||
| 1506 | |||
| 1507 | switch (max (alen, blen)) | ||
| 1508 | { | ||
| 1509 | default: | ||
| 1510 | val = Fcons (make_number (t.ps), val); | ||
| 1511 | /* Fall through. */ | ||
| 1512 | case 3: | ||
| 1513 | val = Fcons (make_number (t.us), val); | ||
| 1514 | /* Fall through. */ | ||
| 1515 | case 2: | ||
| 1516 | val = Fcons (make_number (t.lo), val); | ||
| 1517 | val = Fcons (make_number (t.hi), val); | ||
| 1518 | break; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | return val; | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | DEFUN ("time-add", Ftime_add, Stime_add, 2, 2, 0, | ||
| 1525 | doc: /* Return the sum of two time values A and B, as a time value. */) | ||
| 1526 | (Lisp_Object a, Lisp_Object b) | ||
| 1527 | { | ||
| 1528 | return time_arith (a, b, time_add); | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | DEFUN ("time-subtract", Ftime_subtract, Stime_subtract, 2, 2, 0, | ||
| 1532 | doc: /* Return the difference between two time values A and B, as a time value. */) | ||
| 1533 | (Lisp_Object a, Lisp_Object b) | ||
| 1534 | { | ||
| 1535 | return time_arith (a, b, time_subtract); | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | DEFUN ("time-less-p", Ftime_less_p, Stime_less_p, 2, 2, 0, | ||
| 1539 | doc: /* Return non-nil if time value T1 is earlier than time value T2. */) | ||
| 1540 | (Lisp_Object t1, Lisp_Object t2) | ||
| 1541 | { | ||
| 1542 | int t1len, t2len; | ||
| 1543 | struct lisp_time a = lisp_time_struct (t1, &t1len); | ||
| 1544 | struct lisp_time b = lisp_time_struct (t2, &t2len); | ||
| 1545 | return ((a.hi != b.hi ? a.hi < b.hi | ||
| 1546 | : a.lo != b.lo ? a.lo < b.lo | ||
| 1547 | : a.us != b.us ? a.us < b.us | ||
| 1548 | : a.ps < b.ps) | ||
| 1549 | ? Qt : Qnil); | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | |||
| 1456 | DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time, | 1553 | DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time, |
| 1457 | 0, 0, 0, | 1554 | 0, 0, 0, |
| 1458 | doc: /* Return the current run time used by Emacs. | 1555 | doc: /* Return the current run time used by Emacs. |
| @@ -1491,21 +1588,6 @@ does the same thing as `current-time'. */) | |||
| 1491 | } | 1588 | } |
| 1492 | 1589 | ||
| 1493 | 1590 | ||
| 1494 | /* Make a Lisp list that represents the time T with fraction TAIL. */ | ||
| 1495 | static Lisp_Object | ||
| 1496 | make_time_tail (time_t t, Lisp_Object tail) | ||
| 1497 | { | ||
| 1498 | return Fcons (make_number (hi_time (t)), | ||
| 1499 | Fcons (make_number (lo_time (t)), tail)); | ||
| 1500 | } | ||
| 1501 | |||
| 1502 | /* Make a Lisp list that represents the system time T. */ | ||
| 1503 | static Lisp_Object | ||
| 1504 | make_time (time_t t) | ||
| 1505 | { | ||
| 1506 | return make_time_tail (t, Qnil); | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | /* Make a Lisp list that represents the Emacs time T. T may be an | 1591 | /* Make a Lisp list that represents the Emacs time T. T may be an |
| 1510 | invalid time, with a slightly negative tv_nsec value such as | 1592 | invalid time, with a slightly negative tv_nsec value such as |
| 1511 | UNKNOWN_MODTIME_NSECS; in that case, the Lisp list contains a | 1593 | UNKNOWN_MODTIME_NSECS; in that case, the Lisp list contains a |
| @@ -1513,23 +1595,30 @@ make_time (time_t t) | |||
| 1513 | Lisp_Object | 1595 | Lisp_Object |
| 1514 | make_lisp_time (struct timespec t) | 1596 | make_lisp_time (struct timespec t) |
| 1515 | { | 1597 | { |
| 1598 | time_t s = t.tv_sec; | ||
| 1516 | int ns = t.tv_nsec; | 1599 | int ns = t.tv_nsec; |
| 1517 | return make_time_tail (t.tv_sec, list2i (ns / 1000, ns % 1000 * 1000)); | 1600 | return list4i (hi_time (s), lo_time (s), ns / 1000, ns % 1000 * 1000); |
| 1518 | } | 1601 | } |
| 1519 | 1602 | ||
| 1520 | /* Decode a Lisp list SPECIFIED_TIME that represents a time. | 1603 | /* Decode a Lisp list SPECIFIED_TIME that represents a time. |
| 1521 | Set *PHIGH, *PLOW, *PUSEC, *PPSEC to its parts; do not check their values. | 1604 | Set *PHIGH, *PLOW, *PUSEC, *PPSEC to its parts; do not check their values. |
| 1522 | Return true if successful. */ | 1605 | Return 2, 3, or 4 to indicate the effective length of SPECIFIED_TIME |
| 1523 | static bool | 1606 | if successful, 0 if unsuccessful. */ |
| 1607 | static int | ||
| 1524 | disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, | 1608 | disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, |
| 1525 | Lisp_Object *plow, Lisp_Object *pusec, | 1609 | Lisp_Object *plow, Lisp_Object *pusec, |
| 1526 | Lisp_Object *ppsec) | 1610 | Lisp_Object *ppsec) |
| 1527 | { | 1611 | { |
| 1612 | Lisp_Object high = make_number (0); | ||
| 1613 | Lisp_Object low = specified_time; | ||
| 1614 | Lisp_Object usec = make_number (0); | ||
| 1615 | Lisp_Object psec = make_number (0); | ||
| 1616 | int len = 4; | ||
| 1617 | |||
| 1528 | if (CONSP (specified_time)) | 1618 | if (CONSP (specified_time)) |
| 1529 | { | 1619 | { |
| 1530 | Lisp_Object low = XCDR (specified_time); | 1620 | high = XCAR (specified_time); |
| 1531 | Lisp_Object usec = make_number (0); | 1621 | low = XCDR (specified_time); |
| 1532 | Lisp_Object psec = make_number (0); | ||
| 1533 | if (CONSP (low)) | 1622 | if (CONSP (low)) |
| 1534 | { | 1623 | { |
| 1535 | Lisp_Object low_tail = XCDR (low); | 1624 | Lisp_Object low_tail = XCDR (low); |
| @@ -1540,40 +1629,119 @@ disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, | |||
| 1540 | low_tail = XCDR (low_tail); | 1629 | low_tail = XCDR (low_tail); |
| 1541 | if (CONSP (low_tail)) | 1630 | if (CONSP (low_tail)) |
| 1542 | psec = XCAR (low_tail); | 1631 | psec = XCAR (low_tail); |
| 1632 | else | ||
| 1633 | len = 3; | ||
| 1543 | } | 1634 | } |
| 1544 | else if (!NILP (low_tail)) | 1635 | else if (!NILP (low_tail)) |
| 1545 | usec = low_tail; | 1636 | { |
| 1637 | usec = low_tail; | ||
| 1638 | len = 3; | ||
| 1639 | } | ||
| 1640 | else | ||
| 1641 | len = 2; | ||
| 1546 | } | 1642 | } |
| 1643 | else | ||
| 1644 | len = 2; | ||
| 1547 | 1645 | ||
| 1548 | *phigh = XCAR (specified_time); | 1646 | /* When combining components, require LOW to be an integer, |
| 1549 | *plow = low; | 1647 | as otherwise it would be a pain to add up times. */ |
| 1550 | *pusec = usec; | 1648 | if (! INTEGERP (low)) |
| 1551 | *ppsec = psec; | 1649 | return 0; |
| 1552 | return 1; | ||
| 1553 | } | 1650 | } |
| 1651 | else if (INTEGERP (specified_time)) | ||
| 1652 | len = 2; | ||
| 1653 | |||
| 1654 | *phigh = high; | ||
| 1655 | *plow = low; | ||
| 1656 | *pusec = usec; | ||
| 1657 | *ppsec = psec; | ||
| 1658 | return len; | ||
| 1659 | } | ||
| 1554 | 1660 | ||
| 1555 | return 0; | 1661 | /* Convert T into an Emacs time *RESULT, truncating toward minus infinity. |
| 1662 | Return true if T is in range, false otherwise. */ | ||
| 1663 | static bool | ||
| 1664 | decode_float_time (double t, struct lisp_time *result) | ||
| 1665 | { | ||
| 1666 | double lo_multiplier = 1 << LO_TIME_BITS; | ||
| 1667 | double emacs_time_min = MOST_NEGATIVE_FIXNUM * lo_multiplier; | ||
| 1668 | if (! (emacs_time_min <= t && t < -emacs_time_min)) | ||
| 1669 | return false; | ||
| 1670 | |||
| 1671 | double small_t = t / lo_multiplier; | ||
| 1672 | EMACS_INT hi = small_t; | ||
| 1673 | double t_sans_hi = t - hi * lo_multiplier; | ||
| 1674 | int lo = t_sans_hi; | ||
| 1675 | long double fracps = (t_sans_hi - lo) * 1e12L; | ||
| 1676 | #ifdef INT_FAST64_MAX | ||
| 1677 | int_fast64_t ifracps = fracps; | ||
| 1678 | int us = ifracps / 1000000; | ||
| 1679 | int ps = ifracps % 1000000; | ||
| 1680 | #else | ||
| 1681 | int us = fracps / 1e6L; | ||
| 1682 | int ps = fracps - us * 1e6L; | ||
| 1683 | #endif | ||
| 1684 | us -= (ps < 0); | ||
| 1685 | ps += (ps < 0) * 1000000; | ||
| 1686 | lo -= (us < 0); | ||
| 1687 | us += (us < 0) * 1000000; | ||
| 1688 | hi -= (lo < 0); | ||
| 1689 | lo += (lo < 0) << LO_TIME_BITS; | ||
| 1690 | result->hi = hi; | ||
| 1691 | result->lo = lo; | ||
| 1692 | result->us = us; | ||
| 1693 | result->ps = ps; | ||
| 1694 | return true; | ||
| 1556 | } | 1695 | } |
| 1557 | 1696 | ||
| 1558 | /* From the time components HIGH, LOW, USEC and PSEC taken from a Lisp | 1697 | /* From the time components HIGH, LOW, USEC and PSEC taken from a Lisp |
| 1559 | list, generate the corresponding time value. | 1698 | list, generate the corresponding time value. |
| 1699 | If LOW is floating point, the other components should be zero. | ||
| 1560 | 1700 | ||
| 1561 | If RESULT is not null, store into *RESULT the converted time; | 1701 | If RESULT is not null, store into *RESULT the converted time. |
| 1562 | if the converted time does not fit into struct timespec, | ||
| 1563 | store an invalid timespec to indicate the overflow. | ||
| 1564 | If *DRESULT is not null, store into *DRESULT the number of | 1702 | If *DRESULT is not null, store into *DRESULT the number of |
| 1565 | seconds since the start of the POSIX Epoch. | 1703 | seconds since the start of the POSIX Epoch. |
| 1566 | 1704 | ||
| 1567 | Return true if successful. */ | 1705 | Return true if successful, false if the components are of the |
| 1706 | wrong type or represent a time out of range. */ | ||
| 1568 | bool | 1707 | bool |
| 1569 | decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, | 1708 | decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, |
| 1570 | Lisp_Object psec, | 1709 | Lisp_Object psec, |
| 1571 | struct timespec *result, double *dresult) | 1710 | struct lisp_time *result, double *dresult) |
| 1572 | { | 1711 | { |
| 1573 | EMACS_INT hi, lo, us, ps; | 1712 | EMACS_INT hi, lo, us, ps; |
| 1574 | if (! (INTEGERP (high) && INTEGERP (low) | 1713 | if (! (INTEGERP (high) |
| 1575 | && INTEGERP (usec) && INTEGERP (psec))) | 1714 | && INTEGERP (usec) && INTEGERP (psec))) |
| 1576 | return false; | 1715 | return false; |
| 1716 | if (! INTEGERP (low)) | ||
| 1717 | { | ||
| 1718 | if (FLOATP (low)) | ||
| 1719 | { | ||
| 1720 | double t = XFLOAT_DATA (low); | ||
| 1721 | if (result && ! decode_float_time (t, result)) | ||
| 1722 | return false; | ||
| 1723 | if (dresult) | ||
| 1724 | *dresult = t; | ||
| 1725 | return true; | ||
| 1726 | } | ||
| 1727 | else if (NILP (low)) | ||
| 1728 | { | ||
| 1729 | struct timespec now = current_timespec (); | ||
| 1730 | if (result) | ||
| 1731 | { | ||
| 1732 | result->hi = hi_time (now.tv_sec); | ||
| 1733 | result->lo = lo_time (now.tv_sec); | ||
| 1734 | result->us = now.tv_nsec / 1000; | ||
| 1735 | result->ps = now.tv_nsec % 1000 * 1000; | ||
| 1736 | } | ||
| 1737 | if (dresult) | ||
| 1738 | *dresult = now.tv_sec + now.tv_nsec / 1e9; | ||
| 1739 | return true; | ||
| 1740 | } | ||
| 1741 | else | ||
| 1742 | return false; | ||
| 1743 | } | ||
| 1744 | |||
| 1577 | hi = XINT (high); | 1745 | hi = XINT (high); |
| 1578 | lo = XINT (low); | 1746 | lo = XINT (low); |
| 1579 | us = XINT (usec); | 1747 | us = XINT (usec); |
| @@ -1583,53 +1751,68 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, | |||
| 1583 | each overflow into the next higher-order component. */ | 1751 | each overflow into the next higher-order component. */ |
| 1584 | us += ps / 1000000 - (ps % 1000000 < 0); | 1752 | us += ps / 1000000 - (ps % 1000000 < 0); |
| 1585 | lo += us / 1000000 - (us % 1000000 < 0); | 1753 | lo += us / 1000000 - (us % 1000000 < 0); |
| 1586 | hi += lo >> 16; | 1754 | hi += lo >> LO_TIME_BITS; |
| 1587 | ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); | 1755 | ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); |
| 1588 | us = us % 1000000 + 1000000 * (us % 1000000 < 0); | 1756 | us = us % 1000000 + 1000000 * (us % 1000000 < 0); |
| 1589 | lo &= (1 << 16) - 1; | 1757 | lo &= (1 << LO_TIME_BITS) - 1; |
| 1590 | 1758 | ||
| 1591 | if (result) | 1759 | if (result) |
| 1592 | { | 1760 | { |
| 1593 | if ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 <= hi : 0 <= hi) | 1761 | if (! (MOST_NEGATIVE_FIXNUM <= hi && hi <= MOST_POSITIVE_FIXNUM)) |
| 1594 | && hi <= TIME_T_MAX >> 16) | 1762 | return false; |
| 1595 | { | 1763 | result->hi = hi; |
| 1596 | /* Return the greatest representable time that is not greater | 1764 | result->lo = lo; |
| 1597 | than the requested time. */ | 1765 | result->us = us; |
| 1598 | time_t sec = hi; | 1766 | result->ps = ps; |
| 1599 | *result = make_timespec ((sec << 16) + lo, us * 1000 + ps / 1000); | ||
| 1600 | } | ||
| 1601 | else | ||
| 1602 | *result = invalid_timespec (); | ||
| 1603 | } | 1767 | } |
| 1604 | 1768 | ||
| 1605 | if (dresult) | 1769 | if (dresult) |
| 1606 | *dresult = (us * 1e6 + ps) / 1e12 + lo + hi * 65536.0; | 1770 | { |
| 1771 | double dhi = hi; | ||
| 1772 | *dresult = (us * 1e6 + ps) / 1e12 + lo + dhi * (1 << LO_TIME_BITS); | ||
| 1773 | } | ||
| 1607 | 1774 | ||
| 1608 | return true; | 1775 | return true; |
| 1609 | } | 1776 | } |
| 1610 | 1777 | ||
| 1778 | struct timespec | ||
| 1779 | lisp_to_timespec (struct lisp_time t) | ||
| 1780 | { | ||
| 1781 | if (! ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> LO_TIME_BITS <= t.hi : 0 <= t.hi) | ||
| 1782 | && t.hi <= TIME_T_MAX >> LO_TIME_BITS)) | ||
| 1783 | return invalid_timespec (); | ||
| 1784 | time_t s = (t.hi << LO_TIME_BITS) + t.lo; | ||
| 1785 | int ns = t.us * 1000 + t.ps / 1000; | ||
| 1786 | return make_timespec (s, ns); | ||
| 1787 | } | ||
| 1788 | |||
| 1611 | /* Decode a Lisp list SPECIFIED_TIME that represents a time. | 1789 | /* Decode a Lisp list SPECIFIED_TIME that represents a time. |
| 1790 | Store its effective length into *PLEN. | ||
| 1612 | If SPECIFIED_TIME is nil, use the current time. | 1791 | If SPECIFIED_TIME is nil, use the current time. |
| 1792 | Signal an error if SPECIFIED_TIME does not represent a time. */ | ||
| 1793 | static struct lisp_time | ||
| 1794 | lisp_time_struct (Lisp_Object specified_time, int *plen) | ||
| 1795 | { | ||
| 1796 | Lisp_Object high, low, usec, psec; | ||
| 1797 | struct lisp_time t; | ||
| 1798 | int len = disassemble_lisp_time (specified_time, &high, &low, &usec, &psec); | ||
| 1799 | if (! (len && decode_time_components (high, low, usec, psec, &t, 0))) | ||
| 1800 | invalid_time (); | ||
| 1801 | *plen = len; | ||
| 1802 | return t; | ||
| 1803 | } | ||
| 1613 | 1804 | ||
| 1614 | Round the time down to the nearest struct timespec value. | 1805 | /* Like lisp_time_struct, except return a struct timespec. |
| 1615 | Return seconds since the Epoch. | 1806 | Discard any low-order digits. */ |
| 1616 | Signal an error if unsuccessful. */ | ||
| 1617 | struct timespec | 1807 | struct timespec |
| 1618 | lisp_time_argument (Lisp_Object specified_time) | 1808 | lisp_time_argument (Lisp_Object specified_time) |
| 1619 | { | 1809 | { |
| 1620 | if (NILP (specified_time)) | 1810 | int len; |
| 1621 | return current_timespec (); | 1811 | struct lisp_time lt = lisp_time_struct (specified_time, &len); |
| 1622 | else | 1812 | struct timespec t = lisp_to_timespec (lt); |
| 1623 | { | 1813 | if (! timespec_valid_p (t)) |
| 1624 | Lisp_Object high, low, usec, psec; | 1814 | time_overflow (); |
| 1625 | struct timespec t; | 1815 | return t; |
| 1626 | if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) | ||
| 1627 | && decode_time_components (high, low, usec, psec, &t, 0))) | ||
| 1628 | error ("Invalid time specification"); | ||
| 1629 | if (! timespec_valid_p (t)) | ||
| 1630 | time_overflow (); | ||
| 1631 | return t; | ||
| 1632 | } | ||
| 1633 | } | 1816 | } |
| 1634 | 1817 | ||
| 1635 | /* Like lisp_time_argument, except decode only the seconds part, | 1818 | /* Like lisp_time_argument, except decode only the seconds part, |
| @@ -1637,20 +1820,16 @@ lisp_time_argument (Lisp_Object specified_time) | |||
| 1637 | static time_t | 1820 | static time_t |
| 1638 | lisp_seconds_argument (Lisp_Object specified_time) | 1821 | lisp_seconds_argument (Lisp_Object specified_time) |
| 1639 | { | 1822 | { |
| 1640 | if (NILP (specified_time)) | 1823 | Lisp_Object high, low, usec, psec; |
| 1641 | return time (NULL); | 1824 | struct lisp_time t; |
| 1642 | else | 1825 | if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) |
| 1643 | { | 1826 | && decode_time_components (high, low, make_number (0), |
| 1644 | Lisp_Object high, low, usec, psec; | 1827 | make_number (0), &t, 0))) |
| 1645 | struct timespec t; | 1828 | invalid_time (); |
| 1646 | if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) | 1829 | if (! ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> LO_TIME_BITS <= t.hi : 0 <= t.hi) |
| 1647 | && decode_time_components (high, low, make_number (0), | 1830 | && t.hi <= TIME_T_MAX >> LO_TIME_BITS)) |
| 1648 | make_number (0), &t, 0))) | 1831 | time_overflow (); |
| 1649 | error ("Invalid time specification"); | 1832 | return (t.hi << LO_TIME_BITS) + t.lo; |
| 1650 | if (! timespec_valid_p (t)) | ||
| 1651 | time_overflow (); | ||
| 1652 | return t.tv_sec; | ||
| 1653 | } | ||
| 1654 | } | 1833 | } |
| 1655 | 1834 | ||
| 1656 | DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0, | 1835 | DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0, |
| @@ -1668,18 +1847,10 @@ or (if you need time as a string) `format-time-string'. */) | |||
| 1668 | (Lisp_Object specified_time) | 1847 | (Lisp_Object specified_time) |
| 1669 | { | 1848 | { |
| 1670 | double t; | 1849 | double t; |
| 1671 | if (NILP (specified_time)) | 1850 | Lisp_Object high, low, usec, psec; |
| 1672 | { | 1851 | if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) |
| 1673 | struct timespec now = current_timespec (); | 1852 | && decode_time_components (high, low, usec, psec, 0, &t))) |
| 1674 | t = now.tv_sec + now.tv_nsec / 1e9; | 1853 | invalid_time (); |
| 1675 | } | ||
| 1676 | else | ||
| 1677 | { | ||
| 1678 | Lisp_Object high, low, usec, psec; | ||
| 1679 | if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) | ||
| 1680 | && decode_time_components (high, low, usec, psec, 0, &t))) | ||
| 1681 | error ("Invalid time specification"); | ||
| 1682 | } | ||
| 1683 | return make_float (t); | 1854 | return make_float (t); |
| 1684 | } | 1855 | } |
| 1685 | 1856 | ||
| @@ -1969,7 +2140,7 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) | |||
| 1969 | if (value == (time_t) -1) | 2140 | if (value == (time_t) -1) |
| 1970 | time_overflow (); | 2141 | time_overflow (); |
| 1971 | 2142 | ||
| 1972 | return make_time (value); | 2143 | return list2i (hi_time (value), lo_time (value)); |
| 1973 | } | 2144 | } |
| 1974 | 2145 | ||
| 1975 | DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0, | 2146 | DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0, |
| @@ -4874,6 +5045,9 @@ functions if all the text being accessed has this property. */); | |||
| 4874 | defsubr (&Suser_full_name); | 5045 | defsubr (&Suser_full_name); |
| 4875 | defsubr (&Semacs_pid); | 5046 | defsubr (&Semacs_pid); |
| 4876 | defsubr (&Scurrent_time); | 5047 | defsubr (&Scurrent_time); |
| 5048 | defsubr (&Stime_add); | ||
| 5049 | defsubr (&Stime_subtract); | ||
| 5050 | defsubr (&Stime_less_p); | ||
| 4877 | defsubr (&Sget_internal_run_time); | 5051 | defsubr (&Sget_internal_run_time); |
| 4878 | defsubr (&Sformat_time_string); | 5052 | defsubr (&Sformat_time_string); |
| 4879 | defsubr (&Sfloat_time); | 5053 | defsubr (&Sfloat_time); |