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