Update FSF's address in the preamble.
[bpt/emacs.git] / src / doc.c
CommitLineData
c6045832 1/* Record indices of function doc strings stored in a file.
610f41b7 2 Copyright (C) 1985, 1986, 1993, 1994, 1995 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"
c6045832 42
9fbfa962 43Lisp_Object Vdoc_file_name;
c6045832 44
700ea809
RS
45extern char *index ();
46
9a425dcb
RS
47extern Lisp_Object Voverriding_local_map;
48
778d47c7
RS
49/* For VMS versions with limited file name syntax,
50 convert the name to something VMS will allow. */
51static void
52munge_doc_file_name (name)
53 char *name;
c6045832 54{
c6045832
JB
55#ifdef VMS
56#ifndef VMS4_4
57 /* For VMS versions with limited file name syntax,
58 convert the name to something VMS will allow. */
59 p = name;
60 while (*p)
61 {
62 if (*p == '-')
63 *p = '_';
64 p++;
65 }
66#endif /* not VMS4_4 */
67#ifdef VMS4_4
68 strcpy (name, sys_translate_unix (name));
69#endif /* VMS4_4 */
70#endif /* VMS */
778d47c7
RS
71}
72
700ea809
RS
73/* Extract a doc string from a file. FILEPOS says where to get it.
74 If it is an integer, use that position in the standard DOC-... file.
75 If it is (FILE . INTEGER), use FILE as the file name
0c00bc70
RS
76 and INTEGER as the position in that file.
77 But if INTEGER is negative, make it positive.
78 (A negative integer is used for user variables, so we can distinguish
79 them without actually fetching the doc string.) */
700ea809
RS
80
81static Lisp_Object
778d47c7 82get_doc_string (filepos)
700ea809 83 Lisp_Object filepos;
778d47c7
RS
84{
85 char buf[512 * 32 + 1];
700ea809
RS
86 char *buffer;
87 int buffer_size;
88 int free_it;
89 char *from, *to;
778d47c7
RS
90 register int fd;
91 register char *name;
92 register char *p, *p1;
778d47c7 93 int minsize;
700ea809
RS
94 int position;
95 Lisp_Object file, tem;
778d47c7 96
700ea809
RS
97 if (INTEGERP (filepos))
98 {
99 file = Vdoc_file_name;
100 position = XINT (filepos);
101 }
102 else if (CONSP (filepos))
103 {
104 file = XCONS (filepos)->car;
105 position = XINT (XCONS (filepos)->cdr);
0c00bc70
RS
106 if (position < 0)
107 position = - position;
700ea809
RS
108 }
109 else
778d47c7
RS
110 return Qnil;
111
700ea809
RS
112 if (!STRINGP (Vdoc_directory))
113 return Qnil;
114
115 if (!STRINGP (file))
116 return Qnil;
117
118 /* Put the file name in NAME as a C string.
119 If it is relative, combine it with Vdoc_directory. */
120
121 tem = Ffile_name_absolute_p (file);
122 if (NILP (tem))
123 {
124 minsize = XSTRING (Vdoc_directory)->size;
125 /* sizeof ("../etc/") == 8 */
126 if (minsize < 8)
127 minsize = 8;
128 name = (char *) alloca (minsize + XSTRING (file)->size + 8);
129 strcpy (name, XSTRING (Vdoc_directory)->data);
130 strcat (name, XSTRING (file)->data);
131 munge_doc_file_name (name);
132 }
133 else
134 {
a039f534 135 name = (char *) XSTRING (file)->data;
700ea809 136 }
c6045832
JB
137
138 fd = open (name, O_RDONLY, 0);
139 if (fd < 0)
778d47c7
RS
140 {
141#ifndef CANNOT_DUMP
142 if (!NILP (Vpurify_flag))
143 {
144 /* Preparing to dump; DOC file is probably not installed.
145 So check in ../etc. */
146 strcpy (name, "../etc/");
700ea809 147 strcat (name, XSTRING (file)->data);
778d47c7
RS
148 munge_doc_file_name (name);
149
150 fd = open (name, O_RDONLY, 0);
151 }
152#endif
153
154 if (fd < 0)
155 error ("Cannot open doc string file \"%s\"", name);
156 }
157
700ea809 158 if (0 > lseek (fd, position, 0))
c6045832
JB
159 {
160 close (fd);
161 error ("Position %ld out of range in doc string file \"%s\"",
700ea809 162 position, name);
c6045832 163 }
700ea809
RS
164
165 /* Read the doc string into a buffer.
166 Use the fixed buffer BUF if it is big enough;
167 otherwise allocate one and set FREE_IT.
168 We store the buffer in use in BUFFER and its size in BUFFER_SIZE. */
169
170 buffer = buf;
171 buffer_size = sizeof buf;
172 free_it = 0;
c6045832 173 p = buf;
700ea809 174 while (1)
c6045832 175 {
700ea809
RS
176 int space_left = buffer_size - (p - buffer);
177 int nread;
178
179 /* Switch to a bigger buffer if we need one. */
180 if (space_left == 0)
181 {
182 if (free_it)
183 {
184 int offset = p - buffer;
185 buffer = (char *) xrealloc (buffer,
186 buffer_size *= 2);
187 p = buffer + offset;
188 }
189 else
190 {
191 buffer = (char *) xmalloc (buffer_size *= 2);
192 bcopy (buf, buffer, p - buf);
193 p = buffer + (p - buf);
194 }
195 free_it = 1;
196 space_left = buffer_size - (p - buffer);
197 }
198
199 /* Don't read too too much at one go. */
200 if (space_left > 1024 * 8)
201 space_left = 1024 * 8;
202 nread = read (fd, p, space_left);
203 if (nread < 0)
204 {
205 close (fd);
206 error ("Read error on documentation file");
207 }
208 p[nread] = 0;
209 if (!nread)
c6045832
JB
210 break;
211 p1 = index (p, '\037');
212 if (p1)
213 {
214 *p1 = 0;
215 p = p1;
216 break;
217 }
700ea809 218 p += nread;
c6045832
JB
219 }
220 close (fd);
700ea809
RS
221
222 /* Scan the text and perform quoting with ^A (char code 1).
223 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */
224 from = buffer;
225 to = buffer;
226 while (from != p)
227 {
228 if (*from == 1)
229 {
230 int c;
231
232 from++;
233 c = *from++;
234 if (c == 1)
235 *to++ = c;
236 else if (c == '0')
237 *to++ = 0;
238 else if (c == '_')
239 *to++ = 037;
240 else
241 error ("Invalid data in documentation file -- ^A followed by code 0%o", c);
242 }
243 else
244 *to++ = *from++;
245 }
246
247 tem = make_string (buffer, to - buffer);
248 if (free_it)
249 free (buffer);
250
251 return tem;
252}
253
254/* Get a string from position FILEPOS and pass it through the Lisp reader.
255 We use this for fetching the bytecode string and constants vector
256 of a compiled function from the .elc file. */
257
258Lisp_Object
259read_doc_string (filepos)
260 Lisp_Object filepos;
261{
262 return Fread (get_doc_string (filepos));
c6045832
JB
263}
264
ee04dc54 265DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
08564963 266 "Return the documentation string of FUNCTION.\n\
4acb738e 267Unless a non-nil second argument RAW is given, the\n\
ee04dc54 268string is passed through `substitute-command-keys'.")
502ddf23
JB
269 (function, raw)
270 Lisp_Object function, raw;
c6045832
JB
271{
272 Lisp_Object fun;
273 Lisp_Object funcar;
ee04dc54 274 Lisp_Object tem, doc;
c6045832 275
502ddf23 276 fun = Findirect_function (function);
c6045832 277
5b5f6883 278 if (SUBRP (fun))
c6045832 279 {
c6045832 280 if (XSUBR (fun)->doc == 0) return Qnil;
f0f787b8 281 if ((EMACS_INT) XSUBR (fun)->doc >= 0)
ee04dc54 282 doc = build_string (XSUBR (fun)->doc);
c6045832 283 else
700ea809 284 doc = get_doc_string (make_number (- (EMACS_INT) XSUBR (fun)->doc));
5b5f6883
KH
285 }
286 else if (COMPILEDP (fun))
287 {
f9b4aacf 288 if ((XVECTOR (fun)->size & PSEUDOVECTOR_SIZE_MASK) <= COMPILED_DOC_STRING)
c6045832
JB
289 return Qnil;
290 tem = XVECTOR (fun)->contents[COMPILED_DOC_STRING];
e6d12642 291 if (STRINGP (tem))
ee04dc54 292 doc = tem;
700ea809
RS
293 else if (NATNUMP (tem) || CONSP (tem))
294 doc = get_doc_string (tem);
ee04dc54
RM
295 else
296 return Qnil;
5b5f6883
KH
297 }
298 else if (STRINGP (fun) || VECTORP (fun))
299 {
c6045832 300 return build_string ("Keyboard macro.");
5b5f6883
KH
301 }
302 else if (CONSP (fun))
303 {
c6045832 304 funcar = Fcar (fun);
e6d12642 305 if (!SYMBOLP (funcar))
c6045832 306 return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
502ddf23 307 else if (EQ (funcar, Qkeymap))
c6045832
JB
308 return build_string ("Prefix command (definition is a keymap associating keystrokes with\n\
309subcommands.)");
502ddf23
JB
310 else if (EQ (funcar, Qlambda)
311 || EQ (funcar, Qautoload))
c6045832 312 {
ae44f7a4
RS
313 Lisp_Object tem1;
314 tem1 = Fcdr (Fcdr (fun));
315 tem = Fcar (tem1);
e6d12642 316 if (STRINGP (tem))
ee04dc54 317 doc = tem;
ae44f7a4
RS
318 /* Handle a doc reference--but these never come last
319 in the function body, so reject them if they are last. */
320 else if ((NATNUMP (tem) || CONSP (tem))
321 && ! NILP (XCONS (tem1)->cdr))
700ea809 322 doc = get_doc_string (tem);
ee04dc54
RM
323 else
324 return Qnil;
c6045832 325 }
502ddf23 326 else if (EQ (funcar, Qmocklisp))
c6045832 327 return Qnil;
502ddf23 328 else if (EQ (funcar, Qmacro))
ee04dc54 329 return Fdocumentation (Fcdr (fun), raw);
5b5f6883
KH
330 else
331 goto oops;
332 }
333 else
334 {
335 oops:
336 Fsignal (Qinvalid_function, Fcons (fun, Qnil));
c6045832 337 }
ee04dc54 338
956ace37 339 if (NILP (raw))
665d3046
JB
340 {
341 struct gcpro gcpro1;
342
343 GCPRO1 (doc);
344 doc = Fsubstitute_command_keys (doc);
345 UNGCPRO;
346 }
ee04dc54 347 return doc;
c6045832
JB
348}
349
b6c53774 350DEFUN ("documentation-property", Fdocumentation_property, Sdocumentation_property, 2, 3, 0,
c6045832 351 "Return the documentation string that is SYMBOL's PROP property.\n\
ee04dc54 352This is like `get', but it can refer to strings stored in the\n\
08564963 353`etc/DOC' file; and if the value is a string, it is passed through\n\
4acb738e 354`substitute-command-keys'. A non-nil third argument RAW avoids this\n\
956ace37 355translation.")
4acb738e
EN
356 (symbol, prop, raw)
357 Lisp_Object symbol, prop, raw;
c6045832
JB
358{
359 register Lisp_Object tem;
360
4acb738e 361 tem = Fget (symbol, prop);
e6d12642 362 if (INTEGERP (tem))
700ea809
RS
363 tem = get_doc_string (XINT (tem) > 0 ? tem : make_number (- XINT (tem)));
364 else if (CONSP (tem))
365 tem = get_doc_string (tem);
e6d12642 366 if (NILP (raw) && STRINGP (tem))
992d176e
RS
367 return Fsubstitute_command_keys (tem);
368 return tem;
c6045832
JB
369}
370\f
283e1184
JB
371/* Scanning the DOC files and placing docstring offsets into functions. */
372
373static void
374store_function_docstring (fun, offset)
375 Lisp_Object fun;
e343d389
RS
376 /* Use EMACS_INT because we get this from pointer subtraction. */
377 EMACS_INT offset;
283e1184
JB
378{
379 fun = indirect_function (fun);
380
381 /* The type determines where the docstring is stored. */
382
383 /* Lisp_Subrs have a slot for it. */
e6d12642 384 if (SUBRP (fun))
283e1184
JB
385 XSUBR (fun)->doc = (char *) - offset;
386
387 /* If it's a lisp form, stick it in the form. */
388 else if (CONSP (fun))
389 {
390 Lisp_Object tem;
391
392 tem = XCONS (fun)->car;
393 if (EQ (tem, Qlambda) || EQ (tem, Qautoload))
394 {
395 tem = Fcdr (Fcdr (fun));
e6d12642 396 if (CONSP (tem) && INTEGERP (XCONS (tem)->car))
2ee7863a 397 XSETFASTINT (XCONS (tem)->car, offset);
283e1184
JB
398 }
399 else if (EQ (tem, Qmacro))
400 store_function_docstring (XCONS (fun)->cdr, offset);
401 }
402
403 /* Bytecode objects sometimes have slots for it. */
e6d12642 404 else if (COMPILEDP (fun))
283e1184
JB
405 {
406 /* This bytecode object must have a slot for the
407 docstring, since we've found a docstring for it. */
f9b4aacf 408 if ((XVECTOR (fun)->size & PSEUDOVECTOR_SIZE_MASK) > COMPILED_DOC_STRING)
2ee7863a 409 XSETFASTINT (XVECTOR (fun)->contents[COMPILED_DOC_STRING], offset);
283e1184
JB
410 }
411}
412
413
c6045832
JB
414DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
415 1, 1, 0,
416 "Used during Emacs initialization, before dumping runnable Emacs,\n\
08564963 417to find pointers to doc strings stored in `etc/DOC...' and\n\
c6045832
JB
418record them in function definitions.\n\
419One arg, FILENAME, a string which does not include a directory.\n\
08564963 420The file is found in `../etc' now; found in the `data-directory'\n\
c6045832
JB
421when doc strings are referred to later in the dumped Emacs.")
422 (filename)
423 Lisp_Object filename;
424{
425 int fd;
426 char buf[1024 + 1];
427 register int filled;
428 register int pos;
429 register char *p, *end;
430 Lisp_Object sym, fun, tem;
431 char *name;
432 extern char *index ();
433
2bda628c
JB
434#ifndef CANNOT_DUMP
435 if (NILP (Vpurify_flag))
436 error ("Snarf-documentation can only be called in an undumped Emacs");
437#endif
438
c6045832
JB
439 CHECK_STRING (filename, 0);
440
441#ifndef CANNOT_DUMP
6367dc09 442 name = (char *) alloca (XSTRING (filename)->size + 14);
08564963 443 strcpy (name, "../etc/");
c6045832 444#else /* CANNOT_DUMP */
ba870521 445 CHECK_STRING (Vdoc_directory, 0);
c6045832 446 name = (char *) alloca (XSTRING (filename)->size +
ba870521
KH
447 XSTRING (Vdoc_directory)->size + 1);
448 strcpy (name, XSTRING (Vdoc_directory)->data);
c6045832
JB
449#endif /* CANNOT_DUMP */
450 strcat (name, XSTRING (filename)->data); /*** Add this line ***/
451#ifdef VMS
452#ifndef VMS4_4
453 /* For VMS versions with limited file name syntax,
454 convert the name to something VMS will allow. */
455 p = name;
456 while (*p)
457 {
458 if (*p == '-')
459 *p = '_';
460 p++;
461 }
462#endif /* not VMS4_4 */
463#ifdef VMS4_4
464 strcpy (name, sys_translate_unix (name));
465#endif /* VMS4_4 */
466#endif /* VMS */
467
468 fd = open (name, O_RDONLY, 0);
469 if (fd < 0)
470 report_file_error ("Opening doc string file",
471 Fcons (build_string (name), Qnil));
472 Vdoc_file_name = filename;
473 filled = 0;
474 pos = 0;
475 while (1)
476 {
477 if (filled < 512)
478 filled += read (fd, &buf[filled], sizeof buf - 1 - filled);
479 if (!filled)
480 break;
481
482 buf[filled] = 0;
483 p = buf;
484 end = buf + (filled < 512 ? filled : filled - 128);
485 while (p != end && *p != '\037') p++;
486 /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */
487 if (p != end)
488 {
489 end = index (p, '\n');
490 sym = oblookup (Vobarray, p + 2, end - p - 2);
e6d12642 491 if (SYMBOLP (sym))
c6045832
JB
492 {
493 /* Attach a docstring to a variable? */
494 if (p[1] == 'V')
495 {
496 /* Install file-position as variable-documentation property
497 and make it negative for a user-variable
498 (doc starts with a `*'). */
499 Fput (sym, Qvariable_documentation,
500 make_number ((pos + end + 1 - buf)
501 * (end[1] == '*' ? -1 : 1)));
502 }
503
283e1184 504 /* Attach a docstring to a function? */
c6045832 505 else if (p[1] == 'F')
283e1184
JB
506 store_function_docstring (sym, pos + end + 1 - buf);
507
508 else
509 error ("DOC file invalid at position %d", pos);
c6045832
JB
510 }
511 }
512 pos += end - buf;
513 filled -= end - buf;
514 bcopy (end, buf, filled);
515 }
516 close (fd);
517 return Qnil;
518}
519\f
520DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
521 Ssubstitute_command_keys, 1, 1, 0,
522 "Substitute key descriptions for command names in STRING.\n\
523Return a new string which is STRING with substrings of the form \\=\\[COMMAND]\n\
524replaced by either: a keystroke sequence that will invoke COMMAND,\n\
525or \"M-x COMMAND\" if COMMAND is not on any keys.\n\
526Substrings of the form \\=\\{MAPVAR} are replaced by summaries\n\
527\(made by describe-bindings) of the value of MAPVAR, taken as a keymap.\n\
528Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR\n\
529as the keymap for future \\=\\[COMMAND] substrings.\n\
530\\=\\= quotes the following character and is discarded;\n\
531thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.")
4acb738e
EN
532 (string)
533 Lisp_Object string;
c6045832
JB
534{
535 unsigned char *buf;
536 int changed = 0;
537 register unsigned char *strp;
538 register unsigned char *bufp;
539 int idx;
540 int bsize;
541 unsigned char *new;
665d3046 542 Lisp_Object tem;
c6045832
JB
543 Lisp_Object keymap;
544 unsigned char *start;
545 int length;
665d3046
JB
546 Lisp_Object name;
547 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
c6045832 548
4acb738e 549 if (NILP (string))
c6045832
JB
550 return Qnil;
551
4acb738e 552 CHECK_STRING (string, 0);
665d3046
JB
553 tem = Qnil;
554 keymap = Qnil;
555 name = Qnil;
4acb738e 556 GCPRO4 (string, tem, keymap, name);
c6045832 557
9a425dcb
RS
558 /* KEYMAP is either nil (which means search all the active keymaps)
559 or a specified local map (which means search just that and the
560 global map). If non-nil, it might come from Voverriding_local_map,
4acb738e 561 or from a \\<mapname> construct in STRING itself.. */
f73d1163
KH
562 keymap = current_kboard->Voverriding_terminal_local_map;
563 if (NILP (keymap))
564 keymap = Voverriding_local_map;
c6045832 565
4acb738e 566 bsize = XSTRING (string)->size;
c6045832
JB
567 bufp = buf = (unsigned char *) xmalloc (bsize);
568
4acb738e
EN
569 strp = (unsigned char *) XSTRING (string)->data;
570 while (strp < (unsigned char *) XSTRING (string)->data + XSTRING (string)->size)
c6045832
JB
571 {
572 if (strp[0] == '\\' && strp[1] == '=')
573 {
574 /* \= quotes the next character;
575 thus, to put in \[ without its special meaning, use \=\[. */
576 changed = 1;
577 *bufp++ = strp[2];
578 strp += 3;
579 }
580 else if (strp[0] == '\\' && strp[1] == '[')
581 {
b6c53774
RS
582 Lisp_Object firstkey;
583
c6045832
JB
584 changed = 1;
585 strp += 2; /* skip \[ */
586 start = strp;
587
4acb738e
EN
588 while ((strp - (unsigned char *) XSTRING (string)->data
589 < XSTRING (string)->size)
c6045832
JB
590 && *strp != ']')
591 strp++;
592 length = strp - start;
593 strp++; /* skip ] */
594
595 /* Save STRP in IDX. */
4acb738e 596 idx = strp - (unsigned char *) XSTRING (string)->data;
c6045832 597 tem = Fintern (make_string (start, length), Qnil);
9a425dcb 598 tem = Fwhere_is_internal (tem, keymap, Qt, Qnil);
c6045832 599
b6c53774
RS
600 /* Disregard menu bar bindings; it is positively annoying to
601 mention them when there's no menu bar, and it isn't terribly
602 useful even when there is a menu bar. */
ef586bbd
RS
603 if (!NILP (tem))
604 {
605 firstkey = Faref (tem, make_number (0));
606 if (EQ (firstkey, Qmenu_bar))
607 tem = Qnil;
608 }
b6c53774 609
265a9e55 610 if (NILP (tem)) /* but not on any keys */
c6045832
JB
611 {
612 new = (unsigned char *) xrealloc (buf, bsize += 4);
613 bufp += new - buf;
614 buf = new;
615 bcopy ("M-x ", bufp, 4);
616 bufp += 4;
617 goto subst;
618 }
619 else
620 { /* function is on a key */
621 tem = Fkey_description (tem);
622 goto subst_string;
623 }
624 }
625 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
626 \<foo> just sets the keymap used for \[cmd]. */
627 else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<'))
628 {
629 struct buffer *oldbuf;
c6045832
JB
630
631 changed = 1;
632 strp += 2; /* skip \{ or \< */
633 start = strp;
634
4acb738e
EN
635 while ((strp - (unsigned char *) XSTRING (string)->data
636 < XSTRING (string)->size)
c6045832
JB
637 && *strp != '}' && *strp != '>')
638 strp++;
639 length = strp - start;
640 strp++; /* skip } or > */
641
642 /* Save STRP in IDX. */
4acb738e 643 idx = strp - (unsigned char *) XSTRING (string)->data;
c6045832
JB
644
645 /* Get the value of the keymap in TEM, or nil if undefined.
646 Do this while still in the user's current buffer
647 in case it is a local variable. */
648 name = Fintern (make_string (start, length), Qnil);
649 tem = Fboundp (name);
265a9e55 650 if (! NILP (tem))
c6045832
JB
651 {
652 tem = Fsymbol_value (name);
265a9e55 653 if (! NILP (tem))
665d3046 654 tem = get_keymap_1 (tem, 0, 1);
c6045832
JB
655 }
656
657 /* Now switch to a temp buffer. */
658 oldbuf = current_buffer;
659 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
660
265a9e55 661 if (NILP (tem))
c6045832
JB
662 {
663 name = Fsymbol_name (name);
664 insert_string ("\nUses keymap \"");
5778daa9 665 insert_from_string (name, 0, XSTRING (name)->size, 1);
c6045832
JB
666 insert_string ("\", which is not currently defined.\n");
667 if (start[-1] == '<') keymap = Qnil;
668 }
669 else if (start[-1] == '<')
670 keymap = tem;
671 else
b0053d11 672 describe_map_tree (tem, 1, Qnil, Qnil, (char *)0, 1, 0);
c6045832
JB
673 tem = Fbuffer_string ();
674 Ferase_buffer ();
675 set_buffer_internal (oldbuf);
676
677 subst_string:
678 start = XSTRING (tem)->data;
679 length = XSTRING (tem)->size;
680 subst:
681 new = (unsigned char *) xrealloc (buf, bsize += length);
682 bufp += new - buf;
683 buf = new;
684 bcopy (start, bufp, length);
685 bufp += length;
4acb738e
EN
686 /* Check STRING again in case gc relocated it. */
687 strp = (unsigned char *) XSTRING (string)->data + idx;
c6045832
JB
688 }
689 else /* just copy other chars */
690 *bufp++ = *strp++;
691 }
692
693 if (changed) /* don't bother if nothing substituted */
694 tem = make_string (buf, bufp - buf);
695 else
4acb738e 696 tem = string;
9ac0d9e0 697 xfree (buf);
665d3046 698 RETURN_UNGCPRO (tem);
c6045832
JB
699}
700\f
701syms_of_doc ()
702{
703 DEFVAR_LISP ("internal-doc-file-name", &Vdoc_file_name,
704 "Name of file containing documentation strings of built-in symbols.");
705 Vdoc_file_name = Qnil;
706
707 defsubr (&Sdocumentation);
708 defsubr (&Sdocumentation_property);
709 defsubr (&Ssnarf_documentation);
710 defsubr (&Ssubstitute_command_keys);
711}