/* Lisp functions pertaining to editing.
- Copyright (C) 1985,86,87,89,93,94,95,96,97,98, 1999, 2000, 2001, 2002
+ Copyright (C) 1985,86,87,89,93,94,95,96,97,98, 1999, 2000, 2001, 02, 2003
Free Software Foundation, Inc.
This file is part of GNU Emacs.
Lisp_Object position, object;
register Lisp_Object prop;
{
- struct window *w = 0;
-
CHECK_NUMBER_COERCE_MARKER (position);
if (NILP (object))
XSETBUFFER (object, current_buffer);
-
- if (WINDOWP (object))
- {
- w = XWINDOW (object);
- object = w->buffer;
- }
- if (BUFFERP (object))
+ else if (WINDOWP (object))
+ object = XWINDOW (object)->buffer;
+
+ if (!BUFFERP (object))
+ /* pos-property only makes sense in buffers right now, since strings
+ have no overlays and no notion of insertion for which stickiness
+ could be obeyed. */
+ return Fget_text_property (position, prop, object);
+ else
{
int posn = XINT (position);
int noverlays;
}
}
+ { /* Now check the text-properties. */
+ int stickiness = text_property_stickiness (prop, position, object);
+ if (stickiness > 0)
+ return Fget_text_property (position, prop, object);
+ else if (stickiness < 0
+ && XINT (position) > BUF_BEGV (XBUFFER (object)))
+ return Fget_text_property (make_number (XINT (position) - 1),
+ prop, object);
+ else
+ return Qnil;
+ }
}
-
- { /* Now check the text-properties. */
- int stickiness = text_property_stickiness (prop, position);
- if (stickiness > 0)
- return Fget_text_property (position, prop, Qnil);
- else if (stickiness < 0 && XINT (position) > BEGV)
- return Fget_text_property (make_number (XINT (position) - 1),
- prop, Qnil);
- else
- return Qnil;
- }
}
/* Find the field surrounding POS in *BEG and *END. If POS is nil,
register int n; /* The number of the next arg to substitute */
register int total; /* An estimate of the final length */
char *buf, *p;
- register unsigned char *format, *end;
+ register unsigned char *format, *end, *format_start;
int nchars;
/* Nonzero if the output should be a multibyte string,
which is true if any of the inputs is one. */
int *precision = (int *) (alloca(nargs * sizeof (int)));
int longest_format;
Lisp_Object val;
+ int arg_intervals = 0;
+
+ /* discarded[I] is 1 if byte I of the format
+ string was not copied into the output.
+ It is 2 if byte I was not the first byte of its character. */
+ char *discarded;
+
+ /* Each element records, for one argument,
+ the start and end bytepos in the output string,
+ and whether the argument is a string with intervals.
+ info[0] is unused. Unused elements have -1 for start. */
struct info
{
- int start, end;
+ int start, end, intervals;
} *info = 0;
/* It should not be necessary to GCPRO ARGS, because
This is not always right; sometimes the result needs to be multibyte
because of an object that we will pass through prin1,
and in that case, we won't know it here. */
- for (n = 0; n < nargs; n++) {
- if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
- multibyte = 1;
- /* Piggyback on this loop to initialize precision[N]. */
- precision[n] = -1;
- }
+ for (n = 0; n < nargs; n++)
+ {
+ if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
+ multibyte = 1;
+ /* Piggyback on this loop to initialize precision[N]. */
+ precision[n] = -1;
+ }
CHECK_STRING (args[0]);
/* We may have to change "%S" to "%s". */
args[0] = Fcopy_sequence (args[0]);
+ /* GC should never happen here, so abort if it does. */
+ abort_on_gc++;
+
/* If we start out planning a unibyte result,
- and later find it has to be multibyte, we jump back to retry. */
+ then discover it has to be multibyte, we jump back to retry.
+ That can only happen from the first large while loop below. */
retry:
format = SDATA (args[0]);
+ format_start = format;
end = format + SBYTES (args[0]);
longest_format = 0;
/* Make room in result for all the non-%-codes in the control string. */
total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]);
+ /* Allocate the info and discarded tables. */
+ {
+ int nbytes = nargs * sizeof *info;
+ int i;
+ info = (struct info *) alloca (nbytes);
+ bzero (info, nbytes);
+ for (i = 0; i <= nargs; i++)
+ info[i].start = -1;
+ discarded = (char *) alloca (SBYTES (args[0]));
+ bzero (discarded, SBYTES (args[0]));
+ }
+
/* Add to TOTAL enough space to hold the converted arguments. */
n = 0;
total += thissize + 4;
}
+ abort_on_gc--;
+
/* Now we can no longer jump to retry.
TOTAL and LONGEST_FORMAT are known for certain. */
/* Scan the format and store result in BUF. */
format = SDATA (args[0]);
+ format_start = format;
+ end = format + SBYTES (args[0]);
maybe_combine_byte = 0;
while (format != end)
{
int negative = 0;
unsigned char *this_format_start = format;
+ discarded[format - format_start] = 1;
format++;
/* Process a numeric arg and skip it. */
fixed. */
while ((*format >= '0' && *format <= '9')
|| *format == '-' || *format == ' ' || *format == '.')
- format++;
+ {
+ discarded[format - format_start] = 1;
+ format++;
+ }
if (*format++ == '%')
{
++n;
+ discarded[format - format_start - 1] = 1;
+ info[n].start = nchars;
+
if (STRINGP (args[n]))
{
/* handle case (precision[n] >= 0) */
/* If this argument has text properties, record where
in the result string it appears. */
if (STRING_INTERVALS (args[n]))
- {
- if (!info)
- {
- int nbytes = nargs * sizeof *info;
- info = (struct info *) alloca (nbytes);
- bzero (info, nbytes);
- }
-
- info[n].start = start;
- info[n].end = end;
- }
+ info[n].intervals = arg_intervals = 1;
}
else if (INTEGERP (args[n]) || FLOATP (args[n]))
{
p += this_nchars;
nchars += this_nchars;
}
+
+ info[n].end = nchars;
}
else if (STRING_MULTIBYTE (args[0]))
{
&& !CHAR_HEAD_P (*format))
maybe_combine_byte = 1;
*p++ = *format++;
- while (! CHAR_HEAD_P (*format)) *p++ = *format++;
+ while (! CHAR_HEAD_P (*format))
+ {
+ discarded[format - format_start] = 2;
+ *p++ = *format++;
+ }
nchars++;
}
else if (multibyte)
arguments has text properties, set up text properties of the
result string. */
- if (STRING_INTERVALS (args[0]) || info)
+ if (STRING_INTERVALS (args[0]) || arg_intervals)
{
Lisp_Object len, new_len, props;
struct gcpro gcpro1;
if (CONSP (props))
{
- new_len = make_number (SCHARS (val));
- extend_property_ranges (props, len, new_len);
+ int bytepos = 0, position = 0, translated = 0, argn = 1;
+ Lisp_Object list;
+
+ /* Adjust the bounds of each text property
+ to the proper start and end in the output string. */
+ /* We take advantage of the fact that the positions in PROPS
+ are in increasing order, so that we can do (effectively)
+ one scan through the position space of the format string.
+
+ BYTEPOS is the byte position in the format string,
+ POSITION is the untranslated char position in it,
+ TRANSLATED is the translated char position in BUF,
+ and ARGN is the number of the next arg we will come to. */
+ for (list = props; CONSP (list); list = XCDR (list))
+ {
+ Lisp_Object item;
+ int pos;
+
+ item = XCAR (list);
+
+ /* First adjust the property start position. */
+ pos = XINT (XCAR (item));
+
+ /* Advance BYTEPOS, POSITION, TRANSLATED and ARGN
+ up to this position. */
+ for (; position < pos; bytepos++)
+ {
+ if (! discarded[bytepos])
+ position++, translated++;
+ else if (discarded[bytepos] == 1)
+ {
+ position++;
+ if (translated == info[argn].start)
+ {
+ translated += info[argn].end - info[argn].start;
+ argn++;
+ }
+ }
+ }
+
+ XSETCAR (item, make_number (translated));
+
+ /* Likewise adjust the property end position. */
+ pos = XINT (XCAR (XCDR (item)));
+
+ for (; bytepos < pos; bytepos++)
+ {
+ if (! discarded[bytepos])
+ position++, translated++;
+ else if (discarded[bytepos] == 1)
+ {
+ position++;
+ if (translated == info[argn].start)
+ {
+ translated += info[argn].end - info[argn].start;
+ argn++;
+ }
+ }
+ }
+
+ XSETCAR (XCDR (item), make_number (translated));
+ }
+
add_text_properties_from_list (val, props, make_number (0));
}
/* Add text properties from arguments. */
- if (info)
+ if (arg_intervals)
for (n = 1; n < nargs; ++n)
- if (info[n].end)
+ if (info[n].intervals)
{
len = make_number (SCHARS (args[n]));
new_len = make_number (info[n].end - info[n].start);
Lisp_Object arg0, arg1;
{
Lisp_Object args[3];
- int numargs;
args[0] = build_string (string1);
args[1] = arg0;
args[2] = arg1;