/* Lisp functions pertaining to editing.
- Copyright (C) 1985,86,87,89,93,94,95,96,97,98,1999,2000,01,02,03,2004
- Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1987, 1989, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
#include <sys/types.h>
#include <stdio.h>
-#ifdef VMS
-#include "vms-pwd.h"
-#else
+#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#include <unistd.h>
#endif
+#ifdef HAVE_SYS_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+
+#include "lisp.h"
+
/* systime.h includes <sys/time.h> which, on some systems, is required
for <sys/resource.h>; thus systime.h must be included before
<sys/resource.h> */
#include <ctype.h>
-#include "lisp.h"
#include "intervals.h"
#include "buffer.h"
#include "charset.h"
#include "coding.h"
#include "frame.h"
#include "window.h"
+#include "blockinput.h"
#ifdef STDC_HEADERS
#include <float.h>
extern char **environ;
#endif
-extern Lisp_Object make_time P_ ((time_t));
+#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
+
extern size_t emacs_strftimeu P_ ((char *, size_t, const char *,
const struct tm *, int));
+
+#ifdef WINDOWSNT
+extern Lisp_Object w32_get_internal_run_time ();
+#endif
+
static int tm_diff P_ ((struct tm *, struct tm *));
static void find_field P_ ((Lisp_Object, Lisp_Object, Lisp_Object, int *, Lisp_Object, int *));
static void update_buffer_properties P_ ((int, int));
Lisp_Object Vuser_real_login_name; /* login name of current user ID */
Lisp_Object Vuser_full_name; /* full name of current user */
Lisp_Object Vuser_login_name; /* user name from LOGNAME or USER */
+Lisp_Object Voperating_system_release; /* Operating System Release */
/* Symbol for the text property used to mark fields. */
Vuser_full_name = build_string (p);
else if (NILP (Vuser_full_name))
Vuser_full_name = build_string ("unknown");
+
+#ifdef HAVE_SYS_UTSNAME_H
+ {
+ struct utsname uts;
+ uname (&uts);
+ Voperating_system_release = build_string (uts.release);
+ }
+#else
+ Voperating_system_release = Qnil;
+#endif
}
\f
DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ",
doc: /* Set point to POSITION, a number or marker.
Beginning of buffer is position (point-min), end is (point-max).
-If the position is in the middle of a multibyte form,
-the actual point is set at the head of the multibyte form
-except in the case that `enable-multibyte-characters' is nil. */)
+
+The return value is POSITION. */)
(position)
register Lisp_Object position;
{
if (!NILP (Vtransient_mark_mode)
&& NILP (Vmark_even_if_inactive)
&& NILP (current_buffer->mark_active))
- Fsignal (Qmark_inactive, Qnil);
+ xsignal0 (Qmark_inactive);
m = Fmarker_position (current_buffer->mark);
if (NILP (m))
}
/* Find the field surrounding POS in *BEG and *END. If POS is nil,
- the value of point is used instead. If BEG or END null,
+ the value of point is used instead. If BEG or END is null,
means don't store the beginning or end of the field.
BEG_LIMIT and END_LIMIT serve to limit the ranged of the returned
= (XFASTINT (pos) > BEGV
? get_char_property_and_overlay (make_number (XINT (pos) - 1),
Qfield, Qnil, NULL)
- : Qnil);
+ /* Using nil here would be a more obvious choice, but it would
+ fail when the buffer starts with a non-sticky field. */
+ : after_field);
/* See if we need to handle the case where MERGE_AT_BOUNDARY is nil
and POS is at beginning of a field, which can also be interpreted
{
/* If non-zero, then the original point, before re-positioning. */
int orig_point = 0;
+ int fwd;
+ Lisp_Object prev_old, prev_new;
if (NILP (new_pos))
/* Use the current point, and afterwards, set it. */
XSETFASTINT (new_pos, PT);
}
+ CHECK_NUMBER_COERCE_MARKER (new_pos);
+ CHECK_NUMBER_COERCE_MARKER (old_pos);
+
+ fwd = (XFASTINT (new_pos) > XFASTINT (old_pos));
+
+ prev_old = make_number (XFASTINT (old_pos) - 1);
+ prev_new = make_number (XFASTINT (new_pos) - 1);
+
if (NILP (Vinhibit_field_text_motion)
&& !EQ (new_pos, old_pos)
&& (!NILP (Fget_char_property (new_pos, Qfield, Qnil))
- || !NILP (Fget_char_property (old_pos, Qfield, Qnil)))
+ || !NILP (Fget_char_property (old_pos, Qfield, Qnil))
+ /* To recognize field boundaries, we must also look at the
+ previous positions; we could use `get_pos_property'
+ instead, but in itself that would fail inside non-sticky
+ fields (like comint prompts). */
+ || (XFASTINT (new_pos) > BEGV
+ && !NILP (Fget_char_property (prev_new, Qfield, Qnil)))
+ || (XFASTINT (old_pos) > BEGV
+ && !NILP (Fget_char_property (prev_old, Qfield, Qnil))))
&& (NILP (inhibit_capture_property)
- || NILP (Fget_char_property(old_pos, inhibit_capture_property, Qnil))))
- /* NEW_POS is not within the same field as OLD_POS; try to
- move NEW_POS so that it is. */
+ /* Field boundaries are again a problem; but now we must
+ decide the case exactly, so we need to call
+ `get_pos_property' as well. */
+ || (NILP (get_pos_property (old_pos, inhibit_capture_property, Qnil))
+ && (XFASTINT (old_pos) <= BEGV
+ || NILP (Fget_char_property (old_pos, inhibit_capture_property, Qnil))
+ || NILP (Fget_char_property (prev_old, inhibit_capture_property, Qnil))))))
+ /* It is possible that NEW_POS is not within the same field as
+ OLD_POS; try to move NEW_POS so that it is. */
{
- int fwd, shortage;
+ int shortage;
Lisp_Object field_bound;
- CHECK_NUMBER_COERCE_MARKER (new_pos);
- CHECK_NUMBER_COERCE_MARKER (old_pos);
-
- fwd = (XFASTINT (new_pos) > XFASTINT (old_pos));
-
if (fwd)
field_bound = Ffield_end (old_pos, escape_from_edge, new_pos);
else
With argument N not nil or 1, move forward N - 1 lines first.
If scan reaches end of buffer, return that position.
-The scan does not cross a field boundary unless doing so would move
-beyond there to a different line; if N is nil or 1, and scan starts at a
-field boundary, the scan stops as soon as it starts. To ignore field
+This function constrains the returned position to the current field
+unless that would be on a different line than the original,
+unconstrained result. If N is nil or 1, and a front-sticky field
+starts at point, the scan stops as soon as it starts. To ignore field
boundaries bind `inhibit-field-text-motion' to t.
This function does not move point. */)
Lisp_Object n;
{
int orig, orig_byte, end;
+ int count = SPECPDL_INDEX ();
+ specbind (Qinhibit_point_motion_hooks, Qt);
if (NILP (n))
XSETFASTINT (n, 1);
SET_PT_BOTH (orig, orig_byte);
+ unbind_to (count, Qnil);
+
/* Return END constrained to the current input field. */
return Fconstrain_to_field (make_number (end), make_number (orig),
XINT (n) != 1 ? Qt : Qnil,
With argument N not nil or 1, move forward N - 1 lines first.
If scan reaches end of buffer, return that position.
-The scan does not cross a field boundary unless doing so would move
-beyond there to a different line; if N is nil or 1, and scan starts at a
-field boundary, the scan stops as soon as it starts. To ignore field
+This function constrains the returned position to the current field
+unless that would be on a different line than the original,
+unconstrained result. If N is nil or 1, and a rear-sticky field ends
+at point, the scan stops as soon as it starts. To ignore field
boundaries bind `inhibit-field-text-motion' to t.
This function does not move point. */)
return Vuser_login_name;
CHECK_NUMBER (uid);
+ BLOCK_INPUT;
pw = (struct passwd *) getpwuid (XINT (uid));
+ UNBLOCK_INPUT;
return (pw ? build_string (pw->pw_name) : Qnil);
}
Value is an integer or float, depending on the value. */)
()
{
- return make_fixnum_or_float (geteuid ());
+ /* Assignment to EMACS_INT stops GCC whining about limited range of
+ data type. */
+ EMACS_INT euid = geteuid ();
+ return make_fixnum_or_float (euid);
}
DEFUN ("user-real-uid", Fuser_real_uid, Suser_real_uid, 0, 0, 0,
Value is an integer or float, depending on the value. */)
()
{
- return make_fixnum_or_float (getuid ());
+ /* Assignment to EMACS_INT stops GCC whining about limited range of
+ data type. */
+ EMACS_INT uid = getuid ();
+ return make_fixnum_or_float (uid);
}
DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
if (NILP (uid))
return Vuser_full_name;
else if (NUMBERP (uid))
- pw = (struct passwd *) getpwuid ((uid_t) XFLOATINT (uid));
+ {
+ BLOCK_INPUT;
+ pw = (struct passwd *) getpwuid ((uid_t) XFLOATINT (uid));
+ UNBLOCK_INPUT;
+ }
else if (STRINGP (uid))
- pw = (struct passwd *) getpwnam (SDATA (uid));
+ {
+ BLOCK_INPUT;
+ pw = (struct passwd *) getpwnam (SDATA (uid));
+ UNBLOCK_INPUT;
+ }
else
error ("Invalid UID specification");
}
DEFUN ("system-name", Fsystem_name, Ssystem_name, 0, 0, 0,
- doc: /* Return the name of the machine you are running on, as a string. */)
+ doc: /* Return the host name of the machine you are running on, as a string. */)
()
{
return Vsystem_name;
return "";
}
+char *
+get_operating_system_release()
+{
+ if (STRINGP (Voperating_system_release))
+ return (char *) SDATA (Voperating_system_release);
+ else
+ return "";
+}
+
DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0,
doc: /* Return the process ID of Emacs, as an integer. */)
()
()
{
EMACS_TIME t;
- Lisp_Object result[3];
EMACS_GET_TIME (t);
- XSETINT (result[0], (EMACS_SECS (t) >> 16) & 0xffff);
- XSETINT (result[1], (EMACS_SECS (t) >> 0) & 0xffff);
- XSETINT (result[2], EMACS_USECS (t));
-
- return Flist (3, result);
+ return list3 (make_number ((EMACS_SECS (t) >> 16) & 0xffff),
+ make_number ((EMACS_SECS (t) >> 0) & 0xffff),
+ make_number (EMACS_USECS (t)));
}
DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time,
least significant 16 bits. The third integer gives the microsecond
count.
-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. */)
+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. */)
()
{
#ifdef HAVE_GETRUSAGE
struct rusage usage;
- Lisp_Object result[3];
int secs, usecs;
if (getrusage (RUSAGE_SELF, &usage) < 0)
/* This shouldn't happen. What action is appropriate? */
- Fsignal (Qerror, Qnil);
+ xsignal0 (Qerror);
/* Sum up user time and system time. */
secs = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
secs++;
}
- XSETINT (result[0], (secs >> 16) & 0xffff);
- XSETINT (result[1], (secs >> 0) & 0xffff);
- XSETINT (result[2], usecs);
-
- return Flist (3, result);
-#else
+ return list3 (make_number ((secs >> 16) & 0xffff),
+ make_number ((secs >> 0) & 0xffff),
+ make_number (usecs));
+#else /* ! HAVE_GETRUSAGE */
+#if WINDOWSNT
+ return w32_get_internal_run_time ();
+#else /* ! WINDOWSNT */
return Fcurrent_time ();
-#endif
+#endif /* WINDOWSNT */
+#endif /* HAVE_GETRUSAGE */
}
\f
/* This is probably enough. */
size = SBYTES (format_string) * 6 + 50;
+ BLOCK_INPUT;
tm = ut ? gmtime (&value) : localtime (&value);
+ UNBLOCK_INPUT;
if (! tm)
error ("Specified time is not representable");
int result;
buf[0] = '\1';
+ BLOCK_INPUT;
result = emacs_memftimeu (buf, size, SDATA (format_string),
SBYTES (format_string),
tm, ut);
+ UNBLOCK_INPUT;
if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0'))
- return code_convert_string_norecord (make_string (buf, result),
+ return code_convert_string_norecord (make_unibyte_string (buf, result),
Vlocale_coding_system, 0);
/* If buffer was too small, make it bigger and try again. */
+ BLOCK_INPUT;
result = emacs_memftimeu (NULL, (size_t) -1,
SDATA (format_string),
SBYTES (format_string),
tm, ut);
+ UNBLOCK_INPUT;
size = result + 1;
}
}
DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 1, 0,
doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST ZONE).
The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED),
-as from `current-time' and `file-attributes', or `nil' to use the
+as from `current-time' and `file-attributes', or nil to use the
current time. The obsolete form (HIGH . LOW) is also still accepted.
The list has the following nine members: SEC is an integer between 0
and 60; SEC is 60 for a leap second, which only some operating systems
between 0 and 23. DAY is an integer between 1 and 31. MONTH is an
integer between 1 and 12. YEAR is an integer indicating the
four-digit year. DOW is the day of week, an integer between 0 and 6,
-where 0 is Sunday. DST is t if daylight savings time is effect,
+where 0 is Sunday. DST is t if daylight saving time is in effect,
otherwise nil. ZONE is an integer indicating the number of seconds
east of Greenwich. (Note that Common Lisp has different meanings for
DOW and ZONE.) */)
if (! lisp_time_argument (specified_time, &time_spec, NULL))
error ("Invalid time specification");
+ BLOCK_INPUT;
decoded_time = localtime (&time_spec);
+ UNBLOCK_INPUT;
if (! decoded_time)
error ("Specified time is not representable");
XSETFASTINT (list_args[0], decoded_time->tm_sec);
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);
- XSETINT (list_args[5], decoded_time->tm_year + 1900);
+ /* 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;
/* 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
ZONE defaults to the current time zone rule. This can
be a string or t (as from `set-time-zone-rule'), or it can be a list
\(as from `current-time-zone') or an integer (as from `decode-time')
-applied without consideration for daylight savings time.
+applied without consideration for daylight saving time.
You can pass more than 7 arguments; then the first six arguments
are used as SECOND through YEAR, and the *last* argument is used as ZONE.
tm.tm_hour = XINT (args[2]);
tm.tm_mday = XINT (args[3]);
tm.tm_mon = XINT (args[4]) - 1;
- tm.tm_year = XINT (args[5]) - 1900;
+ tm.tm_year = XINT (args[5]) - TM_YEAR_BASE;
tm.tm_isdst = -1;
if (CONSP (zone))
zone = Fcar (zone);
if (NILP (zone))
- time = mktime (&tm);
+ {
+ BLOCK_INPUT;
+ time = mktime (&tm);
+ UNBLOCK_INPUT;
+ }
else
{
char tzbuf[100];
value doesn't suffice, since that would mishandle leap seconds. */
set_time_zone_rule (tzstring);
+ BLOCK_INPUT;
time = mktime (&tm);
+ UNBLOCK_INPUT;
/* Restore TZ to previous value. */
newenv = environ;
DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0, 1, 0,
doc: /* Return the current time, as a human-readable string.
Programs can use this function to decode a time,
-since the number of columns in each field is fixed.
+since the number of columns in each field is fixed
+if the year is in the range 1000-9999.
The format is `Sun Sep 16 01:03:52 1973'.
However, see also the functions `decode-time' and `format-time-string'
which provide a much more powerful and general facility.
Lisp_Object specified_time;
{
time_t value;
- char buf[30];
+ struct tm *tm;
register char *tem;
if (! lisp_time_argument (specified_time, &value, NULL))
- value = -1;
- tem = (char *) ctime (&value);
+ error ("Invalid time specification");
- strncpy (buf, tem, 24);
- buf[24] = 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. */
+ BLOCK_INPUT;
+ tm = localtime (&value);
+ UNBLOCK_INPUT;
+ if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime (tm))))
+ error ("Specified time is not representable");
- return build_string (buf);
-}
+ /* Remove the trailing newline. */
+ tem[strlen (tem) - 1] = '\0';
-#define TM_YEAR_BASE 1900
+ return build_string (tem);
+}
/* Yield A - B, measured in seconds.
This function is copied from the GNU C Library. */
struct tm *t;
struct tm gmt;
- if (lisp_time_argument (specified_time, &value, NULL)
- && (t = gmtime (&value)) != 0
- && (gmt = *t, t = localtime (&value)) != 0)
+ if (!lisp_time_argument (specified_time, &value, NULL))
+ t = NULL;
+ else
+ {
+ BLOCK_INPUT;
+ t = gmtime (&value);
+ if (t)
+ {
+ gmt = *t;
+ t = localtime (&value);
+ }
+ UNBLOCK_INPUT;
+ }
+
+ if (t)
{
int offset = tm_diff (t, &gmt);
char *s = 0;
char buf[6];
+
#ifdef HAVE_TM_ZONE
if (t->tm_zone)
s = (char *)t->tm_zone;
#endif
#endif /* not HAVE_TM_ZONE */
-#if defined HAVE_TM_ZONE || defined HAVE_TZNAME
- if (s)
- {
- /* On Japanese w32, we can get a Japanese string as time
- zone name. Don't accept that. */
- char *p;
- for (p = s; *p && (isalnum ((unsigned char)*p) || *p == ' '); ++p)
- ;
- if (p == s || *p)
- s = NULL;
- }
-#endif
-
if (!s)
{
/* No local time zone name is available; use "+-NNNN" instead. */
sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60);
s = buf;
}
+
return Fcons (make_number (offset), Fcons (build_string (s), Qnil));
}
else
for (argnum = 0; argnum < nargs; argnum++)
{
val = args[argnum];
- retry:
if (INTEGERP (val))
{
unsigned char str[MAX_MULTIBYTE_LENGTH];
inherit);
}
else
- {
- val = wrong_type_argument (Qchar_or_string_p, val);
- goto retry;
- }
+ wrong_type_argument (Qchar_or_string_p, val);
}
}
}
\f
DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0,
- doc: /* Insert COUNT (second arg) copies of CHARACTER (first arg).
-Both arguments are required.
+ 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. */)
{
register int begp1, endp1, begp2, endp2, temp;
register struct buffer *bp1, *bp2;
- register Lisp_Object *trt
+ register Lisp_Object trt
= (!NILP (current_buffer->case_fold_search)
- ? XCHAR_TABLE (current_buffer->case_canon_table)->contents : 0);
+ ? current_buffer->case_canon_table : Qnil);
int chars = 0;
int i1, i2, i1_byte, i2_byte;
i2++;
}
- if (trt)
+ if (!NILP (trt))
{
- c1 = XINT (trt[c1]);
- c2 = XINT (trt[c2]);
+ c1 = CHAR_TABLE_TRANSLATE (trt, c1);
+ c2 = CHAR_TABLE_TRANSLATE (trt, c2);
}
if (c1 < c2)
return make_number (- 1 - chars);
Lisp_Object start, end, fromchar, tochar, noundo;
{
register int pos, pos_byte, stop, i, len, end_byte;
+ /* Keep track of the first change in the buffer:
+ if 0 we haven't found it yet.
+ if < 0 we've found it and we've run the before-change-function.
+ if > 0 we've actually performed it and the value is its position. */
int changed = 0;
unsigned char fromstr[MAX_MULTIBYTE_LENGTH], tostr[MAX_MULTIBYTE_LENGTH];
unsigned char *p;
int last_changed = 0;
int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
+ restart:
+
validate_region (&start, &end);
CHECK_NUMBER (fromchar);
CHECK_NUMBER (tochar);
{
len = CHAR_STRING (XFASTINT (fromchar), fromstr);
if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
- error ("Characters in subst-char-in-region have different byte-lengths");
+ error ("Characters in `subst-char-in-region' have different byte-lengths");
if (!ASCII_BYTE_P (*tostr))
{
/* If *TOSTR is in the range 0x80..0x9F and TOCHAR is not a
That's faster than getting rid of things,
and it prevents even the entry for a first change.
Also inhibit locking the file. */
- if (!NILP (noundo))
+ if (!changed && !NILP (noundo))
{
record_unwind_protect (subst_char_in_region_unwind,
current_buffer->undo_list);
&& (len == 2 || (p[2] == fromstr[2]
&& (len == 3 || p[3] == fromstr[3]))))))
{
- if (! changed)
+ if (changed < 0)
+ /* We've already seen this and run the before-change-function;
+ this time we only need to record the actual position. */
+ changed = pos;
+ else if (!changed)
{
- changed = pos;
- modify_region (current_buffer, changed, XINT (end));
+ changed = -1;
+ modify_region (current_buffer, pos, XINT (end), 0);
if (! NILP (noundo))
{
if (MODIFF - 1 == current_buffer->auto_save_modified)
current_buffer->auto_save_modified++;
}
+
+ /* The before-change-function may have moved the gap
+ or even modified the buffer so we should start over. */
+ goto restart;
}
/* Take care of the case where the new character
pos++;
}
- if (changed)
+ if (changed > 0)
{
signal_after_change (changed,
last_changed - changed, last_changed - changed);
pos = XINT (start);
pos_byte = CHAR_TO_BYTE (pos);
end_pos = XINT (end);
- modify_region (current_buffer, pos, XINT (end));
+ modify_region (current_buffer, pos, XINT (end), 0);
cnt = 0;
for (; pos < end_pos; )
{
if (tt)
{
+ /* Reload as signal_after_change in last iteration may GC. */
+ tt = SDATA (table);
if (string_multibyte)
{
str = tt + string_char_to_byte (table, oc);
{
validate_region (&start, &end);
if (XINT (start) == XINT (end))
- return build_string ("");
+ return empty_unibyte_string;
return del_range_1 (XINT (start), XINT (end), 1, 1);
}
\f
DEFUN ("save-restriction", Fsave_restriction, Ssave_restriction, 0, UNEVALLED, 0,
doc: /* Execute BODY, saving and restoring current buffer's restrictions.
The buffer's restrictions make parts of the beginning and end invisible.
-(They are set up with `narrow-to-region' and eliminated with `widen'.)
+\(They are set up with `narrow-to-region' and eliminated with `widen'.)
This special form, `save-restriction', saves the current buffer's restrictions
when it is entered, and restores them when it is exited.
So any `narrow-to-region' within BODY lasts only until the end of the form.
static int message_length;
DEFUN ("message", Fmessage, Smessage, 1, MANY, 0,
- doc: /* Print a one-line message at the bottom of the screen.
+ doc: /* Display a message at the bottom of the screen.
The message also goes into the `*Messages*' buffer.
\(In keyboard macros, that's all it does.)
+Return the message.
The first argument is a format control string, and the rest are data
to be formatted under control of the string. See `format' for details.
-If the first argument is nil, the function clears any existing message;
-this lets the minibuffer contents show. See also `current-message'.
+Note: Use (message "%s" VALUE) to print the value of expressions and
+variables to avoid accidentally interpreting `%' as format specifiers.
-usage: (message STRING &rest ARGS) */)
+If the first argument is nil or the empty string, the function clears
+any existing message; this lets the minibuffer contents show. See
+also `current-message'.
+
+usage: (message FORMAT-STRING &rest ARGS) */)
(nargs, args)
int nargs;
Lisp_Object *args;
&& SBYTES (args[0]) == 0))
{
message (0);
- return Qnil;
+ return args[0];
}
else
{
The first argument is a format control string, and the rest are data
to be formatted under control of the string. See `format' for details.
-If the first argument is nil, clear any existing message; let the
-minibuffer contents show.
+If the first argument is nil or the empty string, clear any existing
+message; let the minibuffer contents show.
-usage: (message-box STRING &rest ARGS) */)
+usage: (message-box FORMAT-STRING &rest ARGS) */)
(nargs, args)
int nargs;
Lisp_Object *args;
pane = Fcons (Fcons (build_string ("OK"), Qt), Qnil);
GCPRO1 (pane);
menu = Fcons (val, pane);
- obj = Fx_popup_dialog (Qt, menu);
+ obj = Fx_popup_dialog (Qt, menu, Qt);
UNGCPRO;
return val;
}
The first argument is a format control string, and the rest are data
to be formatted under control of the string. See `format' for details.
-If the first argument is nil, clear any existing message; let the
-minibuffer contents show.
+If the first argument is nil or the empty string, clear any existing
+message; let the minibuffer contents show.
-usage: (message-or-box STRING &rest ARGS) */)
+usage: (message-or-box FORMAT-STRING &rest ARGS) */)
(nargs, args)
int nargs;
Lisp_Object *args;
string = Fcopy_sequence (args[0]);
for (i = 1; i < nargs; i += 2)
- {
- CHECK_SYMBOL (args[i]);
- properties = Fcons (args[i], Fcons (args[i + 1], properties));
- }
+ properties = Fcons (args[i], Fcons (args[i + 1], properties));
Fadd_text_properties (make_number (0),
make_number (SCHARS (string)),
: SBYTES (STRING))
DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
- doc: /* Format a string out of a control-string and arguments.
-The first argument is a control string.
+ doc: /* Format a string out of a format-string and arguments.
+The first argument is a format control string.
The other arguments are substituted into it to make the result, a string.
It may contain %-sequences meaning to substitute the next argument.
%s means print a string argument. Actually, prints any object, with `princ'.
The basic structure of a %-sequence is
% <flags> <width> <precision> character
-where flags is [- #0]+, width is [0-9]+, and precision is .[0-9]+
+where flags is [-+ #0]+, width is [0-9]+, and precision is .[0-9]+
usage: (format STRING &rest OBJECTS) */)
(nargs, args)
where
- flags ::= [- #0]+
+ flags ::= [-+ #0]+
field-width ::= [0-9]+
precision ::= '.' [0-9]*
digits to print after the '.' for floats, or the max.
number of chars to print from a string. */
- while (index ("-0# ", *format))
+ while (format != end
+ && (*format == '-' || *format == '0' || *format == '#'
+ || * format == ' ' || *format == '+'))
++format;
if (*format >= '0' && *format <= '9')
if (*format != 'd' && *format != 'o' && *format != 'x'
&& *format != 'i' && *format != 'X' && *format != 'c')
error ("Invalid format operation %%%c", *format);
- args[n] = Ftruncate (args[n], Qnil);
+ /* This fails unnecessarily if args[n] is bigger than
+ most-positive-fixnum but smaller than MAXINT.
+ These cases are important because we sometimes use floats
+ to represent such integer values (typically such values
+ come from UIDs or PIDs). */
+ /* args[n] = Ftruncate (args[n], Qnil); */
}
/* Note that we're using sprintf to print floats,
discarded[format - format_start] = 1;
format++;
- while (index("-0# ", *format))
+ while (index("-+0# ", *format))
{
if (*format == '-')
{
++nchars;
}
- start = nchars;
+ info[n].start = start = nchars;
nchars += nchars_string;
end = nchars;
nbytes,
STRING_MULTIBYTE (args[n]), multibyte);
+ info[n].end = nchars;
+
if (negative)
while (padding-- > 0)
{
this_format[format - this_format_start] = 0;
if (INTEGERP (args[n]))
- sprintf (p, this_format, XINT (args[n]));
- else
+ {
+ if (format[-1] == 'd')
+ sprintf (p, this_format, XINT (args[n]));
+ /* Don't sign-extend for octal or hex printing. */
+ else
+ sprintf (p, this_format, XUINT (args[n]));
+ }
+ else if (format[-1] == 'e' || format[-1] == 'f' || format[-1] == 'g')
sprintf (p, this_format, XFLOAT_DATA (args[n]));
+ else if (format[-1] == 'd')
+ /* Maybe we should use "%1.0f" instead so it also works
+ for values larger than MAXINT. */
+ sprintf (p, this_format, (EMACS_INT) XFLOAT_DATA (args[n]));
+ else
+ /* Don't sign-extend for octal or hex printing. */
+ sprintf (p, this_format, (EMACS_UINT) XFLOAT_DATA (args[n]));
if (p > buf
&& multibyte
else
p += this_nchars;
nchars += this_nchars;
+ info[n].end = nchars;
}
- info[n].end = nchars;
}
else if (STRING_MULTIBYTE (args[0]))
{
/* Likewise adjust the property end position. */
pos = XINT (XCAR (XCDR (item)));
- for (; bytepos < pos; bytepos++)
+ for (; position < pos; bytepos++)
{
if (! discarded[bytepos])
position++, translated++;
int gap, len1, len_mid, len2;
unsigned char *start1_addr, *start2_addr, *temp;
- INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2;
+ INTERVAL cur_intv, tmp_interval1, tmp_interval_mid, tmp_interval2, tmp_interval3;
+ Lisp_Object buf;
+
+ XSETBUFFER (buf, current_buffer);
cur_intv = BUF_INTERVALS (current_buffer);
validate_region (&startr1, &endr1);
if (end1 == start2) /* adjacent regions */
{
- modify_region (current_buffer, start1, end2);
+ modify_region (current_buffer, start1, end2, 0);
record_change (start1, len1 + len2);
tmp_interval1 = copy_intervals (cur_intv, start1, len1);
tmp_interval2 = copy_intervals (cur_intv, start2, len2);
- Fset_text_properties (make_number (start1), make_number (end2),
- Qnil, Qnil);
+ /* 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))
+ set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
/* First region smaller than second. */
if (len1_byte < len2_byte)
{
USE_SAFE_ALLOCA;
- modify_region (current_buffer, start1, end1);
- modify_region (current_buffer, start2, end2);
+ modify_region (current_buffer, start1, end1, 0);
+ modify_region (current_buffer, start2, end2, 0);
record_change (start1, len1);
record_change (start2, len2);
tmp_interval1 = copy_intervals (cur_intv, start1, len1);
tmp_interval2 = copy_intervals (cur_intv, start2, len2);
- Fset_text_properties (make_number (start1), make_number (end1),
- Qnil, Qnil);
- Fset_text_properties (make_number (start2), make_number (end2),
- Qnil, Qnil);
+
+ tmp_interval3 = validate_interval_range (buf, &startr1, &endr1, 0);
+ if (!NULL_INTERVAL_P (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))
+ set_text_properties_1 (startr2, endr2, Qnil, buf, tmp_interval3);
SAFE_ALLOCA (temp, unsigned char *, len1_byte);
start1_addr = BYTE_POS_ADDR (start1_byte);
{
USE_SAFE_ALLOCA;
- modify_region (current_buffer, start1, end2);
+ modify_region (current_buffer, start1, end2, 0);
record_change (start1, (end2 - start1));
tmp_interval1 = copy_intervals (cur_intv, start1, len1);
tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
tmp_interval2 = copy_intervals (cur_intv, start2, len2);
- Fset_text_properties (make_number (start1), make_number (end2),
- Qnil, Qnil);
+
+ tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
+ if (!NULL_INTERVAL_P (tmp_interval3))
+ set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
/* holds region 2 */
SAFE_ALLOCA (temp, unsigned char *, len2_byte);
USE_SAFE_ALLOCA;
record_change (start1, (end2 - start1));
- modify_region (current_buffer, start1, end2);
+ modify_region (current_buffer, start1, end2, 0);
tmp_interval1 = copy_intervals (cur_intv, start1, len1);
tmp_interval_mid = copy_intervals (cur_intv, end1, len_mid);
tmp_interval2 = copy_intervals (cur_intv, start2, len2);
- Fset_text_properties (make_number (start1), make_number (end2),
- Qnil, Qnil);
+
+ tmp_interval3 = validate_interval_range (buf, &startr1, &endr2, 0);
+ if (!NULL_INTERVAL_P (tmp_interval3))
+ set_text_properties_1 (startr1, endr2, Qnil, buf, tmp_interval3);
/* holds region 1 */
SAFE_ALLOCA (temp, unsigned char *, len1_byte);
fix_start_end_in_overlays (start1, end2);
}
+ signal_after_change (start1, end2 - start1, end2 - start1);
return Qnil;
}
Vbuffer_access_fontified_property = Qnil;
DEFVAR_LISP ("system-name", &Vsystem_name,
- doc: /* The name of the machine Emacs is running on. */);
+ doc: /* The host name of the machine Emacs is running on. */);
DEFVAR_LISP ("user-full-name", &Vuser_full_name,
doc: /* The full name of the user logged in. */);
DEFVAR_LISP ("user-real-login-name", &Vuser_real_login_name,
doc: /* The user's name, based upon the real uid only. */);
+ DEFVAR_LISP ("operating-system-release", &Voperating_system_release,
+ doc: /* The release of the operating system Emacs is running on. */);
+
defsubr (&Spropertize);
defsubr (&Schar_equal);
defsubr (&Sgoto_char);