/* 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.
#include <verify.h>
#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. */
XSETFASTINT (val, 0);
return val;
}
-\f
-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.
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: ",
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,
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);
}
}
- 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);
/* 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);
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
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. */
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,
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,
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));
#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)
{
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
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 ();
}
\f
-/* 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);
}
}
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
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
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,
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);
}
tm.tm_isdst = -1;
if (CONSP (zone))
- zone = Fcar (zone);
+ zone = XCAR (zone);
if (NILP (zone))
{
BLOCK_INPUT;
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)
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.
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)
{
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);
}
}
(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))
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;
}
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)
return Qnil;
}
\f
-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;
char string[4000];
CHECK_CHARACTER (character);
+ if (NILP (count))
+ XSETFASTINT (count, 1);
CHECK_NUMBER (count);
c = XFASTINT (character);
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,
{
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)
INC_POS (pos_byte_next);
if (! NILP (noundo))
- BVAR (current_buffer, undo_list) = tem;
+ BSET (current_buffer, undo_list, tem);
UNGCPRO;
}
{
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;
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. */
}
#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),
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++)
{
/* 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;
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)
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;
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);
/* 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. */
{
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
{
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);
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);
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);
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);