X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/9d6b4d53469a9ffd67bd770fabc6fe254e35c21d..4c31be6153255dfe29a0231253263ea0d9011ac3:/src/editfns.c diff --git a/src/editfns.c b/src/editfns.c index afd4ed4833..60f61d0b43 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -52,46 +52,29 @@ 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 - #ifndef USE_CRT_DLL extern char **environ; #endif #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 +201,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 +216,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 +268,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, @@ -335,7 +310,7 @@ overlays_around (EMACS_INT pos, Lisp_Object *vec, ptrdiff_t len) ptrdiff_t startpos, endpos; ptrdiff_t idx = 0; - for (tail = current_buffer->overlays_before; tail; tail = tail->next) + for (tail = buffer_get_overlays (NULL, OV_BEFORE); tail; tail = tail->next) { XSETMISC (overlay, tail); @@ -354,7 +329,7 @@ overlays_around (EMACS_INT pos, Lisp_Object *vec, ptrdiff_t len) } } - for (tail = current_buffer->overlays_after; tail; tail = tail->next) + for (tail = buffer_get_overlays (NULL, OV_AFTER); tail; tail = tail->next) { XSETMISC (overlay, tail); @@ -409,14 +384,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 +633,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 @@ -906,7 +882,7 @@ save_excursion_restore (Lisp_Object info) info = XCDR (info); tem = XCAR (info); tem1 = BVAR (current_buffer, mark_active); - BVAR (current_buffer, mark_active) = tem; + BSET (current_buffer, mark_active, tem); /* If mark is active now, and either was not active or was at a different place, run the activate hook. */ @@ -1014,7 +990,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 +1010,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 +1317,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 +1364,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 +1398,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 +1434,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 +1445,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 +1612,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 +1690,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 +1744,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; + buf = SAFE_ALLOCA (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 +1819,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 +1905,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 +1935,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 +1976,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 +2048,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 +2072,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 +2103,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 +2120,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 +2161,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 +2364,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 +2402,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); @@ -2722,13 +2816,13 @@ determines whether case is significant or ignored. */) static Lisp_Object subst_char_in_region_unwind (Lisp_Object arg) { - return BVAR (current_buffer, undo_list) = arg; + return BSET (current_buffer, undo_list, arg); } static Lisp_Object subst_char_in_region_unwind_1 (Lisp_Object arg) { - return BVAR (current_buffer, filename) = arg; + return BSET (current_buffer, filename, arg); } DEFUN ("subst-char-in-region", Fsubst_char_in_region, @@ -2802,11 +2896,11 @@ Both characters must have the same length of multi-byte form. */) { record_unwind_protect (subst_char_in_region_unwind, BVAR (current_buffer, undo_list)); - BVAR (current_buffer, undo_list) = Qt; + BSET (current_buffer, undo_list, Qt); /* Don't do file-locking. */ record_unwind_protect (subst_char_in_region_unwind_1, BVAR (current_buffer, filename)); - BVAR (current_buffer, filename) = Qnil; + BSET (current_buffer, filename, Qnil); } if (pos_byte < GPT_BYTE) @@ -2888,7 +2982,7 @@ Both characters must have the same length of multi-byte form. */) INC_POS (pos_byte_next); if (! NILP (noundo)) - BVAR (current_buffer, undo_list) = tem; + BSET (current_buffer, undo_list, tem); UNGCPRO; } @@ -3228,8 +3322,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; @@ -3281,6 +3375,10 @@ save_restriction_restore (Lisp_Object data) buf->clip_changed = 1; /* Remember that the narrowing changed. */ } + /* These aren't needed anymore, so don't wait for GC. */ + free_marker (XCAR (data)); + free_marker (XCDR (data)); + free_cons (XCONS (data)); } else /* A buffer, which means that there was no old restriction. */ @@ -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), @@ -3592,7 +3686,7 @@ usage: (format STRING &rest OBJECTS) */) ptrdiff_t i; if ((SIZE_MAX - formatlen) / sizeof (struct info) <= nargs) memory_full (SIZE_MAX); - SAFE_ALLOCA (info, struct info *, (nargs + 1) * sizeof *info + formatlen); + info = SAFE_ALLOCA ((nargs + 1) * sizeof *info + formatlen); discarded = (char *) &info[nargs + 1]; for (i = 0; i < nargs + 1; i++) { @@ -3839,7 +3933,7 @@ usage: (format STRING &rest OBJECTS) */) /* If this argument has text properties, record where in the result string it appears. */ - if (STRING_INTERVALS (args[n])) + if (string_get_intervals (args[n])) info[n].intervals = arg_intervals = 1; continue; @@ -4183,7 +4277,7 @@ usage: (format STRING &rest OBJECTS) */) arguments has text properties, set up text properties of the result string. */ - if (STRING_INTERVALS (args[0]) || arg_intervals) + if (string_get_intervals (args[0]) || arg_intervals) { Lisp_Object len, new_len, props; struct gcpro gcpro1; @@ -4433,7 +4527,7 @@ Transposing beyond buffer boundaries is an error. */) Lisp_Object buf; XSETBUFFER (buf, current_buffer); - cur_intv = BUF_INTERVALS (current_buffer); + cur_intv = buffer_get_intervals (current_buffer); validate_region (&startr1, &endr1); validate_region (&startr2, &endr2); @@ -4543,7 +4637,7 @@ Transposing beyond buffer boundaries is an error. */) /* Don't use Fset_text_properties: that can cause GC, which can clobber objects stored in the tmp_intervals. */ tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0); - if (!NULL_INTERVAL_P (tmp_interval3)) + if (tmp_interval3) set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3); /* First region smaller than second. */ @@ -4551,7 +4645,7 @@ Transposing beyond buffer boundaries is an error. */) { USE_SAFE_ALLOCA; - SAFE_ALLOCA (temp, unsigned char *, len2_byte); + temp = SAFE_ALLOCA (len2_byte); /* Don't precompute these addresses. We have to compute them at the last minute, because the relocating allocator might @@ -4569,7 +4663,7 @@ Transposing beyond buffer boundaries is an error. */) { USE_SAFE_ALLOCA; - SAFE_ALLOCA (temp, unsigned char *, len1_byte); + temp = SAFE_ALLOCA (len1_byte); start1_addr = BYTE_POS_ADDR (start1_byte); start2_addr = BYTE_POS_ADDR (start2_byte); memcpy (temp, start1_addr, len1_byte); @@ -4602,14 +4696,14 @@ Transposing beyond buffer boundaries is an error. */) tmp_interval2 = copy_intervals (cur_intv, start2, len2); tmp_interval3 = validate_interval_range (buf, &startr1, &endr1, 0); - if (!NULL_INTERVAL_P (tmp_interval3)) + if (tmp_interval3) set_text_properties_1 (startr1, endr1, Qnil, buf, tmp_interval3); tmp_interval3 = validate_interval_range (buf, &startr2, &endr2, 0); - if (!NULL_INTERVAL_P (tmp_interval3)) + if (tmp_interval3) set_text_properties_1 (startr2, endr2, Qnil, buf, tmp_interval3); - SAFE_ALLOCA (temp, unsigned char *, len1_byte); + temp = SAFE_ALLOCA (len1_byte); start1_addr = BYTE_POS_ADDR (start1_byte); start2_addr = BYTE_POS_ADDR (start2_byte); memcpy (temp, start1_addr, len1_byte); @@ -4635,11 +4729,11 @@ Transposing beyond buffer boundaries is an error. */) tmp_interval2 = copy_intervals (cur_intv, start2, len2); tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0); - if (!NULL_INTERVAL_P (tmp_interval3)) + if (tmp_interval3) set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3); /* holds region 2 */ - SAFE_ALLOCA (temp, unsigned char *, len2_byte); + temp = SAFE_ALLOCA (len2_byte); start1_addr = BYTE_POS_ADDR (start1_byte); start2_addr = BYTE_POS_ADDR (start2_byte); memcpy (temp, start2_addr, len2_byte); @@ -4668,11 +4762,11 @@ Transposing beyond buffer boundaries is an error. */) tmp_interval2 = copy_intervals (cur_intv, start2, len2); tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0); - if (!NULL_INTERVAL_P (tmp_interval3)) + if (tmp_interval3) set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3); /* holds region 1 */ - SAFE_ALLOCA (temp, unsigned char *, len1_byte); + temp = SAFE_ALLOCA (len1_byte); start1_addr = BYTE_POS_ADDR (start1_byte); start2_addr = BYTE_POS_ADDR (start2_byte); memcpy (temp, start1_addr, len1_byte);