diff options
Diffstat (limited to 'src/doc.c')
| -rw-r--r-- | src/doc.c | 139 |
1 files changed, 87 insertions, 52 deletions
| @@ -56,6 +56,15 @@ read_bytecode_char (bool unreadflag) | |||
| 56 | return *read_bytecode_pointer++; | 56 | return *read_bytecode_pointer++; |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | /* A module doc file must have a doc extension */ | ||
| 60 | static bool | ||
| 61 | doc_is_from_module_p (const char* path) | ||
| 62 | { | ||
| 63 | int len = strlen (path); | ||
| 64 | return len > 4 && (strcmp (path + len - 4, ".doc") == 0 | ||
| 65 | || (strcmp (path + len - 4, ".DOC") == 0)); | ||
| 66 | } | ||
| 67 | |||
| 59 | /* Extract a doc string from a file. FILEPOS says where to get it. | 68 | /* Extract a doc string from a file. FILEPOS says where to get it. |
| 60 | If it is an integer, use that position in the standard DOC file. | 69 | If it is an integer, use that position in the standard DOC file. |
| 61 | If it is (FILE . INTEGER), use FILE as the file name | 70 | If it is (FILE . INTEGER), use FILE as the file name |
| @@ -109,11 +118,11 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) | |||
| 109 | return Qnil; | 118 | return Qnil; |
| 110 | 119 | ||
| 111 | /* Put the file name in NAME as a C string. | 120 | /* Put the file name in NAME as a C string. |
| 112 | If it is relative, combine it with Vdoc_directory. */ | 121 | If it is relative and not from a module, combine it with Vdoc_directory. */ |
| 113 | 122 | ||
| 114 | tem = Ffile_name_absolute_p (file); | 123 | tem = Ffile_name_absolute_p (file); |
| 115 | file = ENCODE_FILE (file); | 124 | file = ENCODE_FILE (file); |
| 116 | if (NILP (tem)) | 125 | if (NILP (tem) && !doc_is_from_module_p (SSDATA (file))) |
| 117 | { | 126 | { |
| 118 | Lisp_Object docdir = ENCODE_FILE (Vdoc_directory); | 127 | Lisp_Object docdir = ENCODE_FILE (Vdoc_directory); |
| 119 | minsize = SCHARS (docdir); | 128 | minsize = SCHARS (docdir); |
| @@ -211,7 +220,7 @@ get_doc_string (Lisp_Object filepos, bool unibyte, bool definition) | |||
| 211 | SAFE_FREE (); | 220 | SAFE_FREE (); |
| 212 | 221 | ||
| 213 | /* Sanity checking. */ | 222 | /* Sanity checking. */ |
| 214 | if (CONSP (filepos)) | 223 | if (CONSP (filepos) && !doc_is_from_module_p (name)) |
| 215 | { | 224 | { |
| 216 | int test = 1; | 225 | int test = 1; |
| 217 | /* A dynamic docstring should be either at the very beginning of a "#@ | 226 | /* A dynamic docstring should be either at the very beginning of a "#@ |
| @@ -321,7 +330,7 @@ reread_doc_file (Lisp_Object file) | |||
| 321 | #endif | 330 | #endif |
| 322 | 331 | ||
| 323 | if (NILP (file)) | 332 | if (NILP (file)) |
| 324 | Fsnarf_documentation (Vdoc_file_name); | 333 | Fsnarf_documentation (Vdoc_file_name, Qnil); |
| 325 | else | 334 | else |
| 326 | Fload (file, Qt, Qt, Qt, Qnil); | 335 | Fload (file, Qt, Qt, Qt, Qnil); |
| 327 | 336 | ||
| @@ -356,14 +365,16 @@ string is passed through `substitute-command-keys'. */) | |||
| 356 | fun = XCDR (fun); | 365 | fun = XCDR (fun); |
| 357 | if (SUBRP (fun)) | 366 | if (SUBRP (fun)) |
| 358 | { | 367 | { |
| 359 | if (XSUBR (fun)->doc == 0) | 368 | Lisp_Object subrdoc = XSUBR (fun)->doc; |
| 360 | return Qnil; | 369 | |
| 361 | /* FIXME: This is not portable, as it assumes that string | 370 | if (NILP (subrdoc)) |
| 362 | pointers have the top bit clear. */ | 371 | return Qnil; |
| 363 | else if ((intptr_t) XSUBR (fun)->doc >= 0) | 372 | else if (STRINGP (subrdoc)) |
| 364 | doc = build_string (XSUBR (fun)->doc); | 373 | return subrdoc; |
| 374 | else if (INTEGERP (subrdoc) || CONSP (subrdoc)) | ||
| 375 | doc = subrdoc; | ||
| 365 | else | 376 | else |
| 366 | doc = make_number ((intptr_t) XSUBR (fun)->doc); | 377 | error ("invalid value in subr doc field"); |
| 367 | } | 378 | } |
| 368 | else if (COMPILEDP (fun)) | 379 | else if (COMPILEDP (fun)) |
| 369 | { | 380 | { |
| @@ -495,7 +506,7 @@ aren't strings. */) | |||
| 495 | /* Scanning the DOC files and placing docstring offsets into functions. */ | 506 | /* Scanning the DOC files and placing docstring offsets into functions. */ |
| 496 | 507 | ||
| 497 | static void | 508 | static void |
| 498 | store_function_docstring (Lisp_Object obj, ptrdiff_t offset) | 509 | store_function_docstring (Lisp_Object obj, Lisp_Object filename, ptrdiff_t offset, bool module) |
| 499 | { | 510 | { |
| 500 | /* Don't use indirect_function here, or defaliases will apply their | 511 | /* Don't use indirect_function here, or defaliases will apply their |
| 501 | docstrings to the base functions (Bug#2603). */ | 512 | docstrings to the base functions (Bug#2603). */ |
| @@ -506,8 +517,8 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset) | |||
| 506 | /* Lisp_Subrs have a slot for it. */ | 517 | /* Lisp_Subrs have a slot for it. */ |
| 507 | if (SUBRP (fun)) | 518 | if (SUBRP (fun)) |
| 508 | { | 519 | { |
| 509 | intptr_t negative_offset = - offset; | 520 | Lisp_Object neg = make_number (-offset); /* XXX: no sure why.. */ |
| 510 | XSUBR (fun)->doc = (char *) negative_offset; | 521 | XSUBR (fun)->doc = module ? Fcons (filename, neg) : neg; |
| 511 | } | 522 | } |
| 512 | 523 | ||
| 513 | /* If it's a lisp form, stick it in the form. */ | 524 | /* If it's a lisp form, stick it in the form. */ |
| @@ -526,7 +537,7 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset) | |||
| 526 | XSETCAR (tem, make_number (offset)); | 537 | XSETCAR (tem, make_number (offset)); |
| 527 | } | 538 | } |
| 528 | else if (EQ (tem, Qmacro)) | 539 | else if (EQ (tem, Qmacro)) |
| 529 | store_function_docstring (XCDR (fun), offset); | 540 | store_function_docstring (XCDR (fun), filename, offset, module); |
| 530 | } | 541 | } |
| 531 | 542 | ||
| 532 | /* Bytecode objects sometimes have slots for it. */ | 543 | /* Bytecode objects sometimes have slots for it. */ |
| @@ -542,9 +553,24 @@ store_function_docstring (Lisp_Object obj, ptrdiff_t offset) | |||
| 542 | } | 553 | } |
| 543 | } | 554 | } |
| 544 | 555 | ||
| 556 | static bool | ||
| 557 | build_file_p (const char* file, ptrdiff_t len) | ||
| 558 | { | ||
| 559 | /* file can be longer than len, can't use xstrdup */ | ||
| 560 | char *ofile = xmalloc (len + 1); | ||
| 561 | memcpy (ofile, file, len); | ||
| 562 | ofile[len] = 0; | ||
| 563 | |||
| 564 | if (ofile[len-1] == 'c') | ||
| 565 | ofile[len-1] = 'o'; | ||
| 566 | |||
| 567 | bool res = NILP (Fmember (build_string (ofile), Vbuild_files)); | ||
| 568 | xfree (ofile); | ||
| 569 | return res; | ||
| 570 | } | ||
| 545 | 571 | ||
| 546 | DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation, | 572 | DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation, |
| 547 | 1, 1, 0, | 573 | 1, 2, 0, |
| 548 | doc: /* Used during Emacs initialization to scan the `etc/DOC...' file. | 574 | doc: /* Used during Emacs initialization to scan the `etc/DOC...' file. |
| 549 | This searches the `etc/DOC...' file for doc strings and | 575 | This searches the `etc/DOC...' file for doc strings and |
| 550 | records them in function and variable definitions. | 576 | records them in function and variable definitions. |
| @@ -552,7 +578,7 @@ The function takes one argument, FILENAME, a string; | |||
| 552 | it specifies the file name (without a directory) of the DOC file. | 578 | it specifies the file name (without a directory) of the DOC file. |
| 553 | That file is found in `../etc' now; later, when the dumped Emacs is run, | 579 | That file is found in `../etc' now; later, when the dumped Emacs is run, |
| 554 | the same file name is found in the `doc-directory'. */) | 580 | the same file name is found in the `doc-directory'. */) |
| 555 | (Lisp_Object filename) | 581 | (Lisp_Object filename, Lisp_Object module) |
| 556 | { | 582 | { |
| 557 | int fd; | 583 | int fd; |
| 558 | char buf[1024 + 1]; | 584 | char buf[1024 + 1]; |
| @@ -573,22 +599,48 @@ the same file name is found in the `doc-directory'. */) | |||
| 573 | 599 | ||
| 574 | CHECK_STRING (filename); | 600 | CHECK_STRING (filename); |
| 575 | 601 | ||
| 576 | if | 602 | /* Vbuild_files is nil when temacs is run, and non-nil after that. */ |
| 603 | if (NILP (Vbuild_files)) | ||
| 604 | { | ||
| 605 | static char const *const buildobj[] = | ||
| 606 | { | ||
| 607 | #include "buildobj.h" | ||
| 608 | }; | ||
| 609 | int i = ARRAYELTS (buildobj); | ||
| 610 | while (0 <= --i) | ||
| 611 | Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files); | ||
| 612 | Vbuild_files = Fpurecopy (Vbuild_files); | ||
| 613 | } | ||
| 614 | |||
| 615 | if (NILP (module)) | ||
| 616 | { | ||
| 617 | /* If we're not processing a module doc, the doc file becomes | ||
| 618 | the "global" DOC file */ | ||
| 619 | Vdoc_file_name = filename; | ||
| 620 | |||
| 621 | if | ||
| 577 | #ifndef CANNOT_DUMP | 622 | #ifndef CANNOT_DUMP |
| 578 | (!NILP (Vpurify_flag)) | 623 | (!NILP (Vpurify_flag)) |
| 579 | #else /* CANNOT_DUMP */ | 624 | #else /* CANNOT_DUMP */ |
| 580 | (0) | 625 | (0) |
| 581 | #endif /* CANNOT_DUMP */ | 626 | #endif /* CANNOT_DUMP */ |
| 582 | { | 627 | { |
| 583 | static char const sibling_etc[] = "../etc/"; | 628 | static char const sibling_etc[] = "../etc/"; |
| 584 | dirname = sibling_etc; | 629 | dirname = sibling_etc; |
| 585 | dirlen = sizeof sibling_etc - 1; | 630 | dirlen = sizeof sibling_etc - 1; |
| 631 | } | ||
| 632 | else | ||
| 633 | { | ||
| 634 | CHECK_STRING (Vdoc_directory); | ||
| 635 | dirname = SSDATA (Vdoc_directory); | ||
| 636 | dirlen = SBYTES (Vdoc_directory); | ||
| 637 | } | ||
| 586 | } | 638 | } |
| 587 | else | 639 | else |
| 588 | { | 640 | { |
| 589 | CHECK_STRING (Vdoc_directory); | 641 | static char const empty_prefix_dir[] = ""; |
| 590 | dirname = SSDATA (Vdoc_directory); | 642 | dirname = empty_prefix_dir; |
| 591 | dirlen = SBYTES (Vdoc_directory); | 643 | dirlen = 0; |
| 592 | } | 644 | } |
| 593 | 645 | ||
| 594 | count = SPECPDL_INDEX (); | 646 | count = SPECPDL_INDEX (); |
| @@ -597,18 +649,6 @@ the same file name is found in the `doc-directory'. */) | |||
| 597 | strcpy (name, dirname); | 649 | strcpy (name, dirname); |
| 598 | strcat (name, SSDATA (filename)); /*** Add this line ***/ | 650 | strcat (name, SSDATA (filename)); /*** Add this line ***/ |
| 599 | 651 | ||
| 600 | /* Vbuild_files is nil when temacs is run, and non-nil after that. */ | ||
| 601 | if (NILP (Vbuild_files)) | ||
| 602 | { | ||
| 603 | static char const *const buildobj[] = | ||
| 604 | { | ||
| 605 | #include "buildobj.h" | ||
| 606 | }; | ||
| 607 | int i = ARRAYELTS (buildobj); | ||
| 608 | while (0 <= --i) | ||
| 609 | Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files); | ||
| 610 | Vbuild_files = Fpurecopy (Vbuild_files); | ||
| 611 | } | ||
| 612 | 652 | ||
| 613 | fd = emacs_open (name, O_RDONLY, 0); | 653 | fd = emacs_open (name, O_RDONLY, 0); |
| 614 | if (fd < 0) | 654 | if (fd < 0) |
| @@ -618,7 +658,6 @@ the same file name is found in the `doc-directory'. */) | |||
| 618 | open_errno); | 658 | open_errno); |
| 619 | } | 659 | } |
| 620 | record_unwind_protect_int (close_file_unwind, fd); | 660 | record_unwind_protect_int (close_file_unwind, fd); |
| 621 | Vdoc_file_name = filename; | ||
| 622 | filled = 0; | 661 | filled = 0; |
| 623 | pos = 0; | 662 | pos = 0; |
| 624 | while (1) | 663 | while (1) |
| @@ -641,18 +680,13 @@ the same file name is found in the `doc-directory'. */) | |||
| 641 | if (p[1] == 'S') | 680 | if (p[1] == 'S') |
| 642 | { | 681 | { |
| 643 | skip_file = 0; | 682 | skip_file = 0; |
| 644 | if (end - p > 4 && end[-2] == '.' | 683 | if (NILP (module) |
| 645 | && (end[-1] == 'o' || end[-1] == 'c')) | 684 | && end - p > 4 |
| 685 | && end[-2] == '.' | ||
| 686 | && (end[-1] == 'o' || end[-1] == 'c') | ||
| 687 | && build_file_p (&p[2], end - p - 2)) | ||
| 646 | { | 688 | { |
| 647 | ptrdiff_t len = end - p - 2; | 689 | skip_file = 1; |
| 648 | char *fromfile = SAFE_ALLOCA (len + 1); | ||
| 649 | memcpy (fromfile, &p[2], len); | ||
| 650 | fromfile[len] = 0; | ||
| 651 | if (fromfile[len-1] == 'c') | ||
| 652 | fromfile[len-1] = 'o'; | ||
| 653 | |||
| 654 | skip_file = NILP (Fmember (build_string (fromfile), | ||
| 655 | Vbuild_files)); | ||
| 656 | } | 690 | } |
| 657 | } | 691 | } |
| 658 | 692 | ||
| @@ -672,6 +706,7 @@ the same file name is found in the `doc-directory'. */) | |||
| 672 | /* Install file-position as variable-documentation property | 706 | /* Install file-position as variable-documentation property |
| 673 | and make it negative for a user-variable | 707 | and make it negative for a user-variable |
| 674 | (doc starts with a `*'). */ | 708 | (doc starts with a `*'). */ |
| 709 | /* TODO: handle module var */ | ||
| 675 | if (!NILP (Fboundp (sym)) | 710 | if (!NILP (Fboundp (sym)) |
| 676 | || !NILP (Fmemq (sym, delayed_init))) | 711 | || !NILP (Fmemq (sym, delayed_init))) |
| 677 | Fput (sym, Qvariable_documentation, | 712 | Fput (sym, Qvariable_documentation, |
| @@ -683,7 +718,7 @@ the same file name is found in the `doc-directory'. */) | |||
| 683 | else if (p[1] == 'F') | 718 | else if (p[1] == 'F') |
| 684 | { | 719 | { |
| 685 | if (!NILP (Ffboundp (sym))) | 720 | if (!NILP (Ffboundp (sym))) |
| 686 | store_function_docstring (sym, pos + end + 1 - buf); | 721 | store_function_docstring (sym, filename, pos + end + 1 - buf, !NILP (module)); |
| 687 | } | 722 | } |
| 688 | else if (p[1] == 'S') | 723 | else if (p[1] == 'S') |
| 689 | ; /* Just a source file name boundary marker. Ignore it. */ | 724 | ; /* Just a source file name boundary marker. Ignore it. */ |