X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/929bb973dd3faf1655f03ac758942d5b009354ad..257210319f10abebbfd7c12784cf3a8e112c3562:/src/editfns.c diff --git a/src/editfns.c b/src/editfns.c index 16e552afe1..9cfd0449da 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,25 +69,16 @@ 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, Lisp_Object, - int, time_t *, struct tm **); +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); static Lisp_Object Qbuffer_access_fontify_functions; -static Lisp_Object Fuser_full_name (Lisp_Object); /* Symbol for the text property used to mark fields. */ @@ -218,15 +205,6 @@ DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0, XSETFASTINT (val, 0); return val; } - -static Lisp_Object -buildmark (ptrdiff_t charpos, ptrdiff_t bytepos) -{ - register Lisp_Object mark; - mark = Fmake_marker (); - set_marker_both (mark, Qnil, charpos, bytepos); - return mark; -} DEFUN ("point", Fpoint, Spoint, 0, 0, 0, doc: /* Return value of point, as an integer. @@ -242,7 +220,7 @@ DEFUN ("point-marker", Fpoint_marker, Spoint_marker, 0, 0, 0, doc: /* Return value of point, as a marker object. */) (void) { - return buildmark (PT, PT_BYTE); + return build_marker (current_buffer, PT, PT_BYTE); } DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ", @@ -294,9 +272,10 @@ region_limit (int beginningp) if (NILP (m)) error ("The mark is not set now, so there is no region"); - if ((PT < XFASTINT (m)) == (beginningp != 0)) - m = make_number (PT); - return m; + /* Clip to the current narrowing (bug#11770). */ + return make_number ((PT < XFASTINT (m)) == (beginningp != 0) + ? PT + : clip_to_bounds (BEGV, XFASTINT (m), ZV)); } DEFUN ("region-beginning", Fregion_beginning, Sregion_beginning, 0, 0, 0, @@ -409,14 +388,14 @@ get_pos_property (Lisp_Object position, register Lisp_Object prop, Lisp_Object o /* First try with room for 40 overlays. */ noverlays = 40; - overlay_vec = (Lisp_Object *) alloca (noverlays * sizeof (Lisp_Object)); + overlay_vec = alloca (noverlays * sizeof *overlay_vec); noverlays = overlays_around (posn, overlay_vec, noverlays); /* If there are more than 40, make enough space for all, and try again. */ if (noverlays > 40) { - overlay_vec = (Lisp_Object *) alloca (noverlays * sizeof (Lisp_Object)); + overlay_vec = alloca (noverlays * sizeof *overlay_vec); noverlays = overlays_around (posn, overlay_vec, noverlays); } noverlays = sort_overlays (overlay_vec, noverlays, NULL); @@ -658,10 +637,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 @@ -1014,7 +994,7 @@ DEFUN ("point-min-marker", Fpoint_min_marker, Spoint_min_marker, 0, 0, 0, This is the beginning, unless narrowing (a buffer restriction) is in effect. */) (void) { - return buildmark (BEGV, BEGV_BYTE); + return build_marker (current_buffer, BEGV, BEGV_BYTE); } DEFUN ("point-max", Fpoint_max, Spoint_max, 0, 0, 0, @@ -1034,7 +1014,7 @@ This is (1+ (buffer-size)), unless narrowing (a buffer restriction) is in effect, in which case it is less. */) (void) { - return buildmark (ZV, ZV_BYTE); + return build_marker (current_buffer, ZV, ZV_BYTE); } DEFUN ("gap-position", Fgap_position, Sgap_position, 0, 0, 0, @@ -1341,7 +1321,7 @@ name, or nil if there is no such user. */) Lisp_Object login; login = Fuser_login_name (make_number (pw->pw_uid)); - r = (char *) alloca (strlen (p) + SCHARS (login) + 1); + r = alloca (strlen (p) + SCHARS (login) + 1); memcpy (r, p, q - p); r[q - p] = 0; strcat (r, SSDATA (login)); @@ -1388,14 +1368,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) { @@ -1423,34 +1402,23 @@ 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 (current_emacs_time ()); } 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 @@ -1470,10 +1438,7 @@ 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)); + return make_lisp_time (make_emacs_time (secs, usecs * 1000)); #else /* ! HAVE_GETRUSAGE */ #ifdef WINDOWSNT return w32_get_internal_run_time (); @@ -1484,80 +1449,166 @@ 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. */ -int -lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec) +static int +disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, + Lisp_Object *plow, Lisp_Object *pusec, + Lisp_Object *ppsec) { - if (NILP (specified_time)) + if (CONSP (specified_time)) { - if (usec) - { - EMACS_TIME t; + 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; + } - EMACS_GET_TIME (t); - *usec = EMACS_USECS (t); - *result = EMACS_SECS (t); - return 1; - } + *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 time value. + + If RESULT is not null, store into *RESULT the converted time; + this can fail if the converted time does not fit into EMACS_TIME. + If *DRESULT is not null, store into *DRESULT the number of + seconds since the start of the POSIX Epoch. + + Return nonzero if successful. */ +int +decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, + Lisp_Object psec, + EMACS_TIME *result, double *dresult) +{ + EMACS_INT hi, lo, us, ps; + 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; + + if (result) + { + if ((TYPE_SIGNED (time_t) ? TIME_T_MIN >> 16 <= hi : 0 <= hi) + && hi <= TIME_T_MAX >> 16) + { + /* Return the greatest representable time that is not greater + than the requested time. */ + time_t sec = hi; + *result = make_emacs_time ((sec << 16) + lo, us * 1000 + ps / 1000); + } else - return time (result) != -1; + { + /* Overflow in the highest-order component. */ + return 0; + } } + + if (dresult) + *dresult = (us * 1e6 + ps) / 1e12 + lo + hi * 65536.0; + + 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. + Return seconds since the Epoch. + Signal an error if unsuccessful. */ +EMACS_TIME +lisp_time_argument (Lisp_Object specified_time) +{ + EMACS_TIME t; + if (NILP (specified_time)) + t = current_emacs_time (); 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; + if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) + && decode_time_components (high, low, usec, psec, &t, 0))) + error ("Invalid time specification"); + } + return t; +} + +/* Like lisp_time_argument, except decode only the seconds part, + do not allow out-of-range time stamps, 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, 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); } } @@ -1565,22 +1616,30 @@ 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); + double t; + if (NILP (specified_time)) + { + EMACS_TIME now = current_emacs_time (); + t = EMACS_SECS (now) + EMACS_NSECS (now) / 1e9; + } + else + { + Lisp_Object high, low, usec, psec; + if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) + && decode_time_components (high, low, usec, psec, 0, &t))) + error ("Invalid time specification"); + } + return make_float (t); } /* Write information into buffer S of size MAXSIZE, according to the @@ -1635,7 +1694,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 @@ -1689,65 +1748,62 @@ 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 t; - struct tm *tm; + EMACS_TIME t = lisp_time_argument (timeval); + struct tm tm; CHECK_STRING (format_string); format_string = code_convert_string_norecord (format_string, Vlocale_coding_system, 1); return format_time_string (SSDATA (format_string), SBYTES (format_string), - timeval, ! NILP (universal), &t, &tm); + t, ! NILP (universal), &tm); } static Lisp_Object format_time_string (char const *format, ptrdiff_t formatlen, - Lisp_Object timeval, int ut, time_t *tval, struct tm **tmp) + EMACS_TIME t, int ut, struct tm *tmp) { - ptrdiff_t size; - int usec; - int ns; + 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; - - if (! lisp_time_argument (timeval, tval, &usec)) - error ("Invalid time specification"); - ns = usec * 1000; - - /* This is probably enough. */ - size = formatlen; - if (size <= (STRING_BYTES_BOUND - 50) / 6) - size = size * 6 + 50; - - BLOCK_INPUT; - tm = ut ? gmtime (tval) : localtime (tval); - UNBLOCK_INPUT; - if (! tm) - time_overflow (); - *tmp = tm; - - synchronize_system_time_locale (); + USE_SAFE_ALLOCA; while (1) { - char *buf = (char *) alloca (size + 1); - size_t result; + time_t *taddr = emacs_secs_addr (&t); + BLOCK_INPUT; + + synchronize_system_time_locale (); + + tm = ut ? gmtime (taddr) : localtime (taddr); + if (! tm) + { + UNBLOCK_INPUT; + time_overflow (); + } + *tmp = *tm; buf[0] = '\1'; - BLOCK_INPUT; - result = emacs_nmemftime (buf, size, format, formatlen, 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, format, formatlen, - 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, @@ -1767,41 +1823,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); } @@ -1856,7 +1909,7 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) tm.tm_isdst = -1; if (CONSP (zone)) - zone = Fcar (zone); + zone = XCAR (zone); if (NILP (zone)) { BLOCK_INPUT; @@ -1886,21 +1939,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) @@ -1925,26 +1980,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; - - if (! lisp_time_argument (specified_time, &value, NULL)) - error ("Invalid time specification"); + char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; + int len IF_LINT (= 0); - /* 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. @@ -1987,23 +2052,23 @@ 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 localtm; - struct tm *localt; Lisp_Object zone_offset, zone_name; zone_offset = Qnil; - zone_name = format_time_string ("%Z", sizeof "%Z" - 1, specified_time, - 0, &value, &localt); - localtm = *localt; + value = make_emacs_time (lisp_seconds_argument (specified_time), 0); + zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &localtm); BLOCK_INPUT; - t = gmtime (&value); + t = gmtime (emacs_secs_addr (&value)); + if (t) + offset = tm_diff (&localtm, t); UNBLOCK_INPUT; if (t) { - int offset = tm_diff (&localtm, t); zone_offset = make_number (offset); if (SCHARS (zone_name) == 0) { @@ -2011,8 +2076,9 @@ the data it can't find. */) 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); - zone_name = build_string (buf); + zone_name = make_formatted_string (buf, "%c%02d%02d", + (offset < 0 ? '-' : '+'), + am / 60, am % 60); } } @@ -2041,9 +2107,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)) @@ -2051,15 +2124,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); - xfree (environbuf); environbuf = environ; + UNBLOCK_INPUT; + + xfree (old_environbuf); return Qnil; } @@ -2093,8 +2165,8 @@ set_time_zone_rule (const char *tzstring) for (from = environ; *from; from++) continue; envptrs = from - environ + 2; - newenv = to = (char **) xmalloc (envptrs * sizeof (char *) - + (tzstring ? strlen (tzstring) + 4 : 0)); + newenv = to = xmalloc (envptrs * sizeof *newenv + + (tzstring ? strlen (tzstring) + 4 : 0)); /* Add TZSTRING to the end of environ, as a value for TZ. */ if (tzstring) @@ -2296,11 +2368,35 @@ usage: (insert-before-markers-and-inherit &rest ARGS) */) return Qnil; } -DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0, +DEFUN ("insert-char", Finsert_char, Sinsert_char, 1, 3, + "(list (read-char-by-name \"Insert character (Unicode name or hex): \")\ + (prefix-numeric-value current-prefix-arg)\ + t))", doc: /* Insert COUNT copies of CHARACTER. -Point, and before-insertion markers, are relocated as in the function `insert'. -The optional third arg INHERIT, if non-nil, says to inherit text properties -from adjoining text, if those properties are sticky. */) +Interactively, prompt for CHARACTER. You can specify CHARACTER in one +of these ways: + + - As its Unicode character name, e.g. \"LATIN SMALL LETTER A\". + Completion is available; if you type a substring of the name + preceded by an asterisk `*', Emacs shows all names which include + that substring, not necessarily at the beginning of the name. + + - As a hexadecimal code point, e.g. 263A. Note that code points in + Emacs are equivalent to Unicode up to 10FFFF (which is the limit of + the Unicode code space). + + - As a code point with a radix specified with #, e.g. #o21430 + (octal), #x2318 (hex), or #10r8984 (decimal). + +If called interactively, COUNT is given by the prefix argument. If +omitted or nil, it defaults to 1. + +Inserting the character(s) relocates point and before-insertion +markers in the same ways as the function `insert'. + +The optional third argument INHERIT, if non-nil, says to inherit text +properties from adjoining text, if those properties are sticky. If +called interactively, INHERIT is t. */) (Lisp_Object character, Lisp_Object count, Lisp_Object inherit) { int i, stringlen; @@ -2310,6 +2406,8 @@ from adjoining text, if those properties are sticky. */) char string[4000]; CHECK_CHARACTER (character); + if (NILP (count)) + XSETFASTINT (count, 1); CHECK_NUMBER (count); c = XFASTINT (character); @@ -3228,8 +3326,8 @@ save_restriction_save (void) { Lisp_Object beg, end; - beg = buildmark (BEGV, BEGV_BYTE); - end = buildmark (ZV, ZV_BYTE); + beg = build_marker (current_buffer, BEGV, BEGV_BYTE); + end = build_marker (current_buffer, ZV, ZV_BYTE); /* END must move forward if text is inserted at its exact location. */ XMARKER (end)->insertion_type = 1; @@ -3411,15 +3509,11 @@ usage: (message-box FORMAT-STRING &rest ARGS) */) } #endif /* HAVE_MENUS */ /* Copy the data so that it won't move when we GC. */ - if (! message_text) - { - message_text = (char *)xmalloc (80); - message_length = 80; - } if (SBYTES (val) > message_length) { - message_text = (char *) xrealloc (message_text, SBYTES (val)); - message_length = SBYTES (val); + ptrdiff_t new_length = SBYTES (val) + 80; + message_text = xrealloc (message_text, new_length); + message_length = new_length; } memcpy (message_text, SDATA (val), SBYTES (val)); message2 (message_text, SBYTES (val), @@ -3859,7 +3953,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)