X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/7ebd31ee0740d85527a498100d1f14dad5e0350f..2e5a663126a0260f5a8bb9d12b8c02c3745ea94b:/src/editfns.c diff --git a/src/editfns.c b/src/editfns.c index 8489a47649..4c3b80be14 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -1,6 +1,6 @@ /* Lisp functions pertaining to editing. -Copyright (C) 1985-1987, 1989, 1993-2011 Free Software Foundation, Inc. +Copyright (C) 1985-1987, 1989, 1993-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -52,17 +52,13 @@ along with GNU Emacs. If not, see . */ #include #include "intervals.h" -#include "buffer.h" #include "character.h" +#include "buffer.h" #include "coding.h" #include "frame.h" #include "window.h" #include "blockinput.h" -#ifndef NULL -#define NULL 0 -#endif - #ifndef USER_FULL_NAME #define USER_FULL_NAME pw->pw_gecos #endif @@ -73,18 +69,12 @@ extern char **environ; #define TM_YEAR_BASE 1900 -/* Nonzero if TM_YEAR is a struct tm's tm_year value that causes - asctime to have well-defined behavior. */ -#ifndef TM_YEAR_IN_ASCTIME_RANGE -# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \ - (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE) -#endif - #ifdef WINDOWSNT extern Lisp_Object w32_get_internal_run_time (void); #endif -static void time_overflow (void) NO_RETURN; +static Lisp_Object format_time_string (char const *, ptrdiff_t, EMACS_TIME, + int, struct tm *); static int tm_diff (struct tm *, struct tm *); static void update_buffer_properties (ptrdiff_t, ptrdiff_t); @@ -293,8 +283,12 @@ region_limit (int beginningp) error ("The mark is not set now, so there is no region"); if ((PT < XFASTINT (m)) == (beginningp != 0)) - m = make_number (PT); - return m; + return make_number (PT); + else + { /* Clip to the current narrowing (bug#11770). */ + ptrdiff_t mark = XFASTINT (m); + return make_number (mark < BEGV ? BEGV : mark > ZV ? ZV : mark); + } } DEFUN ("region-beginning", Fregion_beginning, Sregion_beginning, 0, 0, 0, @@ -656,10 +650,11 @@ is after LIMIT, then LIMIT will be returned instead. */) DEFUN ("constrain-to-field", Fconstrain_to_field, Sconstrain_to_field, 2, 5, 0, doc: /* Return the position closest to NEW-POS that is in the same field as OLD-POS. - A field is a region of text with the same `field' property. -If NEW-POS is nil, then the current point is used instead, and set to the -constrained position if that is different. + +If NEW-POS is nil, then use the current point instead, and move point +to the resulting constrained position, in addition to returning that +position. If OLD-POS is at the boundary of two fields, then the allowable positions for NEW-POS depends on the value of the optional argument @@ -1386,14 +1381,13 @@ DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0, #endif /* Report that a time value is out of range for Emacs. */ -static void +void time_overflow (void) { error ("Specified time is not representable"); } -/* Return the upper part of the time T (everything but the bottom 16 bits), - making sure that it is representable. */ +/* Return the upper part of the time T (everything but the bottom 16 bits). */ static EMACS_INT hi_time (time_t t) { @@ -1421,40 +1415,33 @@ lo_time (time_t t) DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00. -The time is returned as a list of three integers. The first has the -most significant 16 bits of the seconds, while the second has the -least significant 16 bits. The third integer gives the microsecond -count. - -The microsecond count is zero on systems that do not provide -resolution finer than a second. */) +The time is returned as a list of integers (HIGH LOW USEC PSEC). +HIGH has the most significant bits of the seconds, while LOW has the +least significant 16 bits. USEC and PSEC are the microsecond and +picosecond counts. */) (void) { EMACS_TIME t; EMACS_GET_TIME (t); - return list3 (make_number (hi_time (EMACS_SECS (t))), - make_number (lo_time (EMACS_SECS (t))), - make_number (EMACS_USECS (t))); + return make_lisp_time (t); } DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time, 0, 0, 0, doc: /* Return the current run time used by Emacs. -The time is returned as a list of three integers. The first has the -most significant 16 bits of the seconds, while the second has the -least significant 16 bits. The third integer gives the microsecond -count. +The time is returned as a list (HIGH LOW USEC PSEC), using the same +style as (current-time). On systems that can't determine the run time, `get-internal-run-time' -does the same thing as `current-time'. The microsecond count is zero -on systems that do not provide resolution finer than a second. */) +does the same thing as `current-time'. */) (void) { #ifdef HAVE_GETRUSAGE struct rusage usage; time_t secs; int usecs; + EMACS_TIME t; if (getrusage (RUSAGE_SELF, &usage) < 0) /* This shouldn't happen. What action is appropriate? */ @@ -1468,10 +1455,8 @@ on systems that do not provide resolution finer than a second. */) usecs -= 1000000; secs++; } - - return list3 (make_number (hi_time (secs)), - make_number (lo_time (secs)), - make_number (usecs)); + EMACS_SET_SECS_USECS (t, secs, usecs); + return make_lisp_time (t); #else /* ! HAVE_GETRUSAGE */ #ifdef WINDOWSNT return w32_get_internal_run_time (); @@ -1482,80 +1467,151 @@ on systems that do not provide resolution finer than a second. */) } -/* Make a Lisp list that represents the time T. */ -Lisp_Object +/* Make a Lisp list that represents the time T with fraction TAIL. */ +static Lisp_Object +make_time_tail (time_t t, Lisp_Object tail) +{ + return Fcons (make_number (hi_time (t)), + Fcons (make_number (lo_time (t)), tail)); +} + +/* Make a Lisp list that represents the system time T. */ +static Lisp_Object make_time (time_t t) { - return list2 (make_number (hi_time (t)), - make_number (lo_time (t))); + return make_time_tail (t, Qnil); +} + +/* Make a Lisp list that represents the Emacs time T. T may be an + invalid time, with a slightly negative tv_nsec value such as + UNKNOWN_MODTIME_NSECS; in that case, the Lisp list contains a + correspondingly negative picosecond count. */ +Lisp_Object +make_lisp_time (EMACS_TIME t) +{ + int ns = EMACS_NSECS (t); + return make_time_tail (EMACS_SECS (t), + list2 (make_number (ns / 1000), + make_number (ns % 1000 * 1000))); } /* Decode a Lisp list SPECIFIED_TIME that represents a time. - If SPECIFIED_TIME is nil, use the current time. - Set *RESULT to seconds since the Epoch. - If USEC is not null, set *USEC to the microseconds component. + Set *PHIGH, *PLOW, *PUSEC, *PPSEC to its parts; do not check their values. Return nonzero if successful. */ +static int +disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, + Lisp_Object *plow, Lisp_Object *pusec, + Lisp_Object *ppsec) +{ + if (CONSP (specified_time)) + { + Lisp_Object low = XCDR (specified_time); + Lisp_Object usec = make_number (0); + Lisp_Object psec = make_number (0); + if (CONSP (low)) + { + Lisp_Object low_tail = XCDR (low); + low = XCAR (low); + if (CONSP (low_tail)) + { + usec = XCAR (low_tail); + low_tail = XCDR (low_tail); + if (CONSP (low_tail)) + psec = XCAR (low_tail); + } + else if (!NILP (low_tail)) + usec = low_tail; + } + + *phigh = XCAR (specified_time); + *plow = low; + *pusec = usec; + *ppsec = psec; + return 1; + } + + return 0; +} + +/* From the time components HIGH, LOW, USEC and PSEC taken from a Lisp + list, generate the corresponding EMACS_TIME value *RESULT, and + if RESULT_PSEC is not null store into *RESULT_PSEC the + (nonnegative) difference in picoseconds between the input time and + the returned time. Return nonzero if successful. */ int -lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec) +decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, + Lisp_Object psec, EMACS_TIME *result, int *result_psec) { + EMACS_INT hi, lo, us, ps; + time_t sec; + if (! (INTEGERP (high) && INTEGERP (low) + && INTEGERP (usec) && INTEGERP (psec))) + return 0; + hi = XINT (high); + lo = XINT (low); + us = XINT (usec); + ps = XINT (psec); + + /* Normalize out-of-range lower-order components by carrying + each overflow into the next higher-order component. */ + us += ps / 1000000 - (ps % 1000000 < 0); + lo += us / 1000000 - (us % 1000000 < 0); + hi += lo >> 16; + ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); + us = us % 1000000 + 1000000 * (us % 1000000 < 0); + lo &= (1 << 16) - 1; + + /* Check for overflow in the highest-order component. */ + if (! ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 <= hi : 0 <= hi) + && hi <= TIME_T_MAX >> 16)) + return 0; + + sec = hi; + EMACS_SET_SECS_NSECS (*result, (sec << 16) + lo, us * 1000 + ps / 1000); + if (result_psec) + *result_psec = ps % 1000; + return 1; +} + +/* Decode a Lisp list SPECIFIED_TIME that represents a time. + If SPECIFIED_TIME is nil, use the current time. + Round the time down to the nearest EMACS_TIME value, and + if PPSEC is not null store into *PPSEC the (nonnegative) difference in + picoseconds between the input time and the returned time. + Return seconds since the Epoch. + Signal an error if unsuccessful. */ +EMACS_TIME +lisp_time_argument (Lisp_Object specified_time, int *ppsec) +{ + EMACS_TIME t; if (NILP (specified_time)) + EMACS_GET_TIME (t); + else { - if (usec) - { - EMACS_TIME t; - - EMACS_GET_TIME (t); - *usec = EMACS_USECS (t); - *result = EMACS_SECS (t); - return 1; - } - else - return time (result) != -1; + Lisp_Object high, low, usec, psec; + if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) + && decode_time_components (high, low, usec, psec, &t, ppsec))) + error ("Invalid time specification"); } + return t; +} + +/* Like lisp_time_argument, except decode only the seconds part, + and do not check the subseconds part, and always round down. */ +static time_t +lisp_seconds_argument (Lisp_Object specified_time) +{ + if (NILP (specified_time)) + return time (NULL); else { - Lisp_Object high, low; - EMACS_INT hi; - high = Fcar (specified_time); - CHECK_NUMBER (high); - low = Fcdr (specified_time); - if (CONSP (low)) - { - if (usec) - { - Lisp_Object usec_l = Fcdr (low); - if (CONSP (usec_l)) - usec_l = Fcar (usec_l); - if (NILP (usec_l)) - *usec = 0; - else - { - CHECK_NUMBER (usec_l); - if (! (0 <= XINT (usec_l) && XINT (usec_l) < 1000000)) - return 0; - *usec = XINT (usec_l); - } - } - low = Fcar (low); - } - else if (usec) - *usec = 0; - CHECK_NUMBER (low); - hi = XINT (high); - - /* Check for overflow, helping the compiler for common cases - where no runtime check is needed, and taking care not to - convert negative numbers to unsigned before comparing them. */ - if (! ((TYPE_SIGNED (time_t) - ? (TIME_T_MIN >> 16 <= MOST_NEGATIVE_FIXNUM - || TIME_T_MIN >> 16 <= hi) - : 0 <= hi) - && (MOST_POSITIVE_FIXNUM <= TIME_T_MAX >> 16 - || hi <= TIME_T_MAX >> 16))) - return 0; - - *result = (hi << 16) + (XINT (low) & 0xffff); - return 1; + Lisp_Object high, low, usec, psec; + EMACS_TIME t; + if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) + && decode_time_components (high, low, make_number (0), + make_number (0), &t, 0))) + error ("Invalid time specification"); + return EMACS_SECS (t); } } @@ -1563,22 +1619,22 @@ DEFUN ("float-time", Ffloat_time, Sfloat_time, 0, 1, 0, doc: /* Return the current time, as a float number of seconds since the epoch. If SPECIFIED-TIME is given, it is the time to convert to float instead of the current time. The argument should have the form -(HIGH LOW) or (HIGH LOW USEC). Thus, you can use times obtained from -`current-time' and from `file-attributes'. SPECIFIED-TIME can also -have the form (HIGH . LOW), but this is considered obsolete. +(HIGH LOW) or (HIGH LOW USEC) or (HIGH LOW USEC PSEC). Thus, +you can use times from `current-time' and from `file-attributes'. +SPECIFIED-TIME can also have the form (HIGH . LOW), but this is +considered obsolete. WARNING: Since the result is floating point, it may not be exact. If precise time stamps are required, use either `current-time', or (if you need time as a string) `format-time-string'. */) (Lisp_Object specified_time) { - time_t sec; - int usec; - - if (! lisp_time_argument (specified_time, &sec, &usec)) - error ("Invalid time specification"); - - return make_float ((sec * 1e6 + usec) / 1e6); + int psec; + EMACS_TIME t = lisp_time_argument (specified_time, &psec); + double ps = (1000 * 1000 * 1000 <= INTMAX_MAX / 1000 + ? EMACS_NSECS (t) * (intmax_t) 1000 + psec + : EMACS_NSECS (t) * 1e3 + psec); + return make_float (EMACS_SECS (t) + ps / 1e12); } /* Write information into buffer S of size MAXSIZE, according to the @@ -1633,7 +1689,7 @@ emacs_nmemftime (char *s, size_t maxsize, const char *format, DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0, doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted. -TIME is specified as (HIGH LOW . IGNORED), as returned by +TIME is specified as (HIGH LOW USEC PSEC), as returned by `current-time' or `file-attributes'. The obsolete form (HIGH . LOW) is also still accepted. The third, optional, argument UNIVERSAL, if non-nil, means describe TIME @@ -1687,62 +1743,61 @@ For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z". usage: (format-time-string FORMAT-STRING &optional TIME UNIVERSAL) */) (Lisp_Object format_string, Lisp_Object timeval, Lisp_Object universal) { - time_t value; - ptrdiff_t size; - int usec; - int ns; - struct tm *tm; - int ut = ! NILP (universal); + EMACS_TIME t = lisp_time_argument (timeval, 0); + struct tm tm; CHECK_STRING (format_string); - - if (! (lisp_time_argument (timeval, &value, &usec) - && 0 <= usec && usec < 1000000)) - error ("Invalid time specification"); - ns = usec * 1000; - format_string = code_convert_string_norecord (format_string, Vlocale_coding_system, 1); + return format_time_string (SSDATA (format_string), SBYTES (format_string), + t, ! NILP (universal), &tm); +} - /* This is probably enough. */ - size = SBYTES (format_string); - if (size <= (STRING_BYTES_BOUND - 50) / 6) - size = size * 6 + 50; - - BLOCK_INPUT; - tm = ut ? gmtime (&value) : localtime (&value); - UNBLOCK_INPUT; - if (! tm) - time_overflow (); - - synchronize_system_time_locale (); +static Lisp_Object +format_time_string (char const *format, ptrdiff_t formatlen, + EMACS_TIME t, int ut, struct tm *tmp) +{ + char buffer[4000]; + char *buf = buffer; + ptrdiff_t size = sizeof buffer; + size_t len; + Lisp_Object bufstring; + int ns = EMACS_NSECS (t); + struct tm *tm; + USE_SAFE_ALLOCA; while (1) { - char *buf = (char *) alloca (size + 1); - size_t result; + BLOCK_INPUT; + + synchronize_system_time_locale (); + + tm = ut ? gmtime (EMACS_SECS_ADDR (t)) : localtime (EMACS_SECS_ADDR (t)); + if (! tm) + { + UNBLOCK_INPUT; + time_overflow (); + } + *tmp = *tm; buf[0] = '\1'; - BLOCK_INPUT; - result = emacs_nmemftime (buf, size, SSDATA (format_string), - SBYTES (format_string), - tm, ut, ns); - UNBLOCK_INPUT; - if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0')) - return code_convert_string_norecord (make_unibyte_string (buf, result), - Vlocale_coding_system, 0); + len = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); + if ((0 < len && len < size) || (len == 0 && buf[0] == '\0')) + break; - /* If buffer was too small, make it bigger and try again. */ - BLOCK_INPUT; - result = emacs_nmemftime (NULL, (size_t) -1, - SSDATA (format_string), - SBYTES (format_string), - tm, ut, ns); + /* Buffer was too small, so make it bigger and try again. */ + len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tm, ut, ns); UNBLOCK_INPUT; - if (STRING_BYTES_BOUND <= result) + if (STRING_BYTES_BOUND <= len) string_overflow (); - size = result + 1; + size = len + 1; + SAFE_ALLOCA (buf, char *, size); } + + UNBLOCK_INPUT; + bufstring = make_unibyte_string (buf, len); + SAFE_FREE (); + return code_convert_string_norecord (bufstring, Vlocale_coding_system, 0); } DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0, @@ -1762,41 +1817,38 @@ east of Greenwich. (Note that Common Lisp has different meanings for DOW and ZONE.) */) (Lisp_Object specified_time) { - time_t time_spec; + time_t time_spec = lisp_seconds_argument (specified_time); struct tm save_tm; struct tm *decoded_time; Lisp_Object list_args[9]; - if (! lisp_time_argument (specified_time, &time_spec, NULL)) - error ("Invalid time specification"); - BLOCK_INPUT; decoded_time = localtime (&time_spec); + if (decoded_time) + save_tm = *decoded_time; UNBLOCK_INPUT; if (! (decoded_time - && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= decoded_time->tm_year - && decoded_time->tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) + && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= save_tm.tm_year + && save_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) time_overflow (); - XSETFASTINT (list_args[0], decoded_time->tm_sec); - XSETFASTINT (list_args[1], decoded_time->tm_min); - XSETFASTINT (list_args[2], decoded_time->tm_hour); - XSETFASTINT (list_args[3], decoded_time->tm_mday); - XSETFASTINT (list_args[4], decoded_time->tm_mon + 1); + XSETFASTINT (list_args[0], save_tm.tm_sec); + XSETFASTINT (list_args[1], save_tm.tm_min); + XSETFASTINT (list_args[2], save_tm.tm_hour); + XSETFASTINT (list_args[3], save_tm.tm_mday); + XSETFASTINT (list_args[4], save_tm.tm_mon + 1); /* On 64-bit machines an int is narrower than EMACS_INT, thus the cast below avoids overflow in int arithmetics. */ - XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) decoded_time->tm_year); - XSETFASTINT (list_args[6], decoded_time->tm_wday); - list_args[7] = (decoded_time->tm_isdst)? Qt : Qnil; + XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) save_tm.tm_year); + XSETFASTINT (list_args[6], save_tm.tm_wday); + list_args[7] = save_tm.tm_isdst ? Qt : Qnil; - /* Make a copy, in case gmtime modifies the struct. */ - save_tm = *decoded_time; BLOCK_INPUT; decoded_time = gmtime (&time_spec); - UNBLOCK_INPUT; if (decoded_time == 0) list_args[8] = Qnil; else XSETINT (list_args[8], tm_diff (&save_tm, decoded_time)); + UNBLOCK_INPUT; return Flist (9, list_args); } @@ -1881,21 +1933,23 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) else error ("Invalid time zone specification"); + BLOCK_INPUT; + /* Set TZ before calling mktime; merely adjusting mktime's returned value doesn't suffice, since that would mishandle leap seconds. */ set_time_zone_rule (tzstring); - BLOCK_INPUT; value = mktime (&tm); - UNBLOCK_INPUT; /* Restore TZ to previous value. */ newenv = environ; environ = oldenv; - xfree (newenv); #ifdef LOCALTIME_CACHE tzset (); #endif + UNBLOCK_INPUT; + + xfree (newenv); } if (value == (time_t) -1) @@ -1920,26 +1974,36 @@ Thus, you can use times obtained from `current-time' and from but this is considered obsolete. */) (Lisp_Object specified_time) { - time_t value; + time_t value = lisp_seconds_argument (specified_time); struct tm *tm; - register char *tem; + char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; + int len IF_LINT (= 0); - if (! lisp_time_argument (specified_time, &value, NULL)) - error ("Invalid time specification"); - - /* Convert to a string, checking for out-of-range time stamps. - Don't use 'ctime', as that might dump core if VALUE is out of - range. */ + /* Convert to a string in ctime format, except without the trailing + newline, and without the 4-digit year limit. Don't use asctime + or ctime, as they might dump core if the year is outside the + range -999 .. 9999. */ BLOCK_INPUT; tm = localtime (&value); + if (tm) + { + static char const wday_name[][4] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + static char const mon_name[][4] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + printmax_t year_base = TM_YEAR_BASE; + + len = sprintf (buf, "%s %s%3d %02d:%02d:%02d %"pMd, + wday_name[tm->tm_wday], mon_name[tm->tm_mon], tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + tm->tm_year + year_base); + } UNBLOCK_INPUT; - if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime (tm)))) + if (! tm) time_overflow (); - /* Remove the trailing newline. */ - tem[strlen (tem) - 1] = '\0'; - - return build_string (tem); + return make_unibyte_string (buf, len); } /* Yield A - B, measured in seconds. @@ -1982,53 +2046,36 @@ in this case, `current-time-zone' returns a list containing nil for the data it can't find. */) (Lisp_Object specified_time) { - time_t value; + EMACS_TIME value; + int offset; struct tm *t; - struct tm gmt; + struct tm localtm; + Lisp_Object zone_offset, zone_name; - if (!lisp_time_argument (specified_time, &value, NULL)) - t = NULL; - else - { - BLOCK_INPUT; - t = gmtime (&value); - if (t) - { - gmt = *t; - t = localtime (&value); - } - UNBLOCK_INPUT; - } + zone_offset = Qnil; + EMACS_SET_SECS_NSECS (value, lisp_seconds_argument (specified_time), 0); + zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &localtm); + BLOCK_INPUT; + t = gmtime (EMACS_SECS_ADDR (value)); + if (t) + offset = tm_diff (&localtm, t); + UNBLOCK_INPUT; if (t) { - int offset = tm_diff (t, &gmt); - char *s = 0; - char buf[sizeof "+00" + INT_STRLEN_BOUND (int)]; - -#ifdef HAVE_TM_ZONE - if (t->tm_zone) - s = (char *)t->tm_zone; -#else /* not HAVE_TM_ZONE */ -#ifdef HAVE_TZNAME - if (t->tm_isdst == 0 || t->tm_isdst == 1) - s = tzname[t->tm_isdst]; -#endif -#endif /* not HAVE_TM_ZONE */ - - if (!s) + zone_offset = make_number (offset); + if (SCHARS (zone_name) == 0) { /* No local time zone name is available; use "+-NNNN" instead. */ int m = offset / 60; int am = offset < 0 ? - m : m; + char buf[sizeof "+00" + INT_STRLEN_BOUND (int)]; sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60); - s = buf; + zone_name = build_string (buf); } - - return Fcons (make_number (offset), Fcons (build_string (s), Qnil)); } - else - return Fmake_list (make_number (2), Qnil); + + return list2 (zone_offset, zone_name); } /* This holds the value of `environ' produced by the previous @@ -2053,9 +2100,16 @@ only the former. */) (Lisp_Object tz) { const char *tzstring; + char **old_environbuf; + + if (! (NILP (tz) || EQ (tz, Qt))) + CHECK_STRING (tz); + + BLOCK_INPUT; /* When called for the first time, save the original TZ. */ - if (!environbuf) + old_environbuf = environbuf; + if (!old_environbuf) initial_tz = (char *) getenv ("TZ"); if (NILP (tz)) @@ -2063,15 +2117,14 @@ only the former. */) else if (EQ (tz, Qt)) tzstring = "UTC0"; else - { - CHECK_STRING (tz); - tzstring = SSDATA (tz); - } + tzstring = SSDATA (tz); set_time_zone_rule (tzstring); - free (environbuf); environbuf = environ; + UNBLOCK_INPUT; + + xfree (old_environbuf); return Qnil; } @@ -3871,7 +3924,7 @@ usage: (format STRING &rest OBJECTS) */) enum { /* Maximum precision for a %f conversion such that the - trailing output digit might be nonzero. Any precisions + trailing output digit might be nonzero. Any precision larger than this will not yield useful information. */ USEFUL_PRECISION_MAX = ((1 - DBL_MIN_EXP)