]> code.delx.au - gnu-emacs/blob - src/doc.c
(enriched-mode): Add autoload cookie.
[gnu-emacs] / src / doc.c
1 /* Record indices of function doc strings stored in a file.
2 Copyright (C) 1985, 1986, 1993, 1994 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21 #include <config.h>
22
23 #include <sys/types.h>
24 #include <sys/file.h> /* Must be after sys/types.h for USG and BSD4_1*/
25
26 #ifdef USG5
27 #include <fcntl.h>
28 #endif
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #ifndef O_RDONLY
35 #define O_RDONLY 0
36 #endif
37
38 #include "lisp.h"
39 #include "buffer.h"
40 #include "keyboard.h"
41
42 Lisp_Object Vdoc_file_name;
43
44 extern Lisp_Object Voverriding_local_map;
45
46 /* For VMS versions with limited file name syntax,
47 convert the name to something VMS will allow. */
48 static void
49 munge_doc_file_name (name)
50 char *name;
51 {
52 #ifdef VMS
53 #ifndef VMS4_4
54 /* For VMS versions with limited file name syntax,
55 convert the name to something VMS will allow. */
56 p = name;
57 while (*p)
58 {
59 if (*p == '-')
60 *p = '_';
61 p++;
62 }
63 #endif /* not VMS4_4 */
64 #ifdef VMS4_4
65 strcpy (name, sys_translate_unix (name));
66 #endif /* VMS4_4 */
67 #endif /* VMS */
68 }
69
70 Lisp_Object
71 get_doc_string (filepos)
72 long filepos;
73 {
74 char buf[512 * 32 + 1];
75 register int fd;
76 register char *name;
77 register char *p, *p1;
78 register int count;
79 int minsize;
80 extern char *index ();
81
82 if (!STRINGP (Vdoc_directory) || !STRINGP (Vdoc_file_name))
83 return Qnil;
84
85 minsize = XSTRING (Vdoc_directory)->size;
86 /* sizeof ("../etc/") == 8 */
87 if (minsize < 8)
88 minsize = 8;
89 name = (char *) alloca (minsize + XSTRING (Vdoc_file_name)->size + 8);
90 strcpy (name, XSTRING (Vdoc_directory)->data);
91 strcat (name, XSTRING (Vdoc_file_name)->data);
92 munge_doc_file_name (name);
93
94 fd = open (name, O_RDONLY, 0);
95 if (fd < 0)
96 {
97 #ifndef CANNOT_DUMP
98 if (!NILP (Vpurify_flag))
99 {
100 /* Preparing to dump; DOC file is probably not installed.
101 So check in ../etc. */
102 strcpy (name, "../etc/");
103 strcat (name, XSTRING (Vdoc_file_name)->data);
104 munge_doc_file_name (name);
105
106 fd = open (name, O_RDONLY, 0);
107 }
108 #endif
109
110 if (fd < 0)
111 error ("Cannot open doc string file \"%s\"", name);
112 }
113
114 if (0 > lseek (fd, filepos, 0))
115 {
116 close (fd);
117 error ("Position %ld out of range in doc string file \"%s\"",
118 filepos, name);
119 }
120 p = buf;
121 while (p != buf + sizeof buf - 1)
122 {
123 count = read (fd, p, 512);
124 p[count] = 0;
125 if (!count)
126 break;
127 p1 = index (p, '\037');
128 if (p1)
129 {
130 *p1 = 0;
131 p = p1;
132 break;
133 }
134 p += count;
135 }
136 close (fd);
137 return make_string (buf, p - buf);
138 }
139
140 DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
141 "Return the documentation string of FUNCTION.\n\
142 Unless a non-nil second argument is given, the\n\
143 string is passed through `substitute-command-keys'.")
144 (function, raw)
145 Lisp_Object function, raw;
146 {
147 Lisp_Object fun;
148 Lisp_Object funcar;
149 Lisp_Object tem, doc;
150
151 fun = Findirect_function (function);
152
153 switch (XTYPE (fun))
154 {
155 case Lisp_Subr:
156 if (XSUBR (fun)->doc == 0) return Qnil;
157 if ((EMACS_INT) XSUBR (fun)->doc >= 0)
158 doc = build_string (XSUBR (fun)->doc);
159 else
160 doc = get_doc_string (- (EMACS_INT) XSUBR (fun)->doc);
161 break;
162
163 case Lisp_Compiled:
164 if (XVECTOR (fun)->size <= COMPILED_DOC_STRING)
165 return Qnil;
166 tem = XVECTOR (fun)->contents[COMPILED_DOC_STRING];
167 if (STRINGP (tem))
168 doc = tem;
169 else if (INTEGERP (tem) && XINT (tem) >= 0)
170 doc = get_doc_string (XFASTINT (tem));
171 else
172 return Qnil;
173 break;
174
175 case Lisp_String:
176 case Lisp_Vector:
177 return build_string ("Keyboard macro.");
178
179 case Lisp_Cons:
180 funcar = Fcar (fun);
181 if (!SYMBOLP (funcar))
182 return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
183 else if (EQ (funcar, Qkeymap))
184 return build_string ("Prefix command (definition is a keymap associating keystrokes with\n\
185 subcommands.)");
186 else if (EQ (funcar, Qlambda)
187 || EQ (funcar, Qautoload))
188 {
189 tem = Fcar (Fcdr (Fcdr (fun)));
190 if (STRINGP (tem))
191 doc = tem;
192 else if (INTEGERP (tem) && XINT (tem) >= 0)
193 doc = get_doc_string (XFASTINT (tem));
194 else
195 return Qnil;
196
197 break;
198 }
199 else if (EQ (funcar, Qmocklisp))
200 return Qnil;
201 else if (EQ (funcar, Qmacro))
202 return Fdocumentation (Fcdr (fun), raw);
203
204 /* Fall through to the default to report an error. */
205
206 default:
207 return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
208 }
209
210 if (NILP (raw))
211 {
212 struct gcpro gcpro1;
213
214 GCPRO1 (doc);
215 doc = Fsubstitute_command_keys (doc);
216 UNGCPRO;
217 }
218 return doc;
219 }
220
221 DEFUN ("documentation-property", Fdocumentation_property, Sdocumentation_property, 2, 3, 0,
222 "Return the documentation string that is SYMBOL's PROP property.\n\
223 This is like `get', but it can refer to strings stored in the\n\
224 `etc/DOC' file; and if the value is a string, it is passed through\n\
225 `substitute-command-keys'. A non-nil third argument avoids this\n\
226 translation.")
227 (sym, prop, raw)
228 Lisp_Object sym, prop, raw;
229 {
230 register Lisp_Object tem;
231
232 tem = Fget (sym, prop);
233 if (INTEGERP (tem))
234 tem = get_doc_string (XINT (tem) > 0 ? XINT (tem) : - XINT (tem));
235 if (NILP (raw) && STRINGP (tem))
236 return Fsubstitute_command_keys (tem);
237 return tem;
238 }
239 \f
240 /* Scanning the DOC files and placing docstring offsets into functions. */
241
242 static void
243 store_function_docstring (fun, offset)
244 Lisp_Object fun;
245 int offset;
246 {
247 fun = indirect_function (fun);
248
249 /* The type determines where the docstring is stored. */
250
251 /* Lisp_Subrs have a slot for it. */
252 if (SUBRP (fun))
253 XSUBR (fun)->doc = (char *) - offset;
254
255 /* If it's a lisp form, stick it in the form. */
256 else if (CONSP (fun))
257 {
258 Lisp_Object tem;
259
260 tem = XCONS (fun)->car;
261 if (EQ (tem, Qlambda) || EQ (tem, Qautoload))
262 {
263 tem = Fcdr (Fcdr (fun));
264 if (CONSP (tem) && INTEGERP (XCONS (tem)->car))
265 XSETFASTINT (XCONS (tem)->car, offset);
266 }
267 else if (EQ (tem, Qmacro))
268 store_function_docstring (XCONS (fun)->cdr, offset);
269 }
270
271 /* Bytecode objects sometimes have slots for it. */
272 else if (COMPILEDP (fun))
273 {
274 /* This bytecode object must have a slot for the
275 docstring, since we've found a docstring for it. */
276 if (XVECTOR (fun)->size > COMPILED_DOC_STRING)
277 XSETFASTINT (XVECTOR (fun)->contents[COMPILED_DOC_STRING], offset);
278 }
279 }
280
281
282 DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
283 1, 1, 0,
284 "Used during Emacs initialization, before dumping runnable Emacs,\n\
285 to find pointers to doc strings stored in `etc/DOC...' and\n\
286 record them in function definitions.\n\
287 One arg, FILENAME, a string which does not include a directory.\n\
288 The file is found in `../etc' now; found in the `data-directory'\n\
289 when doc strings are referred to later in the dumped Emacs.")
290 (filename)
291 Lisp_Object filename;
292 {
293 int fd;
294 char buf[1024 + 1];
295 register int filled;
296 register int pos;
297 register char *p, *end;
298 Lisp_Object sym, fun, tem;
299 char *name;
300 extern char *index ();
301
302 #ifndef CANNOT_DUMP
303 if (NILP (Vpurify_flag))
304 error ("Snarf-documentation can only be called in an undumped Emacs");
305 #endif
306
307 CHECK_STRING (filename, 0);
308
309 #ifndef CANNOT_DUMP
310 name = (char *) alloca (XSTRING (filename)->size + 14);
311 strcpy (name, "../etc/");
312 #else /* CANNOT_DUMP */
313 CHECK_STRING (Vdoc_directory, 0);
314 name = (char *) alloca (XSTRING (filename)->size +
315 XSTRING (Vdoc_directory)->size + 1);
316 strcpy (name, XSTRING (Vdoc_directory)->data);
317 #endif /* CANNOT_DUMP */
318 strcat (name, XSTRING (filename)->data); /*** Add this line ***/
319 #ifdef VMS
320 #ifndef VMS4_4
321 /* For VMS versions with limited file name syntax,
322 convert the name to something VMS will allow. */
323 p = name;
324 while (*p)
325 {
326 if (*p == '-')
327 *p = '_';
328 p++;
329 }
330 #endif /* not VMS4_4 */
331 #ifdef VMS4_4
332 strcpy (name, sys_translate_unix (name));
333 #endif /* VMS4_4 */
334 #endif /* VMS */
335
336 fd = open (name, O_RDONLY, 0);
337 if (fd < 0)
338 report_file_error ("Opening doc string file",
339 Fcons (build_string (name), Qnil));
340 Vdoc_file_name = filename;
341 filled = 0;
342 pos = 0;
343 while (1)
344 {
345 if (filled < 512)
346 filled += read (fd, &buf[filled], sizeof buf - 1 - filled);
347 if (!filled)
348 break;
349
350 buf[filled] = 0;
351 p = buf;
352 end = buf + (filled < 512 ? filled : filled - 128);
353 while (p != end && *p != '\037') p++;
354 /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */
355 if (p != end)
356 {
357 end = index (p, '\n');
358 sym = oblookup (Vobarray, p + 2, end - p - 2);
359 if (SYMBOLP (sym))
360 {
361 /* Attach a docstring to a variable? */
362 if (p[1] == 'V')
363 {
364 /* Install file-position as variable-documentation property
365 and make it negative for a user-variable
366 (doc starts with a `*'). */
367 Fput (sym, Qvariable_documentation,
368 make_number ((pos + end + 1 - buf)
369 * (end[1] == '*' ? -1 : 1)));
370 }
371
372 /* Attach a docstring to a function? */
373 else if (p[1] == 'F')
374 store_function_docstring (sym, pos + end + 1 - buf);
375
376 else
377 error ("DOC file invalid at position %d", pos);
378 }
379 }
380 pos += end - buf;
381 filled -= end - buf;
382 bcopy (end, buf, filled);
383 }
384 close (fd);
385 return Qnil;
386 }
387 \f
388 DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
389 Ssubstitute_command_keys, 1, 1, 0,
390 "Substitute key descriptions for command names in STRING.\n\
391 Return a new string which is STRING with substrings of the form \\=\\[COMMAND]\n\
392 replaced by either: a keystroke sequence that will invoke COMMAND,\n\
393 or \"M-x COMMAND\" if COMMAND is not on any keys.\n\
394 Substrings of the form \\=\\{MAPVAR} are replaced by summaries\n\
395 \(made by describe-bindings) of the value of MAPVAR, taken as a keymap.\n\
396 Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR\n\
397 as the keymap for future \\=\\[COMMAND] substrings.\n\
398 \\=\\= quotes the following character and is discarded;\n\
399 thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.")
400 (str)
401 Lisp_Object str;
402 {
403 unsigned char *buf;
404 int changed = 0;
405 register unsigned char *strp;
406 register unsigned char *bufp;
407 int idx;
408 int bsize;
409 unsigned char *new;
410 Lisp_Object tem;
411 Lisp_Object keymap;
412 unsigned char *start;
413 int length;
414 Lisp_Object name;
415 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
416
417 if (NILP (str))
418 return Qnil;
419
420 CHECK_STRING (str, 0);
421 tem = Qnil;
422 keymap = Qnil;
423 name = Qnil;
424 GCPRO4 (str, tem, keymap, name);
425
426 /* KEYMAP is either nil (which means search all the active keymaps)
427 or a specified local map (which means search just that and the
428 global map). If non-nil, it might come from Voverriding_local_map,
429 or from a \\<mapname> construct in STR itself.. */
430 keymap = Voverriding_local_map;
431
432 bsize = XSTRING (str)->size;
433 bufp = buf = (unsigned char *) xmalloc (bsize);
434
435 strp = (unsigned char *) XSTRING (str)->data;
436 while (strp < (unsigned char *) XSTRING (str)->data + XSTRING (str)->size)
437 {
438 if (strp[0] == '\\' && strp[1] == '=')
439 {
440 /* \= quotes the next character;
441 thus, to put in \[ without its special meaning, use \=\[. */
442 changed = 1;
443 *bufp++ = strp[2];
444 strp += 3;
445 }
446 else if (strp[0] == '\\' && strp[1] == '[')
447 {
448 Lisp_Object firstkey;
449
450 changed = 1;
451 strp += 2; /* skip \[ */
452 start = strp;
453
454 while ((strp - (unsigned char *) XSTRING (str)->data
455 < XSTRING (str)->size)
456 && *strp != ']')
457 strp++;
458 length = strp - start;
459 strp++; /* skip ] */
460
461 /* Save STRP in IDX. */
462 idx = strp - (unsigned char *) XSTRING (str)->data;
463 tem = Fintern (make_string (start, length), Qnil);
464 tem = Fwhere_is_internal (tem, keymap, Qt, Qnil);
465
466 /* Disregard menu bar bindings; it is positively annoying to
467 mention them when there's no menu bar, and it isn't terribly
468 useful even when there is a menu bar. */
469 if (!NILP (tem))
470 {
471 firstkey = Faref (tem, make_number (0));
472 if (EQ (firstkey, Qmenu_bar))
473 tem = Qnil;
474 }
475
476 if (NILP (tem)) /* but not on any keys */
477 {
478 new = (unsigned char *) xrealloc (buf, bsize += 4);
479 bufp += new - buf;
480 buf = new;
481 bcopy ("M-x ", bufp, 4);
482 bufp += 4;
483 goto subst;
484 }
485 else
486 { /* function is on a key */
487 tem = Fkey_description (tem);
488 goto subst_string;
489 }
490 }
491 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
492 \<foo> just sets the keymap used for \[cmd]. */
493 else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<'))
494 {
495 struct buffer *oldbuf;
496
497 changed = 1;
498 strp += 2; /* skip \{ or \< */
499 start = strp;
500
501 while ((strp - (unsigned char *) XSTRING (str)->data
502 < XSTRING (str)->size)
503 && *strp != '}' && *strp != '>')
504 strp++;
505 length = strp - start;
506 strp++; /* skip } or > */
507
508 /* Save STRP in IDX. */
509 idx = strp - (unsigned char *) XSTRING (str)->data;
510
511 /* Get the value of the keymap in TEM, or nil if undefined.
512 Do this while still in the user's current buffer
513 in case it is a local variable. */
514 name = Fintern (make_string (start, length), Qnil);
515 tem = Fboundp (name);
516 if (! NILP (tem))
517 {
518 tem = Fsymbol_value (name);
519 if (! NILP (tem))
520 tem = get_keymap_1 (tem, 0, 1);
521 }
522
523 /* Now switch to a temp buffer. */
524 oldbuf = current_buffer;
525 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
526
527 if (NILP (tem))
528 {
529 name = Fsymbol_name (name);
530 insert_string ("\nUses keymap \"");
531 insert_from_string (name, 0, XSTRING (name)->size, 1);
532 insert_string ("\", which is not currently defined.\n");
533 if (start[-1] == '<') keymap = Qnil;
534 }
535 else if (start[-1] == '<')
536 keymap = tem;
537 else
538 describe_map_tree (tem, 1, Qnil, Qnil, 0, 1);
539 tem = Fbuffer_string ();
540 Ferase_buffer ();
541 set_buffer_internal (oldbuf);
542
543 subst_string:
544 start = XSTRING (tem)->data;
545 length = XSTRING (tem)->size;
546 subst:
547 new = (unsigned char *) xrealloc (buf, bsize += length);
548 bufp += new - buf;
549 buf = new;
550 bcopy (start, bufp, length);
551 bufp += length;
552 /* Check STR again in case gc relocated it. */
553 strp = (unsigned char *) XSTRING (str)->data + idx;
554 }
555 else /* just copy other chars */
556 *bufp++ = *strp++;
557 }
558
559 if (changed) /* don't bother if nothing substituted */
560 tem = make_string (buf, bufp - buf);
561 else
562 tem = str;
563 xfree (buf);
564 RETURN_UNGCPRO (tem);
565 }
566 \f
567 syms_of_doc ()
568 {
569 DEFVAR_LISP ("internal-doc-file-name", &Vdoc_file_name,
570 "Name of file containing documentation strings of built-in symbols.");
571 Vdoc_file_name = Qnil;
572
573 defsubr (&Sdocumentation);
574 defsubr (&Sdocumentation_property);
575 defsubr (&Ssnarf_documentation);
576 defsubr (&Ssubstitute_command_keys);
577 }