* gnus-agent.el (gnus-agent-update-files-total-fetched-for): Don't bug out
[bpt/emacs.git] / src / doc.c
CommitLineData
c6045832 1/* Record indices of function doc strings stored in a file.
05920a43 2
2241d76e 3Copyright (C) 1985-1986, 1993-1995, 1997-2014 Free Software Foundation, Inc.
c6045832
JB
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
c6045832 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
c6045832
JB
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c6045832
JB
19
20
18160b98 21#include <config.h>
c6045832 22
b648c163 23#include <errno.h>
c6045832 24#include <sys/types.h>
57618ecf 25#include <sys/file.h> /* Must be after sys/types.h for USG. */
c6045832 26#include <fcntl.h>
29beb080 27#include <unistd.h>
29beb080 28
620f13b0
PE
29#include <c-ctype.h>
30
c6045832 31#include "lisp.h"
e5560ff7 32#include "character.h"
c6045832 33#include "buffer.h"
665d3046 34#include "keyboard.h"
8feddab4 35#include "keymap.h"
c6045832 36
9191c8ae
GM
37Lisp_Object Qfunction_documentation;
38
912e8480
RS
39/* Buffer used for reading from documentation file. */
40static char *get_doc_string_buffer;
3d0c92a2 41static ptrdiff_t get_doc_string_buffer_size;
912e8480 42
32caae30
RS
43static unsigned char *read_bytecode_pointer;
44
57618ecf 45/* `readchar' in lread.c calls back here to fetch the next byte.
32caae30
RS
46 If UNREADFLAG is 1, we unread a byte. */
47
48int
a08d4ba7 49read_bytecode_char (bool unreadflag)
32caae30
RS
50{
51 if (unreadflag)
52 {
53 read_bytecode_pointer--;
54 return 0;
55 }
56 return *read_bytecode_pointer++;
57}
58
700ea809 59/* Extract a doc string from a file. FILEPOS says where to get it.
6e911150 60 If it is an integer, use that position in the standard DOC file.
700ea809 61 If it is (FILE . INTEGER), use FILE as the file name
0c00bc70
RS
62 and INTEGER as the position in that file.
63 But if INTEGER is negative, make it positive.
64 (A negative integer is used for user variables, so we can distinguish
ba29c3c9
RS
65 them without actually fetching the doc string.)
66
a154a4ef
SM
67 If the location does not point to the beginning of a docstring
68 (e.g. because the file has been modified and the location is stale),
69 return nil.
70
a08d4ba7 71 If UNIBYTE, always make a unibyte string.
e96179b3 72
a08d4ba7 73 If DEFINITION, assume this is for reading
f1df0d67
RS
74 a dynamic function definition; convert the bytestring
75 and the constants vector with appropriate byte handling,
76 and return a cons cell. */
700ea809 77
0c3debbc 78Lisp_Object
a08d4ba7 79get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
778d47c7 80{
a08d4ba7
PE
81 char *from, *to, *name, *p, *p1;
82 int fd;
d311d28c
PE
83 ptrdiff_t minsize;
84 int offset;
85 EMACS_INT position;
71376d4b 86 Lisp_Object file, tem, pos;
a8cd4836 87 ptrdiff_t count;
d311d28c 88 USE_SAFE_ALLOCA;
778d47c7 89
700ea809
RS
90 if (INTEGERP (filepos))
91 {
92 file = Vdoc_file_name;
71376d4b 93 pos = filepos;
700ea809
RS
94 }
95 else if (CONSP (filepos))
96 {
03699b14 97 file = XCAR (filepos);
71376d4b 98 pos = XCDR (filepos);
700ea809
RS
99 }
100 else
778d47c7
RS
101 return Qnil;
102
71376d4b 103 position = eabs (XINT (pos));
87afdd65 104
700ea809
RS
105 if (!STRINGP (Vdoc_directory))
106 return Qnil;
107
108 if (!STRINGP (file))
109 return Qnil;
177c0ea7 110
700ea809
RS
111 /* Put the file name in NAME as a C string.
112 If it is relative, combine it with Vdoc_directory. */
113
114 tem = Ffile_name_absolute_p (file);
8fe012c4 115 file = ENCODE_FILE (file);
700ea809
RS
116 if (NILP (tem))
117 {
8fe012c4
SM
118 Lisp_Object docdir = ENCODE_FILE (Vdoc_directory);
119 minsize = SCHARS (docdir);
700ea809
RS
120 /* sizeof ("../etc/") == 8 */
121 if (minsize < 8)
122 minsize = 8;
98c6f1e3 123 name = SAFE_ALLOCA (minsize + SCHARS (file) + 8);
8fe012c4 124 strcpy (name, SSDATA (docdir));
42a5b22f 125 strcat (name, SSDATA (file));
700ea809
RS
126 }
127 else
128 {
51b59d79 129 name = SSDATA (file);
700ea809 130 }
c6045832 131
68c45bf0 132 fd = emacs_open (name, O_RDONLY, 0);
c6045832 133 if (fd < 0)
778d47c7
RS
134 {
135#ifndef CANNOT_DUMP
136 if (!NILP (Vpurify_flag))
137 {
138 /* Preparing to dump; DOC file is probably not installed.
8fe012c4 139 So check in ../etc. */
778d47c7 140 strcpy (name, "../etc/");
42a5b22f 141 strcat (name, SSDATA (file));
778d47c7 142
68c45bf0 143 fd = emacs_open (name, O_RDONLY, 0);
778d47c7
RS
144 }
145#endif
778d47c7 146 if (fd < 0)
a8cd4836
PE
147 {
148 SAFE_FREE ();
149 return concat3 (build_string ("Cannot open doc string file \""),
150 file, build_string ("\"\n"));
151 }
778d47c7 152 }
a8cd4836
PE
153 count = SPECPDL_INDEX ();
154 record_unwind_protect_int (close_file_unwind, fd);
778d47c7 155
0fded513 156 /* Seek only to beginning of disk block. */
a154a4ef
SM
157 /* Make sure we read at least 1024 bytes before `position'
158 so we can check the leading text for consistency. */
159 offset = min (position, max (1024, position % (8 * 1024)));
d311d28c
PE
160 if (TYPE_MAXIMUM (off_t) < position
161 || lseek (fd, position - offset, 0) < 0)
a8cd4836
PE
162 error ("Position %"pI"d out of range in doc string file \"%s\"",
163 position, name);
d311d28c 164
912e8480
RS
165 /* Read the doc string into get_doc_string_buffer.
166 P points beyond the data just read. */
0fded513 167
912e8480 168 p = get_doc_string_buffer;
700ea809 169 while (1)
c6045832 170 {
d31850da 171 ptrdiff_t space_left = (get_doc_string_buffer_size - 1
84c9ce05 172 - (p - get_doc_string_buffer));
700ea809
RS
173 int nread;
174
0fded513 175 /* Allocate or grow the buffer if we need to. */
d31850da 176 if (space_left <= 0)
700ea809 177 {
3d0c92a2 178 ptrdiff_t in_buffer = p - get_doc_string_buffer;
75a65c7e
SM
179 get_doc_string_buffer
180 = xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
181 16 * 1024, -1, 1);
912e8480 182 p = get_doc_string_buffer + in_buffer;
d31850da 183 space_left = (get_doc_string_buffer_size - 1
912e8480 184 - (p - get_doc_string_buffer));
700ea809
RS
185 }
186
0fded513
RS
187 /* Read a disk block at a time.
188 If we read the same block last time, maybe skip this? */
700ea809
RS
189 if (space_left > 1024 * 8)
190 space_left = 1024 * 8;
68c45bf0 191 nread = emacs_read (fd, p, space_left);
700ea809 192 if (nread < 0)
a8cd4836 193 report_file_error ("Read error on documentation file", file);
700ea809
RS
194 p[nread] = 0;
195 if (!nread)
c6045832 196 break;
912e8480 197 if (p == get_doc_string_buffer)
8966b757 198 p1 = strchr (p + offset, '\037');
0fded513 199 else
8966b757 200 p1 = strchr (p, '\037');
c6045832
JB
201 if (p1)
202 {
203 *p1 = 0;
204 p = p1;
205 break;
206 }
700ea809 207 p += nread;
c6045832 208 }
a8cd4836
PE
209 unbind_to (count, Qnil);
210 SAFE_FREE ();
700ea809 211
a154a4ef
SM
212 /* Sanity checking. */
213 if (CONSP (filepos))
214 {
215 int test = 1;
759fd763
SM
216 /* A dynamic docstring should be either at the very beginning of a "#@
217 comment" or right after a dynamic docstring delimiter (in case we
218 pack several such docstrings within the same comment). */
219 if (get_doc_string_buffer[offset - test] != '\037')
220 {
221 if (get_doc_string_buffer[offset - test++] != ' ')
222 return Qnil;
223 while (get_doc_string_buffer[offset - test] >= '0'
224 && get_doc_string_buffer[offset - test] <= '9')
225 test++;
226 if (get_doc_string_buffer[offset - test++] != '@'
227 || get_doc_string_buffer[offset - test] != '#')
228 return Qnil;
229 }
a154a4ef
SM
230 }
231 else
232 {
233 int test = 1;
234 if (get_doc_string_buffer[offset - test++] != '\n')
235 return Qnil;
236 while (get_doc_string_buffer[offset - test] > ' ')
237 test++;
238 if (get_doc_string_buffer[offset - test] != '\037')
239 return Qnil;
240 }
241
700ea809
RS
242 /* Scan the text and perform quoting with ^A (char code 1).
243 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */
912e8480
RS
244 from = get_doc_string_buffer + offset;
245 to = get_doc_string_buffer + offset;
700ea809
RS
246 while (from != p)
247 {
248 if (*from == 1)
249 {
250 int c;
251
252 from++;
253 c = *from++;
254 if (c == 1)
255 *to++ = c;
256 else if (c == '0')
257 *to++ = 0;
258 else if (c == '_')
259 *to++ = 037;
260 else
684a03ef
PE
261 {
262 unsigned char uc = c;
263 error ("\
762b15be 264Invalid data in documentation file -- %c followed by code %03o",
684a03ef
PE
265 1, uc);
266 }
700ea809
RS
267 }
268 else
269 *to++ = *from++;
270 }
271
32caae30
RS
272 /* If DEFINITION, read from this buffer
273 the same way we would read bytes from a file. */
f1df0d67
RS
274 if (definition)
275 {
9eee99eb 276 read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
32caae30 277 return Fread (Qlambda);
f1df0d67
RS
278 }
279
e96179b3
RS
280 if (unibyte)
281 return make_unibyte_string (get_doc_string_buffer + offset,
282 to - (get_doc_string_buffer + offset));
283 else
fb2fdea7 284 {
198a7a97 285 /* The data determines whether the string is multibyte. */
75a65c7e
SM
286 ptrdiff_t nchars
287 = multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
288 + offset),
289 to - (get_doc_string_buffer + offset));
fb2fdea7
RS
290 return make_string_from_bytes (get_doc_string_buffer + offset,
291 nchars,
292 to - (get_doc_string_buffer + offset));
293 }
700ea809
RS
294}
295
296/* Get a string from position FILEPOS and pass it through the Lisp reader.
297 We use this for fetching the bytecode string and constants vector
298 of a compiled function from the .elc file. */
299
300Lisp_Object
971de7fb 301read_doc_string (Lisp_Object filepos)
700ea809 302{
e96179b3 303 return get_doc_string (filepos, 0, 1);
c6045832
JB
304}
305
a08d4ba7 306static bool
971de7fb 307reread_doc_file (Lisp_Object file)
a154a4ef 308{
13d7dc77 309#if 0
a154a4ef
SM
310 Lisp_Object reply, prompt[3];
311 struct gcpro gcpro1;
312 GCPRO1 (file);
313 prompt[0] = build_string ("File ");
314 prompt[1] = NILP (file) ? Vdoc_file_name : file;
13d7dc77 315 prompt[2] = build_string (" is out of sync. Reload? ");
a154a4ef
SM
316 reply = Fy_or_n_p (Fconcat (3, prompt));
317 UNGCPRO;
318 if (NILP (reply))
e5aa79fa 319 return 0;
13d7dc77 320#endif
a154a4ef
SM
321
322 if (NILP (file))
323 Fsnarf_documentation (Vdoc_file_name);
324 else
325 Fload (file, Qt, Qt, Qt, Qnil);
e5aa79fa
SM
326
327 return 1;
a154a4ef
SM
328}
329
ee04dc54 330DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
335c5470
PJ
331 doc: /* Return the documentation string of FUNCTION.
332Unless a non-nil second argument RAW is given, the
333string is passed through `substitute-command-keys'. */)
5842a27b 334 (Lisp_Object function, Lisp_Object raw)
c6045832
JB
335{
336 Lisp_Object fun;
337 Lisp_Object funcar;
a415e694 338 Lisp_Object doc;
a08d4ba7 339 bool try_reload = 1;
e5aa79fa
SM
340
341 documentation:
c6045832 342
8d17fe0b 343 doc = Qnil;
177c0ea7 344
f8aff4c6
JB
345 if (SYMBOLP (function))
346 {
347 Lisp_Object tem = Fget (function, Qfunction_documentation);
348 if (!NILP (tem))
349 return Fdocumentation_property (function, Qfunction_documentation,
350 raw);
351 }
352
a7f96a35 353 fun = Findirect_function (function, Qnil);
57618ecf
SM
354 if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
355 fun = XCDR (fun);
5b5f6883 356 if (SUBRP (fun))
c6045832 357 {
9191c8ae
GM
358 if (XSUBR (fun)->doc == 0)
359 return Qnil;
8f41de3a
PE
360 /* FIXME: This is not portable, as it assumes that string
361 pointers have the top bit clear. */
d01a7826 362 else if ((intptr_t) XSUBR (fun)->doc >= 0)
ee04dc54 363 doc = build_string (XSUBR (fun)->doc);
c6045832 364 else
d01a7826 365 doc = make_number ((intptr_t) XSUBR (fun)->doc);
5b5f6883
KH
366 }
367 else if (COMPILEDP (fun))
368 {
87afdd65 369 if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) <= COMPILED_DOC_STRING)
c6045832 370 return Qnil;
ee04dc54 371 else
a415e694
PE
372 {
373 Lisp_Object tem = AREF (fun, COMPILED_DOC_STRING);
374 if (STRINGP (tem))
375 doc = tem;
376 else if (NATNUMP (tem) || CONSP (tem))
377 doc = tem;
378 else
379 return Qnil;
380 }
5b5f6883
KH
381 }
382 else if (STRINGP (fun) || VECTORP (fun))
383 {
c6045832 384 return build_string ("Keyboard macro.");
5b5f6883
KH
385 }
386 else if (CONSP (fun))
387 {
7d7bbefd 388 funcar = XCAR (fun);
e6d12642 389 if (!SYMBOLP (funcar))
2f0a47f9 390 xsignal1 (Qinvalid_function, fun);
502ddf23 391 else if (EQ (funcar, Qkeymap))
a3cec380 392 return build_string ("Prefix command (definition is a keymap associating keystrokes with commands).");
502ddf23 393 else if (EQ (funcar, Qlambda)
23aba0ea 394 || (EQ (funcar, Qclosure) && (fun = XCDR (fun), 1))
502ddf23 395 || EQ (funcar, Qautoload))
c6045832 396 {
a415e694
PE
397 Lisp_Object tem1 = Fcdr (Fcdr (fun));
398 Lisp_Object tem = Fcar (tem1);
e6d12642 399 if (STRINGP (tem))
ee04dc54 400 doc = tem;
ae44f7a4
RS
401 /* Handle a doc reference--but these never come last
402 in the function body, so reject them if they are last. */
87afdd65
SM
403 else if ((NATNUMP (tem) || (CONSP (tem) && INTEGERP (XCDR (tem))))
404 && !NILP (XCDR (tem1)))
405 doc = tem;
ee04dc54
RM
406 else
407 return Qnil;
c6045832 408 }
5b5f6883
KH
409 else
410 goto oops;
411 }
412 else
413 {
414 oops:
2f0a47f9 415 xsignal1 (Qinvalid_function, fun);
c6045832 416 }
ee04dc54 417
e5aa79fa
SM
418 /* If DOC is 0, it's typically because of a dumped file missing
419 from the DOC file (bug in src/Makefile.in). */
71cdb109
SM
420 if (EQ (doc, make_number (0)))
421 doc = Qnil;
68d8a8e1 422 if (INTEGERP (doc) || CONSP (doc))
a154a4ef
SM
423 {
424 Lisp_Object tem;
425 tem = get_doc_string (doc, 0, 0);
e5aa79fa 426 if (NILP (tem) && try_reload)
a154a4ef
SM
427 {
428 /* The file is newer, we need to reset the pointers. */
429 struct gcpro gcpro1, gcpro2;
430 GCPRO2 (function, raw);
e5aa79fa 431 try_reload = reread_doc_file (Fcar_safe (doc));
a154a4ef 432 UNGCPRO;
e5aa79fa
SM
433 if (try_reload)
434 {
435 try_reload = 0;
436 goto documentation;
437 }
a154a4ef
SM
438 }
439 else
440 doc = tem;
441 }
87afdd65 442
956ace37 443 if (NILP (raw))
441d75e5 444 doc = Fsubstitute_command_keys (doc);
ee04dc54 445 return doc;
c6045832
JB
446}
447
f6ee1260
GM
448DEFUN ("documentation-property", Fdocumentation_property,
449 Sdocumentation_property, 2, 3, 0,
335c5470
PJ
450 doc: /* Return the documentation string that is SYMBOL's PROP property.
451Third argument RAW omitted or nil means pass the result through
452`substitute-command-keys' if it is a string.
453
454This differs from `get' in that it can refer to strings stored in the
455`etc/DOC' file; and that it evaluates documentation properties that
456aren't strings. */)
5842a27b 457 (Lisp_Object symbol, Lisp_Object prop, Lisp_Object raw)
c6045832 458{
a08d4ba7 459 bool try_reload = 1;
2f0b74ea 460 Lisp_Object tem;
c6045832 461
e5aa79fa 462 documentation_property:
177c0ea7 463
4acb738e 464 tem = Fget (symbol, prop);
44766095 465 if (EQ (tem, make_number (0)))
71cdb109 466 tem = Qnil;
68d8a8e1 467 if (INTEGERP (tem) || (CONSP (tem) && INTEGERP (XCDR (tem))))
a154a4ef
SM
468 {
469 Lisp_Object doc = tem;
470 tem = get_doc_string (tem, 0, 0);
e5aa79fa 471 if (NILP (tem) && try_reload)
a154a4ef
SM
472 {
473 /* The file is newer, we need to reset the pointers. */
474 struct gcpro gcpro1, gcpro2, gcpro3;
475 GCPRO3 (symbol, prop, raw);
e5aa79fa 476 try_reload = reread_doc_file (Fcar_safe (doc));
a154a4ef 477 UNGCPRO;
e5aa79fa
SM
478 if (try_reload)
479 {
480 try_reload = 0;
481 goto documentation_property;
482 }
a154a4ef
SM
483 }
484 }
f6ee1260
GM
485 else if (!STRINGP (tem))
486 /* Feval protects its argument. */
a0ee6f27 487 tem = Feval (tem, Qnil);
177c0ea7 488
e6d12642 489 if (NILP (raw) && STRINGP (tem))
bbd7d5d3 490 tem = Fsubstitute_command_keys (tem);
992d176e 491 return tem;
c6045832
JB
492}
493\f
283e1184
JB
494/* Scanning the DOC files and placing docstring offsets into functions. */
495
496static void
6e6c82a4 497store_function_docstring (Lisp_Object obj, ptrdiff_t offset)
283e1184 498{
1449fa1d
CY
499 /* Don't use indirect_function here, or defaliases will apply their
500 docstrings to the base functions (Bug#2603). */
c644523b 501 Lisp_Object fun = SYMBOLP (obj) ? XSYMBOL (obj)->function : obj;
283e1184
JB
502
503 /* The type determines where the docstring is stored. */
504
505 /* Lisp_Subrs have a slot for it. */
e6d12642 506 if (SUBRP (fun))
b08a63cc
PE
507 {
508 intptr_t negative_offset = - offset;
509 XSUBR (fun)->doc = (char *) negative_offset;
510 }
283e1184
JB
511
512 /* If it's a lisp form, stick it in the form. */
513 else if (CONSP (fun))
514 {
515 Lisp_Object tem;
516
03699b14 517 tem = XCAR (fun);
23aba0ea
SM
518 if (EQ (tem, Qlambda) || EQ (tem, Qautoload)
519 || (EQ (tem, Qclosure) && (fun = XCDR (fun), 1)))
283e1184
JB
520 {
521 tem = Fcdr (Fcdr (fun));
03699b14 522 if (CONSP (tem) && INTEGERP (XCAR (tem)))
57618ecf
SM
523 /* FIXME: This modifies typically pure hash-cons'd data, so its
524 correctness is quite delicate. */
d6d23852 525 XSETCAR (tem, make_number (offset));
283e1184
JB
526 }
527 else if (EQ (tem, Qmacro))
03699b14 528 store_function_docstring (XCDR (fun), offset);
283e1184
JB
529 }
530
531 /* Bytecode objects sometimes have slots for it. */
e6d12642 532 else if (COMPILEDP (fun))
283e1184
JB
533 {
534 /* This bytecode object must have a slot for the
535 docstring, since we've found a docstring for it. */
87afdd65 536 if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) > COMPILED_DOC_STRING)
3ae565b3 537 ASET (fun, COMPILED_DOC_STRING, make_number (offset));
283e1184
JB
538 }
539}
540
541
c6045832 542DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
335c5470 543 1, 1, 0,
f4e25f94
RS
544 doc: /* Used during Emacs initialization to scan the `etc/DOC...' file.
545This searches the `etc/DOC...' file for doc strings and
546records them in function and variable definitions.
547The function takes one argument, FILENAME, a string;
548it specifies the file name (without a directory) of the DOC file.
549That file is found in `../etc' now; later, when the dumped Emacs is run,
98b6690a 550the same file name is found in the `doc-directory'. */)
5842a27b 551 (Lisp_Object filename)
c6045832
JB
552{
553 int fd;
554 char buf[1024 + 1];
a08d4ba7
PE
555 int filled;
556 EMACS_INT pos;
24109c98 557 Lisp_Object sym;
a08d4ba7
PE
558 char *p, *name;
559 bool skip_file = 0;
a8cd4836 560 ptrdiff_t count;
2241d76e
GM
561 /* Preloaded defcustoms using custom-initialize-delay are added to
562 this list, but kept unbound. See http://debbugs.gnu.org/11565 */
563 Lisp_Object delayed_init =
564 find_symbol_value (intern ("custom-delayed-init-variables"));
565
566 if (EQ (delayed_init, Qunbound)) delayed_init = Qnil;
c6045832 567
b7826503 568 CHECK_STRING (filename);
c6045832 569
a154a4ef 570 if
c6045832 571#ifndef CANNOT_DUMP
a154a4ef 572 (!NILP (Vpurify_flag))
c6045832 573#else /* CANNOT_DUMP */
a154a4ef 574 (0)
c6045832 575#endif /* CANNOT_DUMP */
a154a4ef 576 {
38182d90 577 name = alloca (SCHARS (filename) + 14);
a154a4ef
SM
578 strcpy (name, "../etc/");
579 }
580 else
581 {
582 CHECK_STRING (Vdoc_directory);
38182d90 583 name = alloca (SCHARS (filename) + SCHARS (Vdoc_directory) + 1);
42a5b22f 584 strcpy (name, SSDATA (Vdoc_directory));
a154a4ef 585 }
42a5b22f 586 strcat (name, SSDATA (filename)); /*** Add this line ***/
c6045832 587
d87a9ab8
JD
588 /* Vbuild_files is nil when temacs is run, and non-nil after that. */
589 if (NILP (Vbuild_files))
c2418359
PE
590 {
591 static char const *const buildobj[] =
592 {
593 #include "buildobj.h"
594 };
595 int i = sizeof buildobj / sizeof *buildobj;
596 while (0 <= --i)
597 Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
598 Vbuild_files = Fpurecopy (Vbuild_files);
599 }
d87a9ab8 600
68c45bf0 601 fd = emacs_open (name, O_RDONLY, 0);
c6045832 602 if (fd < 0)
b648c163
PE
603 {
604 int open_errno = errno;
605 report_file_errno ("Opening doc string file", build_string (name),
606 open_errno);
607 }
a8cd4836
PE
608 count = SPECPDL_INDEX ();
609 record_unwind_protect_int (close_file_unwind, fd);
c6045832
JB
610 Vdoc_file_name = filename;
611 filled = 0;
612 pos = 0;
613 while (1)
614 {
a415e694 615 register char *end;
c6045832 616 if (filled < 512)
68c45bf0 617 filled += emacs_read (fd, &buf[filled], sizeof buf - 1 - filled);
c6045832
JB
618 if (!filled)
619 break;
620
621 buf[filled] = 0;
c6045832 622 end = buf + (filled < 512 ? filled : filled - 128);
a84b7c53 623 p = memchr (buf, '\037', end - buf);
983b8302 624 /* p points to ^_Ffunctionname\n or ^_Vvarname\n or ^_Sfilename\n. */
a84b7c53 625 if (p)
c6045832 626 {
8966b757 627 end = strchr (p, '\n');
d87a9ab8
JD
628
629 /* See if this is a file name, and if it is a file in build-files. */
983b8302 630 if (p[1] == 'S')
d87a9ab8 631 {
983b8302
J
632 skip_file = 0;
633 if (end - p > 4 && end[-2] == '.'
634 && (end[-1] == 'o' || end[-1] == 'c'))
635 {
d311d28c 636 ptrdiff_t len = end - p - 2;
983b8302 637 char *fromfile = alloca (len + 1);
e99a530f 638 memcpy (fromfile, &p[2], len);
983b8302
J
639 fromfile[len] = 0;
640 if (fromfile[len-1] == 'c')
641 fromfile[len-1] = 'o';
642
643 skip_file = NILP (Fmember (build_string (fromfile),
644 Vbuild_files));
645 }
d87a9ab8
JD
646 }
647
141199d1 648 sym = oblookup (Vobarray, p + 2,
9eee99eb
PE
649 multibyte_chars_in_text ((unsigned char *) p + 2,
650 end - p - 2),
141199d1 651 end - p - 2);
11fb4bdb
SM
652 /* Check skip_file so that when a function is defined several
653 times in different files (typically, once in xterm, once in
654 w32term, ...), we only pay attention to the one that
655 matters. */
d87a9ab8 656 if (! skip_file && SYMBOLP (sym))
c6045832
JB
657 {
658 /* Attach a docstring to a variable? */
659 if (p[1] == 'V')
660 {
661 /* Install file-position as variable-documentation property
662 and make it negative for a user-variable
663 (doc starts with a `*'). */
2241d76e
GM
664 if (!NILP (Fboundp (sym))
665 || !NILP (Fmemq (sym, delayed_init)))
05920a43
GM
666 Fput (sym, Qvariable_documentation,
667 make_number ((pos + end + 1 - buf)
668 * (end[1] == '*' ? -1 : 1)));
c6045832
JB
669 }
670
283e1184 671 /* Attach a docstring to a function? */
c6045832 672 else if (p[1] == 'F')
05920a43
GM
673 {
674 if (!NILP (Ffboundp (sym)))
675 store_function_docstring (sym, pos + end + 1 - buf);
676 }
6b61353c
KH
677 else if (p[1] == 'S')
678 ; /* Just a source file name boundary marker. Ignore it. */
679
283e1184 680 else
c2982e87 681 error ("DOC file invalid at position %"pI"d", pos);
c6045832
JB
682 }
683 }
684 pos += end - buf;
685 filled -= end - buf;
840b985a 686 memmove (buf, end, filled);
c6045832 687 }
a8cd4836 688 return unbind_to (count, Qnil);
c6045832
JB
689}
690\f
a7ca3326 691DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
335c5470
PJ
692 Ssubstitute_command_keys, 1, 1, 0,
693 doc: /* Substitute key descriptions for command names in STRING.
353c87f6
CY
694Each substring of the form \\=\\[COMMAND] is replaced by either a
695keystroke sequence that invokes COMMAND, or "M-x COMMAND" if COMMAND
696is not on any keys.
697
698Each substring of the form \\=\\{MAPVAR} is replaced by a summary of
699the value of MAPVAR as a keymap. This summary is similar to the one
700produced by `describe-bindings'. The summary ends in two newlines
701\(used by the helper function `help-make-xrefs' to find the end of the
702summary).
703
704Each substring of the form \\=\\<MAPVAR> specifies the use of MAPVAR
335c5470
PJ
705as the keymap for future \\=\\[COMMAND] substrings.
706\\=\\= quotes the following character and is discarded;
c698360f
KS
707thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
708
353c87f6
CY
709Return the original STRING if no substitutions are made.
710Otherwise, return a new string, without any text properties. */)
5842a27b 711 (Lisp_Object string)
c6045832 712{
9eee99eb 713 char *buf;
a08d4ba7
PE
714 bool changed = 0;
715 unsigned char *strp;
716 char *bufp;
3d0c92a2
PE
717 ptrdiff_t idx;
718 ptrdiff_t bsize;
665d3046 719 Lisp_Object tem;
c6045832
JB
720 Lisp_Object keymap;
721 unsigned char *start;
3d0c92a2 722 ptrdiff_t length, length_byte;
665d3046
JB
723 Lisp_Object name;
724 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
a08d4ba7 725 bool multibyte;
3d0c92a2 726 ptrdiff_t nchars;
c6045832 727
4acb738e 728 if (NILP (string))
c6045832
JB
729 return Qnil;
730
b7826503 731 CHECK_STRING (string);
665d3046
JB
732 tem = Qnil;
733 keymap = Qnil;
734 name = Qnil;
4acb738e 735 GCPRO4 (string, tem, keymap, name);
c6045832 736
141199d1
RS
737 multibyte = STRING_MULTIBYTE (string);
738 nchars = 0;
739
9a425dcb
RS
740 /* KEYMAP is either nil (which means search all the active keymaps)
741 or a specified local map (which means search just that and the
742 global map). If non-nil, it might come from Voverriding_local_map,
4acb738e 743 or from a \\<mapname> construct in STRING itself.. */
bfa3acd6 744 keymap = Voverriding_local_map;
c6045832 745
d5db4077 746 bsize = SBYTES (string);
23f86fce 747 bufp = buf = xmalloc (bsize);
c6045832 748
8a7bde3e 749 strp = SDATA (string);
d5db4077 750 while (strp < SDATA (string) + SBYTES (string))
c6045832
JB
751 {
752 if (strp[0] == '\\' && strp[1] == '=')
753 {
754 /* \= quotes the next character;
755 thus, to put in \[ without its special meaning, use \=\[. */
756 changed = 1;
141199d1
RS
757 strp += 2;
758 if (multibyte)
759 {
760 int len;
141199d1 761
62a6e103 762 STRING_CHAR_AND_LENGTH (strp, len);
141199d1
RS
763 if (len == 1)
764 *bufp = *strp;
765 else
72af86bd 766 memcpy (bufp, strp, len);
141199d1
RS
767 strp += len;
768 bufp += len;
769 nchars++;
770 }
771 else
772 *bufp++ = *strp++, nchars++;
c6045832
JB
773 }
774 else if (strp[0] == '\\' && strp[1] == '[')
775 {
3d0c92a2 776 ptrdiff_t start_idx;
a08d4ba7 777 bool follow_remap = 1;
b6c53774 778
c6045832
JB
779 changed = 1;
780 strp += 2; /* skip \[ */
781 start = strp;
d5db4077 782 start_idx = start - SDATA (string);
c6045832 783
8a7bde3e 784 while ((strp - SDATA (string)
d5db4077 785 < SBYTES (string))
c6045832
JB
786 && *strp != ']')
787 strp++;
141199d1
RS
788 length_byte = strp - start;
789
c6045832
JB
790 strp++; /* skip ] */
791
792 /* Save STRP in IDX. */
8a7bde3e 793 idx = strp - SDATA (string);
9eee99eb 794 name = Fintern (make_string ((char *) start, length_byte), Qnil);
11f9d6e1 795
a1d3a188 796 do_remap:
a88a5372 797 tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
332e51c1 798
77b37c05 799 if (VECTORP (tem) && ASIZE (tem) > 1
a1d3a188
KS
800 && EQ (AREF (tem, 0), Qremap) && SYMBOLP (AREF (tem, 1))
801 && follow_remap)
802 {
803 name = AREF (tem, 1);
804 follow_remap = 0;
805 goto do_remap;
806 }
807
11f9d6e1
GM
808 /* Note the Fwhere_is_internal can GC, so we have to take
809 relocation of string contents into account. */
d5db4077
KR
810 strp = SDATA (string) + idx;
811 start = SDATA (string) + start_idx;
c6045832 812
265a9e55 813 if (NILP (tem)) /* but not on any keys */
c6045832 814 {
3d0c92a2
PE
815 ptrdiff_t offset = bufp - buf;
816 if (STRING_BYTES_BOUND - 4 < bsize)
817 string_overflow ();
38182d90 818 buf = xrealloc (buf, bsize += 4);
8d17fe0b 819 bufp = buf + offset;
72af86bd 820 memcpy (bufp, "M-x ", 4);
c6045832 821 bufp += 4;
141199d1
RS
822 nchars += 4;
823 if (multibyte)
824 length = multibyte_chars_in_text (start, length_byte);
825 else
826 length = length_byte;
c6045832
JB
827 goto subst;
828 }
829 else
830 { /* function is on a key */
a1bfe073 831 tem = Fkey_description (tem, Qnil);
c6045832
JB
832 goto subst_string;
833 }
834 }
835 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
836 \<foo> just sets the keymap used for \[cmd]. */
837 else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<'))
838 {
839 struct buffer *oldbuf;
3d0c92a2 840 ptrdiff_t start_idx;
e679a3c1 841 /* This is for computing the SHADOWS arg for describe_map_tree. */
d42f4f0f 842 Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil);
e679a3c1 843 Lisp_Object earlier_maps;
d17f4dba 844 ptrdiff_t count = SPECPDL_INDEX ();
c6045832
JB
845
846 changed = 1;
847 strp += 2; /* skip \{ or \< */
848 start = strp;
d5db4077 849 start_idx = start - SDATA (string);
c6045832 850
ccddfb9e 851 while ((strp - SDATA (string) < SBYTES (string))
c6045832
JB
852 && *strp != '}' && *strp != '>')
853 strp++;
141199d1
RS
854
855 length_byte = strp - start;
c6045832
JB
856 strp++; /* skip } or > */
857
858 /* Save STRP in IDX. */
8a7bde3e 859 idx = strp - SDATA (string);
c6045832
JB
860
861 /* Get the value of the keymap in TEM, or nil if undefined.
862 Do this while still in the user's current buffer
863 in case it is a local variable. */
9eee99eb 864 name = Fintern (make_string ((char *) start, length_byte), Qnil);
c6045832 865 tem = Fboundp (name);
265a9e55 866 if (! NILP (tem))
c6045832
JB
867 {
868 tem = Fsymbol_value (name);
265a9e55 869 if (! NILP (tem))
11f9d6e1 870 {
02067692
SM
871 tem = get_keymap (tem, 0, 1);
872 /* Note that get_keymap can GC. */
d5db4077
KR
873 strp = SDATA (string) + idx;
874 start = SDATA (string) + start_idx;
11f9d6e1 875 }
c6045832
JB
876 }
877
878 /* Now switch to a temp buffer. */
879 oldbuf = current_buffer;
880 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
d17f4dba
EZ
881 /* This is for an unusual case where some after-change
882 function uses 'format' or 'prin1' or something else that
883 will thrash Vprin1_to_string_buffer we are using. */
884 specbind (Qinhibit_modification_hooks, Qt);
c6045832 885
265a9e55 886 if (NILP (tem))
c6045832
JB
887 {
888 name = Fsymbol_name (name);
c89926a5 889 insert_string ("\nUses keymap `");
141199d1 890 insert_from_string (name, 0, 0,
d5db4077
KR
891 SCHARS (name),
892 SBYTES (name), 1);
c89926a5 893 insert_string ("', which is not currently defined.\n");
c6045832
JB
894 if (start[-1] == '<') keymap = Qnil;
895 }
896 else if (start[-1] == '<')
897 keymap = tem;
898 else
e679a3c1
RS
899 {
900 /* Get the list of active keymaps that precede this one.
901 If this one's not active, get nil. */
902 earlier_maps = Fcdr (Fmemq (tem, Freverse (active_maps)));
903 describe_map_tree (tem, 1, Fnreverse (earlier_maps),
7d652d97 904 Qnil, 0, 1, 0, 0, 1);
e679a3c1 905 }
c6045832
JB
906 tem = Fbuffer_string ();
907 Ferase_buffer ();
908 set_buffer_internal (oldbuf);
d17f4dba 909 unbind_to (count, Qnil);
c6045832
JB
910
911 subst_string:
d5db4077
KR
912 start = SDATA (tem);
913 length = SCHARS (tem);
914 length_byte = SBYTES (tem);
c6045832 915 subst:
8d17fe0b 916 {
3d0c92a2
PE
917 ptrdiff_t offset = bufp - buf;
918 if (STRING_BYTES_BOUND - length_byte < bsize)
919 string_overflow ();
38182d90 920 buf = xrealloc (buf, bsize += length_byte);
8d17fe0b 921 bufp = buf + offset;
72af86bd 922 memcpy (bufp, start, length_byte);
8d17fe0b
GM
923 bufp += length_byte;
924 nchars += length;
925 /* Check STRING again in case gc relocated it. */
51b59d79 926 strp = SDATA (string) + idx;
8d17fe0b 927 }
c6045832 928 }
141199d1
RS
929 else if (! multibyte) /* just copy other chars */
930 *bufp++ = *strp++, nchars++;
931 else
932 {
933 int len;
141199d1 934
62a6e103 935 STRING_CHAR_AND_LENGTH (strp, len);
141199d1
RS
936 if (len == 1)
937 *bufp = *strp;
938 else
72af86bd 939 memcpy (bufp, strp, len);
141199d1
RS
940 strp += len;
941 bufp += len;
942 nchars++;
943 }
c6045832
JB
944 }
945
946 if (changed) /* don't bother if nothing substituted */
cc5bf9eb 947 tem = make_string_from_bytes (buf, nchars, bufp - buf);
c6045832 948 else
4acb738e 949 tem = string;
9ac0d9e0 950 xfree (buf);
665d3046 951 RETURN_UNGCPRO (tem);
c6045832
JB
952}
953\f
dfcf069d 954void
971de7fb 955syms_of_doc (void)
c6045832 956{
cd3520a4 957 DEFSYM (Qfunction_documentation, "function-documentation");
177c0ea7 958
29208e82 959 DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name,
335c5470 960 doc: /* Name of file containing documentation strings of built-in symbols. */);
c6045832
JB
961 Vdoc_file_name = Qnil;
962
29208e82 963 DEFVAR_LISP ("build-files", Vbuild_files,
d87a9ab8
JD
964 doc: /* A list of files used to build this Emacs binary. */);
965 Vbuild_files = Qnil;
966
c6045832
JB
967 defsubr (&Sdocumentation);
968 defsubr (&Sdocumentation_property);
969 defsubr (&Ssnarf_documentation);
970 defsubr (&Ssubstitute_command_keys);
971}