1 /* Record indices of function doc strings stored in a file.
2 Copyright (C) 1985, 86, 93, 94, 95, 97, 1998 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*/
44 Lisp_Object Vdoc_file_name
;
46 extern char *index ();
48 extern Lisp_Object Voverriding_local_map
;
50 /* For VMS versions with limited file name syntax,
51 convert the name to something VMS will allow. */
53 munge_doc_file_name (name
)
58 /* For VMS versions with limited file name syntax,
59 convert the name to something VMS will allow. */
67 #endif /* not VMS4_4 */
69 strcpy (name
, sys_translate_unix (name
));
74 /* Buffer used for reading from documentation file. */
75 static char *get_doc_string_buffer
;
76 static int get_doc_string_buffer_size
;
78 static unsigned char *read_bytecode_pointer
;
80 /* readchar in lread.c calls back here to fetch the next byte.
81 If UNREADFLAG is 1, we unread a byte. */
84 read_bytecode_char (unreadflag
)
88 read_bytecode_pointer
--;
91 return *read_bytecode_pointer
++;
94 /* Extract a doc string from a file. FILEPOS says where to get it.
95 If it is an integer, use that position in the standard DOC-... file.
96 If it is (FILE . INTEGER), use FILE as the file name
97 and INTEGER as the position in that file.
98 But if INTEGER is negative, make it positive.
99 (A negative integer is used for user variables, so we can distinguish
100 them without actually fetching the doc string.)
102 If UNIBYTE is nonzero, always make a unibyte string.
104 If DEFINITION is nonzero, assume this is for reading
105 a dynamic function definition; convert the bytestring
106 and the constants vector with appropriate byte handling,
107 and return a cons cell. */
110 get_doc_string (filepos
, unibyte
, definition
)
112 int unibyte
, definition
;
117 register char *p
, *p1
;
119 int offset
, position
;
120 Lisp_Object file
, tem
;
122 if (INTEGERP (filepos
))
124 file
= Vdoc_file_name
;
125 position
= XINT (filepos
);
127 else if (CONSP (filepos
))
129 file
= XCONS (filepos
)->car
;
130 position
= XINT (XCONS (filepos
)->cdr
);
132 position
= - position
;
137 if (!STRINGP (Vdoc_directory
))
143 /* Put the file name in NAME as a C string.
144 If it is relative, combine it with Vdoc_directory. */
146 tem
= Ffile_name_absolute_p (file
);
149 minsize
= XSTRING (Vdoc_directory
)->size
;
150 /* sizeof ("../etc/") == 8 */
153 name
= (char *) alloca (minsize
+ XSTRING (file
)->size
+ 8);
154 strcpy (name
, XSTRING (Vdoc_directory
)->data
);
155 strcat (name
, XSTRING (file
)->data
);
156 munge_doc_file_name (name
);
160 name
= (char *) XSTRING (file
)->data
;
163 fd
= open (name
, O_RDONLY
, 0);
167 if (!NILP (Vpurify_flag
))
169 /* Preparing to dump; DOC file is probably not installed.
170 So check in ../etc. */
171 strcpy (name
, "../etc/");
172 strcat (name
, XSTRING (file
)->data
);
173 munge_doc_file_name (name
);
175 fd
= open (name
, O_RDONLY
, 0);
179 error ("Cannot open doc string file \"%s\"", name
);
182 /* Seek only to beginning of disk block. */
183 offset
= position
% (8 * 1024);
184 if (0 > lseek (fd
, position
- offset
, 0))
187 error ("Position %ld out of range in doc string file \"%s\"",
191 /* Read the doc string into get_doc_string_buffer.
192 P points beyond the data just read. */
194 p
= get_doc_string_buffer
;
197 int space_left
= (get_doc_string_buffer_size
198 - (p
- get_doc_string_buffer
));
201 /* Allocate or grow the buffer if we need to. */
204 int in_buffer
= p
- get_doc_string_buffer
;
205 get_doc_string_buffer_size
+= 16 * 1024;
206 get_doc_string_buffer
207 = (char *) xrealloc (get_doc_string_buffer
,
208 get_doc_string_buffer_size
+ 1);
209 p
= get_doc_string_buffer
+ in_buffer
;
210 space_left
= (get_doc_string_buffer_size
211 - (p
- get_doc_string_buffer
));
214 /* Read a disk block at a time.
215 If we read the same block last time, maybe skip this? */
216 if (space_left
> 1024 * 8)
217 space_left
= 1024 * 8;
218 nread
= read (fd
, p
, space_left
);
222 error ("Read error on documentation file");
227 if (p
== get_doc_string_buffer
)
228 p1
= index (p
+ offset
, '\037');
230 p1
= index (p
, '\037');
241 /* Scan the text and perform quoting with ^A (char code 1).
242 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */
243 from
= get_doc_string_buffer
+ offset
;
244 to
= get_doc_string_buffer
+ offset
;
260 error ("Invalid data in documentation file -- ^A followed by code 0%o", c
);
266 /* If DEFINITION, read from this buffer
267 the same way we would read bytes from a file. */
270 read_bytecode_pointer
= get_doc_string_buffer
+ offset
;
271 return Fread (Qlambda
);
275 return make_unibyte_string (get_doc_string_buffer
+ offset
,
276 to
- (get_doc_string_buffer
+ offset
));
279 /* Let the data determine whether the string is multibyte,
280 even if Emacs is running in --unibyte mode. */
281 int nchars
= multibyte_chars_in_text (get_doc_string_buffer
+ offset
,
282 to
- (get_doc_string_buffer
+ offset
));
283 return make_string_from_bytes (get_doc_string_buffer
+ offset
,
285 to
- (get_doc_string_buffer
+ offset
));
289 /* Get a string from position FILEPOS and pass it through the Lisp reader.
290 We use this for fetching the bytecode string and constants vector
291 of a compiled function from the .elc file. */
294 read_doc_string (filepos
)
297 return get_doc_string (filepos
, 0, 1);
300 DEFUN ("documentation", Fdocumentation
, Sdocumentation
, 1, 2, 0,
301 "Return the documentation string of FUNCTION.\n\
302 Unless a non-nil second argument RAW is given, the\n\
303 string is passed through `substitute-command-keys'.")
305 Lisp_Object function
, raw
;
309 Lisp_Object tem
, doc
;
311 fun
= Findirect_function (function
);
315 if (XSUBR (fun
)->doc
== 0) return Qnil
;
316 if ((EMACS_INT
) XSUBR (fun
)->doc
>= 0)
317 doc
= build_string (XSUBR (fun
)->doc
);
319 doc
= get_doc_string (make_number (- (EMACS_INT
) XSUBR (fun
)->doc
),
322 else if (COMPILEDP (fun
))
324 if ((XVECTOR (fun
)->size
& PSEUDOVECTOR_SIZE_MASK
) <= COMPILED_DOC_STRING
)
326 tem
= XVECTOR (fun
)->contents
[COMPILED_DOC_STRING
];
329 else if (NATNUMP (tem
) || CONSP (tem
))
330 doc
= get_doc_string (tem
, 0, 0);
334 else if (STRINGP (fun
) || VECTORP (fun
))
336 return build_string ("Keyboard macro.");
338 else if (CONSP (fun
))
341 if (!SYMBOLP (funcar
))
342 return Fsignal (Qinvalid_function
, Fcons (fun
, Qnil
));
343 else if (EQ (funcar
, Qkeymap
))
344 return build_string ("Prefix command (definition is a keymap associating keystrokes with commands).");
345 else if (EQ (funcar
, Qlambda
)
346 || EQ (funcar
, Qautoload
))
349 tem1
= Fcdr (Fcdr (fun
));
353 /* Handle a doc reference--but these never come last
354 in the function body, so reject them if they are last. */
355 else if ((NATNUMP (tem
) || CONSP (tem
))
356 && ! NILP (XCONS (tem1
)->cdr
))
357 doc
= get_doc_string (tem
, 0, 0);
361 else if (EQ (funcar
, Qmocklisp
))
363 else if (EQ (funcar
, Qmacro
))
364 return Fdocumentation (Fcdr (fun
), raw
);
371 Fsignal (Qinvalid_function
, Fcons (fun
, Qnil
));
379 doc
= Fsubstitute_command_keys (doc
);
385 DEFUN ("documentation-property", Fdocumentation_property
, Sdocumentation_property
, 2, 3, 0,
386 "Return the documentation string that is SYMBOL's PROP property.\n\
387 This is like `get', but it can refer to strings stored in the\n\
388 `etc/DOC' file; and if the value is a string, it is passed through\n\
389 `substitute-command-keys'. A non-nil third argument RAW avoids this\n\
392 Lisp_Object symbol
, prop
, raw
;
394 register Lisp_Object tem
;
396 tem
= Fget (symbol
, prop
);
398 tem
= get_doc_string (XINT (tem
) > 0 ? tem
: make_number (- XINT (tem
)), 0, 0);
399 else if (CONSP (tem
))
400 tem
= get_doc_string (tem
, 0, 0);
401 if (NILP (raw
) && STRINGP (tem
))
402 return Fsubstitute_command_keys (tem
);
406 /* Scanning the DOC files and placing docstring offsets into functions. */
409 store_function_docstring (fun
, offset
)
411 /* Use EMACS_INT because we get this from pointer subtraction. */
414 fun
= indirect_function (fun
);
416 /* The type determines where the docstring is stored. */
418 /* Lisp_Subrs have a slot for it. */
420 XSUBR (fun
)->doc
= (char *) - offset
;
422 /* If it's a lisp form, stick it in the form. */
423 else if (CONSP (fun
))
427 tem
= XCONS (fun
)->car
;
428 if (EQ (tem
, Qlambda
) || EQ (tem
, Qautoload
))
430 tem
= Fcdr (Fcdr (fun
));
431 if (CONSP (tem
) && INTEGERP (XCONS (tem
)->car
))
432 XSETFASTINT (XCONS (tem
)->car
, offset
);
434 else if (EQ (tem
, Qmacro
))
435 store_function_docstring (XCONS (fun
)->cdr
, offset
);
438 /* Bytecode objects sometimes have slots for it. */
439 else if (COMPILEDP (fun
))
441 /* This bytecode object must have a slot for the
442 docstring, since we've found a docstring for it. */
443 if ((XVECTOR (fun
)->size
& PSEUDOVECTOR_SIZE_MASK
) > COMPILED_DOC_STRING
)
444 XSETFASTINT (XVECTOR (fun
)->contents
[COMPILED_DOC_STRING
], offset
);
449 DEFUN ("Snarf-documentation", Fsnarf_documentation
, Ssnarf_documentation
,
451 "Used during Emacs initialization, before dumping runnable Emacs,\n\
452 to find pointers to doc strings stored in `etc/DOC...' and\n\
453 record them in function definitions.\n\
454 One arg, FILENAME, a string which does not include a directory.\n\
455 The file is found in `../etc' now; found in the `data-directory'\n\
456 when doc strings are referred to later in the dumped Emacs.")
458 Lisp_Object filename
;
464 register char *p
, *end
;
465 Lisp_Object sym
, fun
, tem
;
467 extern char *index ();
470 if (NILP (Vpurify_flag
))
471 error ("Snarf-documentation can only be called in an undumped Emacs");
474 CHECK_STRING (filename
, 0);
477 name
= (char *) alloca (XSTRING (filename
)->size
+ 14);
478 strcpy (name
, "../etc/");
479 #else /* CANNOT_DUMP */
480 CHECK_STRING (Vdoc_directory
, 0);
481 name
= (char *) alloca (XSTRING (filename
)->size
+
482 XSTRING (Vdoc_directory
)->size
+ 1);
483 strcpy (name
, XSTRING (Vdoc_directory
)->data
);
484 #endif /* CANNOT_DUMP */
485 strcat (name
, XSTRING (filename
)->data
); /*** Add this line ***/
488 /* For VMS versions with limited file name syntax,
489 convert the name to something VMS will allow. */
497 #endif /* not VMS4_4 */
499 strcpy (name
, sys_translate_unix (name
));
503 fd
= open (name
, O_RDONLY
, 0);
505 report_file_error ("Opening doc string file",
506 Fcons (build_string (name
), Qnil
));
507 Vdoc_file_name
= filename
;
513 filled
+= read (fd
, &buf
[filled
], sizeof buf
- 1 - filled
);
519 end
= buf
+ (filled
< 512 ? filled
: filled
- 128);
520 while (p
!= end
&& *p
!= '\037') p
++;
521 /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */
524 end
= index (p
, '\n');
525 sym
= oblookup (Vobarray
, p
+ 2,
526 multibyte_chars_in_text (p
+ 2, end
- p
- 2),
530 /* Attach a docstring to a variable? */
533 /* Install file-position as variable-documentation property
534 and make it negative for a user-variable
535 (doc starts with a `*'). */
536 Fput (sym
, Qvariable_documentation
,
537 make_number ((pos
+ end
+ 1 - buf
)
538 * (end
[1] == '*' ? -1 : 1)));
541 /* Attach a docstring to a function? */
542 else if (p
[1] == 'F')
543 store_function_docstring (sym
, pos
+ end
+ 1 - buf
);
546 error ("DOC file invalid at position %d", pos
);
551 bcopy (end
, buf
, filled
);
557 DEFUN ("substitute-command-keys", Fsubstitute_command_keys
,
558 Ssubstitute_command_keys
, 1, 1, 0,
559 "Substitute key descriptions for command names in STRING.\n\
560 Return a new string which is STRING with substrings of the form \\=\\[COMMAND]\n\
561 replaced by either: a keystroke sequence that will invoke COMMAND,\n\
562 or \"M-x COMMAND\" if COMMAND is not on any keys.\n\
563 Substrings of the form \\=\\{MAPVAR} are replaced by summaries\n\
564 \(made by describe-bindings) of the value of MAPVAR, taken as a keymap.\n\
565 Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR\n\
566 as the keymap for future \\=\\[COMMAND] substrings.\n\
567 \\=\\= quotes the following character and is discarded;\n\
568 thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.")
574 register unsigned char *strp
;
575 register unsigned char *bufp
;
581 unsigned char *start
;
582 int length
, length_byte
;
584 struct gcpro gcpro1
, gcpro2
, gcpro3
, gcpro4
;
591 CHECK_STRING (string
, 0);
595 GCPRO4 (string
, tem
, keymap
, name
);
597 multibyte
= STRING_MULTIBYTE (string
);
600 /* KEYMAP is either nil (which means search all the active keymaps)
601 or a specified local map (which means search just that and the
602 global map). If non-nil, it might come from Voverriding_local_map,
603 or from a \\<mapname> construct in STRING itself.. */
604 keymap
= current_kboard
->Voverriding_terminal_local_map
;
606 keymap
= Voverriding_local_map
;
608 bsize
= STRING_BYTES (XSTRING (string
));
609 bufp
= buf
= (unsigned char *) xmalloc (bsize
);
611 strp
= (unsigned char *) XSTRING (string
)->data
;
612 while (strp
< XSTRING (string
)->data
+ STRING_BYTES (XSTRING (string
)))
614 if (strp
[0] == '\\' && strp
[1] == '=')
616 /* \= quotes the next character;
617 thus, to put in \[ without its special meaning, use \=\[. */
623 int maxlen
= XSTRING (string
)->data
+ STRING_BYTES (XSTRING (string
)) - strp
;
625 STRING_CHAR_AND_LENGTH (strp
, maxlen
, len
);
629 bcopy (strp
, bufp
, len
);
635 *bufp
++ = *strp
++, nchars
++;
637 else if (strp
[0] == '\\' && strp
[1] == '[')
639 Lisp_Object firstkey
;
642 strp
+= 2; /* skip \[ */
645 while ((strp
- (unsigned char *) XSTRING (string
)->data
646 < STRING_BYTES (XSTRING (string
)))
649 length_byte
= strp
- start
;
653 /* Save STRP in IDX. */
654 idx
= strp
- (unsigned char *) XSTRING (string
)->data
;
655 tem
= Fintern (make_string (start
, length_byte
), Qnil
);
656 tem
= Fwhere_is_internal (tem
, keymap
, Qt
, Qnil
);
658 /* Disregard menu bar bindings; it is positively annoying to
659 mention them when there's no menu bar, and it isn't terribly
660 useful even when there is a menu bar. */
663 firstkey
= Faref (tem
, make_number (0));
664 if (EQ (firstkey
, Qmenu_bar
))
668 if (NILP (tem
)) /* but not on any keys */
670 new = (unsigned char *) xrealloc (buf
, bsize
+= 4);
673 bcopy ("M-x ", bufp
, 4);
677 length
= multibyte_chars_in_text (start
, length_byte
);
679 length
= length_byte
;
683 { /* function is on a key */
684 tem
= Fkey_description (tem
);
688 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
689 \<foo> just sets the keymap used for \[cmd]. */
690 else if (strp
[0] == '\\' && (strp
[1] == '{' || strp
[1] == '<'))
692 struct buffer
*oldbuf
;
695 strp
+= 2; /* skip \{ or \< */
698 while ((strp
- (unsigned char *) XSTRING (string
)->data
699 < XSTRING (string
)->size
)
700 && *strp
!= '}' && *strp
!= '>')
703 length_byte
= strp
- start
;
704 strp
++; /* skip } or > */
706 /* Save STRP in IDX. */
707 idx
= strp
- (unsigned char *) XSTRING (string
)->data
;
709 /* Get the value of the keymap in TEM, or nil if undefined.
710 Do this while still in the user's current buffer
711 in case it is a local variable. */
712 name
= Fintern (make_string (start
, length_byte
), Qnil
);
713 tem
= Fboundp (name
);
716 tem
= Fsymbol_value (name
);
718 tem
= get_keymap_1 (tem
, 0, 1);
721 /* Now switch to a temp buffer. */
722 oldbuf
= current_buffer
;
723 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer
));
727 name
= Fsymbol_name (name
);
728 insert_string ("\nUses keymap \"");
729 insert_from_string (name
, 0, 0,
730 XSTRING (name
)->size
,
731 STRING_BYTES (XSTRING (name
)), 1);
732 insert_string ("\", which is not currently defined.\n");
733 if (start
[-1] == '<') keymap
= Qnil
;
735 else if (start
[-1] == '<')
738 describe_map_tree (tem
, 1, Qnil
, Qnil
, (char *)0, 1, 0, 0);
739 tem
= Fbuffer_string ();
741 set_buffer_internal (oldbuf
);
744 start
= XSTRING (tem
)->data
;
745 length
= XSTRING (tem
)->size
;
746 length_byte
= STRING_BYTES (XSTRING (tem
));
748 new = (unsigned char *) xrealloc (buf
, bsize
+= length_byte
);
751 bcopy (start
, bufp
, length_byte
);
754 /* Check STRING again in case gc relocated it. */
755 strp
= (unsigned char *) XSTRING (string
)->data
+ idx
;
757 else if (! multibyte
) /* just copy other chars */
758 *bufp
++ = *strp
++, nchars
++;
762 int maxlen
= XSTRING (string
)->data
+ STRING_BYTES (XSTRING (string
)) - strp
;
764 STRING_CHAR_AND_LENGTH (strp
, maxlen
, len
);
768 bcopy (strp
, bufp
, len
);
775 if (changed
) /* don't bother if nothing substituted */
776 tem
= make_string_from_bytes (buf
, nchars
, bufp
- buf
);
780 RETURN_UNGCPRO (tem
);
786 DEFVAR_LISP ("internal-doc-file-name", &Vdoc_file_name
,
787 "Name of file containing documentation strings of built-in symbols.");
788 Vdoc_file_name
= Qnil
;
790 defsubr (&Sdocumentation
);
791 defsubr (&Sdocumentation_property
);
792 defsubr (&Ssnarf_documentation
);
793 defsubr (&Ssubstitute_command_keys
);