diff options
Diffstat (limited to 'src/editfns.c')
-rw-r--r-- | src/editfns.c | 478 |
1 files changed, 229 insertions, 249 deletions
diff --git a/src/editfns.c b/src/editfns.c index 9c1fcb0b790..376d8e3a0ea 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/>. */ extern Lisp_Object w32_get_internal_run_time (void); #endif +static void set_time_zone_rule (char const *); static Lisp_Object format_time_string (char const *, ptrdiff_t, struct timespec, bool, struct tm *); +static long int tm_gmtoff (struct tm *); static int tm_diff (struct tm *, struct tm *); static void update_buffer_properties (ptrdiff_t, ptrdiff_t); +#ifndef HAVE_TM_GMTOFF +# define HAVE_TM_GMTOFF false +#endif + static Lisp_Object Qbuffer_access_fontify_functions; /* Symbol for the text property used to mark fields. */ @@ -79,15 +85,12 @@ Lisp_Object Qfield; static Lisp_Object Qboundary; -/* The startup value of the TZ environment variable so it can be - restored if the user calls set-time-zone-rule with a nil - argument. If null, the TZ environment variable was unset. */ +/* The startup value of the TZ environment variable; null if unset. */ static char const *initial_tz; -/* True if the static variable tzvalbuf (defined in - set_time_zone_rule) is part of 'environ'. */ -static bool tzvalbuf_in_environ; - +/* A valid but unlikely setting for the TZ environment variable. + It is OK (though a bit slower) if the user chooses this value. */ +static char dump_tz_string[] = "TZ=UtC0"; void init_editfns (void) @@ -101,18 +104,43 @@ init_editfns (void) init_system_name (); #ifndef CANNOT_DUMP - /* Don't bother with this on initial start when just dumping out */ + /* When just dumping out, set the time zone to a known unlikely value + and skip the rest of this function. */ if (!initialized) - return; -#endif /* not CANNOT_DUMP */ + { +# ifdef HAVE_TZSET + xputenv (dump_tz_string); + tzset (); +# endif + return; + } +#endif - initial_tz = getenv ("TZ"); - tzvalbuf_in_environ = 0; + char *tz = getenv ("TZ"); + initial_tz = tz; + +#if !defined CANNOT_DUMP && defined HAVE_TZSET + /* If the execution TZ happens to be the same as the dump TZ, + change it to some other value and then change it back, + to force the underlying implementation to reload the TZ info. + This is needed on implementations that load TZ info from files, + since the TZ file contents may differ between dump and execution. */ + if (tz && strcmp (tz, &dump_tz_string[sizeof "TZ=" - 1]) == 0) + { + ++*tz; + tzset (); + --*tz; + } +#endif + + /* Call set_time_zone_rule now, so that its call to putenv is done + before multiple threads are active. */ + set_time_zone_rule (tz); pw = getpwuid (getuid ()); #ifdef MSDOS /* We let the real user name default to "root" because that's quite - accurate on MSDOG and because it lets Emacs find the init file. + accurate on MS-DOS and because it lets Emacs find the init file. (The DVX libraries override the Djgpp libraries here.) */ Vuser_real_login_name = build_string (pw ? pw->pw_name : "root"); #else @@ -376,13 +404,14 @@ at POSITION. */) set_buffer_temp (XBUFFER (object)); /* First try with room for 40 overlays. */ - noverlays = 40; - overlay_vec = alloca (noverlays * sizeof *overlay_vec); + Lisp_Object overlay_vecbuf[40]; + noverlays = ARRAYELTS (overlay_vecbuf); + overlay_vec = overlay_vecbuf; noverlays = overlays_around (posn, overlay_vec, noverlays); /* If there are more than 40, make enough space for all, and try again. */ - if (noverlays > 40) + if (ARRAYELTS (overlay_vecbuf) < noverlays) { SAFE_ALLOCA_LISP (overlay_vec, noverlays); noverlays = overlays_around (posn, overlay_vec, noverlays); @@ -758,26 +787,17 @@ boundaries, bind `inhibit-field-text-motion' to t. This function does not move point. */) (Lisp_Object n) { - ptrdiff_t orig, orig_byte, end; - ptrdiff_t count = SPECPDL_INDEX (); - specbind (Qinhibit_point_motion_hooks, Qt); + ptrdiff_t charpos, bytepos; if (NILP (n)) XSETFASTINT (n, 1); else CHECK_NUMBER (n); - orig = PT; - orig_byte = PT_BYTE; - Fforward_line (make_number (XINT (n) - 1)); - end = PT; - - SET_PT_BOTH (orig, orig_byte); - - unbind_to (count, Qnil); + scan_newline_from_point (XINT (n) - 1, &charpos, &bytepos); /* Return END constrained to the current input field. */ - return Fconstrain_to_field (make_number (end), make_number (orig), + return Fconstrain_to_field (make_number (charpos), make_number (PT), XINT (n) != 1 ? Qt : Qnil, Qt, Qnil); } @@ -1325,17 +1345,16 @@ name, or nil if there is no such user. */) /* Substitute the login name for the &, upcasing the first character. */ if (q) { - register char *r; - Lisp_Object login; - - login = Fuser_login_name (make_number (pw->pw_uid)); - r = alloca (strlen (p) + SCHARS (login) + 1); + Lisp_Object login = Fuser_login_name (make_number (pw->pw_uid)); + USE_SAFE_ALLOCA; + char *r = SAFE_ALLOCA (strlen (p) + SBYTES (login) + 1); memcpy (r, p, q - p); r[q - p] = 0; strcat (r, SSDATA (login)); r[q - p] = upcase ((unsigned char) r[q - p]); strcat (r, q + 1); full = build_string (r); + SAFE_FREE (); } #endif /* AMPERSAND_FULL_NAME */ @@ -1373,6 +1392,30 @@ time_overflow (void) error ("Specified time is not representable"); } +/* A substitute for mktime_z on platforms that lack it. It's not + thread-safe, but should be good enough for Emacs in typical use. */ +#ifndef HAVE_TZALLOC +time_t +mktime_z (timezone_t tz, struct tm *tm) +{ + char *oldtz = getenv ("TZ"); + USE_SAFE_ALLOCA; + if (oldtz) + { + size_t oldtzsize = strlen (oldtz) + 1; + char *oldtzcopy = SAFE_ALLOCA (oldtzsize); + oldtz = strcpy (oldtzcopy, oldtz); + } + block_input (); + set_time_zone_rule (tz); + time_t t = mktime (tm); + set_time_zone_rule (oldtz); + unblock_input (); + SAFE_FREE (); + return t; +} +#endif + /* Return the upper part of the time T (everything but the bottom 16 bits). */ static EMACS_INT hi_time (time_t t) @@ -1516,7 +1559,8 @@ disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, 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 struct timespec. + if the converted time does not fit into struct timespec, + store an invalid timespec to indicate the overflow. If *DRESULT is not null, store into *DRESULT the number of seconds since the start of the POSIX Epoch. @@ -1529,7 +1573,7 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, EMACS_INT hi, lo, us, ps; if (! (INTEGERP (high) && INTEGERP (low) && INTEGERP (usec) && INTEGERP (psec))) - return 0; + return false; hi = XINT (high); lo = XINT (low); us = XINT (usec); @@ -1555,16 +1599,13 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, *result = make_timespec ((sec << 16) + lo, us * 1000 + ps / 1000); } else - { - /* Overflow in the highest-order component. */ - return 0; - } + *result = invalid_timespec (); } if (dresult) *dresult = (us * 1e6 + ps) / 1e12 + lo + hi * 65536.0; - return 1; + return true; } /* Decode a Lisp list SPECIFIED_TIME that represents a time. @@ -1576,22 +1617,23 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, struct timespec lisp_time_argument (Lisp_Object specified_time) { - struct timespec t; if (NILP (specified_time)) - t = current_timespec (); + return current_timespec (); else { Lisp_Object high, low, usec, psec; + struct timespec t; if (! (disassemble_lisp_time (specified_time, &high, &low, &usec, &psec) && decode_time_components (high, low, usec, psec, &t, 0))) error ("Invalid time specification"); + if (! timespec_valid_p (t)) + time_overflow (); + return t; } - 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. */ + and do not check the subseconds part. */ static time_t lisp_seconds_argument (Lisp_Object specified_time) { @@ -1605,6 +1647,8 @@ lisp_seconds_argument (Lisp_Object specified_time) && decode_time_components (high, low, make_number (0), make_number (0), &t, 0))) error ("Invalid time specification"); + if (! timespec_valid_p (t)) + time_overflow (); return t.tv_sec; } } @@ -1767,39 +1811,28 @@ format_time_string (char const *format, ptrdiff_t formatlen, size_t len; Lisp_Object bufstring; int ns = t.tv_nsec; - struct tm *tm; USE_SAFE_ALLOCA; - while (1) - { - time_t *taddr = &t.tv_sec; - block_input (); - - synchronize_system_time_locale (); - - tm = ut ? gmtime (taddr) : localtime (taddr); - if (! tm) - { - unblock_input (); - time_overflow (); - } - *tmp = *tm; + tmp = ut ? gmtime_r (&t.tv_sec, tmp) : localtime_r (&t.tv_sec, tmp); + if (! tmp) + time_overflow (); + synchronize_system_time_locale (); + while (true) + { buf[0] = '\1'; - len = emacs_nmemftime (buf, size, format, formatlen, tm, ut, ns); + len = emacs_nmemftime (buf, size, format, formatlen, tmp, ut, ns); if ((0 < len && len < size) || (len == 0 && buf[0] == '\0')) break; /* Buffer was too small, so make it bigger and try again. */ - len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tm, ut, ns); - unblock_input (); + len = emacs_nmemftime (NULL, SIZE_MAX, format, formatlen, tmp, ut, ns); if (STRING_BYTES_BOUND <= len) string_overflow (); 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); @@ -1823,38 +1856,30 @@ DOW and ZONE.) */) (Lisp_Object specified_time) { time_t time_spec = lisp_seconds_argument (specified_time); - struct tm save_tm; - struct tm *decoded_time; - Lisp_Object list_args[9]; + struct tm local_tm, gmt_tm; - 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 <= save_tm.tm_year - && save_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) + if (! (localtime_r (&time_spec, &local_tm) + && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year + && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) time_overflow (); - 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) save_tm.tm_year); - XSETFASTINT (list_args[6], save_tm.tm_wday); - list_args[7] = save_tm.tm_isdst ? Qt : Qnil; - block_input (); - decoded_time = gmtime (&time_spec); - 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); + /* Avoid overflow when INT_MAX < EMACS_INT_MAX. */ + EMACS_INT tm_year_base = TM_YEAR_BASE; + + return Flist (9, ((Lisp_Object []) + {make_number (local_tm.tm_sec), + make_number (local_tm.tm_min), + make_number (local_tm.tm_hour), + make_number (local_tm.tm_mday), + make_number (local_tm.tm_mon + 1), + make_number (local_tm.tm_year + tm_year_base), + make_number (local_tm.tm_wday), + local_tm.tm_isdst ? Qt : Qnil, + (HAVE_TM_GMTOFF + ? make_number (tm_gmtoff (&local_tm)) + : gmtime_r (&time_spec, &gmt_tm) + ? make_number (tm_diff (&local_tm, &gmt_tm)) + : Qnil)})); } /* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that @@ -1910,18 +1935,12 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) if (CONSP (zone)) zone = XCAR (zone); if (NILP (zone)) - { - block_input (); - value = mktime (&tm); - unblock_input (); - } + value = mktime (&tm); else { static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d"; char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)]; - char *old_tzstring; const char *tzstring; - USE_SAFE_ALLOCA; if (EQ (zone, Qt)) tzstring = "UTC0"; @@ -1938,29 +1957,13 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) tzstring = tzbuf; } else - error ("Invalid time zone specification"); - - old_tzstring = getenv ("TZ"); - if (old_tzstring) - { - char *buf = SAFE_ALLOCA (strlen (old_tzstring) + 1); - old_tzstring = strcpy (buf, old_tzstring); - } + tzstring = 0; - 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); - - value = mktime (&tm); - - set_time_zone_rule (old_tzstring); -#ifdef LOCALTIME_CACHE - tzset (); -#endif - unblock_input (); - SAFE_FREE (); + timezone_t tz = tzstring ? tzalloc (tzstring) : 0; + if (! tz) + error ("Invalid time zone specification"); + value = mktime_z (tz, &tm); + tzfree (tz); } if (value == (time_t) -1) @@ -1986,34 +1989,27 @@ but this is considered obsolete. */) (Lisp_Object specified_time) { time_t value = lisp_seconds_argument (specified_time); - struct tm *tm; - char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; - int len IF_LINT (= 0); /* 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) + struct tm tm; + if (! localtime_r (&value, &tm)) time_overflow (); + 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; + char buf[sizeof "Mon Apr 30 12:49:17 " + INT_STRLEN_BOUND (int) + 1]; + int 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); + return make_unibyte_string (buf, len); } @@ -2040,6 +2036,17 @@ tm_diff (struct tm *a, struct tm *b) + (a->tm_sec - b->tm_sec)); } +/* Yield A's UTC offset, or an unspecified value if unknown. */ +static long int +tm_gmtoff (struct tm *a) +{ +#if HAVE_TM_GMTOFF + return a->tm_gmtoff; +#else + return 0; +#endif +} + DEFUN ("current-time-zone", Fcurrent_time_zone, Scurrent_time_zone, 0, 1, 0, doc: /* Return the offset and name for the local time zone. This returns a list of the form (OFFSET NAME). @@ -2058,32 +2065,30 @@ the data it can't find. */) (Lisp_Object specified_time) { struct timespec value; - int offset; - struct tm *t; - struct tm localtm; + struct tm local_tm, gmt_tm; Lisp_Object zone_offset, zone_name; zone_offset = Qnil; value = make_timespec (lisp_seconds_argument (specified_time), 0); - zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &localtm); - block_input (); - t = gmtime (&value.tv_sec); - if (t) - offset = tm_diff (&localtm, t); - unblock_input (); + zone_name = format_time_string ("%Z", sizeof "%Z" - 1, value, 0, &local_tm); - if (t) + if (HAVE_TM_GMTOFF || gmtime_r (&value.tv_sec, &gmt_tm)) { + long int offset = (HAVE_TM_GMTOFF + ? tm_gmtoff (&local_tm) + : tm_diff (&local_tm, &gmt_tm)); 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)]; - zone_name = make_formatted_string (buf, "%c%02d%02d", + long int m = offset / 60; + long int am = offset < 0 ? - m : m; + long int hour = am / 60; + int min = am % 60; + char buf[sizeof "+00" + INT_STRLEN_BOUND (long int)]; + zone_name = make_formatted_string (buf, "%c%02ld%02d", (offset < 0 ? '-' : '+'), - am / 60, am % 60); + hour, min); } } @@ -2122,12 +2127,12 @@ only the former. */) /* Set the local time zone rule to TZSTRING. - This function is not thread-safe, partly because putenv, unsetenv - and tzset are not, and partly because of the static storage it - updates. Other threads that invoke localtime etc. may be adversely - affected while this function is executing. */ + This function is not thread-safe, in theory because putenv is not, + but mostly because of the static storage it updates. Other threads + that invoke localtime etc. may be adversely affected while this + function is executing. */ -void +static void set_time_zone_rule (const char *tzstring) { /* A buffer holding a string of the form "TZ=value", intended @@ -2136,75 +2141,47 @@ set_time_zone_rule (const char *tzstring) static ptrdiff_t tzvalbufsize; int tzeqlen = sizeof "TZ=" - 1; + ptrdiff_t tzstringlen = tzstring ? strlen (tzstring) : 0; + char *tzval = tzvalbuf; + bool new_tzvalbuf = tzvalbufsize <= tzeqlen + tzstringlen; -#ifdef LOCALTIME_CACHE - /* These two values are known to load tz files in buggy implementations, - i.e., Solaris 1 executables running under either Solaris 1 or Solaris 2. - Their values shouldn't matter in non-buggy implementations. - We don't use string literals for these strings, - since if a string in the environment is in readonly - storage, it runs afoul of bugs in SVR4 and Solaris 2.3. - See Sun bugs 1113095 and 1114114, ``Timezone routines - improperly modify environment''. */ - - static char set_time_zone_rule_tz[][sizeof "TZ=GMT+0"] - = { "TZ=GMT+0", "TZ=GMT+1" }; - - /* In SunOS 4.1.3_U1 and 4.1.4, if TZ has a value like - "US/Pacific" that loads a tz file, then changes to a value like - "XXX0" that does not load a tz file, and then changes back to - its original value, the last change is (incorrectly) ignored. - Also, if TZ changes twice in succession to values that do - not load a tz file, tzset can dump core (see Sun bug#1225179). - The following code works around these bugs. */ + if (new_tzvalbuf) + { + /* Do not attempt to free the old tzvalbuf, since another thread + may be using it. In practice, the first allocation is large + enough and memory does not leak. */ + tzval = xpalloc (NULL, &tzvalbufsize, + tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1); + tzvalbuf = tzval; + tzval[1] = 'Z'; + tzval[2] = '='; + } if (tzstring) { - /* Temporarily set TZ to a value that loads a tz file - and that differs from tzstring. */ - bool eq0 = strcmp (tzstring, set_time_zone_rule_tz[0] + tzeqlen) == 0; - xputenv (set_time_zone_rule_tz[eq0]); + /* Modify TZVAL in place. Although this is dicey in a + multithreaded environment, we know of no portable alternative. + Calling putenv or setenv could crash some other thread. */ + tzval[0] = 'T'; + strcpy (tzval + tzeqlen, tzstring); } else { - /* The implied tzstring is unknown, so temporarily set TZ to - two different values that each load a tz file. */ - xputenv (set_time_zone_rule_tz[0]); - tzset (); - xputenv (set_time_zone_rule_tz[1]); + /* Turn 'TZ=whatever' into an empty environment variable 'tZ='. + Although this is also dicey, calling unsetenv here can crash Emacs. + See Bug#8705. */ + tzval[0] = 't'; + tzval[tzeqlen] = 0; } - tzset (); - tzvalbuf_in_environ = 0; -#endif - if (!tzstring) + if (new_tzvalbuf) { - unsetenv ("TZ"); - tzvalbuf_in_environ = 0; + /* Although this is not thread-safe, in practice this runs only + on startup when there is only one thread. */ + xputenv (tzval); } - else - { - ptrdiff_t tzstringlen = strlen (tzstring); - - if (tzvalbufsize <= tzeqlen + tzstringlen) - { - unsetenv ("TZ"); - tzvalbuf_in_environ = 0; - tzvalbuf = xpalloc (tzvalbuf, &tzvalbufsize, - tzeqlen + tzstringlen - tzvalbufsize + 1, -1, 1); - memcpy (tzvalbuf, "TZ=", tzeqlen); - } - - strcpy (tzvalbuf + tzeqlen, tzstring); - if (!tzvalbuf_in_environ) - { - xputenv (tzvalbuf); - tzvalbuf_in_environ = 1; - } - } - -#ifdef LOCALTIME_CACHE +#ifdef HAVE_TZSET tzset (); #endif } @@ -2238,7 +2215,7 @@ general_insert_function (void (*insert_func) len = CHAR_STRING (c, str); else { - str[0] = ASCII_CHAR_P (c) ? c : multibyte_char_to_unibyte (c); + str[0] = CHAR_TO_BYTE8 (c); len = 1; } (*insert_func) ((char *) str, len); @@ -2852,7 +2829,7 @@ Both characters must have the same length of multi-byte form. */) len = CHAR_STRING (fromc, fromstr); if (CHAR_STRING (toc, tostr) != len) error ("Characters in `subst-char-in-region' have different byte-lengths"); - if (!ASCII_BYTE_P (*tostr)) + if (!ASCII_CHAR_P (*tostr)) { /* If *TOSTR is in the range 0x80..0x9F and TOCHAR is not a complete multibyte character, it may be combined with the @@ -2945,7 +2922,7 @@ Both characters must have the same length of multi-byte form. */) : ((pos_byte_next < Z_BYTE && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next))) || (pos_byte > BEG_BYTE - && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))) + && ! ASCII_CHAR_P (FETCH_BYTE (pos_byte - 1)))))) { Lisp_Object tem, string; @@ -3011,8 +2988,12 @@ static Lisp_Object check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end, Lisp_Object val) { - int buf_size = 16, buf_used = 0; - int *buf = alloca (sizeof (int) * buf_size); + int initial_buf[16]; + int *buf = initial_buf; + ptrdiff_t buf_size = ARRAYELTS (initial_buf); + int *bufalloc = 0; + ptrdiff_t buf_used = 0; + Lisp_Object result = Qnil; for (; CONSP (val); val = XCDR (val)) { @@ -3037,12 +3018,11 @@ check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end, if (buf_used == buf_size) { - int *newbuf; - - buf_size += 16; - newbuf = alloca (sizeof (int) * buf_size); - memcpy (newbuf, buf, sizeof (int) * buf_used); - buf = newbuf; + bufalloc = xpalloc (bufalloc, &buf_size, 1, -1, + sizeof *bufalloc); + if (buf == initial_buf) + memcpy (bufalloc, buf, sizeof initial_buf); + buf = bufalloc; } buf[buf_used++] = STRING_CHAR_AND_LENGTH (p, len1); pos_byte += len1; @@ -3051,10 +3031,15 @@ check_translation (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t end, break; } if (i == len) - return XCAR (val); + { + result = XCAR (val); + break; + } } } - return Qnil; + + xfree (bufalloc); + return result; } @@ -3126,7 +3111,7 @@ It returns the number of characters changed. */) else { nc = tt[oc]; - if (! ASCII_BYTE_P (nc) && multibyte) + if (! ASCII_CHAR_P (nc) && multibyte) { str_len = BYTE8_STRING (nc, buf); str = buf; @@ -3600,7 +3585,7 @@ specifier truncates the string to the given width. usage: (format STRING &rest OBJECTS) */) (ptrdiff_t nargs, Lisp_Object *args) { - ptrdiff_t n; /* The number of the next arg to substitute */ + ptrdiff_t n; /* The number of the next arg to substitute. */ char initial_buffer[4000]; char *buf = initial_buffer; ptrdiff_t bufsize = sizeof initial_buffer; @@ -3877,7 +3862,7 @@ usage: (format STRING &rest OBJECTS) */) if (p > buf && multibyte - && !ASCII_BYTE_P (*((unsigned char *) p - 1)) + && !ASCII_CHAR_P (*((unsigned char *) p - 1)) && STRING_MULTIBYTE (args[n]) && !CHAR_HEAD_P (SREF (args[n], 0))) maybe_combine_byte = 1; @@ -4167,7 +4152,7 @@ usage: (format STRING &rest OBJECTS) */) { /* Copy a whole multibyte character. */ if (p > buf - && !ASCII_BYTE_P (*((unsigned char *) p - 1)) + && !ASCII_CHAR_P (*((unsigned char *) p - 1)) && !CHAR_HEAD_P (*format)) maybe_combine_byte = 1; @@ -4181,7 +4166,7 @@ usage: (format STRING &rest OBJECTS) */) else { unsigned char uc = *format++; - if (! multibyte || ASCII_BYTE_P (uc)) + if (! multibyte || ASCII_CHAR_P (uc)) convbytes = 1; else { @@ -4353,11 +4338,8 @@ usage: (format STRING &rest OBJECTS) */) Lisp_Object format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1) { - Lisp_Object args[3]; - args[0] = build_string (string1); - args[1] = arg0; - args[2] = arg1; - return Fformat (3, args); + AUTO_STRING (format, string1); + return Fformat (3, (Lisp_Object []) {format, arg0, arg1}); } DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0, @@ -4616,11 +4598,11 @@ Transposing beyond buffer boundaries is an error. */) if (tmp_interval3) set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3); + USE_SAFE_ALLOCA; + /* First region smaller than second. */ if (len1_byte < len2_byte) { - USE_SAFE_ALLOCA; - temp = SAFE_ALLOCA (len2_byte); /* Don't precompute these addresses. We have to compute them @@ -4632,21 +4614,19 @@ Transposing beyond buffer boundaries is an error. */) memcpy (temp, start2_addr, len2_byte); memcpy (start1_addr + len2_byte, start1_addr, len1_byte); memcpy (start1_addr, temp, len2_byte); - SAFE_FREE (); } else /* First region not smaller than second. */ { - USE_SAFE_ALLOCA; - 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); memcpy (start1_addr, start2_addr, len2_byte); memcpy (start1_addr + len2_byte, temp, len1_byte); - SAFE_FREE (); } + + SAFE_FREE (); graft_intervals_into_buffer (tmp_interval1, start1 + len2, len1, current_buffer, 0); graft_intervals_into_buffer (tmp_interval2, start1, |