aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/editfns.c')
-rw-r--r--src/editfns.c420
1 files changed, 204 insertions, 216 deletions
diff --git a/src/editfns.c b/src/editfns.c
index a906aead09a..be1062dbbc5 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -64,11 +64,17 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
64extern Lisp_Object w32_get_internal_run_time (void); 64extern Lisp_Object w32_get_internal_run_time (void);
65#endif 65#endif
66 66
67static void set_time_zone_rule (char const *);
67static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, 68static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec,
68 bool, struct tm *); 69 bool, struct tm *);
70static long int tm_gmtoff (struct tm *);
69static int tm_diff (struct tm *, struct tm *); 71static int tm_diff (struct tm *, struct tm *);
70static void update_buffer_properties (ptrdiff_t, ptrdiff_t); 72static void update_buffer_properties (ptrdiff_t, ptrdiff_t);
71 73
74#ifndef HAVE_TM_GMTOFF
75# define HAVE_TM_GMTOFF false
76#endif
77
72static Lisp_Object Qbuffer_access_fontify_functions; 78static Lisp_Object Qbuffer_access_fontify_functions;
73 79
74/* Symbol for the text property used to mark fields. */ 80/* Symbol for the text property used to mark fields. */
@@ -79,15 +85,12 @@ Lisp_Object Qfield;
79 85
80static Lisp_Object Qboundary; 86static Lisp_Object Qboundary;
81 87
82/* The startup value of the TZ environment variable so it can be 88/* The startup value of the TZ environment variable; null if unset. */
83 restored if the user calls set-time-zone-rule with a nil
84 argument. If null, the TZ environment variable was unset. */
85static char const *initial_tz; 89static char const *initial_tz;
86 90
87/* True if the static variable tzvalbuf (defined in 91/* A valid but unlikely setting for the TZ environment variable.
88 set_time_zone_rule) is part of 'environ'. */ 92 It is OK (though a bit slower) if the user chooses this value. */
89static bool tzvalbuf_in_environ; 93static char dump_tz_string[] = "TZ=UtC0";
90
91 94
92void 95void
93init_editfns (void) 96init_editfns (void)
@@ -101,13 +104,38 @@ init_editfns (void)
101 init_system_name (); 104 init_system_name ();
102 105
103#ifndef CANNOT_DUMP 106#ifndef CANNOT_DUMP
104 /* Don't bother with this on initial start when just dumping out */ 107 /* When just dumping out, set the time zone to a known unlikely value
108 and skip the rest of this function. */
105 if (!initialized) 109 if (!initialized)
106 return; 110 {
107#endif /* not CANNOT_DUMP */ 111# ifdef HAVE_TZSET
112 xputenv (dump_tz_string);
113 tzset ();
114# endif
115 return;
116 }
117#endif
108 118
109 initial_tz = getenv ("TZ"); 119 char *tz = getenv ("TZ");
110 tzvalbuf_in_environ = 0; 120 initial_tz = tz;
121
122#if !defined CANNOT_DUMP && defined HAVE_TZSET
123 /* If the execution TZ happens to be the same as the dump TZ,
124 change it to some other value and then change it back,
125 to force the underlying implementation to reload the TZ info.
126 This is needed on implementations that load TZ info from files,
127 since the TZ file contents may differ between dump and execution. */
128 if (tz && strcmp (tz, &dump_tz_string[sizeof "TZ=" - 1]) == 0)
129 {
130 ++*tz;
131 tzset ();
132 --*tz;
133 }
134#endif
135
136 /* Call set_time_zone_rule now, so that its call to putenv is done
137 before multiple threads are active. */
138 set_time_zone_rule (tz);
111 139
112 pw = getpwuid (getuid ()); 140 pw = getpwuid (getuid ());
113#ifdef MSDOS 141#ifdef MSDOS
@@ -376,13 +404,14 @@ at POSITION. */)
376 set_buffer_temp (XBUFFER (object)); 404 set_buffer_temp (XBUFFER (object));
377 405
378 /* First try with room for 40 overlays. */ 406 /* First try with room for 40 overlays. */
379 noverlays = 40; 407 Lisp_Object overlay_vecbuf[40];
380 overlay_vec = alloca (noverlays * sizeof *overlay_vec); 408 noverlays = ARRAYELTS (overlay_vecbuf);
409 overlay_vec = overlay_vecbuf;
381 noverlays = overlays_around (posn, overlay_vec, noverlays); 410 noverlays = overlays_around (posn, overlay_vec, noverlays);
382 411
383 /* If there are more than 40, 412 /* If there are more than 40,
384 make enough space for all, and try again. */ 413 make enough space for all, and try again. */
385 if (noverlays > 40) 414 if (ARRAYELTS (overlay_vecbuf) < noverlays)
386 { 415 {
387 SAFE_ALLOCA_LISP (overlay_vec, noverlays); 416 SAFE_ALLOCA_LISP (overlay_vec, noverlays);
388 noverlays = overlays_around (posn, overlay_vec, noverlays); 417 noverlays = overlays_around (posn, overlay_vec, noverlays);
@@ -1325,17 +1354,16 @@ name, or nil if there is no such user. */)
1325 /* Substitute the login name for the &, upcasing the first character. */ 1354 /* Substitute the login name for the &, upcasing the first character. */
1326 if (q) 1355 if (q)
1327 { 1356 {
1328 register char *r; 1357 Lisp_Object login = Fuser_login_name (make_number (pw->pw_uid));
1329 Lisp_Object login; 1358 USE_SAFE_ALLOCA;
1330 1359 char *r = SAFE_ALLOCA (strlen (p) + SBYTES (login) + 1);
1331 login = Fuser_login_name (make_number (pw->pw_uid));
1332 r = alloca (strlen (p) + SCHARS (login) + 1);
1333 memcpy (r, p, q - p); 1360 memcpy (r, p, q - p);
1334 r[q - p] = 0; 1361 r[q - p] = 0;
1335 strcat (r, SSDATA (login)); 1362 strcat (r, SSDATA (login));
1336 r[q - p] = upcase ((unsigned char) r[q - p]); 1363 r[q - p] = upcase ((unsigned char) r[q - p]);
1337 strcat (r, q + 1); 1364 strcat (r, q + 1);
1338 full = build_string (r); 1365 full = build_string (r);
1366 SAFE_FREE ();
1339 } 1367 }
1340#endif /* AMPERSAND_FULL_NAME */ 1368#endif /* AMPERSAND_FULL_NAME */
1341 1369
@@ -1373,6 +1401,30 @@ time_overflow (void)
1373 error ("Specified time is not representable"); 1401 error ("Specified time is not representable");
1374} 1402}
1375 1403
1404/* A substitute for mktime_z on platforms that lack it. It's not
1405 thread-safe, but should be good enough for Emacs in typical use. */
1406#ifndef HAVE_TZALLOC
1407time_t
1408mktime_z (timezone_t tz, struct tm *tm)
1409{
1410 char *oldtz = getenv ("TZ");
1411 USE_SAFE_ALLOCA;
1412 if (oldtz)
1413 {
1414 size_t oldtzsize = strlen (oldtz) + 1;
1415 char *oldtzcopy = SAFE_ALLOCA (oldtzsize);
1416 oldtz = strcpy (oldtzcopy, oldtz);
1417 }
1418 block_input ();
1419 set_time_zone_rule (tz);
1420 time_t t = mktime (tm);
1421 set_time_zone_rule (oldtz);
1422 unblock_input ();
1423 SAFE_FREE ();
1424 return t;
1425}
1426#endif
1427
1376/* Return the upper part of the time T (everything but the bottom 16 bits). */ 1428/* Return the upper part of the time T (everything but the bottom 16 bits). */
1377static EMACS_INT 1429static EMACS_INT
1378hi_time (time_t t) 1430hi_time (time_t t)
@@ -1768,39 +1820,28 @@ format_time_string (char const *format, ptrdiff_t formatlen,
1768 size_t len; 1820 size_t len;
1769 Lisp_Object bufstring; 1821 Lisp_Object bufstring;
1770 int ns = t.tv_nsec; 1822 int ns = t.tv_nsec;
1771 struct tm *tm;
1772 USE_SAFE_ALLOCA; 1823 USE_SAFE_ALLOCA;
1773 1824
1774 while (1) 1825 tmp = ut ? gmtime_r (&t.tv_sec, tmp) : localtime_r (&t.tv_sec, tmp);
1775 { 1826 if (! tmp)
1776 time_t *taddr = &t.tv_sec; 1827 time_overflow ();
1777 block_input (); 1828 synchronize_system_time_locale ();
1778
1779 synchronize_system_time_locale ();
1780
1781 tm = ut ? gmtime (taddr) : localtime (taddr);
1782 if (! tm)
1783 {
1784 unblock_input ();
1785 time_overflow ();
1786 }
1787 *tmp = *tm;
1788 1829
1830 while (true)
1831 {
1789 buf[0] = '\1'; 1832 buf[0] = '\1';
1790 len = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); 1833 len = emacs_nmemftime (buf, size, format, formatlen, tmp, ut, ns);
1791 if ((0 < len && len < size) || (len == 0 && buf[0] == '\0')) 1834 if ((0 < len && len < size) || (len == 0 && buf[0] == '\0'))
1792 break; 1835 break;
1793 1836
1794 /* Buffer was too small, so make it bigger and try again. */ 1837 /* Buffer was too small, so make it bigger and try again. */
1795 len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tm, ut, ns); 1838 len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tmp, ut, ns);
1796 unblock_input ();
1797 if (STRING_BYTES_BOUND <= len) 1839 if (STRING_BYTES_BOUND <= len)
1798 string_overflow (); 1840 string_overflow ();
1799 size = len + 1; 1841 size = len + 1;
1800 buf = SAFE_ALLOCA (size); 1842 buf = SAFE_ALLOCA (size);
1801 } 1843 }
1802 1844
1803 unblock_input ();
1804 bufstring = make_unibyte_string (buf, len); 1845 bufstring = make_unibyte_string (buf, len);
1805 SAFE_FREE (); 1846 SAFE_FREE ();
1806 return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0); 1847 return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0);
@@ -1824,38 +1865,30 @@ DOW and ZONE.) */)
1824 (Lisp_Object specified_time) 1865 (Lisp_Object specified_time)
1825{ 1866{
1826 time_t time_spec = lisp_seconds_argument (specified_time); 1867 time_t time_spec = lisp_seconds_argument (specified_time);
1827 struct tm save_tm; 1868 struct tm local_tm, gmt_tm;
1828 struct tm *decoded_time;
1829 Lisp_Object list_args[9];
1830 1869
1831 block_input (); 1870 if (! (localtime_r (&time_spec, &local_tm)
1832 decoded_time = localtime (&time_spec); 1871 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year
1833 if (decoded_time) 1872 && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
1834 save_tm = *decoded_time;
1835 unblock_input ();
1836 if (! (decoded_time
1837 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= save_tm.tm_year
1838 && save_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
1839 time_overflow (); 1873 time_overflow ();
1840 XSETFASTINT (list_args[0], save_tm.tm_sec);
1841 XSETFASTINT (list_args[1], save_tm.tm_min);
1842 XSETFASTINT (list_args[2], save_tm.tm_hour);
1843 XSETFASTINT (list_args[3], save_tm.tm_mday);
1844 XSETFASTINT (list_args[4], save_tm.tm_mon + 1);
1845 /* On 64-bit machines an int is narrower than EMACS_INT, thus the
1846 cast below avoids overflow in int arithmetics. */
1847 XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) save_tm.tm_year);
1848 XSETFASTINT (list_args[6], save_tm.tm_wday);
1849 list_args[7] = save_tm.tm_isdst ? Qt : Qnil;
1850 1874
1851 block_input (); 1875 /* Avoid overflow when INT_MAX < EMACS_INT_MAX. */
1852 decoded_time = gmtime (&time_spec); 1876 EMACS_INT tm_year_base = TM_YEAR_BASE;
1853 if (decoded_time == 0) 1877
1854 list_args[8] = Qnil; 1878 return Flist (9, ((Lisp_Object [])
1855 else 1879 {make_number (local_tm.tm_sec),
1856 XSETINT (list_args[8], tm_diff (&save_tm, decoded_time)); 1880 make_number (local_tm.tm_min),
1857 unblock_input (); 1881 make_number (local_tm.tm_hour),
1858 return Flist (9, list_args); 1882 make_number (local_tm.tm_mday),
1883 make_number (local_tm.tm_mon + 1),
1884 make_number (local_tm.tm_year + tm_year_base),
1885 make_number (local_tm.tm_wday),
1886 local_tm.tm_isdst ? Qt : Qnil,
1887 (HAVE_TM_GMTOFF
1888 ? make_number (tm_gmtoff (&local_tm))
1889 : gmtime_r (&time_spec, &gmt_tm)
1890 ? make_number (tm_diff (&local_tm, &gmt_tm))
1891 : Qnil)}));
1859} 1892}
1860 1893
1861/* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that 1894/* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that
@@ -1911,18 +1944,12 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1911 if (CONSP (zone)) 1944 if (CONSP (zone))
1912 zone = XCAR (zone); 1945 zone = XCAR (zone);
1913 if (NILP (zone)) 1946 if (NILP (zone))
1914 { 1947 value = mktime (&tm);
1915 block_input ();
1916 value = mktime (&tm);
1917 unblock_input ();
1918 }
1919 else 1948 else
1920 { 1949 {
1921 static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d"; 1950 static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d";
1922 char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)]; 1951 char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)];
1923 char *old_tzstring;
1924 const char *tzstring; 1952 const char *tzstring;
1925 USE_SAFE_ALLOCA;
1926 1953
1927 if (EQ (zone, Qt)) 1954 if (EQ (zone, Qt))
1928 tzstring = "UTC0"; 1955 tzstring = "UTC0";
@@ -1939,29 +1966,13 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1939 tzstring = tzbuf; 1966 tzstring = tzbuf;
1940 } 1967 }
1941 else 1968 else
1942 error ("Invalid time zone specification"); 1969 tzstring = 0;
1943
1944 old_tzstring = getenv ("TZ");
1945 if (old_tzstring)
1946 {
1947 char *buf = SAFE_ALLOCA (strlen (old_tzstring) + 1);
1948 old_tzstring = strcpy (buf, old_tzstring);
1949 }
1950
1951 block_input ();
1952
1953 /* Set TZ before calling mktime; merely adjusting mktime's returned
1954 value doesn't suffice, since that would mishandle leap seconds. */
1955 set_time_zone_rule (tzstring);
1956
1957 value = mktime (&tm);
1958 1970
1959 set_time_zone_rule (old_tzstring); 1971 timezone_t tz = tzstring ? tzalloc (tzstring) : 0;
1960#ifdef LOCALTIME_CACHE 1972 if (! tz)
1961 tzset (); 1973 error ("Invalid time zone specification");
1962#endif 1974 value = mktime_z (tz, &tm);
1963 unblock_input (); 1975 tzfree (tz);
1964 SAFE_FREE ();
1965 } 1976 }
1966 1977
1967 if (value == (time_t) -1) 1978 if (value == (time_t) -1)
@@ -1987,34 +1998,27 @@ but this is considered obsolete. */)
1987 (Lisp_Object specified_time) 1998 (Lisp_Object specified_time)
1988{ 1999{
1989 time_t value = lisp_seconds_argument (specified_time); 2000 time_t value = lisp_seconds_argument (specified_time);
1990 struct tm *tm;
1991 char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1];
1992 int len IF_LINT (= 0);
1993 2001
1994 /* Convert to a string in ctime format, except without the trailing 2002 /* Convert to a string in ctime format, except without the trailing
1995 newline, and without the 4-digit year limit. Don't use asctime 2003 newline, and without the 4-digit year limit. Don't use asctime
1996 or ctime, as they might dump core if the year is outside the 2004 or ctime, as they might dump core if the year is outside the
1997 range -999 .. 9999. */ 2005 range -999 .. 9999. */
1998 block_input (); 2006 struct tm tm;
1999 tm = localtime (&value); 2007 if (! localtime_r (&value, &tm))
2000 if (tm)
2001 {
2002 static char const wday_name[][4] =
2003 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
2004 static char const mon_name[][4] =
2005 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2006 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2007 printmax_t year_base = TM_YEAR_BASE;
2008
2009 len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd,
2010 wday_name[tm->tm_wday], mon_name[tm->tm_mon], tm->tm_mday,
2011 tm->tm_hour, tm->tm_min, tm->tm_sec,
2012 tm->tm_year + year_base);
2013 }
2014 unblock_input ();
2015 if (! tm)
2016 time_overflow (); 2008 time_overflow ();
2017 2009
2010 static char const wday_name[][4] =
2011 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
2012 static char const mon_name[][4] =
2013 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2014 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2015 printmax_t year_base = TM_YEAR_BASE;
2016 char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1];
2017 int len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd,
2018 wday_name[tm.tm_wday], mon_name[tm.tm_mon], tm.tm_mday,
2019 tm.tm_hour, tm.tm_min, tm.tm_sec,
2020 tm.tm_year + year_base);
2021
2018 return make_unibyte_string (buf, len); 2022 return make_unibyte_string (buf, len);
2019} 2023}
2020 2024
@@ -2041,6 +2045,17 @@ tm_diff (struct tm *a, struct tm *b)
2041 + (a->tm_sec - b->tm_sec)); 2045 + (a->tm_sec - b->tm_sec));
2042} 2046}
2043 2047
2048/* Yield A's UTC offset, or an unspecified value if unknown. */
2049static long int
2050tm_gmtoff (struct tm *a)
2051{
2052#if HAVE_TM_GMTOFF
2053 return a->tm_gmtoff;
2054#else
2055 return 0;
2056#endif
2057}
2058
2044DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0, 2059DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0,
2045 doc: /* Return the offset and name for the local time zone. 2060 doc: /* Return the offset and name for the local time zone.
2046This returns a list of the form (OFFSET NAME). 2061This returns a list of the form (OFFSET NAME).
@@ -2059,32 +2074,30 @@ the data it can't find. */)
2059 (Lisp_Object specified_time) 2074 (Lisp_Object specified_time)
2060{ 2075{
2061 struct timespec value; 2076 struct timespec value;
2062 int offset; 2077 struct tm local_tm, gmt_tm;
2063 struct tm *t;
2064 struct tm localtm;
2065 Lisp_Object zone_offset, zone_name; 2078 Lisp_Object zone_offset, zone_name;
2066 2079
2067 zone_offset = Qnil; 2080 zone_offset = Qnil;
2068 value = make_timespec (lisp_seconds_argument (specified_time), 0); 2081 value = make_timespec (lisp_seconds_argument (specified_time), 0);
2069 zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &localtm); 2082 zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &local_tm);
2070 block_input ();
2071 t = gmtime (&value.tv_sec);
2072 if (t)
2073 offset = tm_diff (&localtm, t);
2074 unblock_input ();
2075 2083
2076 if (t) 2084 if (HAVE_TM_GMTOFF || gmtime_r (&value.tv_sec, &gmt_tm))
2077 { 2085 {
2086 long int offset = (HAVE_TM_GMTOFF
2087 ? tm_gmtoff (&local_tm)
2088 : tm_diff (&local_tm, &gmt_tm));
2078 zone_offset = make_number (offset); 2089 zone_offset = make_number (offset);
2079 if (SCHARS (zone_name) == 0) 2090 if (SCHARS (zone_name) == 0)
2080 { 2091 {
2081 /* No local time zone name is available; use "+-NNNN" instead. */ 2092 /* No local time zone name is available; use "+-NNNN" instead. */
2082 int m = offset / 60; 2093 long int m = offset / 60;
2083 int am = offset < 0 ? - m : m; 2094 long int am = offset < 0 ? - m : m;
2084 char buf[sizeof "+00" + INT_STRLEN_BOUND (int)]; 2095 long int hour = am / 60;
2085 zone_name = make_formatted_string (buf, "%c%02d%02d", 2096 int min = am % 60;
2097 char buf[sizeof "+00" + INT_STRLEN_BOUND (long int)];
2098 zone_name = make_formatted_string (buf, "%c%02ld%02d",
2086 (offset < 0 ? '-' : '+'), 2099 (offset < 0 ? '-' : '+'),
2087 am / 60, am % 60); 2100 hour, min);
2088 } 2101 }
2089 } 2102 }
2090 2103
@@ -2123,12 +2136,12 @@ only the former. */)
2123 2136
2124/* Set the local time zone rule to TZSTRING. 2137/* Set the local time zone rule to TZSTRING.
2125 2138
2126 This function is not thread-safe, partly because putenv, unsetenv 2139 This function is not thread-safe, in theory because putenv is not,
2127 and tzset are not, and partly because of the static storage it 2140 but mostly because of the static storage it updates. Other threads
2128 updates. Other threads that invoke localtime etc. may be adversely 2141 that invoke localtime etc. may be adversely affected while this
2129 affected while this function is executing. */ 2142 function is executing. */
2130 2143
2131void 2144static void
2132set_time_zone_rule (const char *tzstring) 2145set_time_zone_rule (const char *tzstring)
2133{ 2146{
2134 /* A buffer holding a string of the form "TZ=value", intended 2147 /* A buffer holding a string of the form "TZ=value", intended
@@ -2137,75 +2150,47 @@ set_time_zone_rule (const char *tzstring)
2137 static ptrdiff_t tzvalbufsize; 2150 static ptrdiff_t tzvalbufsize;
2138 2151
2139 int tzeqlen = sizeof "TZ=" - 1; 2152 int tzeqlen = sizeof "TZ=" - 1;
2153 ptrdiff_t tzstringlen = tzstring ? strlen (tzstring) : 0;
2154 char *tzval = tzvalbuf;
2155 bool new_tzvalbuf = tzvalbufsize <= tzeqlen + tzstringlen;
2140 2156
2141#ifdef LOCALTIME_CACHE 2157 if (new_tzvalbuf)
2142 /* These two values are known to load tz files in buggy implementations, 2158 {
2143 i.e., Solaris 1 executables running under either Solaris 1 or Solaris 2. 2159 /* Do not attempt to free the old tzvalbuf, since another thread
2144 Their values shouldn't matter in non-buggy implementations. 2160 may be using it. In practice, the first allocation is large
2145 We don't use string literals for these strings, 2161 enough and memory does not leak. */
2146 since if a string in the environment is in readonly 2162 tzval = xpalloc (NULL, &tzvalbufsize,
2147 storage, it runs afoul of bugs in SVR4 and Solaris 2.3. 2163 tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
2148 See Sun bugs 1113095 and 1114114, ``Timezone routines 2164 tzvalbuf = tzval;
2149 improperly modify environment''. */ 2165 tzval[1] = 'Z';
2150 2166 tzval[2] = '=';
2151 static char set_time_zone_rule_tz[][sizeof "TZ=GMT+0"] 2167 }
2152 = { "TZ=GMT+0", "TZ=GMT+1" };
2153
2154 /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like
2155 "US/Pacific" that loads a tz file, then changes to a value like
2156 "XXX0" that does not load a tz file, and then changes back to
2157 its original value, the last change is (incorrectly) ignored.
2158 Also, if TZ changes twice in succession to values that do
2159 not load a tz file, tzset can dump core (see Sun bug#1225179).
2160 The following code works around these bugs. */
2161 2168
2162 if (tzstring) 2169 if (tzstring)
2163 { 2170 {
2164 /* Temporarily set TZ to a value that loads a tz file 2171 /* Modify TZVAL in place. Although this is dicey in a
2165 and that differs from tzstring. */ 2172 multithreaded environment, we know of no portable alternative.
2166 bool eq0 = strcmp (tzstring, set_time_zone_rule_tz[0] + tzeqlen) == 0; 2173 Calling putenv or setenv could crash some other thread. */
2167 xputenv (set_time_zone_rule_tz[eq0]); 2174 tzval[0] = 'T';
2175 strcpy (tzval + tzeqlen, tzstring);
2168 } 2176 }
2169 else 2177 else
2170 { 2178 {
2171 /* The implied tzstring is unknown, so temporarily set TZ to 2179 /* Turn 'TZ=whatever' into an empty environment variable 'tZ='.
2172 two different values that each load a tz file. */ 2180 Although this is also dicey, calling unsetenv here can crash Emacs.
2173 xputenv (set_time_zone_rule_tz[0]); 2181 See Bug#8705. */
2174 tzset (); 2182 tzval[0] = 't';
2175 xputenv (set_time_zone_rule_tz[1]); 2183 tzval[tzeqlen] = 0;
2176 } 2184 }
2177 tzset ();
2178 tzvalbuf_in_environ = 0;
2179#endif
2180 2185
2181 if (!tzstring) 2186 if (new_tzvalbuf)
2182 { 2187 {
2183 unsetenv ("TZ"); 2188 /* Although this is not thread-safe, in practice this runs only
2184 tzvalbuf_in_environ = 0; 2189 on startup when there is only one thread. */
2185 } 2190 xputenv (tzval);
2186 else
2187 {
2188 ptrdiff_t tzstringlen = strlen (tzstring);
2189
2190 if (tzvalbufsize <= tzeqlen + tzstringlen)
2191 {
2192 unsetenv ("TZ");
2193 tzvalbuf_in_environ = 0;
2194 tzvalbuf = xpalloc (tzvalbuf, &tzvalbufsize,
2195 tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1);
2196 memcpy (tzvalbuf, "TZ=", tzeqlen);
2197 }
2198
2199 strcpy (tzvalbuf + tzeqlen, tzstring);
2200
2201 if (!tzvalbuf_in_environ)
2202 {
2203 xputenv (tzvalbuf);
2204 tzvalbuf_in_environ = 1;
2205 }
2206 } 2191 }
2207 2192
2208#ifdef LOCALTIME_CACHE 2193#ifdef HAVE_TZSET
2209 tzset (); 2194 tzset ();
2210#endif 2195#endif
2211} 2196}
@@ -3012,8 +2997,12 @@ static Lisp_Object
3012check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end, 2997check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end,
3013 Lisp_Object val) 2998 Lisp_Object val)
3014{ 2999{
3015 int buf_size = 16, buf_used = 0; 3000 int initial_buf[16];
3016 int *buf = alloca (sizeof (int) * buf_size); 3001 int *buf = initial_buf;
3002 ptrdiff_t buf_size = ARRAYELTS (initial_buf);
3003 int *bufalloc = 0;
3004 ptrdiff_t buf_used = 0;
3005 Lisp_Object result = Qnil;
3017 3006
3018 for (; CONSP (val); val = XCDR (val)) 3007 for (; CONSP (val); val = XCDR (val))
3019 { 3008 {
@@ -3038,12 +3027,11 @@ check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end,
3038 3027
3039 if (buf_used == buf_size) 3028 if (buf_used == buf_size)
3040 { 3029 {
3041 int *newbuf; 3030 bufalloc = xpalloc (bufalloc, &buf_size, 1, -1,
3042 3031 sizeof *bufalloc);
3043 buf_size += 16; 3032 if (buf == initial_buf)
3044 newbuf = alloca (sizeof (int) * buf_size); 3033 memcpy (bufalloc, buf, sizeof initial_buf);
3045 memcpy (newbuf, buf, sizeof (int) * buf_used); 3034 buf = bufalloc;
3046 buf = newbuf;
3047 } 3035 }
3048 buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, len1); 3036 buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, len1);
3049 pos_byte += len1; 3037 pos_byte += len1;
@@ -3052,10 +3040,15 @@ check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end,
3052 break; 3040 break;
3053 } 3041 }
3054 if (i == len) 3042 if (i == len)
3055 return XCAR (val); 3043 {
3044 result = XCAR (val);
3045 break;
3046 }
3056 } 3047 }
3057 } 3048 }
3058 return Qnil; 3049
3050 xfree (bufalloc);
3051 return result;
3059} 3052}
3060 3053
3061 3054
@@ -4354,11 +4347,8 @@ usage: (format STRING &rest OBJECTS) */)
4354Lisp_Object 4347Lisp_Object
4355format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1) 4348format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1)
4356{ 4349{
4357 Lisp_Object args[3]; 4350 AUTO_STRING (format, string1);
4358 args[0] = build_string (string1); 4351 return Fformat (3, (Lisp_Object []) {format, arg0, arg1});
4359 args[1] = arg0;
4360 args[2] = arg1;
4361 return Fformat (3, args);
4362} 4352}
4363 4353
4364DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0, 4354DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
@@ -4617,11 +4607,11 @@ Transposing beyond buffer boundaries is an error. */)
4617 if (tmp_interval3) 4607 if (tmp_interval3)
4618 set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3); 4608 set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
4619 4609
4610 USE_SAFE_ALLOCA;
4611
4620 /* First region smaller than second. */ 4612 /* First region smaller than second. */
4621 if (len1_byte < len2_byte) 4613 if (len1_byte < len2_byte)
4622 { 4614 {
4623 USE_SAFE_ALLOCA;
4624
4625 temp = SAFE_ALLOCA (len2_byte); 4615 temp = SAFE_ALLOCA (len2_byte);
4626 4616
4627 /* Don't precompute these addresses. We have to compute them 4617 /* Don't precompute these addresses. We have to compute them
@@ -4633,21 +4623,19 @@ Transposing beyond buffer boundaries is an error. */)
4633 memcpy (temp, start2_addr, len2_byte); 4623 memcpy (temp, start2_addr, len2_byte);
4634 memcpy (start1_addr + len2_byte, start1_addr, len1_byte); 4624 memcpy (start1_addr + len2_byte, start1_addr, len1_byte);
4635 memcpy (start1_addr, temp, len2_byte); 4625 memcpy (start1_addr, temp, len2_byte);
4636 SAFE_FREE ();
4637 } 4626 }
4638 else 4627 else
4639 /* First region not smaller than second. */ 4628 /* First region not smaller than second. */
4640 { 4629 {
4641 USE_SAFE_ALLOCA;
4642
4643 temp = SAFE_ALLOCA (len1_byte); 4630 temp = SAFE_ALLOCA (len1_byte);
4644 start1_addr = BYTE_POS_ADDR (start1_byte); 4631 start1_addr = BYTE_POS_ADDR (start1_byte);
4645 start2_addr = BYTE_POS_ADDR (start2_byte); 4632 start2_addr = BYTE_POS_ADDR (start2_byte);
4646 memcpy (temp, start1_addr, len1_byte); 4633 memcpy (temp, start1_addr, len1_byte);
4647 memcpy (start1_addr, start2_addr, len2_byte); 4634 memcpy (start1_addr, start2_addr, len2_byte);
4648 memcpy (start1_addr + len2_byte, temp, len1_byte); 4635 memcpy (start1_addr + len2_byte, temp, len1_byte);
4649 SAFE_FREE ();
4650 } 4636 }
4637
4638 SAFE_FREE ();
4651 graft_intervals_into_buffer (tmp_interval1, start1 + len2, 4639 graft_intervals_into_buffer (tmp_interval1, start1 + len2,
4652 len1, current_buffer, 0); 4640 len1, current_buffer, 0);
4653 graft_intervals_into_buffer (tmp_interval2, start1, 4641 graft_intervals_into_buffer (tmp_interval2, start1,