1 /* Record indices of function doc strings stored in a file.
2 Copyright (C) 1985, 86,93,94,95,97,98,99, 2000 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
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)
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.
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. */
24 #include <sys/types.h>
25 #include <sys/file.h> /* Must be after sys/types.h for USG and BSD4_1*/
45 extern char *index
P_ ((const char *, int));
48 Lisp_Object Vdoc_file_name
, Vhelp_manyarg_func_alist
;
50 Lisp_Object Qfunction_documentation
;
52 extern Lisp_Object Voverriding_local_map
;
54 /* For VMS versions with limited file name syntax,
55 convert the name to something VMS will allow. */
57 munge_doc_file_name (name
)
62 /* For VMS versions with limited file name syntax,
63 convert the name to something VMS will allow. */
71 #endif /* not VMS4_4 */
73 strcpy (name
, sys_translate_unix (name
));
78 /* Buffer used for reading from documentation file. */
79 static char *get_doc_string_buffer
;
80 static int get_doc_string_buffer_size
;
82 static unsigned char *read_bytecode_pointer
;
84 /* readchar in lread.c calls back here to fetch the next byte.
85 If UNREADFLAG is 1, we unread a byte. */
88 read_bytecode_char (unreadflag
)
93 read_bytecode_pointer
--;
96 return *read_bytecode_pointer
++;
99 /* Extract a doc string from a file. FILEPOS says where to get it.
100 If it is an integer, use that position in the standard DOC-... file.
101 If it is (FILE . INTEGER), use FILE as the file name
102 and INTEGER as the position in that file.
103 But if INTEGER is negative, make it positive.
104 (A negative integer is used for user variables, so we can distinguish
105 them without actually fetching the doc string.)
107 If UNIBYTE is nonzero, always make a unibyte string.
109 If DEFINITION is nonzero, assume this is for reading
110 a dynamic function definition; convert the bytestring
111 and the constants vector with appropriate byte handling,
112 and return a cons cell. */
115 get_doc_string (filepos
, unibyte
, definition
)
117 int unibyte
, definition
;
122 register char *p
, *p1
;
124 int offset
, position
;
125 Lisp_Object file
, tem
;
127 if (INTEGERP (filepos
))
129 file
= Vdoc_file_name
;
130 position
= XINT (filepos
);
132 else if (CONSP (filepos
))
134 file
= XCAR (filepos
);
135 position
= XINT (XCDR (filepos
));
137 position
= - position
;
142 if (!STRINGP (Vdoc_directory
))
148 /* Put the file name in NAME as a C string.
149 If it is relative, combine it with Vdoc_directory. */
151 tem
= Ffile_name_absolute_p (file
);
154 minsize
= XSTRING (Vdoc_directory
)->size
;
155 /* sizeof ("../etc/") == 8 */
158 name
= (char *) alloca (minsize
+ XSTRING (file
)->size
+ 8);
159 strcpy (name
, XSTRING (Vdoc_directory
)->data
);
160 strcat (name
, XSTRING (file
)->data
);
161 munge_doc_file_name (name
);
165 name
= (char *) XSTRING (file
)->data
;
168 fd
= emacs_open (name
, O_RDONLY
, 0);
172 if (!NILP (Vpurify_flag
))
174 /* Preparing to dump; DOC file is probably not installed.
175 So check in ../etc. */
176 strcpy (name
, "../etc/");
177 strcat (name
, XSTRING (file
)->data
);
178 munge_doc_file_name (name
);
180 fd
= emacs_open (name
, O_RDONLY
, 0);
184 error ("Cannot open doc string file \"%s\"", name
);
187 /* Seek only to beginning of disk block. */
188 offset
= position
% (8 * 1024);
189 if (0 > lseek (fd
, position
- offset
, 0))
192 error ("Position %ld out of range in doc string file \"%s\"",
196 /* Read the doc string into get_doc_string_buffer.
197 P points beyond the data just read. */
199 p
= get_doc_string_buffer
;
202 int space_left
= (get_doc_string_buffer_size
203 - (p
- get_doc_string_buffer
));
206 /* Allocate or grow the buffer if we need to. */
209 int in_buffer
= p
- get_doc_string_buffer
;
210 get_doc_string_buffer_size
+= 16 * 1024;
211 get_doc_string_buffer
212 = (char *) xrealloc (get_doc_string_buffer
,
213 get_doc_string_buffer_size
+ 1);
214 p
= get_doc_string_buffer
+ in_buffer
;
215 space_left
= (get_doc_string_buffer_size
216 - (p
- get_doc_string_buffer
));
219 /* Read a disk block at a time.
220 If we read the same block last time, maybe skip this? */
221 if (space_left
> 1024 * 8)
222 space_left
= 1024 * 8;
223 nread
= emacs_read (fd
, p
, space_left
);
227 error ("Read error on documentation file");
232 if (p
== get_doc_string_buffer
)
233 p1
= (char *) index (p
+ offset
, '\037');
235 p1
= (char *) index (p
, '\037');
246 /* Scan the text and perform quoting with ^A (char code 1).
247 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */
248 from
= get_doc_string_buffer
+ offset
;
249 to
= get_doc_string_buffer
+ offset
;
265 error ("Invalid data in documentation file -- ^A followed by code 0%o", c
);
271 /* If DEFINITION, read from this buffer
272 the same way we would read bytes from a file. */
275 read_bytecode_pointer
= get_doc_string_buffer
+ offset
;
276 return Fread (Qlambda
);
280 return make_unibyte_string (get_doc_string_buffer
+ offset
,
281 to
- (get_doc_string_buffer
+ offset
));
284 /* Let the data determine whether the string is multibyte,
285 even if Emacs is running in --unibyte mode. */
286 int nchars
= multibyte_chars_in_text (get_doc_string_buffer
+ offset
,
287 to
- (get_doc_string_buffer
+ offset
));
288 return make_string_from_bytes (get_doc_string_buffer
+ offset
,
290 to
- (get_doc_string_buffer
+ offset
));
294 /* Get a string from position FILEPOS and pass it through the Lisp reader.
295 We use this for fetching the bytecode string and constants vector
296 of a compiled function from the .elc file. */
299 read_doc_string (filepos
)
302 return get_doc_string (filepos
, 0, 1);
305 DEFUN ("documentation", Fdocumentation
, Sdocumentation
, 1, 2, 0,
306 "Return the documentation string of FUNCTION.\n\
307 Unless a non-nil second argument RAW is given, the\n\
308 string is passed through `substitute-command-keys'.")
310 Lisp_Object function
, raw
;
314 Lisp_Object tem
, doc
;
316 if (SYMBOLP (function
)
317 && (tem
= Fget (function
, Qfunction_documentation
),
319 return Fdocumentation_property (function
, Qfunction_documentation
, raw
);
321 fun
= Findirect_function (function
);
324 if (XSUBR (fun
)->doc
== 0)
326 else if ((EMACS_INT
) XSUBR (fun
)->doc
>= 0)
327 doc
= build_string (XSUBR (fun
)->doc
);
329 doc
= get_doc_string (make_number (- (EMACS_INT
) XSUBR (fun
)->doc
),
331 if (! NILP (tem
= Fassq (function
, Vhelp_manyarg_func_alist
)))
332 doc
= concat3 (doc
, build_string ("\n"), Fcdr (tem
));
334 else if (COMPILEDP (fun
))
336 if ((XVECTOR (fun
)->size
& PSEUDOVECTOR_SIZE_MASK
) <= COMPILED_DOC_STRING
)
338 tem
= XVECTOR (fun
)->contents
[COMPILED_DOC_STRING
];
341 else if (NATNUMP (tem
) || CONSP (tem
))
342 doc
= get_doc_string (tem
, 0, 0);
346 else if (STRINGP (fun
) || VECTORP (fun
))
348 return build_string ("Keyboard macro.");
350 else if (CONSP (fun
))
353 if (!SYMBOLP (funcar
))
354 return Fsignal (Qinvalid_function
, Fcons (fun
, Qnil
));
355 else if (EQ (funcar
, Qkeymap
))
356 return build_string ("Prefix command (definition is a keymap associating keystrokes with commands).");
357 else if (EQ (funcar
, Qlambda
)
358 || EQ (funcar
, Qautoload
))
361 tem1
= Fcdr (Fcdr (fun
));
365 /* Handle a doc reference--but these never come last
366 in the function body, so reject them if they are last. */
367 else if ((NATNUMP (tem
) || CONSP (tem
))
368 && ! NILP (XCDR (tem1
)))
369 doc
= get_doc_string (tem
, 0, 0);
373 else if (EQ (funcar
, Qmocklisp
))
375 else if (EQ (funcar
, Qmacro
))
376 return Fdocumentation (Fcdr (fun
), raw
);
383 Fsignal (Qinvalid_function
, Fcons (fun
, Qnil
));
387 doc
= Fsubstitute_command_keys (doc
);
391 DEFUN ("documentation-property", Fdocumentation_property
,
392 Sdocumentation_property
, 2, 3, 0,
393 "Return the documentation string that is SYMBOL's PROP property.\n\
394 Third argument RAW omitted or nil means pass the result through\n\
395 `substitute-command-keys' if it is a string.\n\
397 This is differs from `get' in that it can refer to strings stored in the\n\
398 `etc/DOC' file; and that it evaluates documentation properties that\n\
401 Lisp_Object symbol
, prop
, raw
;
405 tem
= Fget (symbol
, prop
);
407 tem
= get_doc_string (XINT (tem
) > 0 ? tem
: make_number (- XINT (tem
)), 0, 0);
408 else if (CONSP (tem
) && INTEGERP (XCDR (tem
)))
409 tem
= get_doc_string (tem
, 0, 0);
410 else if (!STRINGP (tem
))
411 /* Feval protects its argument. */
414 if (NILP (raw
) && STRINGP (tem
))
415 tem
= Fsubstitute_command_keys (tem
);
419 /* Scanning the DOC files and placing docstring offsets into functions. */
422 store_function_docstring (fun
, offset
)
424 /* Use EMACS_INT because we get this from pointer subtraction. */
427 fun
= indirect_function (fun
);
429 /* The type determines where the docstring is stored. */
431 /* Lisp_Subrs have a slot for it. */
433 XSUBR (fun
)->doc
= (char *) - offset
;
435 /* If it's a lisp form, stick it in the form. */
436 else if (CONSP (fun
))
441 if (EQ (tem
, Qlambda
) || EQ (tem
, Qautoload
))
443 tem
= Fcdr (Fcdr (fun
));
444 if (CONSP (tem
) && INTEGERP (XCAR (tem
)))
445 XSETFASTINT (XCAR (tem
), offset
);
447 else if (EQ (tem
, Qmacro
))
448 store_function_docstring (XCDR (fun
), offset
);
451 /* Bytecode objects sometimes have slots for it. */
452 else if (COMPILEDP (fun
))
454 /* This bytecode object must have a slot for the
455 docstring, since we've found a docstring for it. */
456 if ((XVECTOR (fun
)->size
& PSEUDOVECTOR_SIZE_MASK
) > COMPILED_DOC_STRING
)
457 XSETFASTINT (XVECTOR (fun
)->contents
[COMPILED_DOC_STRING
], offset
);
462 DEFUN ("Snarf-documentation", Fsnarf_documentation
, Ssnarf_documentation
,
464 "Used during Emacs initialization, before dumping runnable Emacs,\n\
465 to find pointers to doc strings stored in `etc/DOC...' and\n\
466 record them in function definitions.\n\
467 One arg, FILENAME, a string which does not include a directory.\n\
468 The file is found in `../etc' now; found in the `data-directory'\n\
469 when doc strings are referred to later in the dumped Emacs.")
471 Lisp_Object filename
;
477 register char *p
, *end
;
478 Lisp_Object sym
, fun
, tem
;
482 if (NILP (Vpurify_flag
))
483 error ("Snarf-documentation can only be called in an undumped Emacs");
486 CHECK_STRING (filename
, 0);
489 name
= (char *) alloca (XSTRING (filename
)->size
+ 14);
490 strcpy (name
, "../etc/");
491 #else /* CANNOT_DUMP */
492 CHECK_STRING (Vdoc_directory
, 0);
493 name
= (char *) alloca (XSTRING (filename
)->size
+
494 XSTRING (Vdoc_directory
)->size
+ 1);
495 strcpy (name
, XSTRING (Vdoc_directory
)->data
);
496 #endif /* CANNOT_DUMP */
497 strcat (name
, XSTRING (filename
)->data
); /*** Add this line ***/
500 /* For VMS versions with limited file name syntax,
501 convert the name to something VMS will allow. */
509 #endif /* not VMS4_4 */
511 strcpy (name
, sys_translate_unix (name
));
515 fd
= emacs_open (name
, O_RDONLY
, 0);
517 report_file_error ("Opening doc string file",
518 Fcons (build_string (name
), Qnil
));
519 Vdoc_file_name
= filename
;
525 filled
+= emacs_read (fd
, &buf
[filled
], sizeof buf
- 1 - filled
);
531 end
= buf
+ (filled
< 512 ? filled
: filled
- 128);
532 while (p
!= end
&& *p
!= '\037') p
++;
533 /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */
536 end
= (char *) index (p
, '\n');
537 sym
= oblookup (Vobarray
, p
+ 2,
538 multibyte_chars_in_text (p
+ 2, end
- p
- 2),
542 /* Attach a docstring to a variable? */
545 /* Install file-position as variable-documentation property
546 and make it negative for a user-variable
547 (doc starts with a `*'). */
548 Fput (sym
, Qvariable_documentation
,
549 make_number ((pos
+ end
+ 1 - buf
)
550 * (end
[1] == '*' ? -1 : 1)));
553 /* Attach a docstring to a function? */
554 else if (p
[1] == 'F')
555 store_function_docstring (sym
, pos
+ end
+ 1 - buf
);
558 error ("DOC file invalid at position %d", pos
);
563 bcopy (end
, buf
, filled
);
569 DEFUN ("substitute-command-keys", Fsubstitute_command_keys
,
570 Ssubstitute_command_keys
, 1, 1, 0,
571 "Substitute key descriptions for command names in STRING.\n\
572 Return a new string which is STRING with substrings of the form \\=\\[COMMAND]\n\
573 replaced by either: a keystroke sequence that will invoke COMMAND,\n\
574 or \"M-x COMMAND\" if COMMAND is not on any keys.\n\
575 Substrings of the form \\=\\{MAPVAR} are replaced by summaries\n\
576 \(made by describe-bindings) of the value of MAPVAR, taken as a keymap.\n\
577 Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR\n\
578 as the keymap for future \\=\\[COMMAND] substrings.\n\
579 \\=\\= quotes the following character and is discarded;\n\
580 thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.")
586 register unsigned char *strp
;
587 register unsigned char *bufp
;
593 unsigned char *start
;
594 int length
, length_byte
;
596 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
;
603 CHECK_STRING (string
, 0);
607 GCPRO4 (string
, tem
, keymap
, name
);
609 multibyte
= STRING_MULTIBYTE (string
);
612 /* KEYMAP is either nil (which means search all the active keymaps)
613 or a specified local map (which means search just that and the
614 global map). If non-nil, it might come from Voverriding_local_map,
615 or from a \\<mapname> construct in STRING itself.. */
616 keymap
= current_kboard
->Voverriding_terminal_local_map
;
618 keymap
= Voverriding_local_map
;
620 bsize
= STRING_BYTES (XSTRING (string
));
621 bufp
= buf
= (unsigned char *) xmalloc (bsize
);
623 strp
= (unsigned char *) XSTRING (string
)->data
;
624 while (strp
< XSTRING (string
)->data
+ STRING_BYTES (XSTRING (string
)))
626 if (strp
[0] == '\\' && strp
[1] == '=')
628 /* \= quotes the next character;
629 thus, to put in \[ without its special meaning, use \=\[. */
635 int maxlen
= XSTRING (string
)->data
+ STRING_BYTES (XSTRING (string
)) - strp
;
637 STRING_CHAR_AND_LENGTH (strp
, maxlen
, len
);
641 bcopy (strp
, bufp
, len
);
647 *bufp
++ = *strp
++, nchars
++;
649 else if (strp
[0] == '\\' && strp
[1] == '[')
651 Lisp_Object firstkey
;
655 strp
+= 2; /* skip \[ */
657 start_idx
= start
- XSTRING (string
)->data
;
659 while ((strp
- (unsigned char *) XSTRING (string
)->data
660 < STRING_BYTES (XSTRING (string
)))
663 length_byte
= strp
- start
;
667 /* Save STRP in IDX. */
668 idx
= strp
- (unsigned char *) XSTRING (string
)->data
;
669 tem
= Fintern (make_string (start
, length_byte
), Qnil
);
671 /* Note the Fwhere_is_internal can GC, so we have to take
672 relocation of string contents into account. */
673 tem
= Fwhere_is_internal (tem
, keymap
, Qt
, Qnil
);
674 strp
= XSTRING (string
)->data
+ idx
;
675 start
= XSTRING (string
)->data
+ start_idx
;
677 /* Disregard menu bar bindings; it is positively annoying to
678 mention them when there's no menu bar, and it isn't terribly
679 useful even when there is a menu bar. */
682 firstkey
= Faref (tem
, make_number (0));
683 if (EQ (firstkey
, Qmenu_bar
))
687 if (NILP (tem
)) /* but not on any keys */
689 new = (unsigned char *) xrealloc (buf
, bsize
+= 4);
692 bcopy ("M-x ", bufp
, 4);
696 length
= multibyte_chars_in_text (start
, length_byte
);
698 length
= length_byte
;
702 { /* function is on a key */
703 tem
= Fkey_description (tem
);
707 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
708 \<foo> just sets the keymap used for \[cmd]. */
709 else if (strp
[0] == '\\' && (strp
[1] == '{' || strp
[1] == '<'))
711 struct buffer
*oldbuf
;
715 strp
+= 2; /* skip \{ or \< */
717 start_idx
= start
- XSTRING (string
)->data
;
719 while ((strp
- (unsigned char *) XSTRING (string
)->data
720 < XSTRING (string
)->size
)
721 && *strp
!= '}' && *strp
!= '>')
724 length_byte
= strp
- start
;
725 strp
++; /* skip } or > */
727 /* Save STRP in IDX. */
728 idx
= strp
- (unsigned char *) XSTRING (string
)->data
;
730 /* Get the value of the keymap in TEM, or nil if undefined.
731 Do this while still in the user's current buffer
732 in case it is a local variable. */
733 name
= Fintern (make_string (start
, length_byte
), Qnil
);
734 tem
= Fboundp (name
);
737 tem
= Fsymbol_value (name
);
740 tem
= get_keymap (tem
, 0, 1);
741 /* Note that get_keymap can GC. */
742 strp
= XSTRING (string
)->data
+ idx
;
743 start
= XSTRING (string
)->data
+ start_idx
;
747 /* Now switch to a temp buffer. */
748 oldbuf
= current_buffer
;
749 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer
));
753 name
= Fsymbol_name (name
);
754 insert_string ("\nUses keymap \"");
755 insert_from_string (name
, 0, 0,
756 XSTRING (name
)->size
,
757 STRING_BYTES (XSTRING (name
)), 1);
758 insert_string ("\", which is not currently defined.\n");
759 if (start
[-1] == '<') keymap
= Qnil
;
761 else if (start
[-1] == '<')
764 describe_map_tree (tem
, 1, Qnil
, Qnil
, (char *)0, 1, 0, 0);
765 tem
= Fbuffer_string ();
767 set_buffer_internal (oldbuf
);
770 start
= XSTRING (tem
)->data
;
771 length
= XSTRING (tem
)->size
;
772 length_byte
= STRING_BYTES (XSTRING (tem
));
774 new = (unsigned char *) xrealloc (buf
, bsize
+= length_byte
);
777 bcopy (start
, bufp
, length_byte
);
780 /* Check STRING again in case gc relocated it. */
781 strp
= (unsigned char *) XSTRING (string
)->data
+ idx
;
783 else if (! multibyte
) /* just copy other chars */
784 *bufp
++ = *strp
++, nchars
++;
788 int maxlen
= XSTRING (string
)->data
+ STRING_BYTES (XSTRING (string
)) - strp
;
790 STRING_CHAR_AND_LENGTH (strp
, maxlen
, len
);
794 bcopy (strp
, bufp
, len
);
801 if (changed
) /* don't bother if nothing substituted */
802 tem
= make_string_from_bytes (buf
, nchars
, bufp
- buf
);
806 RETURN_UNGCPRO (tem
);
812 Qfunction_documentation
= intern ("function-documentation");
813 staticpro (&Qfunction_documentation
);
815 DEFVAR_LISP ("internal-doc-file-name", &Vdoc_file_name
,
816 "Name of file containing documentation strings of built-in symbols.");
817 Vdoc_file_name
= Qnil
;
818 DEFVAR_LISP ("help-manyarg-func-alist", &Vhelp_manyarg_func_alist
,
819 "Alist of primitive functions and descriptions of their arg lists.\n\
820 All special forms and primitives which effectively have &rest args\n\
821 should have an entry here so that `documentation' can provide their\n\
823 Vhelp_manyarg_func_alist
= Qnil
;
825 defsubr (&Sdocumentation
);
826 defsubr (&Sdocumentation_property
);
827 defsubr (&Ssnarf_documentation
);
828 defsubr (&Ssubstitute_command_keys
);