diff options
| author | Paul Eggert | 2012-05-25 11:19:24 -0700 |
|---|---|---|
| committer | Paul Eggert | 2012-05-25 11:19:24 -0700 |
| commit | 42b2a986d9d4b7040fb20c90ec0efeffb78e761a (patch) | |
| tree | d38e7bf5307837f2f38982757f088100de18a64e /src/editfns.c | |
| parent | e4d81efc58695c19154d5f6733d91172b4c3e5b7 (diff) | |
| parent | a8d3cbf75d219d7a249fc0623219511179e959da (diff) | |
| download | emacs-42b2a986d9d4b7040fb20c90ec0efeffb78e761a.tar.gz emacs-42b2a986d9d4b7040fb20c90ec0efeffb78e761a.zip | |
Merge from trunk.
Diffstat (limited to 'src/editfns.c')
| -rw-r--r-- | src/editfns.c | 168 |
1 files changed, 90 insertions, 78 deletions
diff --git a/src/editfns.c b/src/editfns.c index 7e7f82c5992..6d59b89513c 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -59,10 +59,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 59 | #include "window.h" | 59 | #include "window.h" |
| 60 | #include "blockinput.h" | 60 | #include "blockinput.h" |
| 61 | 61 | ||
| 62 | #ifndef NULL | ||
| 63 | #define NULL 0 | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifndef USER_FULL_NAME | 62 | #ifndef USER_FULL_NAME |
| 67 | #define USER_FULL_NAME pw->pw_gecos | 63 | #define USER_FULL_NAME pw->pw_gecos |
| 68 | #endif | 64 | #endif |
| @@ -73,20 +69,13 @@ extern char **environ; | |||
| 73 | 69 | ||
| 74 | #define TM_YEAR_BASE 1900 | 70 | #define TM_YEAR_BASE 1900 |
| 75 | 71 | ||
| 76 | /* Nonzero if TM_YEAR is a struct tm's tm_year value that causes | ||
| 77 | asctime to have well-defined behavior. */ | ||
| 78 | #ifndef TM_YEAR_IN_ASCTIME_RANGE | ||
| 79 | # define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \ | ||
| 80 | (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE) | ||
| 81 | #endif | ||
| 82 | |||
| 83 | #ifdef WINDOWSNT | 72 | #ifdef WINDOWSNT |
| 84 | extern Lisp_Object w32_get_internal_run_time (void); | 73 | extern Lisp_Object w32_get_internal_run_time (void); |
| 85 | #endif | 74 | #endif |
| 86 | 75 | ||
| 87 | static void time_overflow (void) NO_RETURN; | 76 | static void time_overflow (void) NO_RETURN; |
| 88 | static Lisp_Object format_time_string (char const *, ptrdiff_t, Lisp_Object, | 77 | static Lisp_Object format_time_string (char const *, ptrdiff_t, Lisp_Object, |
| 89 | int, time_t *, struct tm **); | 78 | int, time_t *, struct tm *); |
| 90 | static int tm_diff (struct tm *, struct tm *); | 79 | static int tm_diff (struct tm *, struct tm *); |
| 91 | static void update_buffer_properties (ptrdiff_t, ptrdiff_t); | 80 | static void update_buffer_properties (ptrdiff_t, ptrdiff_t); |
| 92 | 81 | ||
| @@ -1691,7 +1680,7 @@ usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */) | |||
| 1691 | (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object universal) | 1680 | (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object universal) |
| 1692 | { | 1681 | { |
| 1693 | time_t t; | 1682 | time_t t; |
| 1694 | struct tm *tm; | 1683 | struct tm tm; |
| 1695 | 1684 | ||
| 1696 | CHECK_STRING (format_string); | 1685 | CHECK_STRING (format_string); |
| 1697 | format_string = code_convert_string_norecord (format_string, | 1686 | format_string = code_convert_string_norecord (format_string, |
| @@ -1702,53 +1691,54 @@ usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */) | |||
| 1702 | 1691 | ||
| 1703 | static Lisp_Object | 1692 | static Lisp_Object |
| 1704 | format_time_string (char const *format, ptrdiff_t formatlen, | 1693 | format_time_string (char const *format, ptrdiff_t formatlen, |
| 1705 | Lisp_Object timeval, int ut, time_t *tval, struct tm **tmp) | 1694 | Lisp_Object timeval, int ut, time_t *tval, struct tm *tmp) |
| 1706 | { | 1695 | { |
| 1707 | ptrdiff_t size; | 1696 | char buffer[4000]; |
| 1697 | char *buf = buffer; | ||
| 1698 | size_t size = sizeof buffer; | ||
| 1699 | size_t len; | ||
| 1700 | Lisp_Object bufstring; | ||
| 1708 | int usec; | 1701 | int usec; |
| 1709 | int ns; | 1702 | int ns; |
| 1710 | struct tm *tm; | 1703 | struct tm *tm; |
| 1704 | USE_SAFE_ALLOCA; | ||
| 1711 | 1705 | ||
| 1712 | if (! lisp_time_argument (timeval, tval, &usec)) | 1706 | if (! lisp_time_argument (timeval, tval, &usec)) |
| 1713 | error ("Invalid time specification"); | 1707 | error ("Invalid time specification"); |
| 1714 | ns = usec * 1000; | 1708 | ns = usec * 1000; |
| 1715 | 1709 | ||
| 1716 | /* This is probably enough. */ | ||
| 1717 | size = formatlen; | ||
| 1718 | if (size <= (STRING_BYTES_BOUND - 50) / 6) | ||
| 1719 | size = size * 6 + 50; | ||
| 1720 | |||
| 1721 | BLOCK_INPUT; | ||
| 1722 | tm = ut ? gmtime (tval) : localtime (tval); | ||
| 1723 | UNBLOCK_INPUT; | ||
| 1724 | if (! tm) | ||
| 1725 | time_overflow (); | ||
| 1726 | *tmp = tm; | ||
| 1727 | |||
| 1728 | synchronize_system_time_locale (); | ||
| 1729 | |||
| 1730 | while (1) | 1710 | while (1) |
| 1731 | { | 1711 | { |
| 1732 | char *buf = (char *) alloca (size + 1); | 1712 | BLOCK_INPUT; |
| 1733 | size_t result; | 1713 | |
| 1714 | synchronize_system_time_locale (); | ||
| 1715 | |||
| 1716 | tm = ut ? gmtime (tval) : localtime (tval); | ||
| 1717 | if (! tm) | ||
| 1718 | { | ||
| 1719 | UNBLOCK_INPUT; | ||
| 1720 | time_overflow (); | ||
| 1721 | } | ||
| 1722 | *tmp = *tm; | ||
| 1734 | 1723 | ||
| 1735 | buf[0] = '\1'; | 1724 | buf[0] = '\1'; |
| 1736 | BLOCK_INPUT; | 1725 | len = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); |
| 1737 | result = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); | 1726 | if ((0 < len && len < size) || (len == 0 && buf[0] == '\0')) |
| 1738 | UNBLOCK_INPUT; | 1727 | break; |
| 1739 | if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0')) | ||
| 1740 | return code_convert_string_norecord (make_unibyte_string (buf, result), | ||
| 1741 | Vlocale_coding_system, 0); | ||
| 1742 | 1728 | ||
| 1743 | /* If buffer was too small, make it bigger and try again. */ | 1729 | /* Buffer was too small, so make it bigger and try again. */ |
| 1744 | BLOCK_INPUT; | 1730 | len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tm, ut, ns); |
| 1745 | result = emacs_nmemftime (NULL, (size_t) -1, format, formatlen, | ||
| 1746 | tm, ut, ns); | ||
| 1747 | UNBLOCK_INPUT; | 1731 | UNBLOCK_INPUT; |
| 1748 | if (STRING_BYTES_BOUND <= result) | 1732 | if (STRING_BYTES_BOUND <= len) |
| 1749 | string_overflow (); | 1733 | string_overflow (); |
| 1750 | size = result + 1; | 1734 | size = len + 1; |
| 1735 | SAFE_ALLOCA (buf, char *, size); | ||
| 1751 | } | 1736 | } |
| 1737 | |||
| 1738 | UNBLOCK_INPUT; | ||
| 1739 | bufstring = make_unibyte_string (buf, len); | ||
| 1740 | SAFE_FREE (); | ||
| 1741 | return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0); | ||
| 1752 | } | 1742 | } |
| 1753 | 1743 | ||
| 1754 | DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0, | 1744 | DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0, |
| @@ -1778,31 +1768,32 @@ DOW and ZONE.) */) | |||
| 1778 | 1768 | ||
| 1779 | BLOCK_INPUT; | 1769 | BLOCK_INPUT; |
| 1780 | decoded_time = localtime (&time_spec); | 1770 | decoded_time = localtime (&time_spec); |
| 1771 | /* Make a copy, in case a signal handler modifies TZ or the struct. */ | ||
| 1772 | if (decoded_time) | ||
| 1773 | save_tm = *decoded_time; | ||
| 1781 | UNBLOCK_INPUT; | 1774 | UNBLOCK_INPUT; |
| 1782 | if (! (decoded_time | 1775 | if (! (decoded_time |
| 1783 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= decoded_time->tm_year | 1776 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= save_tm.tm_year |
| 1784 | && decoded_time->tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) | 1777 | && save_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) |
| 1785 | time_overflow (); | 1778 | time_overflow (); |
| 1786 | XSETFASTINT (list_args[0], decoded_time->tm_sec); | 1779 | XSETFASTINT (list_args[0], save_tm.tm_sec); |
| 1787 | XSETFASTINT (list_args[1], decoded_time->tm_min); | 1780 | XSETFASTINT (list_args[1], save_tm.tm_min); |
| 1788 | XSETFASTINT (list_args[2], decoded_time->tm_hour); | 1781 | XSETFASTINT (list_args[2], save_tm.tm_hour); |
| 1789 | XSETFASTINT (list_args[3], decoded_time->tm_mday); | 1782 | XSETFASTINT (list_args[3], save_tm.tm_mday); |
| 1790 | XSETFASTINT (list_args[4], decoded_time->tm_mon + 1); | 1783 | XSETFASTINT (list_args[4], save_tm.tm_mon + 1); |
| 1791 | /* On 64-bit machines an int is narrower than EMACS_INT, thus the | 1784 | /* On 64-bit machines an int is narrower than EMACS_INT, thus the |
| 1792 | cast below avoids overflow in int arithmetics. */ | 1785 | cast below avoids overflow in int arithmetics. */ |
| 1793 | XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) decoded_time->tm_year); | 1786 | XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) save_tm.tm_year); |
| 1794 | XSETFASTINT (list_args[6], decoded_time->tm_wday); | 1787 | XSETFASTINT (list_args[6], save_tm.tm_wday); |
| 1795 | list_args[7] = (decoded_time->tm_isdst)? Qt : Qnil; | 1788 | list_args[7] = save_tm.tm_isdst ? Qt : Qnil; |
| 1796 | 1789 | ||
| 1797 | /* Make a copy, in case gmtime modifies the struct. */ | ||
| 1798 | save_tm = *decoded_time; | ||
| 1799 | BLOCK_INPUT; | 1790 | BLOCK_INPUT; |
| 1800 | decoded_time = gmtime (&time_spec); | 1791 | decoded_time = gmtime (&time_spec); |
| 1801 | UNBLOCK_INPUT; | ||
| 1802 | if (decoded_time == 0) | 1792 | if (decoded_time == 0) |
| 1803 | list_args[8] = Qnil; | 1793 | list_args[8] = Qnil; |
| 1804 | else | 1794 | else |
| 1805 | XSETINT (list_args[8], tm_diff (&save_tm, decoded_time)); | 1795 | XSETINT (list_args[8], tm_diff (&save_tm, decoded_time)); |
| 1796 | UNBLOCK_INPUT; | ||
| 1806 | return Flist (9, list_args); | 1797 | return Flist (9, list_args); |
| 1807 | } | 1798 | } |
| 1808 | 1799 | ||
| @@ -1887,21 +1878,23 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) | |||
| 1887 | else | 1878 | else |
| 1888 | error ("Invalid time zone specification"); | 1879 | error ("Invalid time zone specification"); |
| 1889 | 1880 | ||
| 1881 | BLOCK_INPUT; | ||
| 1882 | |||
| 1890 | /* Set TZ before calling mktime; merely adjusting mktime's returned | 1883 | /* Set TZ before calling mktime; merely adjusting mktime's returned |
| 1891 | value doesn't suffice, since that would mishandle leap seconds. */ | 1884 | value doesn't suffice, since that would mishandle leap seconds. */ |
| 1892 | set_time_zone_rule (tzstring); | 1885 | set_time_zone_rule (tzstring); |
| 1893 | 1886 | ||
| 1894 | BLOCK_INPUT; | ||
| 1895 | value = mktime (&tm); | 1887 | value = mktime (&tm); |
| 1896 | UNBLOCK_INPUT; | ||
| 1897 | 1888 | ||
| 1898 | /* Restore TZ to previous value. */ | 1889 | /* Restore TZ to previous value. */ |
| 1899 | newenv = environ; | 1890 | newenv = environ; |
| 1900 | environ = oldenv; | 1891 | environ = oldenv; |
| 1901 | xfree (newenv); | ||
| 1902 | #ifdef LOCALTIME_CACHE | 1892 | #ifdef LOCALTIME_CACHE |
| 1903 | tzset (); | 1893 | tzset (); |
| 1904 | #endif | 1894 | #endif |
| 1895 | UNBLOCK_INPUT; | ||
| 1896 | |||
| 1897 | xfree (newenv); | ||
| 1905 | } | 1898 | } |
| 1906 | 1899 | ||
| 1907 | if (value == (time_t) -1) | 1900 | if (value == (time_t) -1) |
| @@ -1928,24 +1921,37 @@ but this is considered obsolete. */) | |||
| 1928 | { | 1921 | { |
| 1929 | time_t value; | 1922 | time_t value; |
| 1930 | struct tm *tm; | 1923 | struct tm *tm; |
| 1931 | register char *tem; | 1924 | char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; |
| 1925 | int len IF_LINT (= 0); | ||
| 1932 | 1926 | ||
| 1933 | if (! lisp_time_argument (specified_time, &value, NULL)) | 1927 | if (! lisp_time_argument (specified_time, &value, NULL)) |
| 1934 | error ("Invalid time specification"); | 1928 | error ("Invalid time specification"); |
| 1935 | 1929 | ||
| 1936 | /* Convert to a string, checking for out-of-range time stamps. | 1930 | /* Convert to a string in ctime format, except without the trailing |
| 1937 | Don't use 'ctime', as that might dump core if VALUE is out of | 1931 | newline, and without the 4-digit year limit. Don't use asctime |
| 1938 | range. */ | 1932 | or ctime, as they might dump core if the year is outside the |
| 1933 | range -999 .. 9999. */ | ||
| 1939 | BLOCK_INPUT; | 1934 | BLOCK_INPUT; |
| 1940 | tm = localtime (&value); | 1935 | tm = localtime (&value); |
| 1936 | if (tm) | ||
| 1937 | { | ||
| 1938 | static char const wday_name[][4] = | ||
| 1939 | { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; | ||
| 1940 | static char const mon_name[][4] = | ||
| 1941 | { "Jan", "Feb", "Mar", "Apr", "May", "Jun", | ||
| 1942 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | ||
| 1943 | printmax_t year_base = TM_YEAR_BASE; | ||
| 1944 | |||
| 1945 | len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd, | ||
| 1946 | wday_name[tm->tm_wday], mon_name[tm->tm_mon], tm->tm_mday, | ||
| 1947 | tm->tm_hour, tm->tm_min, tm->tm_sec, | ||
| 1948 | tm->tm_year + year_base); | ||
| 1949 | } | ||
| 1941 | UNBLOCK_INPUT; | 1950 | UNBLOCK_INPUT; |
| 1942 | if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime (tm)))) | 1951 | if (! tm) |
| 1943 | time_overflow (); | 1952 | time_overflow (); |
| 1944 | 1953 | ||
| 1945 | /* Remove the trailing newline. */ | 1954 | return make_unibyte_string (buf, len); |
| 1946 | tem[strlen (tem) - 1] = '\0'; | ||
| 1947 | |||
| 1948 | return build_string (tem); | ||
| 1949 | } | 1955 | } |
| 1950 | 1956 | ||
| 1951 | /* Yield A - B, measured in seconds. | 1957 | /* Yield A - B, measured in seconds. |
| @@ -1989,22 +1995,22 @@ the data it can't find. */) | |||
| 1989 | (Lisp_Object specified_time) | 1995 | (Lisp_Object specified_time) |
| 1990 | { | 1996 | { |
| 1991 | time_t value; | 1997 | time_t value; |
| 1998 | int offset; | ||
| 1992 | struct tm *t; | 1999 | struct tm *t; |
| 1993 | struct tm localtm; | 2000 | struct tm localtm; |
| 1994 | struct tm *localt; | ||
| 1995 | Lisp_Object zone_offset, zone_name; | 2001 | Lisp_Object zone_offset, zone_name; |
| 1996 | 2002 | ||
| 1997 | zone_offset = Qnil; | 2003 | zone_offset = Qnil; |
| 1998 | zone_name = format_time_string ("%Z", sizeof "%Z" - 1, specified_time, | 2004 | zone_name = format_time_string ("%Z", sizeof "%Z" - 1, specified_time, |
| 1999 | 0, &value, &localt); | 2005 | 0, &value, &localtm); |
| 2000 | localtm = *localt; | ||
| 2001 | BLOCK_INPUT; | 2006 | BLOCK_INPUT; |
| 2002 | t = gmtime (&value); | 2007 | t = gmtime (&value); |
| 2008 | if (t) | ||
| 2009 | offset = tm_diff (&localtm, t); | ||
| 2003 | UNBLOCK_INPUT; | 2010 | UNBLOCK_INPUT; |
| 2004 | 2011 | ||
| 2005 | if (t) | 2012 | if (t) |
| 2006 | { | 2013 | { |
| 2007 | int offset = tm_diff (&localtm, t); | ||
| 2008 | zone_offset = make_number (offset); | 2014 | zone_offset = make_number (offset); |
| 2009 | if (SCHARS (zone_name) == 0) | 2015 | if (SCHARS (zone_name) == 0) |
| 2010 | { | 2016 | { |
| @@ -2042,9 +2048,16 @@ only the former. */) | |||
| 2042 | (Lisp_Object tz) | 2048 | (Lisp_Object tz) |
| 2043 | { | 2049 | { |
| 2044 | const char *tzstring; | 2050 | const char *tzstring; |
| 2051 | char **old_environbuf; | ||
| 2052 | |||
| 2053 | if (! (NILP (tz) || EQ (tz, Qt))) | ||
| 2054 | CHECK_STRING (tz); | ||
| 2055 | |||
| 2056 | BLOCK_INPUT; | ||
| 2045 | 2057 | ||
| 2046 | /* When called for the first time, save the original TZ. */ | 2058 | /* When called for the first time, save the original TZ. */ |
| 2047 | if (!environbuf) | 2059 | old_environbuf = environbuf; |
| 2060 | if (!old_environbuf) | ||
| 2048 | initial_tz = (char *) getenv ("TZ"); | 2061 | initial_tz = (char *) getenv ("TZ"); |
| 2049 | 2062 | ||
| 2050 | if (NILP (tz)) | 2063 | if (NILP (tz)) |
| @@ -2052,15 +2065,14 @@ only the former. */) | |||
| 2052 | else if (EQ (tz, Qt)) | 2065 | else if (EQ (tz, Qt)) |
| 2053 | tzstring = "UTC0"; | 2066 | tzstring = "UTC0"; |
| 2054 | else | 2067 | else |
| 2055 | { | 2068 | tzstring = SSDATA (tz); |
| 2056 | CHECK_STRING (tz); | ||
| 2057 | tzstring = SSDATA (tz); | ||
| 2058 | } | ||
| 2059 | 2069 | ||
| 2060 | set_time_zone_rule (tzstring); | 2070 | set_time_zone_rule (tzstring); |
| 2061 | xfree (environbuf); | ||
| 2062 | environbuf = environ; | 2071 | environbuf = environ; |
| 2063 | 2072 | ||
| 2073 | UNBLOCK_INPUT; | ||
| 2074 | |||
| 2075 | xfree (old_environbuf); | ||
| 2064 | return Qnil; | 2076 | return Qnil; |
| 2065 | } | 2077 | } |
| 2066 | 2078 | ||