summaryrefslogtreecommitdiff
path: root/src/doc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc.c')
-rw-r--r--src/doc.c289
1 files changed, 127 insertions, 162 deletions
diff --git a/src/doc.c b/src/doc.c
index 36d18b99b05..6a78ed657c1 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -339,16 +339,7 @@ string is passed through `substitute-command-keys'. */)
if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
fun = XCDR (fun);
if (SUBRP (fun))
- {
- if (XSUBR (fun)->doc == 0)
- return Qnil;
- /* FIXME: This is not portable, as it assumes that string
- pointers have the top bit clear. */
- else if ((intptr_t) XSUBR (fun)->doc >= 0)
- doc = build_string (XSUBR (fun)->doc);
- else
- doc = make_number ((intptr_t) XSUBR (fun)->doc);
- }
+ doc = make_number (XSUBR (fun)->doc);
else if (COMPILEDP (fun))
{
if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) <= COMPILED_DOC_STRING)
@@ -473,7 +464,7 @@ aren't strings. */)
/* Scanning the DOC files and placing docstring offsets into functions. */
static void
-store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
+store_function_docstring (Lisp_Object obj, EMACS_INT offset)
{
/* Don't use indirect_function here, or defaliases will apply their
docstrings to the base functions (Bug#2603). */
@@ -481,15 +472,10 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
/* The type determines where the docstring is stored. */
- /* Lisp_Subrs have a slot for it. */
- if (SUBRP (fun))
- {
- intptr_t negative_offset = - offset;
- XSUBR (fun)->doc = (char *) negative_offset;
- }
-
/* If it's a lisp form, stick it in the form. */
- else if (CONSP (fun))
+ if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
+ fun = XCDR (fun);
+ if (CONSP (fun))
{
Lisp_Object tem;
@@ -503,10 +489,12 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
correctness is quite delicate. */
XSETCAR (tem, make_number (offset));
}
- else if (EQ (tem, Qmacro))
- store_function_docstring (XCDR (fun), offset);
}
+ /* Lisp_Subrs have a slot for it. */
+ else if (SUBRP (fun))
+ XSUBR (fun)->doc = offset;
+
/* Bytecode objects sometimes have slots for it. */
else if (COMPILEDP (fun))
{
@@ -726,13 +714,13 @@ summary).
Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR
as the keymap for future \\=\\[COMMAND] substrings.
-Each \\=‘ and \\=` is replaced by left quote, and each \\=’ and \\='
+Each grave accent \\=` is replaced by left quote, and each apostrophe \\='
is replaced by right quote. Left and right quote characters are
specified by `text-quoting-style'.
-\\=\\= quotes the following character and is discarded; thus,
-\\=\\=\\=\\= puts \\=\\= into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and
-\\=\\=\\=` puts \\=` into the output.
+\\=\\= quotes the following character and is discarded; thus, \\=\\=\\=\\= puts \\=\\=
+into the output, \\=\\=\\=\\[ puts \\=\\[ into the output, and \\=\\=\\=` puts \\=` into the
+output.
Return the original STRING if no substitutions are made.
Otherwise, return a new string. */)
@@ -750,25 +738,20 @@ Otherwise, return a new string. */)
unsigned char const *start;
ptrdiff_t length, length_byte;
Lisp_Object name;
- bool multibyte, pure_ascii;
ptrdiff_t nchars;
if (NILP (string))
return Qnil;
- CHECK_STRING (string);
- tem = Qnil;
- keymap = Qnil;
- name = Qnil;
+ /* If STRING contains non-ASCII unibyte data, process its
+ properly-encoded multibyte equivalent instead. This simplifies
+ the implementation and is OK since substitute-command-keys is
+ intended for use only on text strings. Keep STRING around, since
+ it will be returned if no changes occur. */
+ Lisp_Object str = Fstring_make_multibyte (string);
enum text_quoting_style quoting_style = text_quoting_style ();
- multibyte = STRING_MULTIBYTE (string);
- /* Pure-ASCII unibyte input strings should produce unibyte strings
- if substitution doesn't yield non-ASCII bytes, otherwise they
- should produce multibyte strings. */
- pure_ascii = SBYTES (string) == count_size_as_multibyte (SDATA (string),
- SCHARS (string));
nchars = 0;
/* KEYMAP is either nil (which means search all the active keymaps)
@@ -777,59 +760,58 @@ Otherwise, return a new string. */)
or from a \\<mapname> construct in STRING itself.. */
keymap = Voverriding_local_map;
- bsize = SBYTES (string);
+ ptrdiff_t strbytes = SBYTES (str);
+ bsize = strbytes;
+
+ /* Fixed-size stack buffer. */
+ char sbuf[MAX_ALLOCA];
- /* Add some room for expansion due to quote replacement. */
- enum { EXTRA_ROOM = 20 };
- if (bsize <= STRING_BYTES_BOUND - EXTRA_ROOM)
- bsize += EXTRA_ROOM;
+ /* Heap-allocated buffer, if any. */
+ char *abuf;
- bufp = buf = xmalloc (bsize);
+ /* Extra room for expansion due to replacing ‘\[]’ with ‘M-x ’. */
+ enum { EXTRA_ROOM = sizeof "M-x " - sizeof "\\[]" };
- strp = SDATA (string);
- while (strp < SDATA (string) + SBYTES (string))
+ ptrdiff_t count = SPECPDL_INDEX ();
+
+ if (bsize <= sizeof sbuf - EXTRA_ROOM)
{
- if (strp[0] == '\\' && strp[1] == '=')
+ abuf = NULL;
+ buf = sbuf;
+ bsize = sizeof sbuf;
+ }
+ else
+ {
+ buf = abuf = xpalloc (NULL, &bsize, EXTRA_ROOM, STRING_BYTES_BOUND, 1);
+ record_unwind_protect_ptr (xfree, abuf);
+ }
+ bufp = buf;
+
+ strp = SDATA (str);
+ while (strp < SDATA (str) + strbytes)
+ {
+ unsigned char *close_bracket;
+
+ if (strp[0] == '\\' && strp[1] == '='
+ && strp + 2 < SDATA (str) + strbytes)
{
/* \= quotes the next character;
thus, to put in \[ without its special meaning, use \=\[. */
changed = nonquotes_changed = true;
strp += 2;
- if (multibyte)
- {
- int len;
-
- STRING_CHAR_AND_LENGTH (strp, len);
- if (len == 1)
- *bufp = *strp;
- else
- memcpy (bufp, strp, len);
- strp += len;
- bufp += len;
- nchars++;
- }
- else
- *bufp++ = *strp++, nchars++;
+ /* Fall through to copy one char. */
}
- else if (strp[0] == '\\' && strp[1] == '[')
+ else if (strp[0] == '\\' && strp[1] == '['
+ && (close_bracket
+ = memchr (strp + 2, ']',
+ SDATA (str) + strbytes - (strp + 2))))
{
- ptrdiff_t start_idx;
bool follow_remap = 1;
- strp += 2; /* skip \[ */
- start = strp;
- start_idx = start - SDATA (string);
-
- while ((strp - SDATA (string)
- < SBYTES (string))
- && *strp != ']')
- strp++;
- length_byte = strp - start;
-
- strp++; /* skip ] */
+ start = strp + 2;
+ length_byte = close_bracket - start;
+ idx = close_bracket + 1 - SDATA (str);
- /* Save STRP in IDX. */
- idx = strp - SDATA (string);
name = Fintern (make_string ((char *) start, length_byte), Qnil);
do_remap:
@@ -844,25 +826,17 @@ Otherwise, return a new string. */)
goto do_remap;
}
- /* Note the Fwhere_is_internal can GC, so we have to take
- relocation of string contents into account. */
- strp = SDATA (string) + idx;
- start = SDATA (string) + start_idx;
+ /* Fwhere_is_internal can GC, so take relocation of string
+ contents into account. */
+ strp = SDATA (str) + idx;
+ start = strp - length_byte - 1;
if (NILP (tem)) /* but not on any keys */
{
- ptrdiff_t offset = bufp - buf;
- if (STRING_BYTES_BOUND - 4 < bsize)
- string_overflow ();
- buf = xrealloc (buf, bsize += 4);
- bufp = buf + offset;
memcpy (bufp, "M-x ", 4);
bufp += 4;
nchars += 4;
- if (multibyte)
- length = multibyte_chars_in_text (start, length_byte);
- else
- length = length_byte;
+ length = multibyte_chars_in_text (start, length_byte);
goto subst;
}
else
@@ -873,28 +847,20 @@ Otherwise, return a new string. */)
}
/* \{foo} is replaced with a summary of the keymap (symbol-value foo).
\<foo> just sets the keymap used for \[cmd]. */
- else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<'))
+ else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<')
+ && (close_bracket
+ = memchr (strp + 2, strp[1] == '{' ? '}' : '>',
+ SDATA (str) + strbytes - (strp + 2))))
{
- struct buffer *oldbuf;
- ptrdiff_t start_idx;
+ {
+ bool generate_summary = strp[1] == '{';
/* This is for computing the SHADOWS arg for describe_map_tree. */
Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil);
- Lisp_Object earlier_maps;
ptrdiff_t count = SPECPDL_INDEX ();
- strp += 2; /* skip \{ or \< */
- start = strp;
- start_idx = start - SDATA (string);
-
- while ((strp - SDATA (string) < SBYTES (string))
- && *strp != '}' && *strp != '>')
- strp++;
-
- length_byte = strp - start;
- strp++; /* skip } or > */
-
- /* Save STRP in IDX. */
- idx = strp - SDATA (string);
+ start = strp + 2;
+ length_byte = close_bracket - start;
+ idx = close_bracket + 1 - SDATA (str);
/* Get the value of the keymap in TEM, or nil if undefined.
Do this while still in the user's current buffer
@@ -905,16 +871,11 @@ Otherwise, return a new string. */)
{
tem = Fsymbol_value (name);
if (! NILP (tem))
- {
- tem = get_keymap (tem, 0, 1);
- /* Note that get_keymap can GC. */
- strp = SDATA (string) + idx;
- start = SDATA (string) + start_idx;
- }
+ tem = get_keymap (tem, 0, 1);
}
/* Now switch to a temp buffer. */
- oldbuf = current_buffer;
+ struct buffer *oldbuf = current_buffer;
set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
/* This is for an unusual case where some after-change
function uses 'format' or 'prin1' or something else that
@@ -931,15 +892,17 @@ Otherwise, return a new string. */)
SBYTES (name), 1);
AUTO_STRING (msg_suffix, "', which is not currently defined.\n");
insert1 (Fsubstitute_command_keys (msg_suffix));
- if (start[-1] == '<') keymap = Qnil;
+ if (!generate_summary)
+ keymap = Qnil;
}
- else if (start[-1] == '<')
+ else if (!generate_summary)
keymap = tem;
else
{
/* Get the list of active keymaps that precede this one.
If this one's not active, get nil. */
- earlier_maps = Fcdr (Fmemq (tem, Freverse (active_maps)));
+ Lisp_Object earlier_maps
+ = Fcdr (Fmemq (tem, Freverse (active_maps)));
describe_map_tree (tem, 1, Fnreverse (earlier_maps),
Qnil, 0, 1, 0, 0, 1);
}
@@ -947,42 +910,57 @@ Otherwise, return a new string. */)
Ferase_buffer ();
set_buffer_internal (oldbuf);
unbind_to (count, Qnil);
+ }
subst_string:
+ /* Convert non-ASCII unibyte data to properly-encoded multibyte,
+ for the same reason STRING was converted to STR. */
+ tem = Fstring_make_multibyte (tem);
start = SDATA (tem);
+ length = SCHARS (tem);
length_byte = SBYTES (tem);
- if (multibyte || pure_ascii)
- length = SCHARS (tem);
- else
- length = length_byte;
subst:
nonquotes_changed = true;
subst_quote:
changed = true;
{
ptrdiff_t offset = bufp - buf;
- if (STRING_BYTES_BOUND - length_byte < bsize)
+ ptrdiff_t avail = bsize - offset;
+ ptrdiff_t need = strbytes - idx;
+ if (INT_ADD_WRAPV (need, length_byte + EXTRA_ROOM, &need))
string_overflow ();
- buf = xrealloc (buf, bsize += length_byte);
- bufp = buf + offset;
+ if (avail < need)
+ {
+ abuf = xpalloc (abuf, &bsize, need - avail,
+ STRING_BYTES_BOUND, 1);
+ if (buf == sbuf)
+ {
+ record_unwind_protect_ptr (xfree, abuf);
+ memcpy (abuf, sbuf, offset);
+ }
+ else
+ set_unwind_protect_ptr (count, xfree, abuf);
+ buf = abuf;
+ bufp = buf + offset;
+ }
memcpy (bufp, start, length_byte);
bufp += length_byte;
nchars += length;
- /* Check STRING again in case gc relocated it. */
- strp = SDATA (string) + idx;
+
+ /* Some of the previous code can GC, so take relocation of
+ string contents into account. */
+ strp = SDATA (str) + idx;
+
+ continue;
}
}
else if ((strp[0] == '`' || strp[0] == '\'')
- && quoting_style == CURVE_QUOTING_STYLE
- && (multibyte || pure_ascii))
+ && quoting_style == CURVE_QUOTING_STYLE)
{
start = (unsigned char const *) (strp[0] == '`' ? uLSQM : uRSQM);
+ length = 1;
length_byte = sizeof uLSQM - 1;
- if (multibyte || pure_ascii)
- length = 1;
- else
- length = length_byte;
- idx = strp - SDATA (string) + 1;
+ idx = strp - SDATA (str) + 1;
goto subst_quote;
}
else if (strp[0] == '`' && quoting_style == STRAIGHT_QUOTING_STYLE)
@@ -991,31 +969,14 @@ Otherwise, return a new string. */)
strp++;
nchars++;
changed = true;
+ continue;
}
- else if (! multibyte)
- *bufp++ = *strp++, nchars++;
- else
- {
- int len;
- int ch = STRING_CHAR_AND_LENGTH (strp, len);
- if ((ch == LEFT_SINGLE_QUOTATION_MARK
- || ch == RIGHT_SINGLE_QUOTATION_MARK)
- && quoting_style != CURVE_QUOTING_STYLE)
- {
- *bufp++ = ((ch == LEFT_SINGLE_QUOTATION_MARK
- && quoting_style == GRAVE_QUOTING_STYLE)
- ? '`' : '\'');
- strp += len;
- changed = true;
- }
- else
- {
- do
- *bufp++ = *strp++;
- while (--len != 0);
- }
- nchars++;
- }
+
+ /* Copy one char. */
+ do
+ *bufp++ = *strp++;
+ while (! CHAR_HEAD_P (*strp));
+ nchars++;
}
if (changed) /* don't bother if nothing substituted */
@@ -1037,8 +998,7 @@ Otherwise, return a new string. */)
}
else
tem = string;
- xfree (buf);
- return tem;
+ return unbind_to (count, tem);
}
void
@@ -1058,12 +1018,17 @@ syms_of_doc (void)
DEFVAR_LISP ("text-quoting-style", Vtext_quoting_style,
doc: /* Style to use for single quotes in help and messages.
-Its value should be a symbol.
-`curve' means quote with curved single quotes \\=‘like this\\=’.
+Its value should be a symbol. It works by substituting certain single
+quotes for grave accent and apostrophe. This is done in help output
+and in functions like `message' and `format-message'. It is not done
+in `format'.
+
+`curve' means quote with curved single quotes ‘like this’.
`straight' means quote with straight apostrophes \\='like this\\='.
-`grave' means quote with grave accent and apostrophe \\=`like this\\='.
-The default value nil acts like `curve' if curved single quotes are
-displayable, and like `grave' otherwise. */);
+`grave' means quote with grave accent and apostrophe \\=`like this\\=';
+i.e., do not alter quote marks. The default value nil acts like
+`curve' if curved single quotes are displayable, and like `grave'
+otherwise. */);
Vtext_quoting_style = Qnil;
DEFVAR_BOOL ("internal--text-quoting-flag", text_quoting_flag,