CHECK_STRING (string, 0);
p = XSTRING (string);
if (p->size)
- XSETFASTINT (val, STRING_CHAR (p->data, STRING_BYTES (p)));
+ {
+ if (STRING_MULTIBYTE (string))
+ XSETFASTINT (val, STRING_CHAR (p->data, STRING_BYTES (p)));
+ else
+ XSETFASTINT (val, p->data[0]);
+ }
else
XSETFASTINT (val, 0);
return val;
if (NILP (pos))
{
pos_byte = PT_BYTE;
- pos = PT;
+ XSETFASTINT (pos, PT);
}
if (MARKERP (pos))
if (NILP (pos))
{
pos_byte = PT_BYTE;
- pos = PT;
+ XSETFASTINT (pos, PT);
}
if (MARKERP (pos))
DEFUN ("user-full-name", Fuser_full_name, Suser_full_name, 0, 1, 0,
"Return the full name of the user logged in, as a string.\n\
+If the full name corresponding to Emacs's userid is not known,\n\
+return \"unknown\".\n\
+\n\
If optional argument UID is an integer, return the full name of the user\n\
-with that uid, or \"unknown\" if there is no such user.\n\
+with that uid, or nil if there is no such user.\n\
If UID is a string, return the full name of the user with that login\n\
-name, or \"unknown\" if no such user could be found.")
+name, or nil if there is no such user.")
(uid)
Lisp_Object uid;
{
}
}
+/* Write information into buffer S of size MAXSIZE, according to the
+ FORMAT of length FORMAT_LEN, using time information taken from *TP.
+ Return the number of bytes written, not including the terminating
+ '\0'. If S is NULL, nothing will be written anywhere; so to
+ determine how many bytes would be written, use NULL for S and
+ ((size_t) -1) for MAXSIZE.
+
+ This function behaves like emacs_strftime, except it allows null
+ bytes in FORMAT. */
+static size_t
+emacs_memftime (s, maxsize, format, format_len, tp)
+ char *s;
+ size_t maxsize;
+ const char *format;
+ size_t format_len;
+ const struct tm *tp;
+{
+ size_t total = 0;
+
+ /* Loop through all the null-terminated strings in the format
+ argument. Normally there's just one null-terminated string, but
+ there can be arbitrarily many, concatenated together, if the
+ format contains '\0' bytes. emacs_strftime stops at the first
+ '\0' byte so we must invoke it separately for each such string. */
+ for (;;)
+ {
+ size_t len;
+ size_t result;
+
+ if (s)
+ s[0] = '\1';
+
+ result = emacs_strftime (s, maxsize, format, tp);
+
+ if (s)
+ {
+ if (result == 0 && s[0] != '\0')
+ return 0;
+ s += result + 1;
+ }
+
+ maxsize -= result + 1;
+ total += result;
+ len = strlen (format);
+ if (len == format_len)
+ return total;
+ total++;
+ format += len + 1;
+ format_len -= len + 1;
+ }
+}
+
/*
DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
"Use FORMAT-STRING to format the time TIME, or now if omitted.\n\
int result;
buf[0] = '\1';
- result = emacs_strftime (buf, size, XSTRING (format_string)->data,
+ result = emacs_memftime (buf, size, XSTRING (format_string)->data,
+ STRING_BYTES (XSTRING (format_string)),
tm);
if ((result > 0 && result < size) || (result == 0 && buf[0] == '\0'))
- return build_string (buf);
+ return make_string (buf, result);
/* If buffer was too small, make it bigger and try again. */
- result = emacs_strftime (NULL, 0x7fffffff, XSTRING (format_string)->data,
+ result = emacs_memftime (NULL, (size_t) -1,
+ XSTRING (format_string)->data,
+ STRING_BYTES (XSTRING (format_string)),
tm);
size = result + 1;
}
{
Lisp_Object result, tem, tem1;
+ if (INTEGERP (current_buffer->minibuffer_prompt_length))
+ {
+ int len = XFASTINT (current_buffer->minibuffer_prompt_length);
+ start = min (end, max (len, start));
+ start_byte = CHAR_TO_BYTE (start);
+ }
+
if (start < GPT && GPT < end)
move_gap (start);
int changed = 0;
unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p;
int count = specpdl_ptr - specpdl;
+#define COMBINING_NO 0
+#define COMBINING_BEFORE 1
+#define COMBINING_AFTER 2
+#define COMBINING_BOTH (COMBINING_BEFORE | COMBINING_AFTER)
+ int maybe_byte_combining = COMBINING_NO;
validate_region (&start, &end);
CHECK_NUMBER (fromchar, 2);
len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr);
if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len)
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
+ complete multibyte character, it may be combined with the
+ after bytes. If it is in the range 0xA0..0xFF, it may be
+ combined with the before and after bytes. */
+ if (!CHAR_HEAD_P (*tostr))
+ maybe_byte_combining = COMBINING_BOTH;
+ else if (BYTES_BY_CHAR_HEAD (*tostr) > len)
+ maybe_byte_combining = COMBINING_AFTER;
+ }
}
else
{
stop = min (stop, GPT_BYTE);
while (1)
{
+ int pos_byte_next = pos_byte;
+
if (pos_byte >= stop)
{
if (pos_byte >= end_byte) break;
stop = end_byte;
}
p = BYTE_POS_ADDR (pos_byte);
- if (p[0] == fromstr[0]
+ INC_POS (pos_byte_next);
+ if (pos_byte_next - pos_byte == len
+ && p[0] == fromstr[0]
&& (len == 1
|| (p[1] == fromstr[1]
&& (len == 2 || (p[2] == fromstr[2]
/* Take care of the case where the new character
combines with neighboring bytes. */
- if (len == 1
- && ((! CHAR_HEAD_P (tostr[0])
- && pos_byte > BEGV_BYTE
- && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))
- ||
- (! ASCII_BYTE_P (tostr[0])
- && pos_byte + 1 < ZV_BYTE
- && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1)))))
+ if (maybe_byte_combining
+ && (maybe_byte_combining == COMBINING_AFTER
+ ? (pos_byte_next < Z_BYTE
+ && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte_next)))
+ : ((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))))))
{
Lisp_Object tem, string;
tem = current_buffer->undo_list;
GCPRO1 (tem);
- /* Make a multibyte string containing this
- single-byte character. */
- string = Fmake_string (make_number (1),
- make_number (tochar));
- SET_STRING_BYTES (XSTRING (string), 1);
+ /* Make a multibyte string containing this single character. */
+ string = make_multibyte_string (tostr, 1, len);
/* replace_range is less efficient, because it moves the gap,
but it handles combining correctly. */
replace_range (pos, pos + 1, string,
- 0, 0, 0);
+ 0, 0, 1);
+ pos_byte_next = CHAR_TO_BYTE (pos);
+ if (pos_byte_next > pos_byte)
+ /* Before combining happened. We should not increment
+ POS. So, to cancel the later increment of POS,
+ decrease it now. */
+ pos--;
+ else
+ INC_POS (pos_byte_next);
+
if (! NILP (noundo))
current_buffer->undo_list = tem;
for (i = 0; i < len; i++) *p++ = tostr[i];
}
}
- INC_BOTH (pos, pos_byte);
+ pos_byte = pos_byte_next;
+ pos++;
}
if (changed)
register unsigned char *p = BYTE_POS_ADDR (pos_byte);
int len;
int oc;
+ int pos_byte_next;
oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
+ pos_byte_next = pos_byte + len;
if (oc < size && len == 1)
{
nc = tt[oc];
{
/* Take care of the case where the new character
combines with neighboring bytes. */
- if ((! CHAR_HEAD_P (nc)
- && pos_byte > BEGV_BYTE
- && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))
- ||
- (! ASCII_BYTE_P (nc)
- && pos_byte + 1 < ZV_BYTE
- && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))))
+ if (!ASCII_BYTE_P (nc)
+ && (CHAR_HEAD_P (nc)
+ ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
+ : (pos_byte > BEG_BYTE
+ && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))
{
Lisp_Object string;
- string = Fmake_string (make_number (1),
- make_number (nc));
- SET_STRING_BYTES (XSTRING (string), 1);
-
+ string = make_multibyte_string (tt + oc, 1, 1);
/* This is less efficient, because it moves the gap,
but it handles combining correctly. */
replace_range (pos, pos + 1, string,
- 1, 0, 0);
+ 1, 0, 1);
+ pos_byte_next = CHAR_TO_BYTE (pos);
+ if (pos_byte_next > pos_byte)
+ /* Before combining happened. We should not
+ increment POS. So, to cancel the later
+ increment of POS, we decrease it now. */
+ pos--;
+ else
+ INC_POS (pos_byte_next);
}
else
{
++cnt;
}
}
- pos_byte += len;
+ pos_byte = pos_byte_next;
pos++;
}
\n\
`save-restriction' can get confused if, within the BODY, you widen\n\
and then make changes outside the area within the saved restrictions.\n\
+See Info node `(elisp)Narrowing' for details and an appropriate technique.\n\
\n\
Note: if you are using both `save-excursion' and `save-restriction',\n\
use `save-excursion' outermost:\n\
{
register Lisp_Object val;
val = Fformat (nargs, args);
- /* Copy the data so that it won't move when we GC. */
- if (! message_text)
- {
- message_text = (char *)xmalloc (80);
- message_length = 80;
- }
- if (STRING_BYTES (XSTRING (val)) > message_length)
- {
- message_length = STRING_BYTES (XSTRING (val));
- message_text = (char *)xrealloc (message_text, message_length);
- }
- bcopy (XSTRING (val)->data, message_text, STRING_BYTES (XSTRING (val)));
- message2 (message_text, STRING_BYTES (XSTRING (val)),
- STRING_MULTIBYTE (val));
+ message3 (val, STRING_BYTES (XSTRING (val)), STRING_MULTIBYTE (val));
return val;
}
}
"Return the string currently displayed in the echo area, or nil if none.")
()
{
- return (echo_area_glyphs
- ? make_string (echo_area_glyphs, echo_area_glyphs_length)
- : Qnil);
+ return current_message ();
}
/* Number of bytes that STRING will occupy when put into the result.
%g means print a number in exponential notation\n\
or decimal-point notation, whichever uses fewer characters.\n\
%c means print a number as a single character.\n\
-%S means print any object as an s-expression (using prin1).\n\
+%S means print any object as an s-expression (using `prin1').\n\
The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.\n\
Use %% to put a single % into the output.")
(nargs, args)
unsigned char *this_format;
int longest_format;
Lisp_Object val;
+ struct info
+ {
+ int start, end;
+ } *info = 0;
extern char *index ();
be a double. */
if (*format == 'e' || *format == 'f' || *format == 'g')
args[n] = Ffloat (args[n]);
+ else
#endif
+ if (*format != 'd' && *format != 'o' && *format != 'x'
+ && *format != 'i' && *format != 'X' && *format != 'c')
+ error ("Invalid format operation %%%c", *format);
+
thissize = 30;
if (*format == 'c'
&& (! SINGLE_BYTE_CHAR_P (XINT (args[n]))
{
if (! (*format == 'e' || *format == 'f' || *format == 'g'))
args[n] = Ftruncate (args[n], Qnil);
- thissize = 60;
+ thissize = 200;
}
#endif
else
int padding, nbytes;
int width = strwidth (XSTRING (args[n])->data,
STRING_BYTES (XSTRING (args[n])));
+ int start = nchars;
/* If spec requires it, pad on right with spaces. */
padding = minlen - width;
*p++ = ' ';
nchars++;
}
+
+ /* If this argument has text properties, record where
+ in the result string it appears. */
+ if (XSTRING (args[n])->intervals)
+ {
+ if (!info)
+ {
+ int nbytes = nargs * sizeof *info;
+ info = (struct info *) alloca (nbytes);
+ bzero (info, nbytes);
+ }
+
+ info[n].start = start;
+ info[n].end = nchars;
+ }
}
else if (INTEGERP (args[n]) || FLOATP (args[n]))
{
if (total >= 1000)
xfree (buf);
+ /* If the format string has text properties, or any of the string
+ arguments has text properties, set up text properties of the
+ result string. */
+
+ if (XSTRING (args[0])->intervals || info)
+ {
+ Lisp_Object len, new_len, props;
+ struct gcpro gcpro1;
+
+ /* Add text properties from the format string. */
+ len = make_number (XSTRING (args[0])->size);
+ props = text_property_list (args[0], make_number (0), len, Qnil);
+ GCPRO1 (props);
+
+ if (CONSP (props))
+ {
+ new_len = make_number (XSTRING (val)->size);
+ extend_property_ranges (props, len, new_len);
+ add_text_properties_from_list (val, props, make_number (0));
+ }
+
+ /* Add text properties from arguments. */
+ if (info)
+ for (n = 1; n < nargs; ++n)
+ if (info[n].end)
+ {
+ len = make_number (XSTRING (args[n])->size);
+ new_len = make_number (info[n].end - info[n].start);
+ props = text_property_list (args[n], make_number (0), len, Qnil);
+ extend_property_ranges (props, len, new_len);
+ add_text_properties_from_list (val, props,
+ make_number (info[n].start));
+ }
+
+ UNGCPRO;
+ }
+
return val;
}