Mercurial > hg > xemacs-beta
annotate src/doc.c @ 4468:a78d697ccd2c
Import and extend GNU's descr-text.el, supporting prefix argument for C-x =
2008-05-25 Aidan Kehoe <kehoea@parhasard.net>
* descr-text.el: New.
Taken from GNU's GPLV2 version of 2007-02-14, with modifications
for XEmacs support and extensions for Unihan.txt support and
db/dbm caches.
* simple.el (what-cursor-position):
Support an optional prefix argument, as does GNU, calling
#'describe-char to giving more detail on the character at point,
notably from UnicodeData and (in our case, optionally) Unihan.txt.
* syntax.el (syntax-after):
Make this available for the sake of #'describe-char.
* mule/mule-cmds.el (iso-2022-control-alist):
Make this available, for the sake of #'encoded-string-description
and #'describe-char.
* mule/mule-cmds.el (encoded-string-description):
Make this available, for the sake of #'describe-char.
* unicode.el (unicode-error-default-translation-table):
Make this a char table of type generic, not of type char. Makes it
possible to have the relevant logic in #'describe-char reasonably
clear; also, and this is undocumented, makes it much easier to
implement #'frob-unicode-errors-region. I should document this,
and revise #'frob-unicode-errors-region.
| author | Aidan Kehoe <kehoea@parhasard.net> |
|---|---|
| date | Sun, 25 May 2008 21:11:35 +0200 |
| parents | 3906442b491b |
| children | 061e030e3270 |
| rev | line source |
|---|---|
| 428 | 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. | |
| 2367 | 4 Copyright (C) 2001, 2002, 2004 Ben Wing. |
| 428 | 5 |
| 6 This file is part of XEmacs. | |
| 7 | |
| 8 XEmacs is free software; you can redistribute it and/or modify it | |
| 9 under the terms of the GNU General Public License as published by the | |
| 10 Free Software Foundation; either version 2, or (at your option) any | |
| 11 later version. | |
| 12 | |
| 13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
| 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 16 for more details. | |
| 17 | |
| 18 You should have received a copy of the GNU General Public License | |
| 19 along with XEmacs; see the file COPYING. If not, write to | |
| 20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
| 21 Boston, MA 02111-1307, USA. */ | |
| 22 | |
| 23 /* Synched up with: FSF 19.30. */ | |
| 24 | |
| 814 | 25 /* This file has been Mule-ized. */ |
| 428 | 26 |
| 27 #include <config.h> | |
| 28 #include "lisp.h" | |
| 29 | |
| 30 #include "buffer.h" | |
| 31 #include "bytecode.h" | |
| 814 | 32 #include "file-coding.h" |
| 428 | 33 #include "insdel.h" |
| 34 #include "keymap.h" | |
| 814 | 35 #include "lstream.h" |
| 428 | 36 #include "sysfile.h" |
| 37 | |
| 38 Lisp_Object Vinternal_doc_file_name; | |
| 39 | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
40 Lisp_Object QSsubstitute, Qdefvar; |
| 428 | 41 |
| 3368 | 42 /* Work out what source file a function or variable came from, taking the |
| 43 information from the documentation file. */ | |
| 44 | |
| 45 static Lisp_Object | |
| 46 extract_object_file_name (int fd, EMACS_INT doc_pos, | |
| 47 Ibyte *name_nonreloc, Lisp_Object name_reloc, | |
| 48 int standard_doc_file) | |
| 49 { | |
| 3383 | 50 Ibyte buf[DOC_MAX_FILENAME_LENGTH+1]; |
| 3368 | 51 Ibyte *buffer = buf; |
| 3411 | 52 int buffer_size = sizeof (buf) - 1, space_left; |
| 3368 | 53 Ibyte *from, *to; |
| 54 REGISTER Ibyte *p = buffer; | |
| 55 Lisp_Object return_me; | |
| 56 Lisp_Object fdstream = Qnil, instream = Qnil; | |
| 57 struct gcpro gcpro1, gcpro2; | |
| 58 EMACS_INT position, seenS = 0; | |
| 59 | |
| 60 GCPRO2 (fdstream, instream); | |
| 61 | |
| 3411 | 62 position = doc_pos > buffer_size ? |
| 63 doc_pos - buffer_size : 0; | |
| 3368 | 64 |
| 65 if (0 > lseek (fd, position, 0)) | |
| 66 { | |
| 67 if (name_nonreloc) | |
| 68 name_reloc = build_intstring (name_nonreloc); | |
| 69 return_me = list3 (build_msg_string | |
| 70 ("Position out of range in doc string file"), | |
| 71 name_reloc, make_int (position)); | |
| 72 goto done; | |
| 73 } | |
| 74 | |
| 75 fdstream = make_filedesc_input_stream (fd, 0, -1, 0); | |
| 76 Lstream_set_buffering (XLSTREAM (fdstream), LSTREAM_UNBUFFERED, 0); | |
| 77 instream = | |
| 78 make_coding_input_stream | |
| 79 (XLSTREAM (fdstream), standard_doc_file ? Qescape_quoted : Qbinary, | |
| 80 CODING_DECODE, 0); | |
| 81 Lstream_set_buffering (XLSTREAM (instream), LSTREAM_UNBUFFERED, 0); | |
| 82 | |
| 83 space_left = buffer_size - (p - buffer); | |
| 84 while (space_left > 0) | |
| 85 { | |
| 86 int nread; | |
| 87 | |
| 88 nread = Lstream_read (XLSTREAM (instream), p, space_left); | |
| 89 if (nread < 0) | |
| 90 { | |
| 91 return_me = list1 (build_msg_string | |
| 92 ("Read error on documentation file")); | |
| 93 goto done; | |
| 94 } | |
| 95 | |
| 96 p[nread] = 0; | |
| 97 | |
| 98 if (!nread) | |
| 99 break; | |
| 100 | |
| 101 p += nread; | |
| 102 space_left = buffer_size - (p - buffer); | |
| 103 } | |
| 104 | |
| 105 /* First, search backward for the "\037S" that marks the beginning of the | |
| 106 file name, then search forward from that to the newline or to the end | |
| 107 of the buffer. */ | |
| 108 from = p; | |
| 109 | |
| 110 while (from > buf) | |
| 111 { | |
| 112 --from; | |
| 113 if (seenS) | |
| 114 { | |
| 115 if ('\037' == *from) | |
| 116 { | |
| 117 /* Got a file name; adjust `from' to point to it, break out of | |
| 118 the loop. */ | |
| 119 from += 2; | |
| 120 break; | |
| 121 } | |
| 122 } | |
| 123 /* Is *from 'S' ? */ | |
| 124 seenS = ('S' == *from); | |
| 125 } | |
| 126 | |
| 127 if (buf == from) | |
| 128 { | |
| 129 /* We've scanned back to the beginning of the buffer without hitting | |
| 130 the file name. Either the file name plus the symbol name is longer | |
| 131 than DOC_MAX_FILENAME_LENGTH--which shouldn't happen, because it'll | |
| 132 trigger an assertion failure in make-docfile, the DOC file is | |
| 133 corrupt, or it was produced by a version of make-docfile that | |
| 134 doesn't store the file name with the symbol name and docstring. */ | |
| 135 return_me = list1 (build_msg_string | |
| 136 ("Object file name not stored in doc file")); | |
| 137 goto done; | |
| 138 } | |
| 139 | |
| 140 to = from; | |
| 141 /* Search for the end of the file name. */ | |
| 142 while (++to < p) | |
| 143 { | |
| 144 if ('\n' == *to || '\037' == *to) | |
| 145 { | |
| 146 break; | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 /* Don't require the file name to end in a newline. */ | |
| 151 return_me = make_string (from, to - from); | |
| 152 | |
| 153 done: | |
| 154 if (!NILP (instream)) | |
| 155 { | |
| 156 Lstream_delete (XLSTREAM (instream)); | |
| 157 Lstream_delete (XLSTREAM (fdstream)); | |
| 158 } | |
| 159 | |
| 160 UNGCPRO; | |
| 161 return return_me; | |
| 162 } | |
| 428 | 163 |
| 164 Lisp_Object | |
| 165 unparesseuxify_doc_string (int fd, EMACS_INT position, | |
| 867 | 166 Ibyte *name_nonreloc, Lisp_Object name_reloc, |
| 814 | 167 int standard_doc_file) |
| 428 | 168 { |
| 867 | 169 Ibyte buf[512 * 32 + 1]; |
| 170 Ibyte *buffer = buf; | |
| 3411 | 171 int buffer_size = sizeof (buf) - 1; |
| 867 | 172 Ibyte *from, *to; |
| 173 REGISTER Ibyte *p = buffer; | |
| 428 | 174 Lisp_Object return_me; |
| 814 | 175 Lisp_Object fdstream = Qnil, instream = Qnil; |
| 176 struct gcpro gcpro1, gcpro2; | |
| 177 | |
| 178 GCPRO2 (fdstream, instream); | |
| 428 | 179 |
| 180 if (0 > lseek (fd, position, 0)) | |
| 181 { | |
| 182 if (name_nonreloc) | |
| 771 | 183 name_reloc = build_intstring (name_nonreloc); |
| 184 return_me = list3 (build_msg_string | |
| 428 | 185 ("Position out of range in doc string file"), |
| 186 name_reloc, make_int (position)); | |
| 187 goto done; | |
| 188 } | |
| 189 | |
| 814 | 190 fdstream = make_filedesc_input_stream (fd, 0, -1, 0); |
| 191 Lstream_set_buffering (XLSTREAM (fdstream), LSTREAM_UNBUFFERED, 0); | |
| 192 instream = | |
| 193 make_coding_input_stream | |
| 194 /* Major trouble if we are too clever when reading byte-code | |
| 195 instructions! | |
| 196 | |
| 197 #### We should have a way of handling escape-quoted elc files | |
| 198 (i.e. files with non-ASCII/Latin-1 chars in them). Currently this | |
| 199 is "solved" in bytecomp.el by never inserting lazy references in | |
| 200 such files. */ | |
| 826 | 201 (XLSTREAM (fdstream), standard_doc_file ? Qescape_quoted : Qbinary, |
| 814 | 202 CODING_DECODE, 0); |
| 203 Lstream_set_buffering (XLSTREAM (instream), LSTREAM_UNBUFFERED, 0); | |
| 204 | |
| 428 | 205 /* Read the doc string into a buffer. |
| 206 Use the fixed buffer BUF if it is big enough; otherwise allocate one. | |
| 207 We store the buffer in use in BUFFER and its size in BUFFER_SIZE. */ | |
| 208 | |
| 209 while (1) | |
| 210 { | |
| 211 int space_left = buffer_size - (p - buffer); | |
| 212 int nread; | |
| 213 | |
| 214 /* Switch to a bigger buffer if we need one. */ | |
| 215 if (space_left == 0) | |
| 216 { | |
| 867 | 217 Ibyte *old_buffer = buffer; |
| 3411 | 218 buffer_size *= 2; |
| 219 | |
| 771 | 220 if (buffer == buf) |
| 221 { | |
| 3411 | 222 buffer = xnew_ibytes (buffer_size + 1); |
| 771 | 223 memcpy (buffer, old_buffer, p - old_buffer); |
| 224 } | |
| 225 else | |
| 3411 | 226 XREALLOC_ARRAY (buffer, Ibyte, buffer_size + 1); |
| 428 | 227 p += buffer - old_buffer; |
| 228 space_left = buffer_size - (p - buffer); | |
| 229 } | |
| 230 | |
| 231 /* Don't read too much at one go. */ | |
| 232 if (space_left > 1024 * 8) | |
| 233 space_left = 1024 * 8; | |
| 814 | 234 nread = Lstream_read (XLSTREAM (instream), p, space_left); |
| 428 | 235 if (nread < 0) |
| 236 { | |
| 771 | 237 return_me = list1 (build_msg_string |
| 428 | 238 ("Read error on documentation file")); |
| 239 goto done; | |
| 240 } | |
| 241 p[nread] = 0; | |
| 242 if (!nread) | |
| 243 break; | |
| 244 { | |
| 867 | 245 Ibyte *p1 = qxestrchr (p, '\037'); /* End of doc string marker */ |
| 814 | 246 if (p1) |
| 247 { | |
| 248 *p1 = 0; | |
| 249 p = p1; | |
| 250 break; | |
| 251 } | |
| 428 | 252 } |
| 253 p += nread; | |
| 254 } | |
| 255 | |
| 256 /* Scan the text and remove quoting with ^A (char code 1). | |
| 257 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */ | |
| 258 from = to = buffer; | |
| 259 while (from < p) | |
| 260 { | |
| 261 if (*from != 1 /*^A*/) | |
| 262 *to++ = *from++; | |
| 263 else | |
| 264 { | |
| 265 int c = *(++from); | |
| 266 | |
| 267 from++; | |
| 268 switch (c) | |
| 269 { | |
| 270 case 1: *to++ = c; break; | |
| 271 case '0': *to++ = '\0'; break; | |
| 272 case '_': *to++ = '\037'; break; | |
| 273 default: | |
| 771 | 274 return_me = list2 (build_msg_string |
| 428 | 275 ("Invalid data in documentation file -- ^A followed by weird code"), |
| 276 make_int (c)); | |
| 277 goto done; | |
| 278 } | |
| 279 } | |
| 280 } | |
| 281 | |
| 814 | 282 return_me = make_string (buffer, to - buffer); |
| 428 | 283 |
| 284 done: | |
| 814 | 285 if (!NILP (instream)) |
| 286 { | |
| 287 Lstream_delete (XLSTREAM (instream)); | |
| 288 Lstream_delete (XLSTREAM (fdstream)); | |
| 289 } | |
| 290 UNGCPRO; | |
| 428 | 291 if (buffer != buf) /* We must have allocated buffer above */ |
| 1726 | 292 xfree (buffer, Ibyte *); |
| 428 | 293 return return_me; |
| 294 } | |
| 295 | |
| 771 | 296 #define string_join(dest, s1, s2) \ |
| 297 memcpy (dest, XSTRING_DATA (s1), XSTRING_LENGTH (s1)); \ | |
| 298 memcpy (dest + XSTRING_LENGTH (s1), XSTRING_DATA (s2), \ | |
| 299 XSTRING_LENGTH (s2)); \ | |
| 428 | 300 dest[XSTRING_LENGTH (s1) + XSTRING_LENGTH (s2)] = '\0' |
| 301 | |
| 302 /* Extract a doc string from a file. FILEPOS says where to get it. | |
| 303 (This could actually be byte code instructions/constants instead | |
| 304 of a doc string.) | |
| 305 If it is an integer, use that position in the standard DOC file. | |
| 306 If it is (FILE . INTEGER), use FILE as the file name | |
| 307 and INTEGER as the position in that file. | |
| 308 But if INTEGER is negative, make it positive. | |
| 309 (A negative integer is used for user variables, so we can distinguish | |
| 310 them without actually fetching the doc string.) */ | |
| 311 | |
| 312 static Lisp_Object | |
| 313 get_doc_string (Lisp_Object filepos) | |
| 314 { | |
| 315 REGISTER int fd; | |
| 867 | 316 REGISTER Ibyte *name_nonreloc = 0; |
| 428 | 317 EMACS_INT position; |
| 318 Lisp_Object file, tem; | |
| 319 Lisp_Object name_reloc = Qnil; | |
| 814 | 320 int standard_doc_file = 0; |
| 428 | 321 |
| 322 if (INTP (filepos)) | |
| 323 { | |
| 324 file = Vinternal_doc_file_name; | |
| 814 | 325 standard_doc_file = 1; |
| 428 | 326 position = XINT (filepos); |
| 327 } | |
| 328 else if (CONSP (filepos) && INTP (XCDR (filepos))) | |
| 329 { | |
| 330 file = XCAR (filepos); | |
| 331 position = XINT (XCDR (filepos)); | |
| 332 if (position < 0) | |
| 333 position = - position; | |
| 334 } | |
| 335 else | |
| 336 return Qnil; | |
| 337 | |
| 338 if (!STRINGP (file)) | |
| 339 return Qnil; | |
| 340 | |
| 341 /* Put the file name in NAME as a C string. | |
| 342 If it is relative, combine it with Vdoc_directory. */ | |
| 343 | |
| 344 tem = Ffile_name_absolute_p (file); | |
| 345 if (NILP (tem)) | |
| 346 { | |
| 647 | 347 Bytecount minsize; |
| 428 | 348 /* XEmacs: Move this check here. OK if called during loadup to |
| 349 load byte code instructions. */ | |
| 350 if (!STRINGP (Vdoc_directory)) | |
| 351 return Qnil; | |
| 352 | |
| 353 minsize = XSTRING_LENGTH (Vdoc_directory); | |
| 354 /* sizeof ("../lib-src/") == 12 */ | |
| 355 if (minsize < 12) | |
| 356 minsize = 12; | |
| 867 | 357 name_nonreloc = alloca_ibytes (minsize + XSTRING_LENGTH (file) + 8); |
| 428 | 358 string_join (name_nonreloc, Vdoc_directory, file); |
| 359 } | |
| 360 else | |
| 361 name_reloc = file; | |
| 362 | |
| 771 | 363 fd = qxe_open (name_nonreloc ? name_nonreloc : |
| 364 XSTRING_DATA (name_reloc), O_RDONLY | OPEN_BINARY, 0); | |
| 428 | 365 if (fd < 0) |
| 366 { | |
| 367 if (purify_flag) | |
| 368 { | |
| 369 /* sizeof ("../lib-src/") == 12 */ | |
| 2367 | 370 name_nonreloc = alloca_ibytes (12 + XSTRING_LENGTH (file) + 8); |
| 428 | 371 /* Preparing to dump; DOC file is probably not installed. |
| 372 So check in ../lib-src. */ | |
| 2367 | 373 qxestrcpy_ascii (name_nonreloc, "../lib-src/"); |
| 771 | 374 qxestrcat (name_nonreloc, XSTRING_DATA (file)); |
| 428 | 375 |
| 771 | 376 fd = qxe_open (name_nonreloc, O_RDONLY | OPEN_BINARY, 0); |
| 428 | 377 } |
| 378 | |
| 379 if (fd < 0) | |
| 814 | 380 report_file_error ("Cannot open doc string file", |
| 381 name_nonreloc ? build_intstring (name_nonreloc) : | |
| 382 name_reloc); | |
| 428 | 383 } |
| 384 | |
| 814 | 385 tem = unparesseuxify_doc_string (fd, position, name_nonreloc, name_reloc, |
| 386 standard_doc_file); | |
| 771 | 387 retry_close (fd); |
| 428 | 388 |
| 389 if (!STRINGP (tem)) | |
| 563 | 390 signal_error_1 (Qinvalid_byte_code, tem); |
| 428 | 391 |
| 392 return tem; | |
| 393 } | |
| 394 | |
| 395 /* Get a string from position FILEPOS and pass it through the Lisp reader. | |
| 396 We use this for fetching the bytecode string and constants vector | |
| 397 of a compiled function from the .elc file. */ | |
| 398 | |
| 399 Lisp_Object | |
| 400 read_doc_string (Lisp_Object filepos) | |
| 401 { | |
| 402 Lisp_Object string = get_doc_string (filepos); | |
| 403 | |
| 404 if (!STRINGP (string)) | |
| 563 | 405 invalid_state ("loading bytecode failed to return string", string); |
| 428 | 406 return Fread (string); |
| 407 } | |
| 408 | |
| 3368 | 409 static Lisp_Object |
| 410 get_object_file_name (Lisp_Object filepos) | |
| 411 { | |
| 412 REGISTER int fd; | |
| 413 REGISTER Ibyte *name_nonreloc = 0; | |
| 414 EMACS_INT position; | |
| 415 Lisp_Object file, tem; | |
| 416 Lisp_Object name_reloc = Qnil; | |
| 417 int standard_doc_file = 0; | |
| 418 | |
| 419 if (INTP (filepos)) | |
| 420 { | |
| 421 file = Vinternal_doc_file_name; | |
| 422 standard_doc_file = 1; | |
| 423 position = XINT (filepos); | |
| 424 } | |
| 425 else if (CONSP (filepos) && INTP (XCDR (filepos))) | |
| 426 { | |
| 427 file = XCAR (filepos); | |
| 428 position = XINT (XCDR (filepos)); | |
| 429 if (position < 0) | |
| 430 position = - position; | |
| 431 } | |
| 432 else | |
| 433 return Qnil; | |
| 434 | |
| 435 if (!STRINGP (file)) | |
| 436 return Qnil; | |
| 437 | |
| 438 /* Put the file name in NAME as a C string. | |
| 439 If it is relative, combine it with Vdoc_directory. */ | |
| 440 | |
| 441 tem = Ffile_name_absolute_p (file); | |
| 442 if (NILP (tem)) | |
| 443 { | |
| 444 Bytecount minsize; | |
| 445 /* XEmacs: Move this check here. OK if called during loadup to | |
| 446 load byte code instructions. */ | |
| 447 if (!STRINGP (Vdoc_directory)) | |
| 448 return Qnil; | |
| 449 | |
| 450 minsize = XSTRING_LENGTH (Vdoc_directory); | |
| 451 /* sizeof ("../lib-src/") == 12 */ | |
| 452 if (minsize < 12) | |
| 453 minsize = 12; | |
| 454 name_nonreloc = alloca_ibytes (minsize + XSTRING_LENGTH (file) + 8); | |
| 455 string_join (name_nonreloc, Vdoc_directory, file); | |
| 456 } | |
| 457 else | |
| 458 name_reloc = file; | |
| 459 | |
| 460 fd = qxe_open (name_nonreloc ? name_nonreloc : | |
| 461 XSTRING_DATA (name_reloc), O_RDONLY | OPEN_BINARY, 0); | |
| 462 if (fd < 0) | |
| 463 { | |
| 464 if (purify_flag) | |
| 465 { | |
| 466 /* sizeof ("../lib-src/") == 12 */ | |
| 467 name_nonreloc = alloca_ibytes (12 + XSTRING_LENGTH (file) + 8); | |
| 468 /* Preparing to dump; DOC file is probably not installed. | |
| 469 So check in ../lib-src. */ | |
| 470 qxestrcpy_ascii (name_nonreloc, "../lib-src/"); | |
| 471 qxestrcat (name_nonreloc, XSTRING_DATA (file)); | |
| 472 | |
| 473 fd = qxe_open (name_nonreloc, O_RDONLY | OPEN_BINARY, 0); | |
| 474 } | |
| 475 | |
| 476 if (fd < 0) | |
| 477 report_file_error ("Cannot open doc string file", | |
| 478 name_nonreloc ? build_intstring (name_nonreloc) : | |
| 479 name_reloc); | |
| 480 } | |
| 481 | |
| 482 tem = extract_object_file_name (fd, position, name_nonreloc, name_reloc, | |
| 483 standard_doc_file); | |
| 484 retry_close (fd); | |
| 485 | |
| 486 if (!STRINGP (tem)) | |
| 487 signal_error_1 (Qinvalid_byte_code, tem); | |
| 488 | |
| 489 return tem; | |
| 490 } | |
| 491 | |
| 492 | |
| 493 static void | |
| 494 weird_doc (Lisp_Object sym, const CIbyte *weirdness, const CIbyte *type, | |
| 495 int pos) | |
| 496 { | |
| 497 if (!strcmp (weirdness, GETTEXT ("duplicate"))) return; | |
| 498 message ("Note: Strange doc (%s) for %s %s @ %d", | |
| 499 weirdness, type, XSTRING_DATA (XSYMBOL (sym)->name), pos); | |
| 500 } | |
| 501 | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
502 DEFUN ("built-in-symbol-file", Fbuilt_in_symbol_file, 1, 2, 0, /* |
| 3368 | 503 Return the C source file built-in symbol SYM comes from. |
| 504 Don't use this. Use the more general `symbol-file' (q.v.) instead. | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
505 |
|
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
506 If TYPE is nil or omitted, any kind of definition is acceptable. |
|
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
507 If TYPE is `defun', then function, subr, special form or macro definitions |
|
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
508 are acceptable. |
|
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
509 If TYPE is `defvar', then variable definitions are acceptable. |
| 3368 | 510 */ |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
511 (symbol, type)) |
| 3368 | 512 { |
| 513 /* This function can GC */ | |
| 514 Lisp_Object fun; | |
| 515 Lisp_Object filename = Qnil; | |
| 516 | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
517 if (EQ(Ffboundp(symbol), Qt) && (EQ(type, Qnil) || EQ(type, Qdefun))) |
| 3368 | 518 { |
| 519 fun = Findirect_function (symbol); | |
| 520 | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
521 if (SUBRP (fun) || (CONSP(fun) && (EQ (Qmacro, Fcar_safe (fun))) |
|
4381
3906442b491b
Improve style and add tests for 'built-in-symbol-file'.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4377
diff
changeset
|
522 && (fun = Fcdr_safe (fun), SUBRP (fun)))) |
| 3368 | 523 { |
| 524 if (XSUBR (fun)->doc == 0) | |
| 525 return Qnil; | |
| 526 | |
| 527 if ((EMACS_INT) XSUBR (fun)->doc >= 0) | |
| 528 { | |
| 529 weird_doc (symbol, "No file info available for function", | |
| 530 GETTEXT("function"), 0); | |
| 531 return Qnil; | |
| 532 } | |
| 533 else | |
| 534 filename = get_object_file_name | |
| 535 (make_int (- (EMACS_INT) XSUBR (fun)->doc)); | |
| 536 } | |
| 537 } | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
538 else if (EQ(Fboundp(symbol), Qt) && (EQ(type, Qnil) || EQ(type, Qdefvar))) |
| 3368 | 539 { |
| 540 Lisp_Object doc_offset = Fget (symbol, Qvariable_documentation, Qnil); | |
| 541 | |
| 542 if (!NILP(doc_offset)) | |
| 543 { | |
| 544 if (INTP(doc_offset)) | |
| 545 { | |
| 546 filename = get_object_file_name | |
| 547 (XINT (doc_offset) > 0 ? doc_offset | |
| 548 : make_int (- XINT (doc_offset))); | |
| 549 } | |
| 550 else if (CONSP(doc_offset)) | |
| 551 { | |
| 552 filename = get_object_file_name(doc_offset); | |
| 553 } | |
| 554 } | |
| 555 } | |
| 556 return filename; | |
| 557 } | |
| 558 | |
| 428 | 559 DEFUN ("documentation", Fdocumentation, 1, 2, 0, /* |
| 560 Return the documentation string of FUNCTION. | |
| 444 | 561 Unless a non-nil second argument RAW is given, the |
| 428 | 562 string is passed through `substitute-command-keys'. |
| 563 */ | |
| 564 (function, raw)) | |
| 565 { | |
| 566 /* This function can GC */ | |
| 567 Lisp_Object fun; | |
| 568 Lisp_Object doc; | |
| 569 | |
| 570 fun = Findirect_function (function); | |
| 571 | |
| 572 if (SUBRP (fun)) | |
| 573 { | |
| 574 if (XSUBR (fun)->doc == 0) | |
| 575 return Qnil; | |
| 576 if ((EMACS_INT) XSUBR (fun)->doc >= 0) | |
| 577 doc = build_string (XSUBR (fun)->doc); | |
| 578 else | |
| 579 doc = get_doc_string (make_int (- (EMACS_INT) XSUBR (fun)->doc)); | |
| 580 } | |
| 581 else if (COMPILED_FUNCTIONP (fun)) | |
| 582 { | |
| 583 Lisp_Object tem; | |
| 440 | 584 Lisp_Compiled_Function *f = XCOMPILED_FUNCTION (fun); |
| 428 | 585 if (! (f->flags.documentationp)) |
| 586 return Qnil; | |
| 587 tem = compiled_function_documentation (f); | |
| 588 if (STRINGP (tem)) | |
| 589 doc = tem; | |
| 590 else if (NATNUMP (tem) || CONSP (tem)) | |
| 591 doc = get_doc_string (tem); | |
| 592 else | |
| 593 return Qnil; | |
| 594 } | |
| 595 else if (KEYMAPP (fun)) | |
| 771 | 596 return build_msg_string ("Prefix command (definition is a keymap of subcommands)."); |
| 428 | 597 else if (STRINGP (fun) || VECTORP (fun)) |
| 771 | 598 return build_msg_string ("Keyboard macro."); |
| 428 | 599 else if (CONSP (fun)) |
| 600 { | |
| 601 Lisp_Object funcar = Fcar (fun); | |
| 602 | |
| 603 if (!SYMBOLP (funcar)) | |
| 604 return Fsignal (Qinvalid_function, list1 (fun)); | |
| 605 else if (EQ (funcar, Qlambda) | |
| 606 || EQ (funcar, Qautoload)) | |
| 607 { | |
| 608 Lisp_Object tem, tem1; | |
| 609 tem1 = Fcdr (Fcdr (fun)); | |
| 610 tem = Fcar (tem1); | |
| 611 if (STRINGP (tem)) | |
| 612 doc = tem; | |
| 613 /* Handle a doc reference--but these never come last | |
| 614 in the function body, so reject them if they are last. */ | |
| 615 else if ((NATNUMP (tem) || CONSP (tem)) | |
| 616 && ! NILP (XCDR (tem1))) | |
| 617 doc = get_doc_string (tem); | |
| 618 else | |
| 619 return Qnil; | |
| 620 } | |
| 621 else if (EQ (funcar, Qmacro)) | |
| 622 return Fdocumentation (Fcdr (fun), raw); | |
| 623 else | |
| 624 goto oops; | |
| 625 } | |
| 626 else | |
| 627 { | |
| 628 oops: | |
| 629 return Fsignal (Qinvalid_function, list1 (fun)); | |
| 630 } | |
| 631 | |
| 632 if (NILP (raw)) | |
| 633 { | |
| 634 struct gcpro gcpro1; | |
| 635 #ifdef I18N3 | |
| 636 Lisp_Object domain = Qnil; | |
| 637 if (COMPILED_FUNCTIONP (fun)) | |
| 638 domain = compiled_function_domain (XCOMPILED_FUNCTION (fun)); | |
| 639 if (NILP (domain)) | |
| 640 doc = Fgettext (doc); | |
| 641 else | |
| 642 doc = Fdgettext (domain, doc); | |
| 643 #endif | |
| 644 | |
| 645 GCPRO1 (doc); | |
| 646 doc = Fsubstitute_command_keys (doc); | |
| 647 UNGCPRO; | |
| 648 } | |
| 649 return doc; | |
| 650 } | |
| 651 | |
| 652 DEFUN ("documentation-property", Fdocumentation_property, 2, 3, 0, /* | |
| 653 Return the documentation string that is SYMBOL's PROP property. | |
| 654 This is like `get', but it can refer to strings stored in the | |
| 655 `doc-directory/DOC' file; and if the value is a string, it is passed | |
| 656 through `substitute-command-keys'. A non-nil third argument avoids this | |
| 657 translation. | |
| 658 */ | |
| 444 | 659 (symbol, prop, raw)) |
| 428 | 660 { |
| 661 /* This function can GC */ | |
| 1849 | 662 Lisp_Object doc = Qnil; |
| 428 | 663 #ifdef I18N3 |
| 664 REGISTER Lisp_Object domain; | |
| 665 #endif | |
| 666 struct gcpro gcpro1; | |
| 667 | |
| 668 GCPRO1 (doc); | |
| 669 | |
| 444 | 670 doc = Fget (symbol, prop, Qnil); |
| 428 | 671 if (INTP (doc)) |
| 672 doc = get_doc_string (XINT (doc) > 0 ? doc : make_int (- XINT (doc))); | |
| 673 else if (CONSP (doc)) | |
| 674 doc = get_doc_string (doc); | |
| 675 #ifdef I18N3 | |
| 676 if (!NILP (doc)) | |
| 677 { | |
| 444 | 678 domain = Fget (symbol, Qvariable_domain, Qnil); |
| 428 | 679 if (NILP (domain)) |
| 680 doc = Fgettext (doc); | |
| 681 else | |
| 682 doc = Fdgettext (domain, doc); | |
| 683 } | |
| 684 #endif | |
| 685 if (NILP (raw) && STRINGP (doc)) | |
| 686 doc = Fsubstitute_command_keys (doc); | |
| 687 UNGCPRO; | |
| 688 return doc; | |
| 689 } | |
| 690 | |
| 691 | |
| 692 DEFUN ("Snarf-documentation", Fsnarf_documentation, 1, 1, 0, /* | |
| 693 Used during Emacs initialization, before dumping runnable Emacs, | |
| 694 to find pointers to doc strings stored in `.../lib-src/DOC' and | |
| 695 record them in function definitions. | |
| 696 One arg, FILENAME, a string which does not include a directory. | |
| 697 The file is written to `../lib-src', and later found in `exec-directory' | |
| 698 when doc strings are referred to in the dumped Emacs. | |
| 699 */ | |
| 700 (filename)) | |
| 701 { | |
| 702 int fd; | |
| 867 | 703 Ibyte buf[1024 + 1]; |
| 428 | 704 REGISTER int filled; |
| 705 REGISTER int pos; | |
| 867 | 706 REGISTER Ibyte *p, *end; |
| 428 | 707 Lisp_Object sym, fun, tem; |
| 867 | 708 Ibyte *name; |
| 428 | 709 |
| 814 | 710 /* This function should not pass the data it's reading through a coding |
| 711 stream. The reason is that the only purpose of this function is to | |
| 712 find the file offsets for the documentation of the various functions, | |
| 713 not do anything with the documentation itself. If we pass through a | |
| 714 coding stream, the pointers will get messed up when we start reading | |
| 715 ISO 2022 data because our pointers will reflect internal format, not | |
| 716 external format. */ | |
| 717 | |
| 428 | 718 if (!purify_flag) |
| 563 | 719 invalid_operation ("Snarf-documentation can only be called in an undumped Emacs", Qunbound); |
| 428 | 720 |
| 721 CHECK_STRING (filename); | |
| 722 | |
| 1330 | 723 { |
| 724 name = alloca_ibytes (XSTRING_LENGTH (filename) + 14); | |
| 2367 | 725 qxestrcpy_ascii (name, "../lib-src/"); |
| 1330 | 726 } |
| 428 | 727 |
| 771 | 728 qxestrcat (name, XSTRING_DATA (filename)); |
| 428 | 729 |
| 771 | 730 fd = qxe_open (name, O_RDONLY | OPEN_BINARY, 0); |
| 428 | 731 if (fd < 0) |
| 771 | 732 report_file_error ("Opening doc string file", build_intstring (name)); |
| 428 | 733 Vinternal_doc_file_name = filename; |
| 734 filled = 0; | |
| 735 pos = 0; | |
| 736 while (1) | |
| 737 { | |
| 738 if (filled < 512) | |
| 771 | 739 filled += retry_read (fd, &buf[filled], sizeof (buf) - 1 - filled); |
| 428 | 740 if (!filled) |
| 741 break; | |
| 742 | |
| 743 buf[filled] = 0; | |
| 744 p = buf; | |
| 745 end = buf + (filled < 512 ? filled : filled - 128); | |
| 746 while (p != end && *p != '\037') p++; | |
| 747 /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */ | |
| 748 if (p != end) | |
| 749 { | |
| 771 | 750 end = qxestrchr (p, '\n'); |
| 3548 | 751 /* If you trigger a failure with this assertion, you probably |
| 752 configured with --quick-build and need to rebuild your DOC | |
| 3545 | 753 file. */ |
| 754 assert((end - p - 2) > -1); | |
| 771 | 755 sym = oblookup (Vobarray, p + 2, end - p - 2); |
| 428 | 756 if (SYMBOLP (sym)) |
| 757 { | |
| 758 Lisp_Object offset = make_int (pos + end + 1 - buf); | |
| 759 /* Attach a docstring to a variable */ | |
| 760 if (p[1] == 'V') | |
| 761 { | |
| 762 /* Install file-position as variable-documentation property | |
| 763 and make it negative for a user-variable | |
| 764 (doc starts with a `*'). */ | |
| 765 Lisp_Object old = Fget (sym, Qvariable_documentation, Qzero); | |
| 766 if (!ZEROP (old)) | |
| 767 { | |
| 768 weird_doc (sym, GETTEXT ("duplicate"), | |
| 769 GETTEXT ("variable"), pos); | |
| 770 /* In the case of duplicate doc file entries, always | |
| 771 take the later one. But if the doc is not an int | |
| 772 (a string, say) leave it alone. */ | |
| 773 if (!INTP (old)) | |
| 774 goto weird; | |
| 775 } | |
| 776 Fput (sym, Qvariable_documentation, | |
| 777 ((end[1] == '*') | |
| 778 ? make_int (- XINT (offset)) | |
| 779 : offset)); | |
| 780 } | |
| 781 /* Attach a docstring to a function. | |
| 782 The type determines where the docstring is stored. */ | |
| 783 else if (p[1] == 'F') | |
| 784 { | |
| 785 fun = indirect_function (sym,0); | |
| 786 | |
| 787 if (CONSP (fun) && EQ (XCAR (fun), Qmacro)) | |
| 788 fun = XCDR (fun); | |
| 789 | |
| 790 if (UNBOUNDP (fun)) | |
| 791 { | |
| 771 | 792 #if 0 /* There are lots of legitimate cases where this message will appear |
| 793 (e.g. any function that's only defined when MULE is defined, | |
| 794 provided that the function is used somewhere in a dumped Lisp | |
| 795 file, so that the symbol is interned in the dumped XEmacs), and | |
| 796 there's not a lot that can be done to eliminate the warning other | |
| 797 than kludges like moving the function to a Mule-only source file, | |
| 798 which often results in ugly code. Furthermore, the only point of | |
| 799 this warning is to warn you when you have a DEFUN that you forget | |
| 800 to DEFSUBR, but the compiler will also warn you, because the DEFUN | |
| 801 declares a static object, and the object will be unused -- you'll | |
| 802 get something like | |
| 803 | |
| 804 /src/xemacs/mule/src/abbrev.c:269: warning: `SFexpand_abbrev' defined but not used | |
| 805 | |
| 806 So I'm disabling this. --ben */ | |
| 807 | |
| 428 | 808 /* May have been #if'ed out or something */ |
| 809 weird_doc (sym, GETTEXT ("not fboundp"), | |
| 810 GETTEXT ("function"), pos); | |
| 771 | 811 #endif |
| 428 | 812 goto weird; |
| 813 } | |
| 814 else if (SUBRP (fun)) | |
| 815 { | |
| 816 /* Lisp_Subrs have a slot for it. */ | |
| 817 if (XSUBR (fun)->doc) | |
| 818 { | |
| 819 weird_doc (sym, GETTEXT ("duplicate"), | |
| 820 GETTEXT ("subr"), pos); | |
| 821 goto weird; | |
| 822 } | |
| 823 XSUBR (fun)->doc = (char *) (- XINT (offset)); | |
| 824 } | |
| 825 else if (CONSP (fun)) | |
| 826 { | |
| 827 /* If it's a lisp form, stick it in the form. */ | |
| 828 tem = XCAR (fun); | |
| 829 if (EQ (tem, Qlambda) || EQ (tem, Qautoload)) | |
| 830 { | |
| 831 tem = Fcdr (Fcdr (fun)); | |
| 832 if (CONSP (tem) && | |
| 833 INTP (XCAR (tem))) | |
| 834 { | |
| 835 Lisp_Object old = XCAR (tem); | |
| 836 if (!ZEROP (old)) | |
| 837 { | |
| 838 weird_doc (sym, GETTEXT ("duplicate"), | |
| 839 (EQ (tem, Qlambda) | |
| 840 ? GETTEXT ("lambda") | |
| 841 : GETTEXT ("autoload")), | |
| 842 pos); | |
| 843 /* In the case of duplicate doc file entries, | |
| 844 always take the later one. But if the doc | |
| 845 is not an int (a string, say) leave it | |
| 846 alone. */ | |
| 847 if (!INTP (old)) | |
| 848 goto weird; | |
| 849 } | |
| 850 XCAR (tem) = offset; | |
| 851 } | |
| 852 else if (!CONSP (tem)) | |
| 853 { | |
| 854 weird_doc (sym, GETTEXT ("!CONSP(tem)"), | |
| 855 GETTEXT ("function"), pos); | |
| 856 goto cont; | |
| 857 } | |
| 858 else | |
| 859 { | |
| 860 /* DOC string is a string not integer 0 */ | |
| 861 #if 0 | |
| 862 weird_doc (sym, GETTEXT ("!INTP(XCAR(tem))"), | |
| 863 GETTEXT ("function"), pos); | |
| 864 #endif | |
| 865 goto cont; | |
| 866 } | |
| 867 } | |
| 868 else | |
| 869 { | |
| 870 weird_doc (sym, GETTEXT ("not lambda or autoload"), | |
| 871 GETTEXT ("function"), pos); | |
| 872 goto cont; | |
| 873 } | |
| 874 } | |
| 875 else if (COMPILED_FUNCTIONP (fun)) | |
| 876 { | |
| 877 /* Compiled-Function objects sometimes have | |
| 878 slots for it. */ | |
| 440 | 879 Lisp_Compiled_Function *f = XCOMPILED_FUNCTION (fun); |
| 428 | 880 |
| 881 /* This compiled-function object must have a | |
| 882 slot for the docstring, since we've found a | |
| 883 docstring for it. Unless there were multiple | |
| 884 definitions of it, and the latter one didn't | |
| 885 have any doc, which is a legal if slightly | |
| 886 bogus situation, so don't blow up. */ | |
| 887 | |
| 888 if (! (f->flags.documentationp)) | |
| 889 { | |
| 890 weird_doc (sym, GETTEXT ("no doc slot"), | |
| 891 GETTEXT ("bytecode"), pos); | |
| 892 goto weird; | |
| 893 } | |
| 894 else | |
| 895 { | |
| 896 Lisp_Object old = | |
| 897 compiled_function_documentation (f); | |
| 898 if (!ZEROP (old)) | |
| 899 { | |
| 900 weird_doc (sym, GETTEXT ("duplicate"), | |
| 901 GETTEXT ("bytecode"), pos); | |
| 902 /* In the case of duplicate doc file entries, | |
| 903 always take the later one. But if the doc is | |
| 904 not an int (a string, say) leave it alone. */ | |
| 905 if (!INTP (old)) | |
| 906 goto weird; | |
| 907 } | |
| 908 set_compiled_function_documentation (f, offset); | |
| 909 } | |
| 910 } | |
| 911 else | |
| 912 { | |
| 913 /* Otherwise the function is undefined or | |
| 914 otherwise weird. Ignore it. */ | |
| 915 weird_doc (sym, GETTEXT ("weird function"), | |
| 916 GETTEXT ("function"), pos); | |
| 917 goto weird; | |
| 918 } | |
| 919 } | |
| 920 else | |
| 921 { | |
| 922 /* lose: */ | |
| 771 | 923 signal_error (Qfile_error, "DOC file invalid at position", |
| 924 make_int (pos)); | |
| 428 | 925 weird: |
| 926 /* goto lose */; | |
| 927 } | |
| 928 } | |
| 929 } | |
| 930 cont: | |
| 931 pos += end - buf; | |
| 932 filled -= end - buf; | |
| 933 memmove (buf, end, filled); | |
| 934 } | |
| 771 | 935 retry_close (fd); |
| 428 | 936 return Qnil; |
| 937 } | |
| 938 | |
| 939 #if 1 /* Don't warn about functions whose doc was lost because they were | |
| 940 wrapped by advice-freeze.el... */ | |
| 941 static int | |
| 942 kludgily_ignore_lost_doc_p (Lisp_Object sym) | |
| 943 { | |
| 944 # define kludge_prefix "ad-Orig-" | |
| 793 | 945 Lisp_Object name = XSYMBOL (sym)->name; |
| 946 return (XSTRING_LENGTH (name) > (Bytecount) (sizeof (kludge_prefix)) && | |
| 2367 | 947 !qxestrncmp_ascii (XSTRING_DATA (name), kludge_prefix, |
| 793 | 948 sizeof (kludge_prefix) - 1)); |
| 428 | 949 # undef kludge_prefix |
| 950 } | |
| 951 #else | |
| 952 # define kludgily_ignore_lost_doc_p(sym) 0 | |
| 953 #endif | |
| 954 | |
| 955 | |
| 956 static int | |
| 957 verify_doc_mapper (Lisp_Object sym, void *arg) | |
| 958 { | |
| 793 | 959 Lisp_Object closure = * (Lisp_Object *) arg; |
| 428 | 960 |
| 961 if (!NILP (Ffboundp (sym))) | |
| 962 { | |
| 963 int doc = 0; | |
| 964 Lisp_Object fun = XSYMBOL (sym)->function; | |
| 965 if (CONSP (fun) && | |
| 966 EQ (XCAR (fun), Qmacro)) | |
| 967 fun = XCDR (fun); | |
| 968 | |
| 969 if (SUBRP (fun)) | |
| 970 doc = (EMACS_INT) XSUBR (fun)->doc; | |
| 971 else if (SYMBOLP (fun)) | |
| 972 doc = -1; | |
| 973 else if (KEYMAPP (fun)) | |
| 974 doc = -1; | |
| 975 else if (CONSP (fun)) | |
| 976 { | |
| 977 Lisp_Object tem = XCAR (fun); | |
| 978 if (EQ (tem, Qlambda) || EQ (tem, Qautoload)) | |
| 979 { | |
| 980 doc = -1; | |
| 981 tem = Fcdr (Fcdr (fun)); | |
| 982 if (CONSP (tem) && | |
| 983 INTP (XCAR (tem))) | |
| 984 doc = XINT (XCAR (tem)); | |
| 985 } | |
| 986 } | |
| 987 else if (COMPILED_FUNCTIONP (fun)) | |
| 988 { | |
| 440 | 989 Lisp_Compiled_Function *f = XCOMPILED_FUNCTION (fun); |
| 428 | 990 if (! (f->flags.documentationp)) |
| 991 doc = -1; | |
| 992 else | |
| 993 { | |
| 994 Lisp_Object tem = compiled_function_documentation (f); | |
| 995 if (INTP (tem)) | |
| 996 doc = XINT (tem); | |
| 997 } | |
| 998 } | |
| 999 | |
| 1000 if (doc == 0 && !kludgily_ignore_lost_doc_p (sym)) | |
| 1001 { | |
| 1002 message ("Warning: doc lost for function %s.", | |
| 793 | 1003 XSTRING_DATA (XSYMBOL (sym)->name)); |
| 428 | 1004 XCDR (closure) = Qt; |
| 1005 } | |
| 1006 } | |
| 1007 if (!NILP (Fboundp (sym))) | |
| 1008 { | |
| 1009 Lisp_Object doc = Fget (sym, Qvariable_documentation, Qnil); | |
| 1010 if (ZEROP (doc)) | |
| 1011 { | |
| 1012 message ("Warning: doc lost for variable %s.", | |
| 793 | 1013 XSTRING_DATA (XSYMBOL (sym)->name)); |
| 428 | 1014 XCDR (closure) = Qt; |
| 1015 } | |
| 1016 } | |
| 1017 return 0; /* Never stop */ | |
| 1018 } | |
| 1019 | |
| 1020 DEFUN ("Verify-documentation", Fverify_documentation, 0, 0, 0, /* | |
| 1021 Used to make sure everything went well with Snarf-documentation. | |
| 1022 Writes to stderr if not. | |
| 1023 */ | |
| 1024 ()) | |
| 1025 { | |
| 1026 Lisp_Object closure = Fcons (Qnil, Qnil); | |
| 1027 struct gcpro gcpro1; | |
| 1028 GCPRO1 (closure); | |
| 1029 map_obarray (Vobarray, verify_doc_mapper, &closure); | |
| 1030 if (!NILP (Fcdr (closure))) | |
| 1031 message ("\n" | |
| 1032 "This is usually because some files were preloaded by loaddefs.el or\n" | |
| 1033 "site-load.el, but were not passed to make-docfile by Makefile.\n"); | |
| 1034 UNGCPRO; | |
| 1035 return NILP (Fcdr (closure)) ? Qt : Qnil; | |
| 1036 } | |
| 1037 | |
| 1038 | |
| 1039 DEFUN ("substitute-command-keys", Fsubstitute_command_keys, 1, 1, 0, /* | |
| 1040 Substitute key descriptions for command names in STRING. | |
| 1041 Return a new string which is STRING with substrings of the form \\=\\[COMMAND] | |
| 1042 replaced by either: a keystroke sequence that will invoke COMMAND, | |
| 1043 or "M-x COMMAND" if COMMAND is not on any keys. | |
| 1044 Substrings of the form \\=\\{MAPVAR} are replaced by summaries | |
| 444 | 1045 \(made by `describe-bindings') of the value of MAPVAR, taken as a keymap. |
| 428 | 1046 Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR |
| 1047 as the keymap for future \\=\\[COMMAND] substrings. | |
| 1048 \\=\\= quotes the following character and is discarded; | |
| 1049 thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output. | |
| 1050 */ | |
| 444 | 1051 (string)) |
| 428 | 1052 { |
| 1053 /* This function can GC */ | |
| 867 | 1054 Ibyte *buf; |
| 428 | 1055 int changed = 0; |
| 867 | 1056 REGISTER Ibyte *strdata; |
| 1057 REGISTER Ibyte *bufp; | |
| 428 | 1058 Bytecount strlength; |
| 1059 Bytecount idx; | |
| 1060 Bytecount bsize; | |
| 3025 | 1061 Ibyte *new_; |
| 444 | 1062 Lisp_Object tem = Qnil; |
| 1063 Lisp_Object keymap = Qnil; | |
| 1064 Lisp_Object name = Qnil; | |
| 867 | 1065 Ibyte *start; |
| 428 | 1066 Bytecount length; |
| 1067 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; | |
| 1068 | |
| 444 | 1069 if (NILP (string)) |
| 428 | 1070 return Qnil; |
| 1071 | |
| 444 | 1072 CHECK_STRING (string); |
| 1073 GCPRO4 (string, tem, keymap, name); | |
| 428 | 1074 |
| 1075 /* There is the possibility that the string is not destined for a | |
| 1076 translating stream, and it could be argued that we should do the | |
| 1077 same thing here as in Fformat(), but there are very few times | |
| 1078 when this will be the case and many calls to this function | |
| 1079 would have to have `gettext' calls added. (I18N3) */ | |
| 444 | 1080 string = LISP_GETTEXT (string); |
| 428 | 1081 |
| 1082 /* KEYMAP is either nil (which means search all the active keymaps) | |
| 1083 or a specified local map (which means search just that and the | |
| 1084 global map). If non-nil, it might come from Voverriding_local_map, | |
| 444 | 1085 or from a \\<mapname> construct in STRING itself.. */ |
| 428 | 1086 #if 0 /* FSFmacs */ |
| 1087 /* This is really weird and garbagey. If keymap is nil and there's | |
| 1088 an overriding-local-map, `where-is-internal' will correctly note | |
| 1089 this, so there's no reason to do it here. Maybe FSFmacs | |
| 1090 `where-is-internal' is broken. */ | |
| 1091 /* | |
| 1092 keymap = current_kboard->Voverriding_terminal_local_map; | |
| 1093 if (NILP (keymap)) | |
| 1094 keymap = Voverriding_local_map; | |
| 1095 */ | |
| 1096 #endif | |
| 1097 | |
| 444 | 1098 strlength = XSTRING_LENGTH (string); |
| 2367 | 1099 bsize = ITEXT_ZTERM_SIZE + strlength; |
| 1100 buf = xnew_ibytes (bsize); | |
| 428 | 1101 bufp = buf; |
| 1102 | |
| 1103 /* Have to reset strdata every time GC might be called */ | |
| 444 | 1104 strdata = XSTRING_DATA (string); |
| 428 | 1105 for (idx = 0; idx < strlength; ) |
| 1106 { | |
| 867 | 1107 Ibyte *strp = strdata + idx; |
| 428 | 1108 |
| 1109 if (strp[0] != '\\') | |
| 1110 { | |
| 1111 /* just copy other chars */ | |
| 1112 /* As it happens, this will work with Mule even if the | |
| 1113 character quoted is multi-byte; the remaining multi-byte | |
| 1114 characters will just be copied by this loop. */ | |
| 1115 *bufp++ = *strp; | |
| 1116 idx++; | |
| 1117 } | |
| 1118 else switch (strp[1]) | |
| 1119 { | |
| 1120 default: | |
| 1121 { | |
| 1122 /* just copy unknown escape sequences */ | |
| 1123 *bufp++ = *strp; | |
| 1124 idx++; | |
| 1125 break; | |
| 1126 } | |
| 1127 case '=': | |
| 1128 { | |
| 1129 /* \= quotes the next character; | |
| 1130 thus, to put in \[ without its special meaning, use \=\[. */ | |
| 1131 /* As it happens, this will work with Mule even if the | |
| 1132 character quoted is multi-byte; the remaining multi-byte | |
| 1133 characters will just be copied by this loop. */ | |
| 1134 changed = 1; | |
| 1135 *bufp++ = strp[2]; | |
| 1136 idx += 3; | |
| 1137 break; | |
| 1138 } | |
| 1139 case '[': | |
| 1140 { | |
| 1141 changed = 1; | |
| 1142 idx += 2; /* skip \[ */ | |
| 1143 strp += 2; | |
| 1144 start = strp; | |
| 1145 | |
| 1146 while ((idx < strlength) | |
| 1147 && *strp != ']') | |
| 1148 { | |
| 1149 strp++; | |
| 1150 idx++; | |
| 1151 } | |
| 1152 length = strp - start; | |
| 1153 idx++; /* skip ] */ | |
| 1154 | |
| 1155 tem = Fintern (make_string (start, length), Qnil); | |
| 1156 tem = Fwhere_is_internal (tem, keymap, Qt, Qnil, Qnil); | |
| 1157 | |
| 1158 #if 0 /* FSFmacs */ | |
| 444 | 1159 /* Disregard menu bar bindings; it is positively annoying to |
| 1160 mention them when there's no menu bar, and it isn't terribly | |
| 1161 useful even when there is a menu bar. */ | |
| 1162 if (!NILP (tem)) | |
| 1163 { | |
| 1164 firstkey = Faref (tem, Qzero); | |
| 1165 if (EQ (firstkey, Qmenu_bar)) | |
| 1166 tem = Qnil; | |
| 1167 } | |
| 428 | 1168 #endif |
| 1169 | |
| 1170 if (NILP (tem)) /* but not on any keys */ | |
| 1171 { | |
| 3025 | 1172 new_ = (Ibyte *) xrealloc (buf, bsize += 4); |
| 1173 bufp += new_ - buf; | |
| 1174 buf = new_; | |
| 428 | 1175 memcpy (bufp, "M-x ", 4); |
| 1176 bufp += 4; | |
| 1177 goto subst; | |
| 1178 } | |
| 1179 else | |
| 1180 { /* function is on a key */ | |
| 1181 tem = Fkey_description (tem); | |
| 1182 goto subst_string; | |
| 1183 } | |
| 1184 } | |
| 1185 case '{': | |
| 1186 case '<': | |
| 1187 { | |
| 444 | 1188 Lisp_Object buffer = Fget_buffer_create (QSsubstitute); |
| 1189 struct buffer *buf_ = XBUFFER (buffer); | |
| 428 | 1190 |
| 1191 Fbuffer_disable_undo (buffer); | |
| 1192 Ferase_buffer (buffer); | |
| 1193 | |
| 1194 /* \{foo} is replaced with a summary of keymap (symbol-value foo). | |
| 1195 \<foo> just sets the keymap used for \[cmd]. */ | |
| 1196 changed = 1; | |
| 1197 idx += 2; /* skip \{ or \< */ | |
| 1198 strp += 2; | |
| 1199 start = strp; | |
| 1200 | |
| 1201 while ((idx < strlength) | |
| 1202 && *strp != '}' && *strp != '>') | |
| 1203 { | |
| 1204 strp++; | |
| 1205 idx++; | |
| 1206 } | |
| 1207 length = strp - start; | |
| 1208 idx++; /* skip } or > */ | |
| 1209 | |
| 1210 /* Get the value of the keymap in TEM, or nil if undefined. | |
| 1211 Do this while still in the user's current buffer | |
| 1212 in case it is a local variable. */ | |
| 1213 name = Fintern (make_string (start, length), Qnil); | |
| 1214 tem = Fboundp (name); | |
| 1215 if (! NILP (tem)) | |
| 1216 { | |
| 1217 tem = Fsymbol_value (name); | |
| 1218 if (! NILP (tem)) | |
| 1219 tem = get_keymap (tem, 0, 1); | |
| 1220 } | |
| 1221 | |
| 1222 if (NILP (tem)) | |
| 1223 { | |
| 444 | 1224 buffer_insert_c_string (buf_, "(uses keymap \""); |
| 1225 buffer_insert_lisp_string (buf_, Fsymbol_name (name)); | |
| 1226 buffer_insert_c_string (buf_, "\", which is not currently defined) "); | |
| 428 | 1227 |
| 1228 if (start[-1] == '<') keymap = Qnil; | |
| 1229 } | |
| 1230 else if (start[-1] == '<') | |
| 1231 keymap = tem; | |
| 1232 else | |
| 1233 describe_map_tree (tem, 1, Qnil, Qnil, 0, buffer); | |
| 1234 | |
| 1235 tem = make_string_from_buffer (buf_, BUF_BEG (buf_), | |
| 1236 BUF_Z (buf_) - BUF_BEG (buf_)); | |
| 1237 Ferase_buffer (buffer); | |
| 444 | 1238 } |
| 1239 goto subst_string; | |
| 428 | 1240 |
| 444 | 1241 subst_string: |
| 1242 start = XSTRING_DATA (tem); | |
| 1243 length = XSTRING_LENGTH (tem); | |
| 1244 subst: | |
| 1245 bsize += length; | |
| 3025 | 1246 new_ = (Ibyte *) xrealloc (buf, bsize); |
| 1247 bufp += new_ - buf; | |
| 1248 buf = new_; | |
| 444 | 1249 memcpy (bufp, start, length); |
| 1250 bufp += length; | |
| 428 | 1251 |
| 444 | 1252 /* Reset STRDATA in case gc relocated it. */ |
| 1253 strdata = XSTRING_DATA (string); | |
| 428 | 1254 |
| 444 | 1255 break; |
| 428 | 1256 } |
| 1257 } | |
| 1258 | |
| 1259 if (changed) /* don't bother if nothing substituted */ | |
| 1260 tem = make_string (buf, bufp - buf); | |
| 1261 else | |
| 444 | 1262 tem = string; |
| 1726 | 1263 xfree (buf, Ibyte *); |
| 428 | 1264 UNGCPRO; |
| 1265 return tem; | |
| 1266 } | |
| 1267 | |
| 1268 | |
| 1269 /************************************************************************/ | |
| 1270 /* initialization */ | |
| 1271 /************************************************************************/ | |
| 1272 | |
| 1273 void | |
| 1274 syms_of_doc (void) | |
| 1275 { | |
| 3368 | 1276 DEFSUBR (Fbuilt_in_symbol_file); |
| 428 | 1277 DEFSUBR (Fdocumentation); |
| 1278 DEFSUBR (Fdocumentation_property); | |
| 1279 DEFSUBR (Fsnarf_documentation); | |
| 1280 DEFSUBR (Fverify_documentation); | |
| 1281 DEFSUBR (Fsubstitute_command_keys); | |
|
4367
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
1282 |
|
69e6352406f0
Handle macros, autoloads correctly in symbol-file. Add an incomplete TYPE arg.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3548
diff
changeset
|
1283 DEFSYMBOL (Qdefvar); |
| 428 | 1284 } |
| 1285 | |
| 1286 void | |
| 1287 vars_of_doc (void) | |
| 1288 { | |
| 1289 DEFVAR_LISP ("internal-doc-file-name", &Vinternal_doc_file_name /* | |
| 1290 Name of file containing documentation strings of built-in symbols. | |
| 1291 */ ); | |
| 1292 Vinternal_doc_file_name = Qnil; | |
| 1293 | |
| 1294 QSsubstitute = build_string (" *substitute*"); | |
| 1295 staticpro (&QSsubstitute); | |
| 1296 } |
