This source file includes following definitions.
- read_bytecode_char
- get_doc_string
- read_doc_string
- reread_doc_file
- store_function_docstring
- DEFUN
- default_to_grave_quoting_style
- DEFUN
- syms_of_doc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include <config.h>
23
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/file.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29
30 #include <c-ctype.h>
31
32 #include "lisp.h"
33 #include "character.h"
34 #include "coding.h"
35 #include "buffer.h"
36 #include "disptab.h"
37 #include "intervals.h"
38 #include "keymap.h"
39
40
41 static char *get_doc_string_buffer;
42 static ptrdiff_t get_doc_string_buffer_size;
43
44 static unsigned char *read_bytecode_pointer;
45
46 static char const sibling_etc[] = "../etc/";
47
48
49
50
51 int
52 read_bytecode_char (bool unreadflag)
53 {
54 if (unreadflag)
55 {
56 read_bytecode_pointer--;
57 return 0;
58 }
59 return *read_bytecode_pointer++;
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 Lisp_Object
82 get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
83 {
84 char *from, *to, *name, *p, *p1;
85 Lisp_Object file, pos;
86 specpdl_ref count = SPECPDL_INDEX ();
87 Lisp_Object dir;
88 USE_SAFE_ALLOCA;
89
90 if (FIXNUMP (filepos))
91 {
92 file = Vdoc_file_name;
93 dir = Vdoc_directory;
94 pos = filepos;
95 }
96 else if (CONSP (filepos))
97 {
98 file = XCAR (filepos);
99 dir = Fsymbol_value (Qlisp_directory);
100 pos = XCDR (filepos);
101 }
102 else
103 return Qnil;
104
105 EMACS_INT position = eabs (XFIXNUM (pos));
106
107 if (!STRINGP (dir))
108 return Qnil;
109
110 if (!STRINGP (file))
111 return Qnil;
112
113
114
115
116 Lisp_Object tem = Ffile_name_absolute_p (file);
117 file = ENCODE_FILE (file);
118 Lisp_Object docdir
119 = NILP (tem) ? ENCODE_FILE (dir) : empty_unibyte_string;
120 ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1;
121 if (will_dump_p ())
122 docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc);
123 name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file));
124 lispstpcpy (lispstpcpy (name, docdir), file);
125
126 int fd = emacs_open (name, O_RDONLY, 0);
127 if (fd < 0)
128 {
129 if (will_dump_p ())
130 {
131
132
133 lispstpcpy (stpcpy (name, sibling_etc), file);
134
135 fd = emacs_open (name, O_RDONLY, 0);
136 }
137 if (fd < 0)
138 {
139 if (errno != ENOENT && errno != ENOTDIR)
140 report_file_error ("Read error on documentation file", file);
141
142 SAFE_FREE ();
143 AUTO_STRING (cannot_open, "Cannot open doc string file \"");
144 AUTO_STRING (quote_nl, "\"\n");
145 return concat3 (cannot_open, file, quote_nl);
146 }
147 }
148 record_unwind_protect_int (close_file_unwind, fd);
149
150
151
152
153 int offset = min (position, max (1024, position % (8 * 1024)));
154 if (TYPE_MAXIMUM (off_t) < position
155 || lseek (fd, position - offset, 0) < 0)
156 error ("Position %"pI"d out of range in doc string file \"%s\"",
157 position, name);
158
159
160
161
162 p = get_doc_string_buffer;
163 while (1)
164 {
165 ptrdiff_t space_left = (get_doc_string_buffer_size - 1
166 - (p - get_doc_string_buffer));
167
168
169 if (space_left <= 0)
170 {
171 ptrdiff_t in_buffer = p - get_doc_string_buffer;
172 get_doc_string_buffer
173 = xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
174 16 * 1024, -1, 1);
175 p = get_doc_string_buffer + in_buffer;
176 space_left = (get_doc_string_buffer_size - 1
177 - (p - get_doc_string_buffer));
178 }
179
180
181
182 if (space_left > 1024 * 8)
183 space_left = 1024 * 8;
184 int nread = emacs_read_quit (fd, p, space_left);
185 if (nread < 0)
186 report_file_error ("Read error on documentation file", file);
187 p[nread] = 0;
188 if (!nread)
189 break;
190 if (p == get_doc_string_buffer)
191 p1 = strchr (p + offset, '\037');
192 else
193 p1 = strchr (p, '\037');
194 if (p1)
195 {
196 *p1 = 0;
197 p = p1;
198 break;
199 }
200 p += nread;
201 }
202 SAFE_FREE_UNBIND_TO (count, Qnil);
203
204
205 if (CONSP (filepos))
206 {
207 int test = 1;
208
209
210
211 if (get_doc_string_buffer[offset - test] != '\037')
212 {
213 if (get_doc_string_buffer[offset - test++] != ' ')
214 return Qnil;
215 while (get_doc_string_buffer[offset - test] >= '0'
216 && get_doc_string_buffer[offset - test] <= '9')
217 test++;
218 if (get_doc_string_buffer[offset - test++] != '@'
219 || get_doc_string_buffer[offset - test] != '#')
220 return Qnil;
221 }
222 }
223 else
224 {
225 int test = 1;
226 if (get_doc_string_buffer[offset - test++] != '\n')
227 return Qnil;
228 while (get_doc_string_buffer[offset - test] > ' ')
229 test++;
230 if (get_doc_string_buffer[offset - test] != '\037')
231 return Qnil;
232 }
233
234
235
236 from = get_doc_string_buffer + offset;
237 to = get_doc_string_buffer + offset;
238 while (from != p)
239 {
240 if (*from == 1)
241 {
242 from++;
243 int c = *from++;
244 if (c == 1)
245 *to++ = c;
246 else if (c == '0')
247 *to++ = 0;
248 else if (c == '_')
249 *to++ = 037;
250 else
251 {
252 unsigned char uc = c;
253 error ("\
254 Invalid data in documentation file -- %c followed by code %03o",
255 1, uc);
256 }
257 }
258 else
259 *to++ = *from++;
260 }
261
262
263
264 if (definition)
265 {
266 read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
267 return Fread (Qlambda);
268 }
269
270 if (unibyte)
271 return make_unibyte_string (get_doc_string_buffer + offset,
272 to - (get_doc_string_buffer + offset));
273 else
274 {
275
276 ptrdiff_t nchars
277 = multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
278 + offset),
279 to - (get_doc_string_buffer + offset));
280 return make_string_from_bytes (get_doc_string_buffer + offset,
281 nchars,
282 to - (get_doc_string_buffer + offset));
283 }
284 }
285
286
287
288
289
290 Lisp_Object
291 read_doc_string (Lisp_Object filepos)
292 {
293 return get_doc_string (filepos, 0, 1);
294 }
295
296 static bool
297 reread_doc_file (Lisp_Object file)
298 {
299 if (NILP (file))
300 Fsnarf_documentation (Vdoc_file_name);
301 else
302 save_match_data_load (file, Qt, Qt, Qt, Qnil);
303
304 return 1;
305 }
306
307 DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
308 doc:
309
310 )
311 (Lisp_Object function, Lisp_Object raw)
312 {
313 Lisp_Object doc;
314 bool try_reload = true;
315
316 documentation:
317
318 doc = Qnil;
319
320 if (SYMBOLP (function))
321 {
322 Lisp_Object tem = Fget (function, Qfunction_documentation);
323 if (!NILP (tem))
324 return Fdocumentation_property (function, Qfunction_documentation,
325 raw);
326 }
327
328 Lisp_Object fun = Findirect_function (function, Qnil);
329 if (NILP (fun))
330 xsignal1 (Qvoid_function, function);
331 if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
332 fun = XCDR (fun);
333 #ifdef HAVE_NATIVE_COMP
334 if (!NILP (Fsubr_native_elisp_p (fun)))
335 doc = native_function_doc (fun);
336 else
337 #endif
338 if (SUBRP (fun))
339 doc = make_fixnum (XSUBR (fun)->doc);
340 #ifdef HAVE_MODULES
341 else if (MODULE_FUNCTIONP (fun))
342 doc = module_function_documentation (XMODULE_FUNCTION (fun));
343 #endif
344 else
345 doc = call1 (Qfunction_documentation, fun);
346
347
348
349 if (BASE_EQ (doc, make_fixnum (0)))
350 doc = Qnil;
351 if (FIXNUMP (doc) || CONSP (doc))
352 {
353 Lisp_Object tem;
354 tem = get_doc_string (doc, 0, 0);
355 if (NILP (tem) && try_reload)
356 {
357
358 try_reload = reread_doc_file (Fcar_safe (doc));
359 if (try_reload)
360 {
361 try_reload = false;
362 goto documentation;
363 }
364 }
365 else
366 doc = tem;
367 }
368
369 if (NILP (raw))
370 doc = call1 (Qsubstitute_command_keys, doc);
371 return doc;
372 }
373
374 DEFUN ("documentation-property", Fdocumentation_property,
375 Sdocumentation_property, 2, 3, 0,
376 doc:
377
378
379
380
381
382 )
383 (Lisp_Object symbol, Lisp_Object prop, Lisp_Object raw)
384 {
385 bool try_reload = true;
386 Lisp_Object tem;
387
388 documentation_property:
389
390 tem = Fget (symbol, prop);
391
392
393
394
395 if (EQ (prop, Qvariable_documentation)
396 && NILP (tem))
397 {
398 Lisp_Object indirect = Findirect_variable (symbol);
399 if (!NILP (indirect))
400 tem = Fget (indirect, prop);
401 }
402
403 if (BASE_EQ (tem, make_fixnum (0)))
404 tem = Qnil;
405
406
407 if (FIXNUMP (tem) || (CONSP (tem) && FIXNUMP (XCDR (tem))))
408 {
409 Lisp_Object doc = tem;
410 tem = get_doc_string (tem, 0, 0);
411 if (NILP (tem) && try_reload)
412 {
413
414 try_reload = reread_doc_file (Fcar_safe (doc));
415 if (try_reload)
416 {
417 try_reload = false;
418 goto documentation_property;
419 }
420 }
421 }
422 else if (!STRINGP (tem))
423
424 tem = Feval (tem, Qnil);
425
426 if (NILP (raw) && STRINGP (tem))
427 tem = call1 (Qsubstitute_command_keys, tem);
428 return tem;
429 }
430
431
432
433 static void
434 store_function_docstring (Lisp_Object obj, EMACS_INT offset)
435 {
436
437
438 Lisp_Object fun = SYMBOLP (obj) ? XSYMBOL (obj)->u.s.function : obj;
439
440
441
442
443 if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
444 fun = XCDR (fun);
445 if (CONSP (fun))
446 {
447 Lisp_Object tem = XCAR (fun);
448 if (EQ (tem, Qlambda) || EQ (tem, Qautoload)
449 || (EQ (tem, Qclosure) && (fun = XCDR (fun), 1)))
450 {
451 tem = Fcdr (Fcdr (fun));
452 if (CONSP (tem) && FIXNUMP (XCAR (tem)))
453
454
455 XSETCAR (tem, make_fixnum (offset));
456 }
457 }
458
459 else if (SUBRP (fun) && !SUBR_NATIVE_COMPILEDP (fun))
460 {
461 XSUBR (fun)->doc = offset;
462 }
463
464
465 else if (COMPILEDP (fun))
466 {
467
468
469 if (PVSIZE (fun) > COMPILED_DOC_STRING
470
471
472 && VALID_DOCSTRING_P (AREF (fun, COMPILED_DOC_STRING)))
473 ASET (fun, COMPILED_DOC_STRING, make_fixnum (offset));
474 else
475 {
476 AUTO_STRING (format,
477 (PVSIZE (fun) > COMPILED_DOC_STRING
478 ? "Docstring slot busy for %s"
479 : "No docstring slot for %s"));
480 CALLN (Fmessage, format,
481 (SYMBOLP (obj)
482 ? SYMBOL_NAME (obj)
483 : build_string ("<anonymous>")));
484 }
485 }
486 }
487
488
489 DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
490 1, 1, 0,
491 doc:
492
493
494
495
496
497 )
498 (Lisp_Object filename)
499 {
500 int fd;
501 char buf[1024 + 1];
502 int filled;
503 EMACS_INT pos;
504 Lisp_Object sym;
505 char *p, *name;
506 char const *dirname;
507 ptrdiff_t dirlen;
508
509
510 Lisp_Object delayed_init =
511 find_symbol_value (intern ("custom-delayed-init-variables"));
512
513 if (!CONSP (delayed_init)) delayed_init = Qnil;
514
515 CHECK_STRING (filename);
516
517 if (will_dump_p ())
518 {
519 dirname = sibling_etc;
520 dirlen = sizeof sibling_etc - 1;
521 }
522 else
523 {
524 CHECK_STRING (Vdoc_directory);
525 dirname = SSDATA (Vdoc_directory);
526 dirlen = SBYTES (Vdoc_directory);
527 }
528
529 specpdl_ref count = SPECPDL_INDEX ();
530 USE_SAFE_ALLOCA;
531 name = SAFE_ALLOCA (dirlen + SBYTES (filename) + 1);
532 lispstpcpy (stpcpy (name, dirname), filename);
533
534
535 if (NILP (Vbuild_files))
536 {
537 static char const *const buildobj[] =
538 {
539 #include "buildobj.h"
540 };
541 int i = ARRAYELTS (buildobj);
542 while (0 <= --i)
543 Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
544 Vbuild_files = Fpurecopy (Vbuild_files);
545 }
546
547 fd = emacs_open (name, O_RDONLY, 0);
548 if (fd < 0)
549 {
550 int open_errno = errno;
551 report_file_errno ("Opening doc string file", build_string (name),
552 open_errno);
553 }
554 record_unwind_protect_int (close_file_unwind, fd);
555 Vdoc_file_name = filename;
556 filled = 0;
557 pos = 0;
558 while (true)
559 {
560 if (filled < 512)
561 filled += emacs_read_quit (fd, &buf[filled], sizeof buf - 1 - filled);
562 if (!filled)
563 break;
564
565 buf[filled] = 0;
566 char *end = buf + (filled < 512 ? filled : filled - 128);
567 p = memchr (buf, '\037', end - buf);
568
569 if (p)
570 {
571 end = strchr (p, '\n');
572 if (!end)
573 error ("DOC file invalid at position %"pI"d", pos);
574
575
576
577
578
579
580
581
582
583
584
585
586 sym = oblookup (Vobarray, p + 2,
587 multibyte_chars_in_text ((unsigned char *) p + 2,
588 end - p - 2),
589 end - p - 2);
590
591
592 if (SYMBOLP (sym))
593 {
594
595 if (p[1] == 'V')
596 {
597
598
599
600 if ((!NILP (Fboundp (sym))
601 || !NILP (Fmemq (sym, delayed_init)))
602 && strncmp (end, "\nSKIP", 5))
603 Fput (sym, Qvariable_documentation,
604 make_fixnum ((pos + end + 1 - buf)
605 * (end[1] == '*' ? -1 : 1)));
606 }
607
608
609 else if (p[1] == 'F')
610 {
611 if (!NILP (Ffboundp (sym)) && strncmp (end, "\nSKIP", 5))
612 store_function_docstring (sym, pos + end + 1 - buf);
613 }
614 else if (p[1] == 'S')
615 ;
616
617 else
618 error ("DOC file invalid at position %"pI"d", pos);
619 }
620 }
621 pos += end - buf;
622 filled -= end - buf;
623 memmove (buf, end, filled);
624 }
625
626 return SAFE_FREE_UNBIND_TO (count, Qnil);
627 }
628
629
630 static bool
631 default_to_grave_quoting_style (void)
632 {
633 if (!text_quoting_flag)
634 return true;
635 if (! DISP_TABLE_P (Vstandard_display_table))
636 return false;
637 Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table),
638 LEFT_SINGLE_QUOTATION_MARK);
639 return (VECTORP (dv) && ASIZE (dv) == 1
640 && BASE_EQ (AREF (dv, 0), make_fixnum ('`')));
641 }
642
643 DEFUN ("text-quoting-style", Ftext_quoting_style,
644 Stext_quoting_style, 0, 0, 0,
645 doc:
646
647
648
649
650
651
652
653 )
654 (void)
655 {
656
657 if (NILP (Vtext_quoting_style)
658 ? default_to_grave_quoting_style ()
659 : EQ (Vtext_quoting_style, Qgrave))
660 return Qgrave;
661
662
663 else if (EQ (Vtext_quoting_style, Qstraight))
664 return Qstraight;
665
666
667 else
668 return Qcurve;
669 }
670
671
672 void
673 syms_of_doc (void)
674 {
675 DEFSYM (Qlisp_directory, "lisp-directory");
676 DEFSYM (Qsubstitute_command_keys, "substitute-command-keys");
677 DEFSYM (Qfunction_documentation, "function-documentation");
678 DEFSYM (Qgrave, "grave");
679 DEFSYM (Qstraight, "straight");
680 DEFSYM (Qcurve, "curve");
681
682 DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name,
683 doc: );
684 Vdoc_file_name = Qnil;
685
686 DEFVAR_LISP ("build-files", Vbuild_files,
687 doc: );
688 Vbuild_files = Qnil;
689
690 DEFVAR_LISP ("text-quoting-style", Vtext_quoting_style,
691 doc:
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708 );
709 Vtext_quoting_style = Qnil;
710
711 DEFVAR_BOOL ("internal--text-quoting-flag", text_quoting_flag,
712 doc: );
713
714
715 defsubr (&Sdocumentation);
716 defsubr (&Sdocumentation_property);
717 defsubr (&Ssnarf_documentation);
718 defsubr (&Stext_quoting_style);
719 }