Update FSF's address in the preamble.
[bpt/emacs.git] / src / doc.c
1 /* Record indices of function doc strings stored in a file.
2 Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #include <config.h>
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
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #ifndef O_RDONLY
36 #define O_RDONLY 0
37 #endif
38
39 #include "lisp.h"
40 #include "buffer.h"
41 #include "keyboard.h"
42
43 Lisp_Object Vdoc_file_name;
44
45 extern char *index ();
46
47 extern Lisp_Object Voverriding_local_map;
48
49 /* For VMS versions with limited file name syntax,
50 convert the name to something VMS will allow. */
51 static void
52 munge_doc_file_name (name)
53 char *name;
54 {
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 */
71 }
72
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
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.) */
80
81 static Lisp_Object
82 get_doc_string (filepos)
83 Lisp_Object filepos;
84 {
85 char buf[512 * 32 + 1];
86 char *buffer;
87 int buffer_size;
88 int free_it;
89 char *from, *to;
90 register int fd;
91 register char *name;
92 register char *p, *p1;
93 int minsize;
94 int position;
95 Lisp_Object file, tem;
96
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);
106 if (position < 0)
107 position = - position;
108 }
109 else
110 return Qnil;
111
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 {
135 name = (char *) XSTRING (file)->data;
136 }
137
138 fd = open (name, O_RDONLY, 0);
139 if (fd < 0)
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/");
147 strcat (name, XSTRING (file)->data);
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
158 if (0 > lseek (fd, position, 0))
159 {
160 close (fd);
161 error ("Position %ld out of range in doc string file \"%s\"",
162 position, name);
163 }
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;
173 p = buf;
174 while (1)
175 {
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)
210 break;
211 p1 = index (p, '\037');
212 if (p1)
213 {
214 *p1 = 0;
215 p = p1;
216 break;
217 }
218 p += nread;
219 }
220 close (fd);
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
258 Lisp_Object
259 read_doc_string (filepos)
260 Lisp_Object filepos;
261 {
262 return Fread (get_doc_string (filepos));
263 }
264
265 DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
266 "Return the documentation string of FUNCTION.\n\
267 Unless a non-nil second argument RAW is given, the\n\
268 string is passed through `substitute-command-keys'.")
269 (function, raw)
270 Lisp_Object function, raw;
271 {
272 Lisp_Object fun;
273 Lisp_Object funcar;
274 Lisp_Object tem, doc;
275
276 fun = Findirect_function (function);
277
278 if (SUBRP (fun))
279 {
280 if (XSUBR (fun)->doc == 0) return Qnil;
281 if ((EMACS_INT) XSUBR (fun)->doc >= 0)
282 doc = build_string (XSUBR (fun)->doc);
283 else
284 doc = get_doc_string (make_number (- (EMACS_INT) XSUBR (fun)->doc));
285 }
286 else if (COMPILEDP (fun))
287 {
288 if ((XVECTOR (fun)->size & PSEUDOVECTOR_SIZE_MASK) <= COMPILED_DOC_STRING)
289 return Qnil;
290 tem = XVECTOR (fun)->contents[COMPILED_DOC_STRING];
291 if (STRINGP (tem))
292 doc = tem;
293 else if (NATNUMP (tem) || CONSP (tem))
294 doc = get_doc_string (tem);
295 else
296 return Qnil;
297 }
298 else if (STRINGP (fun) || VECTORP (fun))
299 {
300 return build_string ("Keyboard macro.");
301 }
302 else if (CONSP (fun))
303 {
304 funcar = Fcar (fun);
305 if (!SYMBOLP (funcar))
306 return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
307 else if (EQ (funcar, Qkeymap))
308 return build_string ("Prefix command (definition is a keymap associating keystrokes with\n\
309 subcommands.)");
310 else if (EQ (funcar, Qlambda)
311 || EQ (funcar, Qautoload))
312 {
313 Lisp_Object tem1;
314 tem1 = Fcdr (Fcdr (fun));
315 tem = Fcar (tem1);
316 if (STRINGP (tem))
317 doc = tem;
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))
322 doc = get_doc_string (tem);
323 else
324 return Qnil;
325 }
326 else if (EQ (funcar, Qmocklisp))
327 return Qnil;
328 else if (EQ (funcar, Qmacro))
329 return Fdocumentation (Fcdr (fun), raw);
330 else
331 goto oops;
332 }
333 else
334 {
335 oops:
336 Fsignal (Qinvalid_function, Fcons (fun, Qnil));
337 }
338
339 if (NILP (raw))
340 {
341 struct gcpro gcpro1;
342
343 GCPRO1 (doc);
344 doc = Fsubstitute_command_keys (doc);
345 UNGCPRO;
346 }
347 return doc;
348 }
349
350 DEFUN ("documentation-property", Fdocumentation_property, Sdocumentation_property, 2, 3, 0,
351 "Return the documentation string that is SYMBOL's PROP property.\n\
352 This is like `get', but it can refer to strings stored in the\n\
353 `etc/DOC' file; and if the value is a string, it is passed through\n\
354 `substitute-command-keys'. A non-nil third argument RAW avoids this\n\
355 translation.")
356 (symbol, prop, raw)
357 Lisp_Object symbol, prop, raw;
358 {
359 register Lisp_Object tem;
360
361 tem = Fget (symbol, prop);
362 if (INTEGERP (tem))
363 tem = get_doc_string (XINT (tem) > 0 ? tem : make_number (- XINT (tem)));
364 else if (CONSP (tem))
365 tem = get_doc_string (tem);
366 if (NILP (raw) && STRINGP (tem))
367 return Fsubstitute_command_keys (tem);
368 return tem;
369 }
370 \f
371 /* Scanning the DOC files and placing docstring offsets into functions. */
372
373 static void
374 store_function_docstring (fun, offset)
375 Lisp_Object fun;
376 /* Use EMACS_INT because we get this from pointer subtraction. */
377 EMACS_INT offset;
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. */
384 if (SUBRP (fun))
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));
396 if (CONSP (tem) && INTEGERP (XCONS (tem)->car))
397 XSETFASTINT (XCONS (tem)->car, offset);
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. */
404 else if (COMPILEDP (fun))
405 {
406 /* This bytecode object must have a slot for the
407 docstring, since we've found a docstring for it. */
408 if ((XVECTOR (fun)->size & PSEUDOVECTOR_SIZE_MASK) > COMPILED_DOC_STRING)
409 XSETFASTINT (XVECTOR (fun)->contents[COMPILED_DOC_STRING], offset);
410 }
411 }
412
413
414 DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
415 1, 1, 0,
416 "Used during Emacs initialization, before dumping runnable Emacs,\n\
417 to find pointers to doc strings stored in `etc/DOC...' and\n\
418 record them in function definitions.\n\
419 One arg, FILENAME, a string which does not include a directory.\n\
420 The file is found in `../etc' now; found in the `data-directory'\n\
421 when 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
434 #ifndef CANNOT_DUMP
435 if (NILP (Vpurify_flag))
436 error ("Snarf-documentation can only be called in an undumped Emacs");
437 #endif
438
439 CHECK_STRING (filename, 0);
440
441 #ifndef CANNOT_DUMP
442 name = (char *) alloca (XSTRING (filename)->size + 14);
443 strcpy (name, "../etc/");
444 #else /* CANNOT_DUMP */
445 CHECK_STRING (Vdoc_directory, 0);
446 name = (char *) alloca (XSTRING (filename)->size +
447 XSTRING (Vdoc_directory)->size + 1);
448 strcpy (name, XSTRING (Vdoc_directory)->data);
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);
491 if (SYMBOLP (sym))
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
504 /* Attach a docstring to a function? */
505 else if (p[1] == 'F')
506 store_function_docstring (sym, pos + end + 1 - buf);
507
508 else
509 error ("DOC file invalid at position %d", pos);
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
520 DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
521 Ssubstitute_command_keys, 1, 1, 0,
522 "Substitute key descriptions for command names in STRING.\n\
523 Return a new string which is STRING with substrings of the form \\=\\[COMMAND]\n\
524 replaced by either: a keystroke sequence that will invoke COMMAND,\n\
525 or \"M-x COMMAND\" if COMMAND is not on any keys.\n\
526 Substrings of the form \\=\\{MAPVAR} are replaced by summaries\n\
527 \(made by describe-bindings) of the value of MAPVAR, taken as a keymap.\n\
528 Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR\n\
529 as the keymap for future \\=\\[COMMAND] substrings.\n\
530 \\=\\= quotes the following character and is discarded;\n\
531 thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.")
532 (string)
533 Lisp_Object string;
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;
542 Lisp_Object tem;
543 Lisp_Object keymap;
544 unsigned char *start;
545 int length;
546 Lisp_Object name;
547 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
548
549 if (NILP (string))
550 return Qnil;
551
552 CHECK_STRING (string, 0);
553 tem = Qnil;
554 keymap = Qnil;
555 name = Qnil;
556 GCPRO4 (string, tem, keymap, name);
557
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,
561 or from a \\<mapname> construct in STRING itself.. */
562 keymap = current_kboard->Voverriding_terminal_local_map;
563 if (NILP (keymap))
564 keymap = Voverriding_local_map;
565
566 bsize = XSTRING (string)->size;
567 bufp = buf = (unsigned char *) xmalloc (bsize);
568
569 strp = (unsigned char *) XSTRING (string)->data;
570 while (strp < (unsigned char *) XSTRING (string)->data + XSTRING (string)->size)
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 {
582 Lisp_Object firstkey;
583
584 changed = 1;
585 strp += 2; /* skip \[ */
586 start = strp;
587
588 while ((strp - (unsigned char *) XSTRING (string)->data
589 < XSTRING (string)->size)
590 && *strp != ']')
591 strp++;
592 length = strp - start;
593 strp++; /* skip ] */
594
595 /* Save STRP in IDX. */
596 idx = strp - (unsigned char *) XSTRING (string)->data;
597 tem = Fintern (make_string (start, length), Qnil);
598 tem = Fwhere_is_internal (tem, keymap, Qt, Qnil);
599
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. */
603 if (!NILP (tem))
604 {
605 firstkey = Faref (tem, make_number (0));
606 if (EQ (firstkey, Qmenu_bar))
607 tem = Qnil;
608 }
609
610 if (NILP (tem)) /* but not on any keys */
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;
630
631 changed = 1;
632 strp += 2; /* skip \{ or \< */
633 start = strp;
634
635 while ((strp - (unsigned char *) XSTRING (string)->data
636 < XSTRING (string)->size)
637 && *strp != '}' && *strp != '>')
638 strp++;
639 length = strp - start;
640 strp++; /* skip } or > */
641
642 /* Save STRP in IDX. */
643 idx = strp - (unsigned char *) XSTRING (string)->data;
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);
650 if (! NILP (tem))
651 {
652 tem = Fsymbol_value (name);
653 if (! NILP (tem))
654 tem = get_keymap_1 (tem, 0, 1);
655 }
656
657 /* Now switch to a temp buffer. */
658 oldbuf = current_buffer;
659 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
660
661 if (NILP (tem))
662 {
663 name = Fsymbol_name (name);
664 insert_string ("\nUses keymap \"");
665 insert_from_string (name, 0, XSTRING (name)->size, 1);
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
672 describe_map_tree (tem, 1, Qnil, Qnil, (char *)0, 1, 0);
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;
686 /* Check STRING again in case gc relocated it. */
687 strp = (unsigned char *) XSTRING (string)->data + idx;
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
696 tem = string;
697 xfree (buf);
698 RETURN_UNGCPRO (tem);
699 }
700 \f
701 syms_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 }