diff options
Diffstat (limited to 'src/doc.c')
-rw-r--r-- | src/doc.c | 169 |
1 files changed, 108 insertions, 61 deletions
diff --git a/src/doc.c b/src/doc.c index 6dae67b0c25..b5a9ed498af 100644 --- a/src/doc.c +++ b/src/doc.c @@ -37,6 +37,39 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "intervals.h" #include "keymap.h" + + +#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY \ + || (__ANDROID_API__ < 9) +#define doc_fd int +#define doc_fd_p(fd) ((fd) >= 0) +#define doc_open emacs_open +#define doc_read_quit emacs_read_quit +#define doc_lseek lseek +#else /* HAVE_ANDROID && !defined ANDROID_STUBIFY + && __ANDROID_API__ >= 9 */ + +#include "android.h" + +/* Use an Android file descriptor under Android instead, as this + allows loading directly from asset files without loading each asset + into memory and creating a separate file descriptor every time. + + However, lread requires the ability to seek inside asset files, + which is not provided under Android 2.2. So when building for that + particular system, fall back to the usual file descriptor-based + code. */ + +#define doc_fd struct android_fd_or_asset +#define doc_fd_p(fd) ((fd).asset != (void *) -1) +#define doc_open android_open_asset +#define doc_read_quit android_asset_read_quit +#define doc_lseek android_asset_lseek +#define USE_ANDROID_ASSETS +#endif /* !HAVE_ANDROID || ANDROID_STUBIFY || __ANDROID_API__ < 9 */ + + + /* Buffer used for reading from documentation file. */ static char *get_doc_string_buffer; static ptrdiff_t get_doc_string_buffer_size; @@ -59,6 +92,22 @@ read_bytecode_char (bool unreadflag) return *read_bytecode_pointer++; } +#ifdef USE_ANDROID_ASSETS + +/* Like `close_file_unwind'. However, PTR is a pointer to an Android + file descriptor instead of a system file descriptor. */ + +static void +close_file_unwind_android_fd (void *ptr) +{ + struct android_fd_or_asset *fd; + + fd = ptr; + android_close_asset (*fd); +} + +#endif /* USE_ANDROID_ASSETS */ + /* Extract a doc string from a file. FILEPOS says where to get it. If it is an integer, use that position in the standard DOC file. If it is (FILE . INTEGER), use FILE as the file name @@ -123,8 +172,8 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file)); lispstpcpy (lispstpcpy (name, docdir), file); - int fd = emacs_open (name, O_RDONLY, 0); - if (fd < 0) + doc_fd fd = doc_open (name, O_RDONLY, 0); + if (!doc_fd_p (fd)) { if (will_dump_p ()) { @@ -132,9 +181,9 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) So check in ../etc. */ lispstpcpy (stpcpy (name, sibling_etc), file); - fd = emacs_open (name, O_RDONLY, 0); + fd = doc_open (name, O_RDONLY, 0); } - if (fd < 0) + if (!doc_fd_p (fd)) { if (errno != ENOENT && errno != ENOTDIR) report_file_error ("Read error on documentation file", file); @@ -145,14 +194,18 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) return concat3 (cannot_open, file, quote_nl); } } +#ifndef USE_ANDROID_ASSETS record_unwind_protect_int (close_file_unwind, fd); +#else /* USE_ANDROID_ASSETS */ + record_unwind_protect_ptr (close_file_unwind_android_fd, &fd); +#endif /* !USE_ANDROID_ASSETS */ /* Seek only to beginning of disk block. */ /* Make sure we read at least 1024 bytes before `position' so we can check the leading text for consistency. */ int offset = min (position, max (1024, position % (8 * 1024))); if (TYPE_MAXIMUM (off_t) < position - || lseek (fd, position - offset, 0) < 0) + || doc_lseek (fd, position - offset, 0) < 0) error ("Position %"pI"d out of range in doc string file \"%s\"", position, name); @@ -181,7 +234,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) If we read the same block last time, maybe skip this? */ if (space_left > 1024 * 8) space_left = 1024 * 8; - int nread = emacs_read_quit (fd, p, space_left); + int nread = doc_read_quit (fd, p, space_left); if (nread < 0) report_file_error ("Read error on documentation file", file); p[nread] = 0; @@ -304,6 +357,20 @@ reread_doc_file (Lisp_Object file) return 1; } +DEFUN ("documentation-stringp", Fdocumentation_stringp, Sdocumentation_stringp, + 1, 1, 0, + doc: /* Return non-nil if OBJECT is a well-formed docstring object. +OBJECT can be either a string or a reference if it's kept externally. */) + (Lisp_Object object) +{ + return (STRINGP (object) + || FIXNUMP (object) /* Reference to DOC. */ + || (CONSP (object) /* Reference to .elc. */ + && STRINGP (XCAR (object)) + && FIXNUMP (XCDR (object))) + ? Qt : Qnil); +} + DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0, doc: /* Return the documentation string of FUNCTION. Unless a non-nil second argument RAW is given, the @@ -330,19 +397,7 @@ string is passed through `substitute-command-keys'. */) xsignal1 (Qvoid_function, function); if (CONSP (fun) && EQ (XCAR (fun), Qmacro)) fun = XCDR (fun); -#ifdef HAVE_NATIVE_COMP - if (!NILP (Fsubr_native_elisp_p (fun))) - doc = native_function_doc (fun); - else -#endif - if (SUBRP (fun)) - doc = make_fixnum (XSUBR (fun)->doc); -#ifdef HAVE_MODULES - else if (MODULE_FUNCTIONP (fun)) - doc = module_function_documentation (XMODULE_FUNCTION (fun)); -#endif - else - doc = call1 (Qfunction_documentation, fun); + doc = call1 (Qfunction_documentation, fun); /* If DOC is 0, it's typically because of a dumped file missing from the DOC file (bug in src/Makefile.in). */ @@ -371,6 +426,25 @@ string is passed through `substitute-command-keys'. */) return doc; } +DEFUN ("internal-subr-documentation", Fsubr_documentation, Ssubr_documentation, 1, 1, 0, + doc: /* Return the raw documentation info of a C primitive. */) + (Lisp_Object function) +{ +#ifdef HAVE_NATIVE_COMP + if (!NILP (Fsubr_native_elisp_p (function))) + return native_function_doc (function); + else +#endif + if (SUBRP (function)) + return make_fixnum (XSUBR (function)->doc); +#ifdef HAVE_MODULES + else if (MODULE_FUNCTIONP (function)) + return module_function_documentation (XMODULE_FUNCTION (function)); +#endif + else + return Qt; +} + DEFUN ("documentation-property", Fdocumentation_property, Sdocumentation_property, 2, 3, 0, doc: /* Return the documentation string that is SYMBOL's PROP property. @@ -442,46 +516,13 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset) /* If it's a lisp form, stick it in the form. */ if (CONSP (fun) && EQ (XCAR (fun), Qmacro)) fun = XCDR (fun); - if (CONSP (fun)) - { - Lisp_Object tem = XCAR (fun); - if (EQ (tem, Qlambda) || EQ (tem, Qautoload) - || (EQ (tem, Qclosure) && (fun = XCDR (fun), 1))) - { - tem = Fcdr (Fcdr (fun)); - if (CONSP (tem) && FIXNUMP (XCAR (tem))) - /* FIXME: This modifies typically pure hash-cons'd data, so its - correctness is quite delicate. */ - XSETCAR (tem, make_fixnum (offset)); - } - } /* Lisp_Subrs have a slot for it. */ - else if (SUBRP (fun) && !SUBR_NATIVE_COMPILEDP (fun)) - { - XSUBR (fun)->doc = offset; - } - - /* Bytecode objects sometimes have slots for it. */ - else if (COMPILEDP (fun)) + if (SUBRP (fun) && !SUBR_NATIVE_COMPILEDP (fun)) + XSUBR (fun)->doc = offset; + else { - /* This bytecode object must have a slot for the - docstring, since we've found a docstring for it. */ - if (PVSIZE (fun) > COMPILED_DOC_STRING - /* Don't overwrite a non-docstring value placed there, - * such as the symbols used for Oclosures. */ - && VALID_DOCSTRING_P (AREF (fun, COMPILED_DOC_STRING))) - ASET (fun, COMPILED_DOC_STRING, make_fixnum (offset)); - else - { - AUTO_STRING (format, - (PVSIZE (fun) > COMPILED_DOC_STRING - ? "Docstring slot busy for %s" - : "No docstring slot for %s")); - CALLN (Fmessage, format, - (SYMBOLP (obj) - ? SYMBOL_NAME (obj) - : build_string ("<anonymous>"))); - } + AUTO_STRING (format, "Ignoring DOC string on non-subr: %S"); + CALLN (Fmessage, format, obj); } } @@ -497,7 +538,7 @@ That file is found in `../etc' now; later, when the dumped Emacs is run, the same file name is found in the `doc-directory'. */) (Lisp_Object filename) { - int fd; + doc_fd fd; char buf[1024 + 1]; int filled; EMACS_INT pos; @@ -544,21 +585,25 @@ the same file name is found in the `doc-directory'. */) Vbuild_files = Fpurecopy (Vbuild_files); } - fd = emacs_open (name, O_RDONLY, 0); - if (fd < 0) + fd = doc_open (name, O_RDONLY, 0); + if (!doc_fd_p (fd)) { int open_errno = errno; report_file_errno ("Opening doc string file", build_string (name), open_errno); } +#ifndef USE_ANDROID_ASSETS record_unwind_protect_int (close_file_unwind, fd); +#else /* USE_ANDROID_ASSETS */ + record_unwind_protect_ptr (close_file_unwind_android_fd, &fd); +#endif /* !USE_ANDROID_ASSETS */ Vdoc_file_name = filename; filled = 0; pos = 0; while (true) { if (filled < 512) - filled += emacs_read_quit (fd, &buf[filled], sizeof buf - 1 - filled); + filled += doc_read_quit (fd, &buf[filled], sizeof buf - 1 - filled); if (!filled) break; @@ -712,7 +757,9 @@ compute the correct value for the current terminal in the nil case. */); doc: /* If nil, a nil `text-quoting-style' is treated as `grave'. */); /* Initialized by ‘main’. */ + defsubr (&Sdocumentation_stringp); defsubr (&Sdocumentation); + defsubr (&Ssubr_documentation); defsubr (&Sdocumentation_property); defsubr (&Ssnarf_documentation); defsubr (&Stext_quoting_style); |