summaryrefslogtreecommitdiff
path: root/src/doc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc.c')
-rw-r--r--src/doc.c248
1 files changed, 158 insertions, 90 deletions
diff --git a/src/doc.c b/src/doc.c
index d3f8fde08f6..694c159fc09 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -1,6 +1,6 @@
-/* Record indices of function doc strings stored in a file.
+/* Record indices of function doc strings stored in a file. -*- coding: utf-8 -*-
-Copyright (C) 1985-1986, 1993-1995, 1997-2013 Free Software Foundation,
+Copyright (C) 1985-1986, 1993-1995, 1997-2015 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
@@ -31,18 +31,19 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "lisp.h"
#include "character.h"
+#include "coding.h"
#include "buffer.h"
-#include "keyboard.h"
+#include "disptab.h"
#include "keymap.h"
-Lisp_Object Qfunction_documentation;
-
/* Buffer used for reading from documentation file. */
static char *get_doc_string_buffer;
static ptrdiff_t get_doc_string_buffer_size;
static unsigned char *read_bytecode_pointer;
+static char const sibling_etc[] = "../etc/";
+
/* `readchar' in lread.c calls back here to fetch the next byte.
If UNREADFLAG is 1, we unread a byte. */
@@ -81,7 +82,6 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
{
char *from, *to, *name, *p, *p1;
int fd;
- ptrdiff_t minsize;
int offset;
EMACS_INT position;
Lisp_Object file, tem, pos;
@@ -114,21 +114,14 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
tem = Ffile_name_absolute_p (file);
file = ENCODE_FILE (file);
- if (NILP (tem))
- {
- Lisp_Object docdir = ENCODE_FILE (Vdoc_directory);
- minsize = SCHARS (docdir);
- /* sizeof ("../etc/") == 8 */
- if (minsize < 8)
- minsize = 8;
- name = SAFE_ALLOCA (minsize + SCHARS (file) + 8);
- strcpy (name, SSDATA (docdir));
- strcat (name, SSDATA (file));
- }
- else
- {
- name = SSDATA (file);
- }
+ Lisp_Object docdir
+ = NILP (tem) ? ENCODE_FILE (Vdoc_directory) : empty_unibyte_string;
+ ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1;
+#ifndef CANNOT_DUMP
+ docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc);
+#endif
+ name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file));
+ lispstpcpy (lispstpcpy (name, docdir), file);
fd = emacs_open (name, O_RDONLY, 0);
if (fd < 0)
@@ -138,8 +131,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
{
/* Preparing to dump; DOC file is probably not installed.
So check in ../etc. */
- strcpy (name, "../etc/");
- strcat (name, SSDATA (file));
+ lispstpcpy (stpcpy (name, sibling_etc), file);
fd = emacs_open (name, O_RDONLY, 0);
}
@@ -147,8 +139,9 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
if (fd < 0)
{
SAFE_FREE ();
- return concat3 (build_string ("Cannot open doc string file \""),
- file, build_string ("\"\n"));
+ AUTO_STRING (cannot_open, "Cannot open doc string file \"");
+ AUTO_STRING (quote_nl, "\"\n");
+ return concat3 (cannot_open, file, quote_nl);
}
}
count = SPECPDL_INDEX ();
@@ -307,19 +300,6 @@ read_doc_string (Lisp_Object filepos)
static bool
reread_doc_file (Lisp_Object file)
{
-#if 0
- Lisp_Object reply, prompt[3];
- struct gcpro gcpro1;
- GCPRO1 (file);
- prompt[0] = build_string ("File ");
- prompt[1] = NILP (file) ? Vdoc_file_name : file;
- prompt[2] = build_string (" is out of sync. Reload? ");
- reply = Fy_or_n_p (Fconcat (3, prompt));
- UNGCPRO;
- if (NILP (reply))
- return 0;
-#endif
-
if (NILP (file))
Fsnarf_documentation (Vdoc_file_name);
else
@@ -416,21 +396,6 @@ string is passed through `substitute-command-keys'. */)
xsignal1 (Qinvalid_function, fun);
}
- /* Check for a dynamic docstring. These come with
- a dynamic-docstring-function text property. */
- if (STRINGP (doc))
- {
- Lisp_Object func
- = Fget_text_property (make_number (0),
- intern ("dynamic-docstring-function"),
- doc);
- if (!NILP (func))
- /* Pass both `doc' and `function' since `function' can be needed, and
- finding `doc' can be annoying: calling `documentation' is not an
- option because it would infloop. */
- doc = call2 (func, doc, function);
- }
-
/* If DOC is 0, it's typically because of a dumped file missing
from the DOC file (bug in src/Makefile.in). */
if (EQ (doc, make_number (0)))
@@ -442,10 +407,7 @@ string is passed through `substitute-command-keys'. */)
if (NILP (tem) && try_reload)
{
/* The file is newer, we need to reset the pointers. */
- struct gcpro gcpro1, gcpro2;
- GCPRO2 (function, raw);
try_reload = reread_doc_file (Fcar_safe (doc));
- UNGCPRO;
if (try_reload)
{
try_reload = 0;
@@ -487,10 +449,7 @@ aren't strings. */)
if (NILP (tem) && try_reload)
{
/* The file is newer, we need to reset the pointers. */
- struct gcpro gcpro1, gcpro2, gcpro3;
- GCPRO3 (symbol, prop, raw);
try_reload = reread_doc_file (Fcar_safe (doc));
- UNGCPRO;
if (try_reload)
{
try_reload = 0;
@@ -551,6 +510,14 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
docstring, since we've found a docstring for it. */
if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) > COMPILED_DOC_STRING)
ASET (fun, COMPILED_DOC_STRING, make_number (offset));
+ else
+ {
+ AUTO_STRING (format, "No docstring slot for %s");
+ CALLN (Fmessage, format,
+ (SYMBOLP (obj)
+ ? SYMBOL_NAME (obj)
+ : build_string ("<anonymous>")));
+ }
}
}
@@ -574,6 +541,14 @@ the same file name is found in the `doc-directory'. */)
char *p, *name;
bool skip_file = 0;
ptrdiff_t count;
+ char const *dirname;
+ ptrdiff_t dirlen;
+ /* Preloaded defcustoms using custom-initialize-delay are added to
+ this list, but kept unbound. See http://debbugs.gnu.org/11565 */
+ Lisp_Object delayed_init =
+ find_symbol_value (intern ("custom-delayed-init-variables"));
+
+ if (EQ (delayed_init, Qunbound)) delayed_init = Qnil;
CHECK_STRING (filename);
@@ -584,16 +559,20 @@ the same file name is found in the `doc-directory'. */)
(0)
#endif /* CANNOT_DUMP */
{
- name = alloca (SCHARS (filename) + 14);
- strcpy (name, "../etc/");
+ dirname = sibling_etc;
+ dirlen = sizeof sibling_etc - 1;
}
else
{
CHECK_STRING (Vdoc_directory);
- name = alloca (SCHARS (filename) + SCHARS (Vdoc_directory) + 1);
- strcpy (name, SSDATA (Vdoc_directory));
+ dirname = SSDATA (Vdoc_directory);
+ dirlen = SBYTES (Vdoc_directory);
}
- strcat (name, SSDATA (filename)); /*** Add this line ***/
+
+ count = SPECPDL_INDEX ();
+ USE_SAFE_ALLOCA;
+ name = SAFE_ALLOCA (dirlen + SBYTES (filename) + 1);
+ lispstpcpy (stpcpy (name, dirname), filename); /*** Add this line ***/
/* Vbuild_files is nil when temacs is run, and non-nil after that. */
if (NILP (Vbuild_files))
@@ -602,7 +581,7 @@ the same file name is found in the `doc-directory'. */)
{
#include "buildobj.h"
};
- int i = sizeof buildobj / sizeof *buildobj;
+ int i = ARRAYELTS (buildobj);
while (0 <= --i)
Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
Vbuild_files = Fpurecopy (Vbuild_files);
@@ -615,7 +594,6 @@ the same file name is found in the `doc-directory'. */)
report_file_errno ("Opening doc string file", build_string (name),
open_errno);
}
- count = SPECPDL_INDEX ();
record_unwind_protect_int (close_file_unwind, fd);
Vdoc_file_name = filename;
filled = 0;
@@ -644,7 +622,7 @@ the same file name is found in the `doc-directory'. */)
&& (end[-1] == 'o' || end[-1] == 'c'))
{
ptrdiff_t len = end - p - 2;
- char *fromfile = alloca (len + 1);
+ char *fromfile = SAFE_ALLOCA (len + 1);
memcpy (fromfile, &p[2], len);
fromfile[len] = 0;
if (fromfile[len-1] == 'c')
@@ -671,7 +649,8 @@ the same file name is found in the `doc-directory'. */)
/* Install file-position as variable-documentation property
and make it negative for a user-variable
(doc starts with a `*'). */
- if (!NILP (Fboundp (sym)))
+ if (!NILP (Fboundp (sym))
+ || !NILP (Fmemq (sym, delayed_init)))
Fput (sym, Qvariable_documentation,
make_number ((pos + end + 1 - buf)
* (end[1] == '*' ? -1 : 1)));
@@ -694,9 +673,39 @@ the same file name is found in the `doc-directory'. */)
filled -= end - buf;
memmove (buf, end, filled);
}
+
+ SAFE_FREE ();
return unbind_to (count, Qnil);
}
+/* Return true if text quoting style should default to quote `like this'. */
+static bool
+default_to_grave_quoting_style (void)
+{
+ if (!text_quoting_flag)
+ return true;
+ if (! DISP_TABLE_P (Vstandard_display_table))
+ return false;
+ Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table),
+ LEFT_SINGLE_QUOTATION_MARK);
+ return (VECTORP (dv) && ASIZE (dv) == 1
+ && EQ (AREF (dv, 0), make_number ('`')));
+}
+
+/* Return the current effective text quoting style. */
+enum text_quoting_style
+text_quoting_style (void)
+{
+ if (NILP (Vtext_quoting_style)
+ ? default_to_grave_quoting_style ()
+ : EQ (Vtext_quoting_style, Qgrave))
+ return GRAVE_QUOTING_STYLE;
+ else if (EQ (Vtext_quoting_style, Qstraight))
+ return STRAIGHT_QUOTING_STYLE;
+ else
+ return CURVE_QUOTING_STYLE;
+}
+
DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
Ssubstitute_command_keys, 1, 1, 0,
doc: /* Substitute key descriptions for command names in STRING.
@@ -707,30 +716,35 @@ is not on any keys.
Each substring of the form \\=\\{MAPVAR} is replaced by a summary of
the value of MAPVAR as a keymap. This summary is similar to the one
produced by `describe-bindings'. The summary ends in two newlines
-\(used by the helper function `help-make-xrefs' to find the end of the
+(used by the helper function `help-make-xrefs' to find the end of the
summary).
Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR
as the keymap for future \\=\\[COMMAND] substrings.
-\\=\\= quotes the following character and is discarded;
-thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
+
+Each \\=‘ and \\=` is replaced by left quote, and each \\=’ and \\='
+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.
Return the original STRING if no substitutions are made.
-Otherwise, return a new string, without any text properties. */)
+Otherwise, return a new string. */)
(Lisp_Object string)
{
char *buf;
- bool changed = 0;
+ bool changed = false;
unsigned char *strp;
char *bufp;
ptrdiff_t idx;
ptrdiff_t bsize;
Lisp_Object tem;
Lisp_Object keymap;
- unsigned char *start;
+ unsigned char const *start;
ptrdiff_t length, length_byte;
Lisp_Object name;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
bool multibyte;
ptrdiff_t nchars;
@@ -741,7 +755,8 @@ Otherwise, return a new string, without any text properties. */)
tem = Qnil;
keymap = Qnil;
name = Qnil;
- GCPRO4 (string, tem, keymap, name);
+
+ enum text_quoting_style quoting_style = text_quoting_style ();
multibyte = STRING_MULTIBYTE (string);
nchars = 0;
@@ -753,6 +768,12 @@ Otherwise, return a new string, without any text properties. */)
keymap = Voverriding_local_map;
bsize = SBYTES (string);
+
+ /* Add some room for expansion due to quote replacement. */
+ enum { EXTRA_ROOM = 20 };
+ if (bsize <= STRING_BYTES_BOUND - EXTRA_ROOM)
+ bsize += EXTRA_ROOM;
+
bufp = buf = xmalloc (bsize);
strp = SDATA (string);
@@ -762,7 +783,7 @@ Otherwise, return a new string, without any text properties. */)
{
/* \= quotes the next character;
thus, to put in \[ without its special meaning, use \=\[. */
- changed = 1;
+ changed = true;
strp += 2;
if (multibyte)
{
@@ -785,7 +806,6 @@ Otherwise, return a new string, without any text properties. */)
ptrdiff_t start_idx;
bool follow_remap = 1;
- changed = 1;
strp += 2; /* skip \[ */
start = strp;
start_idx = start - SDATA (string);
@@ -850,8 +870,8 @@ Otherwise, return a new string, without any text properties. */)
/* 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 ();
- changed = 1;
strp += 2; /* skip \{ or \< */
start = strp;
start_idx = start - SDATA (string);
@@ -886,15 +906,21 @@ Otherwise, return a new string, without any text properties. */)
/* Now switch to a temp 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
+ will thrash Vprin1_to_string_buffer we are using. */
+ specbind (Qinhibit_modification_hooks, Qt);
if (NILP (tem))
{
name = Fsymbol_name (name);
- insert_string ("\nUses keymap `");
+ AUTO_STRING (msg_prefix, "\nUses keymap `");
+ insert1 (Fsubstitute_command_keys (msg_prefix));
insert_from_string (name, 0, 0,
SCHARS (name),
SBYTES (name), 1);
- insert_string ("', which is not currently defined.\n");
+ AUTO_STRING (msg_suffix, "', which is not currently defined.\n");
+ insert1 (Fsubstitute_command_keys (msg_suffix));
if (start[-1] == '<') keymap = Qnil;
}
else if (start[-1] == '<')
@@ -910,12 +936,14 @@ Otherwise, return a new string, without any text properties. */)
tem = Fbuffer_string ();
Ferase_buffer ();
set_buffer_internal (oldbuf);
+ unbind_to (count, Qnil);
subst_string:
start = SDATA (tem);
length = SCHARS (tem);
length_byte = SBYTES (tem);
subst:
+ changed = true;
{
ptrdiff_t offset = bufp - buf;
if (STRING_BYTES_BOUND - length_byte < bsize)
@@ -929,19 +957,44 @@ Otherwise, return a new string, without any text properties. */)
strp = SDATA (string) + idx;
}
}
- else if (! multibyte) /* just copy other chars */
+ else if ((strp[0] == '`' || strp[0] == '\'')
+ && quoting_style == CURVE_QUOTING_STYLE)
+ {
+ start = (unsigned char const *) (strp[0] == '`' ? uLSQM : uRSQM);
+ length = 1;
+ length_byte = sizeof uLSQM - 1;
+ idx = strp - SDATA (string) + 1;
+ goto subst;
+ }
+ else if (strp[0] == '`' && quoting_style == STRAIGHT_QUOTING_STYLE)
+ {
+ *bufp++ = '\'';
+ strp++;
+ nchars++;
+ changed = true;
+ }
+ else if (! multibyte)
*bufp++ = *strp++, nchars++;
else
{
int len;
-
- STRING_CHAR_AND_LENGTH (strp, len);
- if (len == 1)
- *bufp = *strp;
+ 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
- memcpy (bufp, strp, len);
- strp += len;
- bufp += len;
+ {
+ do
+ *bufp++ = *strp++;
+ while (--len != 0);
+ }
nchars++;
}
}
@@ -951,13 +1004,15 @@ Otherwise, return a new string, without any text properties. */)
else
tem = string;
xfree (buf);
- RETURN_UNGCPRO (tem);
+ return tem;
}
void
syms_of_doc (void)
{
DEFSYM (Qfunction_documentation, "function-documentation");
+ DEFSYM (Qgrave, "grave");
+ DEFSYM (Qstraight, "straight");
DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name,
doc: /* Name of file containing documentation strings of built-in symbols. */);
@@ -967,6 +1022,19 @@ syms_of_doc (void)
doc: /* A list of files used to build this Emacs binary. */);
Vbuild_files = Qnil;
+ DEFVAR_LISP ("text-quoting-style", Vtext_quoting_style,
+ doc: /* Style to use for single quotes when generating text.
+`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. */);
+ Vtext_quoting_style = Qnil;
+
+ DEFVAR_BOOL ("internal--text-quoting-flag", text_quoting_flag,
+ doc: /* If nil, a nil `text-quoting-style' is treated as `grave'. */);
+ /* Initialized by ‘main’. */
+
defsubr (&Sdocumentation);
defsubr (&Sdocumentation_property);
defsubr (&Ssnarf_documentation);