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