comparison src/doc.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Record indices of function doc strings stored in a file.
2 Copyright (C) 1985, 1986, 1992, 1993, 1994, 1995
3 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Synched up with: FSF 19.30. */
23
24 /* This file has been Mule-ized except as noted. */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "buffer.h"
30 #include "bytecode.h"
31 #include "insdel.h"
32 #include "keymap.h"
33
34 #include "sysfile.h"
35
36
37 Lisp_Object Vdoc_file_name;
38
39 #ifdef VMS
40 /* For VMS versions with limited file name syntax,
41 convert the name to something VMS will allow. */
42 static void
43 munge_doc_file_name (char *name)
44 {
45 #ifndef VMS4_4
46 /* For VMS versions with limited file name syntax,
47 convert the name to something VMS will allow. */
48 p = name;
49 while (*p)
50 {
51 if (*p == '-')
52 *p = '_';
53 p++;
54 }
55 #endif /* not VMS4_4 */
56 #ifdef VMS4_4
57 strcpy (name, sys_translate_unix (name));
58 #endif /* VMS4_4 */
59 }
60 #else /* NOT VMS */
61 #define munge_doc_file_name(name)
62 #endif /* VMS */
63
64 /* Read and return doc string from open file descriptor FD
65 at position POSITION. Does not close the file. Returns
66 string; or if error, returns a cons holding the error
67 data to pass to Fsignal. NAME_NONRELOC and NAME_RELOC
68 are only used for the error messages. */
69
70 Lisp_Object
71 unparesseuxify_doc_string (int fd, EMACS_INT position,
72 char *name_nonreloc, Lisp_Object name_reloc)
73 {
74 char buf[512 * 32 + 1];
75 char *buffer = buf;
76 int buffer_size = sizeof (buf);
77 char *from, *to;
78 REGISTER char *p = buffer;
79 Lisp_Object return_me;
80
81 if (0 > lseek (fd, position, 0))
82 {
83 if (name_nonreloc)
84 name_reloc = build_string (name_nonreloc);
85 return_me = list3 (build_string
86 ("Position out of range in doc string file"),
87 name_reloc, make_int (position));
88 goto done;
89 }
90
91 /* Read the doc string into a buffer.
92 Use the fixed buffer BUF if it is big enough; otherwise allocate one.
93 We store the buffer in use in BUFFER and its size in BUFFER_SIZE. */
94
95 while (1)
96 {
97 int space_left = buffer_size - (p - buffer);
98 int nread;
99
100 /* Switch to a bigger buffer if we need one. */
101 if (space_left == 0)
102 {
103 char * old_buffer = buffer;
104 if (buffer == buf) {
105 buffer = (char *) xmalloc (buffer_size *= 2);
106 memcpy (buffer, old_buffer, p - old_buffer);
107 } else {
108 buffer = (char *) xrealloc (buffer, buffer_size *= 2);
109 }
110 p += buffer - old_buffer;
111 space_left = buffer_size - (p - buffer);
112 }
113
114 /* Don't read too too much at one go. */
115 if (space_left > 1024 * 8)
116 space_left = 1024 * 8;
117 nread = read (fd, p, space_left);
118 if (nread < 0)
119 {
120 return_me = list1 (build_string
121 ("Read error on documentation file"));
122 goto done;
123 }
124 p[nread] = 0;
125 if (!nread)
126 break;
127 {
128 char *p1 = strchr (p, '\037'); /* End of doc string marker */
129 if (p1)
130 {
131 *p1 = 0;
132 p = p1;
133 break;
134 }
135 }
136 p += nread;
137 }
138
139 /* Scan the text and remove quoting with ^A (char code 1).
140 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */
141 from = to = buffer;
142 while (from < p)
143 {
144 if (*from != 1 /*^A*/)
145 *to++ = *from++;
146 else
147 {
148 int c = *(++from);
149
150 from++;
151 switch (c)
152 {
153 case 1: *to++ = c; break;
154 case '0': *to++ = '\0'; break;
155 case '_': *to++ = '\037'; break;
156 default:
157 return_me = list2 (build_string
158 ("Invalid data in documentation file -- ^A followed by weird code"),
159 make_int (c));
160 goto done;
161 }
162 }
163 }
164
165 /* #### mrb: following STILL completely broken */
166 return_me = make_ext_string ((Bufbyte *) buffer, to - buffer, FORMAT_BINARY);
167
168 done:
169 if (buffer != buf) /* We must have allocated buffer above */
170 xfree (buffer);
171 return return_me;
172 }
173
174 /* Extract a doc string from a file. FILEPOS says where to get it.
175 (This could actually be byte code instructions/constants instead
176 of a doc string.)
177 If it is an integer, use that position in the standard DOC-... file.
178 If it is (FILE . INTEGER), use FILE as the file name
179 and INTEGER as the position in that file.
180 But if INTEGER is negative, make it positive.
181 (A negative integer is used for user variables, so we can distinguish
182 them without actually fetching the doc string.) */
183
184 static Lisp_Object
185 get_doc_string (Lisp_Object filepos)
186 {
187 /* !!#### This function has not been Mule-ized */
188 REGISTER int fd;
189 REGISTER char *name_nonreloc = 0;
190 int minsize;
191 EMACS_INT position;
192 Lisp_Object file, tem;
193 Lisp_Object name_reloc;
194
195 if (INTP (filepos))
196 {
197 file = Vdoc_file_name;
198 position = XINT (filepos);
199 }
200 else if (CONSP (filepos) && INTP (XCDR (filepos)))
201 {
202 file = XCAR (filepos);
203 position = XINT (XCDR (filepos));
204 if (position < 0)
205 position = - position;
206 }
207 else
208 return Qnil;
209
210 if (!STRINGP (file))
211 return Qnil;
212
213 /* Put the file name in NAME as a C string.
214 If it is relative, combine it with Vdoc_directory. */
215
216 tem = Ffile_name_absolute_p (file);
217 if (NILP (tem))
218 {
219 /* XEmacs: Move this check here. OK if called during loadup to
220 load byte code instructions. */
221 if (!STRINGP (Vdoc_directory))
222 return Qnil;
223
224 minsize = string_length (XSTRING (Vdoc_directory));
225 /* sizeof ("../lib-src/") == 12 */
226 if (minsize < 12)
227 minsize = 12;
228 name_nonreloc
229 = (char *) alloca (minsize + string_length (XSTRING (file)) + 8);
230 strcpy (name_nonreloc, (char *) string_data (XSTRING (Vdoc_directory)));
231 strcat (name_nonreloc, (char *) string_data (XSTRING (file)));
232 munge_doc_file_name (name_nonreloc);
233 }
234 else
235 name_reloc = file;
236
237 fd = open (name_nonreloc ? name_nonreloc :
238 (char *) string_data (XSTRING (name_reloc)), O_RDONLY, 0);
239 if (fd < 0)
240 {
241 #ifndef CANNOT_DUMP
242 if (purify_flag)
243 {
244 name_nonreloc
245 /* sizeof ("../lib-src/") == 12 */
246 = (char *) alloca (12 + string_length (XSTRING (file)) + 8);
247 /* Preparing to dump; DOC file is probably not installed.
248 So check in ../lib-src. */
249 strcpy (name_nonreloc, "../lib-src/");
250 strcat (name_nonreloc, (char *) string_data (XSTRING (file)));
251 munge_doc_file_name (name_nonreloc);
252
253 fd = open (name_nonreloc, O_RDONLY, 0);
254 }
255 #endif
256
257 if (fd < 0)
258 error ("Cannot open doc string file \"%s\"",
259 name_nonreloc ? name_nonreloc :
260 (char *) string_data (XSTRING (name_reloc)));
261 }
262
263 tem = unparesseuxify_doc_string (fd, position, name_nonreloc, name_reloc);
264 close (fd);
265
266 if (!STRINGP (tem))
267 signal_error (Qerror, tem);
268
269 return tem;
270 }
271
272 /* Get a string from position FILEPOS and pass it through the Lisp reader.
273 We use this for fetching the bytecode string and constants vector
274 of a compiled function from the .elc file. */
275
276 Lisp_Object
277 read_doc_string (Lisp_Object filepos)
278 {
279 Lisp_Object string = get_doc_string (filepos);
280
281 if (!STRINGP (string))
282 signal_simple_error ("loading bytecode failed to return string", string);
283 return Fread (string);
284 }
285
286 DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0 /*
287 Return the documentation string of FUNCTION.
288 Unless a non-nil second argument is given, the
289 string is passed through `substitute-command-keys'.
290 */ )
291 (function, raw)
292 Lisp_Object function, raw;
293 {
294 /* This function can GC */
295 Lisp_Object fun;
296 Lisp_Object doc;
297
298 fun = Findirect_function (function);
299
300 if (SUBRP (fun))
301 {
302 if (XSUBR (fun)->doc == 0)
303 return Qnil;
304 if ((EMACS_INT) XSUBR (fun)->doc >= 0)
305 doc = build_string (XSUBR (fun)->doc);
306 else
307 doc = get_doc_string (make_int (- (EMACS_INT) XSUBR (fun)->doc));
308 }
309 else if (COMPILED_FUNCTIONP (fun))
310 {
311 Lisp_Object tem;
312 struct Lisp_Compiled_Function *b = XCOMPILED_FUNCTION (fun);
313 if (! (b->flags.documentationp))
314 return Qnil;
315 tem = compiled_function_documentation (b);
316 if (STRINGP (tem))
317 doc = tem;
318 else if (NATNUMP (tem) || CONSP (tem))
319 doc = get_doc_string (tem);
320 else
321 return Qnil;
322 }
323 else if (KEYMAPP (fun))
324 return build_translated_string ("Prefix command (definition is a keymap of subcommands).");
325 else if (STRINGP (fun) || VECTORP (fun))
326 return build_translated_string ("Keyboard macro.");
327 else if (CONSP (fun))
328 {
329 Lisp_Object funcar = Fcar (fun);
330
331 if (!SYMBOLP (funcar))
332 return Fsignal (Qinvalid_function, list1 (fun));
333 else if (EQ (funcar, Qlambda)
334 || EQ (funcar, Qautoload))
335 {
336 Lisp_Object tem, tem1;
337 tem1 = Fcdr (Fcdr (fun));
338 tem = Fcar (tem1);
339 if (STRINGP (tem))
340 doc = tem;
341 /* Handle a doc reference--but these never come last
342 in the function body, so reject them if they are last. */
343 else if ((NATNUMP (tem) || CONSP (tem))
344 && ! NILP (XCDR (tem1)))
345 doc = get_doc_string (tem);
346 else
347 return Qnil;
348 }
349 #ifdef MOCKLISP_SUPPORT
350 else if (EQ (funcar, Qmocklisp))
351 return Qnil;
352 #endif
353 else if (EQ (funcar, Qmacro))
354 return Fdocumentation (Fcdr (fun), raw);
355 else
356 goto oops;
357 }
358 else
359 {
360 oops:
361 return Fsignal (Qinvalid_function, list1 (fun));
362 }
363
364 if (NILP (raw))
365 {
366 struct gcpro gcpro1;
367 #ifdef I18N3
368 Lisp_Object domain = Qnil;
369 if (COMPILED_FUNCTIONP (fun))
370 domain = Fcompiled_function_domain (fun);
371 if (NILP (domain))
372 doc = Fgettext (doc);
373 else
374 doc = Fdgettext (domain, doc);
375 #endif
376
377 GCPRO1 (doc);
378 doc = Fsubstitute_command_keys (doc);
379 UNGCPRO;
380 }
381 return doc;
382 }
383
384 DEFUN ("documentation-property", Fdocumentation_property,
385 Sdocumentation_property, 2, 3, 0 /*
386 Return the documentation string that is SYMBOL's PROP property.
387 This is like `get', but it can refer to strings stored in the
388 `doc-directory/DOC' file; and if the value is a string, it is passed
389 through `substitute-command-keys'. A non-nil third argument avoids this
390 translation.
391 */ )
392 (sym, prop, raw)
393 Lisp_Object sym, prop, raw;
394 {
395 /* This function can GC */
396 REGISTER Lisp_Object doc;
397 #ifdef I18N3
398 REGISTER Lisp_Object domain;
399 #endif
400
401 doc = Fget (sym, prop, Qnil);
402 if (INTP (doc))
403 doc = get_doc_string (XINT (doc) > 0 ? doc : make_int (- XINT (doc)));
404 else if (CONSP (doc))
405 doc = get_doc_string (doc);
406 #ifdef I18N3
407 if (!NILP (doc))
408 {
409 domain = Fget (sym, Qvariable_domain, Qnil);
410 if (NILP (domain))
411 doc = Fgettext (doc);
412 else
413 doc = Fdgettext (domain, doc);
414 }
415 #endif
416 if (NILP (raw) && STRINGP (doc))
417 doc = Fsubstitute_command_keys (doc);
418 return doc;
419 }
420
421 static void
422 weird_doc (Lisp_Object sym, CONST char *weirdness, CONST char *type, int pos)
423 {
424 #ifdef ENERGIZE /* hide kludgery... */
425 if (!strcmp (weirdness, GETTEXT ("duplicate"))) return;
426 #endif
427 message ("Note: Strange doc (%s) for %s %s @ %d",
428 weirdness, type, string_data (XSYMBOL (sym)->name), pos);
429 }
430
431
432 DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
433 1, 1, 0 /*
434 Used during Emacs initialization, before dumping runnable Emacs,
435 to find pointers to doc strings stored in `.../lib-src/DOC' and
436 record them in function definitions.
437 One arg, FILENAME, a string which does not include a directory.
438 The file is written to `../lib-src', and later found in `exec-directory'
439 when doc strings are referred to in the dumped Emacs.
440 */ )
441 (filename)
442 Lisp_Object filename;
443 {
444 /* !!#### This function has not been Mule-ized */
445 int fd;
446 char buf[1024 + 1];
447 REGISTER int filled;
448 REGISTER int pos;
449 REGISTER char *p, *end;
450 Lisp_Object sym, fun, tem;
451 char *name;
452
453 #ifndef CANNOT_DUMP
454 if (!purify_flag)
455 error ("Snarf-documentation can only be called in an undumped Emacs");
456 #endif
457
458 CHECK_STRING (filename);
459
460 #ifndef CANNOT_DUMP
461 name = (char *) alloca (string_length (XSTRING (filename)) + 14);
462 strcpy (name, "../lib-src/");
463 #else /* CANNOT_DUMP */
464 CHECK_STRING (Vdoc_directory);
465 name = (char *) alloca (string_length (XSTRING (filename))
466 + string_length (XSTRING (Vdoc_directory))
467 + 1);
468 strcpy (name, (char *) string_data (XSTRING (Vdoc_directory)));
469 #endif /* CANNOT_DUMP */
470 strcat (name, (char *) string_data (XSTRING (filename)));
471 #ifdef VMS
472 #ifndef VMS4_4
473 /* For VMS versions with limited file name syntax,
474 convert the name to something VMS will allow. */
475 p = name;
476 while (*p)
477 {
478 if (*p == '-')
479 *p = '_';
480 p++;
481 }
482 #endif /* not VMS4_4 */
483 #ifdef VMS4_4
484 strcpy (name, sys_translate_unix (name));
485 #endif /* VMS4_4 */
486 #endif /* VMS */
487
488 fd = open (name, O_RDONLY, 0);
489 if (fd < 0)
490 report_file_error ("Opening doc string file",
491 Fcons (build_string (name), Qnil));
492 Vdoc_file_name = filename;
493 filled = 0;
494 pos = 0;
495 while (1)
496 {
497 if (filled < 512)
498 filled += read (fd, &buf[filled], sizeof buf - 1 - filled);
499 if (!filled)
500 break;
501
502 buf[filled] = 0;
503 p = buf;
504 end = buf + (filled < 512 ? filled : filled - 128);
505 while (p != end && *p != '\037') p++;
506 /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */
507 if (p != end)
508 {
509 end = strchr (p, '\n');
510 sym = oblookup (Vobarray, (Bufbyte *) p + 2, end - p - 2);
511 if (SYMBOLP (sym))
512 {
513 Lisp_Object offset = make_int (pos + end + 1 - buf);
514 /* Attach a docstring to a variable */
515 if (p[1] == 'V')
516 {
517 /* Install file-position as variable-documentation property
518 and make it negative for a user-variable
519 (doc starts with a `*'). */
520 Lisp_Object old = Fget (sym, Qvariable_documentation, Qzero);
521 if (!ZEROP (old))
522 {
523 weird_doc (sym, GETTEXT ("duplicate"),
524 GETTEXT ("variable"), pos);
525 /* In the case of duplicate doc file entries, always
526 take the later one. But if the doc is not an int
527 (a string, say) leave it alone. */
528 if (!INTP (old))
529 goto weird;
530 }
531 Fput (sym, Qvariable_documentation,
532 ((end[1] == '*')
533 ? make_int (- XINT (offset))
534 : offset));
535 }
536 /* Attach a docstring to a function.
537 The type determines where the docstring is stored. */
538 else if (p[1] == 'F')
539 {
540 fun = XSYMBOL (sym)->function;/*indirect_function (sym,0);*/
541
542 if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
543 fun = XCDR (fun);
544
545 if (UNBOUNDP (fun))
546 {
547 /* May have been #if'ed out or something */
548 weird_doc (sym, GETTEXT ("not fboundp"),
549 GETTEXT ("function"), pos);
550 goto weird;
551 }
552 else if (SUBRP (fun))
553 {
554 /* Lisp_Subrs have a slot for it. */
555 if (XSUBR (fun)->doc)
556 {
557 weird_doc (sym, GETTEXT ("duplicate"),
558 GETTEXT ("subr"), pos);
559 goto weird;
560 }
561 XSUBR (fun)->doc = (char *) (- XINT (offset));
562 }
563 else if (CONSP (fun))
564 {
565 /* If it's a lisp form, stick it in the form. */
566 tem = XCAR (fun);
567 if (EQ (tem, Qlambda) || EQ (tem, Qautoload))
568 {
569 tem = Fcdr (Fcdr (fun));
570 if (CONSP (tem) &&
571 INTP (XCAR (tem)))
572 {
573 Lisp_Object old = XCAR (tem);
574 if (!ZEROP (old))
575 {
576 weird_doc (sym, GETTEXT ("duplicate"),
577 (EQ (tem, Qlambda)
578 ? GETTEXT ("lambda")
579 : GETTEXT ("autoload")),
580 pos);
581 /* In the case of duplicate doc file entries,
582 always take the later one. But if the doc
583 is not an int (a string, say) leave it
584 alone. */
585 if (!INTP (old))
586 goto weird;
587 }
588 XCAR (tem) = offset;
589 }
590 else goto weird_function;
591 }
592 else goto weird_function;
593 }
594 else if (COMPILED_FUNCTIONP (fun))
595 {
596 /* Compiled-Function objects sometimes have
597 slots for it. */
598 struct Lisp_Compiled_Function *b =
599 XCOMPILED_FUNCTION (fun);
600
601 /* This compiled-function object must have a
602 slot for the docstring, since we've found a
603 docstring for it. Unless there were multiple
604 definitions of it, and the latter one didn't
605 have any doc, which is a legal if slightly
606 bogus situation, so don't blow up. */
607
608 if (! (b->flags.documentationp))
609 {
610 weird_doc (sym, GETTEXT ("no doc slot"),
611 GETTEXT ("bytecode"), pos);
612 goto weird;
613 }
614 else
615 {
616 Lisp_Object old =
617 compiled_function_documentation (b);
618 if (!ZEROP (old))
619 {
620 weird_doc (sym, GETTEXT ("duplicate"),
621 GETTEXT ("bytecode"), pos);
622 /* In the case of duplicate doc file entries,
623 always take the later one. But if the doc is
624 not an int (a string, say) leave it alone. */
625 if (!INTP (old))
626 goto weird;
627 }
628 set_compiled_function_documentation (b, offset);
629 }
630 }
631 else
632 {
633 /* Otherwise the function is undefined or
634 otherwise weird. Ignore it. */
635 weird_function:
636 weird_doc (sym, GETTEXT ("weird function"),
637 GETTEXT ("function"), pos);
638 goto weird;
639 }
640 }
641 else
642 {
643 /* lose: */
644 error ("DOC file invalid at position %d", pos);
645 weird:
646 /* goto lose */;
647 }
648 }
649 }
650 pos += end - buf;
651 filled -= end - buf;
652 memmove (buf, end, filled);
653 }
654 close (fd);
655 return Qnil;
656 }
657
658
659 #if 1 /* Don't warn about functions whose doc was lost because they were
660 wrapped by advice-freeze.el... */
661 static int
662 kludgily_ignore_lost_doc_p (Lisp_Object sym)
663 {
664 # define kludge_prefix "ad-Orig-"
665 return (string_length (XSYMBOL (sym)->name) > sizeof (kludge_prefix) &&
666 !strncmp ((char *) string_data (XSYMBOL (sym)->name), kludge_prefix,
667 sizeof (kludge_prefix) - 1));
668 # undef kludge_prefix
669 }
670 #else
671 # define kludgily_ignore_lost_doc_p(sym) 0
672 #endif
673
674
675 static void
676 verify_doc_mapper (Lisp_Object sym, Lisp_Object closure)
677 {
678 if (!NILP (Ffboundp (sym)))
679 {
680 int doc = 0;
681 Lisp_Object fun = XSYMBOL (sym)->function;
682 if (CONSP (fun) &&
683 EQ (XCAR (fun), Qmacro))
684 fun = XCDR (fun);
685
686 if (SUBRP (fun))
687 doc = (EMACS_INT) XSUBR (fun)->doc;
688 else if (SYMBOLP (fun))
689 doc = -1;
690 else if (KEYMAPP (fun))
691 doc = -1;
692 else if (CONSP (fun))
693 {
694 Lisp_Object tem = XCAR (fun);
695 if (EQ (tem, Qlambda) || EQ (tem, Qautoload))
696 {
697 doc = -1;
698 tem = Fcdr (Fcdr (fun));
699 if (CONSP (tem) &&
700 INTP (XCAR (tem)))
701 doc = XINT (XCAR (tem));
702 }
703 }
704 else if (COMPILED_FUNCTIONP (fun))
705 {
706 struct Lisp_Compiled_Function *b = XCOMPILED_FUNCTION (fun);
707 if (! (b->flags.documentationp))
708 doc = -1;
709 else
710 {
711 Lisp_Object tem = compiled_function_documentation (b);
712 if (INTP (tem))
713 doc = XINT (tem);
714 }
715 }
716
717 if (doc == 0 && !kludgily_ignore_lost_doc_p (sym))
718 {
719 message ("Warning: doc lost for function %s.",
720 string_data (XSYMBOL (sym)->name));
721 XCDR (closure) = Qt;
722 }
723 }
724 if (!NILP (Fboundp (sym)))
725 {
726 Lisp_Object doc = Fget (sym, Qvariable_documentation, Qnil);
727 if (ZEROP (doc))
728 {
729 message ("Warning: doc lost for variable %s.",
730 string_data (XSYMBOL (sym)->name));
731 XCDR (closure) = Qt;
732 }
733 }
734 }
735
736 DEFUN ("Verify-documentation", Fverify_documentation, Sverify_documentation,
737 0, 0, 0 /*
738 Used to make sure everything went well with Snarf-documentation.
739 Writes to stderr if not.
740 */ )
741 ()
742 {
743 Lisp_Object closure = Fcons (Qnil, Qnil);
744 struct gcpro gcpro1;
745 GCPRO1 (closure);
746 map_obarray (Vobarray, verify_doc_mapper, closure);
747 if (!NILP (Fcdr (closure)))
748 message ("\n"
749 "This is usually because some files were preloaded by loaddefs.el or\n"
750 "site-load.el, but were not passed to make-docfile by Makefile.\n");
751 UNGCPRO;
752 return (NILP (Fcdr (closure)) ? Qt : Qnil);
753 }
754
755
756 DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
757 Ssubstitute_command_keys, 1, 1, 0 /*
758 Substitute key descriptions for command names in STRING.
759 Return a new string which is STRING with substrings of the form \\=\\[COMMAND]
760 replaced by either: a keystroke sequence that will invoke COMMAND,
761 or \"M-x COMMAND\" if COMMAND is not on any keys.
762 Substrings of the form \\=\\{MAPVAR} are replaced by summaries
763 \(made by describe-bindings) of the value of MAPVAR, taken as a keymap.
764 Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR
765 as the keymap for future \\=\\[COMMAND] substrings.
766 \\=\\= quotes the following character and is discarded;
767 thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
768 */ )
769 (str)
770 Lisp_Object str;
771 {
772 /* This function can GC */
773 Bufbyte *buf;
774 int changed = 0;
775 REGISTER Bufbyte *strdata;
776 REGISTER Bufbyte *bufp;
777 Bytecount strlength;
778 Bytecount idx;
779 Bytecount bsize;
780 Bufbyte *new;
781 Lisp_Object tem = Qnil;
782 Lisp_Object keymap;
783 Bufbyte *start;
784 Bytecount length;
785 Lisp_Object name;
786 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
787
788 if (NILP (str))
789 return Qnil;
790
791 CHECK_STRING (str);
792 tem = Qnil;
793 keymap = Qnil;
794 name = Qnil;
795 GCPRO4 (str, tem, keymap, name);
796
797 /* There is the possibility that the string is not destined for a
798 translating stream, and it could be argued that we should do the
799 same thing here as in Fformat(), but there are very few times
800 when this will be the case and many calls to this function
801 would have to have `gettext' calls added. (I18N3) */
802 str = LISP_GETTEXT (str);
803
804 /* KEYMAP is either nil (which means search all the active keymaps)
805 or a specified local map (which means search just that and the
806 global map). If non-nil, it might come from Voverriding_local_map,
807 or from a \\<mapname> construct in STR itself.. */
808 #if 0 /* FSFmacs */
809 /* This is really weird and garbagey. If keymap is nil and there's
810 an overriding-local-map, `where-is-internal' will correctly note
811 this, so there's no reason to do it here. Maybe FSFmacs
812 `where-is-internal' is broken. */
813 keymap = current_kboard->Voverriding_terminal_local_map;
814 if (NILP (keymap))
815 keymap = Voverriding_local_map;
816 #endif
817
818 strlength = string_length (XSTRING (str));
819 bsize = strlength;
820 buf = (Bufbyte *) xmalloc (bsize);
821 bufp = buf;
822
823 /* Have to reset strdata every time GC might be called */
824 strdata = string_data (XSTRING (str));
825 for (idx = 0; idx < strlength; )
826 {
827 Bufbyte *strp = strdata + idx;
828
829 if (strp[0] != '\\')
830 {
831 /* just copy other chars */
832 /* As it happens, this will work with Mule even if the
833 character quoted is multi-byte; the remaining multi-byte
834 characters will just be copied by this loop. */
835 *bufp++ = *strp;
836 idx++;
837 }
838 else switch (strp[1])
839 {
840 default:
841 {
842 /* just copy unknown escape sequences */
843 *bufp++ = *strp;
844 idx++;
845 break;
846 }
847 case '=':
848 {
849 /* \= quotes the next character;
850 thus, to put in \[ without its special meaning, use \=\[. */
851 /* As it happens, this will work with Mule even if the
852 character quoted is multi-byte; the remaining multi-byte
853 characters will just be copied by this loop. */
854 changed = 1;
855 *bufp++ = strp[2];
856 idx += 3;
857 break;
858 }
859 case '[':
860 {
861 changed = 1;
862 idx += 2; /* skip \[ */
863 strp += 2;
864 start = strp;
865
866 while ((idx < strlength)
867 && *strp != ']')
868 {
869 strp++;
870 idx++;
871 }
872 length = strp - start;
873 idx++; /* skip ] */
874
875 tem = Fintern (make_string (start, length), Qnil);
876 tem = Fwhere_is_internal (tem, keymap, Qt, Qnil, Qnil);
877
878 #if 0 /* FSFmacs */
879 /* Disregard menu bar bindings; it is positively annoying to
880 mention them when there's no menu bar, and it isn't terribly
881 useful even when there is a menu bar. */
882 if (!NILP (tem))
883 {
884 firstkey = Faref (tem, Qzero);
885 if (EQ (firstkey, Qmenu_bar))
886 tem = Qnil;
887 }
888 #endif
889
890 if (NILP (tem)) /* but not on any keys */
891 {
892 new = (Bufbyte *) xrealloc (buf, bsize += 4);
893 bufp += new - buf;
894 buf = new;
895 memcpy (bufp, "M-x ", 4);
896 bufp += 4;
897 goto subst;
898 }
899 else
900 { /* function is on a key */
901 tem = Fkey_description (tem);
902 goto subst_string;
903 }
904 }
905 case '{':
906 case '<':
907 {
908 /* \{foo} is replaced with a summary of keymap (symbol-value foo).
909 \<foo> just sets the keymap used for \[cmd]. */
910 struct buffer *oldbuf;
911
912 changed = 1;
913 idx += 2; /* skip \{ or \< */
914 strp += 2;
915 start = strp;
916
917 while ((idx < strlength)
918 && *strp != '}' && *strp != '>')
919 {
920 strp++;
921 idx++;
922 }
923 length = strp - start;
924 idx++; /* skip } or > */
925
926 /* Get the value of the keymap in TEM, or nil if undefined.
927 Do this while still in the user's current buffer
928 in case it is a local variable. */
929 name = Fintern (make_string (start, length), Qnil);
930 tem = Fboundp (name);
931 if (! NILP (tem))
932 {
933 tem = Fsymbol_value (name);
934 if (! NILP (tem))
935 tem = get_keymap (tem, 0, 1);
936 }
937
938 /* Now switch to a temp buffer. */
939 oldbuf = current_buffer;
940 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
941
942 if (NILP (tem))
943 {
944 char boof[255], *b = boof;
945 *b++ = '\n';
946 sprintf (b, GETTEXT (
947 "Uses keymap \"%s\", which is not currently defined."),
948 (char *) string_data (XSTRING (Fsymbol_name (name))));
949 b += strlen (b);
950 *b++ = '\n';
951 *b++ = 0;
952 buffer_insert_c_string (current_buffer, boof);
953
954 if (start[-1] == '<') keymap = Qnil;
955 }
956 else if (start[-1] == '<')
957 keymap = tem;
958 else
959 describe_map_tree (tem, 1, Qnil, Qnil, 0);
960 tem = Fbuffer_substring (Qnil, Qnil, Fcurrent_buffer ());
961 Ferase_buffer (Fcurrent_buffer ());
962 set_buffer_internal (oldbuf);
963 goto subst_string;
964
965 subst_string:
966 start = string_data (XSTRING (tem));
967 length = string_length (XSTRING (tem));
968 subst:
969 bsize += length;
970 new = (Bufbyte *) xrealloc (buf, bsize);
971 bufp += new - buf;
972 buf = new;
973 memcpy (bufp, start, length);
974 bufp += length;
975
976 /* Reset STRDATA in case gc relocated it. */
977 strdata = string_data (XSTRING (str));
978
979 break;
980 }
981 }
982 }
983
984 if (changed) /* don't bother if nothing substituted */
985 tem = make_string (buf, bufp - buf);
986 else
987 tem = str;
988 xfree (buf);
989 UNGCPRO;
990 return (tem);
991 }
992
993
994 /************************************************************************/
995 /* initialization */
996 /************************************************************************/
997
998 void
999 syms_of_doc (void)
1000 {
1001 defsubr (&Sdocumentation);
1002 defsubr (&Sdocumentation_property);
1003 defsubr (&Ssnarf_documentation);
1004 defsubr (&Sverify_documentation);
1005 defsubr (&Ssubstitute_command_keys);
1006 }
1007
1008 void
1009 vars_of_doc (void)
1010 {
1011 DEFVAR_LISP ("internal-doc-file-name", &Vdoc_file_name /*
1012 Name of file containing documentation strings of built-in symbols.
1013 */ );
1014 Vdoc_file_name = Qnil;
1015 }