Use gnulib's mktime module.
[bpt/emacs.git] / src / doc.c
CommitLineData
c6045832 1/* Record indices of function doc strings stored in a file.
0b5538bd 2 Copyright (C) 1985, 1986, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
114f9c96 3 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
8cabe764 4 Free Software Foundation, Inc.
c6045832
JB
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
c6045832 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
c6045832
JB
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c6045832
JB
20
21
18160b98 22#include <config.h>
c6045832
JB
23
24#include <sys/types.h>
f2a77c3a 25#include <sys/file.h> /* Must be after sys/types.h for USG*/
9f77d2aa 26#include <ctype.h>
d7306fe6 27#include <setjmp.h>
c6045832 28#include <fcntl.h>
c6045832 29
29beb080
RS
30#ifdef HAVE_UNISTD_H
31#include <unistd.h>
32#endif
33
c6045832
JB
34#include "lisp.h"
35#include "buffer.h"
665d3046 36#include "keyboard.h"
83be827a 37#include "character.h"
8feddab4 38#include "keymap.h"
878bde49 39#include "buildobj.h"
c6045832 40
512ca171 41Lisp_Object Vdoc_file_name;
c6045832 42
9191c8ae
GM
43Lisp_Object Qfunction_documentation;
44
d87a9ab8
JD
45/* A list of files used to build this Emacs binary. */
46static Lisp_Object Vbuild_files;
47
912e8480
RS
48/* Buffer used for reading from documentation file. */
49static char *get_doc_string_buffer;
50static int get_doc_string_buffer_size;
51
32caae30 52static unsigned char *read_bytecode_pointer;
f57e2426 53Lisp_Object Fsnarf_documentation (Lisp_Object);
32caae30
RS
54
55/* readchar in lread.c calls back here to fetch the next byte.
56 If UNREADFLAG is 1, we unread a byte. */
57
58int
971de7fb 59read_bytecode_char (int unreadflag)
32caae30
RS
60{
61 if (unreadflag)
62 {
63 read_bytecode_pointer--;
64 return 0;
65 }
66 return *read_bytecode_pointer++;
67}
68
700ea809
RS
69/* Extract a doc string from a file. FILEPOS says where to get it.
70 If it is an integer, use that position in the standard DOC-... file.
71 If it is (FILE . INTEGER), use FILE as the file name
0c00bc70
RS
72 and INTEGER as the position in that file.
73 But if INTEGER is negative, make it positive.
74 (A negative integer is used for user variables, so we can distinguish
ba29c3c9
RS
75 them without actually fetching the doc string.)
76
a154a4ef
SM
77 If the location does not point to the beginning of a docstring
78 (e.g. because the file has been modified and the location is stale),
79 return nil.
80
e96179b3
RS
81 If UNIBYTE is nonzero, always make a unibyte string.
82
f1df0d67
RS
83 If DEFINITION is nonzero, assume this is for reading
84 a dynamic function definition; convert the bytestring
85 and the constants vector with appropriate byte handling,
86 and return a cons cell. */
700ea809 87
0c3debbc 88Lisp_Object
971de7fb 89get_doc_string (Lisp_Object filepos, int unibyte, int definition)
778d47c7 90{
700ea809 91 char *from, *to;
778d47c7
RS
92 register int fd;
93 register char *name;
94 register char *p, *p1;
84c9ce05
LMI
95 EMACS_INT minsize;
96 EMACS_INT offset, position;
700ea809 97 Lisp_Object file, tem;
778d47c7 98
700ea809
RS
99 if (INTEGERP (filepos))
100 {
101 file = Vdoc_file_name;
102 position = XINT (filepos);
103 }
104 else if (CONSP (filepos))
105 {
03699b14
KR
106 file = XCAR (filepos);
107 position = XINT (XCDR (filepos));
700ea809
RS
108 }
109 else
778d47c7
RS
110 return Qnil;
111
87afdd65
SM
112 if (position < 0)
113 position = - position;
114
700ea809
RS
115 if (!STRINGP (Vdoc_directory))
116 return Qnil;
117
118 if (!STRINGP (file))
119 return Qnil;
177c0ea7 120
700ea809
RS
121 /* Put the file name in NAME as a C string.
122 If it is relative, combine it with Vdoc_directory. */
123
124 tem = Ffile_name_absolute_p (file);
125 if (NILP (tem))
126 {
d5db4077 127 minsize = SCHARS (Vdoc_directory);
700ea809
RS
128 /* sizeof ("../etc/") == 8 */
129 if (minsize < 8)
130 minsize = 8;
d5db4077
KR
131 name = (char *) alloca (minsize + SCHARS (file) + 8);
132 strcpy (name, SDATA (Vdoc_directory));
133 strcat (name, SDATA (file));
700ea809
RS
134 }
135 else
136 {
d5db4077 137 name = (char *) SDATA (file);
700ea809 138 }
c6045832 139
68c45bf0 140 fd = emacs_open (name, O_RDONLY, 0);
c6045832 141 if (fd < 0)
778d47c7
RS
142 {
143#ifndef CANNOT_DUMP
144 if (!NILP (Vpurify_flag))
145 {
146 /* Preparing to dump; DOC file is probably not installed.
147 So check in ../etc. */
148 strcpy (name, "../etc/");
d5db4077 149 strcat (name, SDATA (file));
778d47c7 150
68c45bf0 151 fd = emacs_open (name, O_RDONLY, 0);
778d47c7
RS
152 }
153#endif
778d47c7
RS
154 if (fd < 0)
155 error ("Cannot open doc string file \"%s\"", name);
156 }
157
0fded513 158 /* Seek only to beginning of disk block. */
a154a4ef
SM
159 /* Make sure we read at least 1024 bytes before `position'
160 so we can check the leading text for consistency. */
161 offset = min (position, max (1024, position % (8 * 1024)));
0fded513 162 if (0 > lseek (fd, position - offset, 0))
c6045832 163 {
68c45bf0 164 emacs_close (fd);
c6045832 165 error ("Position %ld out of range in doc string file \"%s\"",
700ea809 166 position, name);
c6045832 167 }
700ea809 168
912e8480
RS
169 /* Read the doc string into get_doc_string_buffer.
170 P points beyond the data just read. */
0fded513 171
912e8480 172 p = get_doc_string_buffer;
700ea809 173 while (1)
c6045832 174 {
84c9ce05
LMI
175 EMACS_INT space_left = (get_doc_string_buffer_size
176 - (p - get_doc_string_buffer));
700ea809
RS
177 int nread;
178
0fded513 179 /* Allocate or grow the buffer if we need to. */
700ea809
RS
180 if (space_left == 0)
181 {
84c9ce05 182 EMACS_INT in_buffer = p - get_doc_string_buffer;
912e8480
RS
183 get_doc_string_buffer_size += 16 * 1024;
184 get_doc_string_buffer
185 = (char *) xrealloc (get_doc_string_buffer,
186 get_doc_string_buffer_size + 1);
187 p = get_doc_string_buffer + in_buffer;
188 space_left = (get_doc_string_buffer_size
189 - (p - get_doc_string_buffer));
700ea809
RS
190 }
191
0fded513
RS
192 /* Read a disk block at a time.
193 If we read the same block last time, maybe skip this? */
700ea809
RS
194 if (space_left > 1024 * 8)
195 space_left = 1024 * 8;
68c45bf0 196 nread = emacs_read (fd, p, space_left);
700ea809
RS
197 if (nread < 0)
198 {
68c45bf0 199 emacs_close (fd);
700ea809
RS
200 error ("Read error on documentation file");
201 }
202 p[nread] = 0;
203 if (!nread)
c6045832 204 break;
912e8480 205 if (p == get_doc_string_buffer)
8966b757 206 p1 = strchr (p + offset, '\037');
0fded513 207 else
8966b757 208 p1 = strchr (p, '\037');
c6045832
JB
209 if (p1)
210 {
211 *p1 = 0;
212 p = p1;
213 break;
214 }
700ea809 215 p += nread;
c6045832 216 }
68c45bf0 217 emacs_close (fd);
700ea809 218
a154a4ef
SM
219 /* Sanity checking. */
220 if (CONSP (filepos))
221 {
222 int test = 1;
223 if (get_doc_string_buffer[offset - test++] != ' ')
224 return Qnil;
225 while (get_doc_string_buffer[offset - test] >= '0'
226 && get_doc_string_buffer[offset - test] <= '9')
227 test++;
228 if (get_doc_string_buffer[offset - test++] != '@'
229 || get_doc_string_buffer[offset - test] != '#')
230 return Qnil;
231 }
232 else
233 {
234 int test = 1;
235 if (get_doc_string_buffer[offset - test++] != '\n')
236 return Qnil;
237 while (get_doc_string_buffer[offset - test] > ' ')
238 test++;
239 if (get_doc_string_buffer[offset - test] != '\037')
240 return Qnil;
241 }
242
700ea809
RS
243 /* Scan the text and perform quoting with ^A (char code 1).
244 ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_. */
912e8480
RS
245 from = get_doc_string_buffer + offset;
246 to = get_doc_string_buffer + offset;
700ea809
RS
247 while (from != p)
248 {
249 if (*from == 1)
250 {
251 int c;
252
253 from++;
254 c = *from++;
255 if (c == 1)
256 *to++ = c;
257 else if (c == '0')
258 *to++ = 0;
259 else if (c == '_')
260 *to++ = 037;
261 else
262 error ("Invalid data in documentation file -- ^A followed by code 0%o", c);
263 }
264 else
265 *to++ = *from++;
266 }
267
32caae30
RS
268 /* If DEFINITION, read from this buffer
269 the same way we would read bytes from a file. */
f1df0d67
RS
270 if (definition)
271 {
32caae30
RS
272 read_bytecode_pointer = get_doc_string_buffer + offset;
273 return Fread (Qlambda);
f1df0d67
RS
274 }
275
e96179b3
RS
276 if (unibyte)
277 return make_unibyte_string (get_doc_string_buffer + offset,
278 to - (get_doc_string_buffer + offset));
279 else
fb2fdea7 280 {
198a7a97 281 /* The data determines whether the string is multibyte. */
84c9ce05
LMI
282 EMACS_INT nchars = multibyte_chars_in_text (get_doc_string_buffer + offset,
283 to - (get_doc_string_buffer + offset));
fb2fdea7
RS
284 return make_string_from_bytes (get_doc_string_buffer + offset,
285 nchars,
286 to - (get_doc_string_buffer + offset));
287 }
700ea809
RS
288}
289
290/* Get a string from position FILEPOS and pass it through the Lisp reader.
291 We use this for fetching the bytecode string and constants vector
292 of a compiled function from the .elc file. */
293
294Lisp_Object
971de7fb 295read_doc_string (Lisp_Object filepos)
700ea809 296{
e96179b3 297 return get_doc_string (filepos, 0, 1);
c6045832
JB
298}
299
e5aa79fa 300static int
971de7fb 301reread_doc_file (Lisp_Object file)
a154a4ef 302{
13d7dc77 303#if 0
a154a4ef
SM
304 Lisp_Object reply, prompt[3];
305 struct gcpro gcpro1;
306 GCPRO1 (file);
307 prompt[0] = build_string ("File ");
308 prompt[1] = NILP (file) ? Vdoc_file_name : file;
13d7dc77 309 prompt[2] = build_string (" is out of sync. Reload? ");
a154a4ef
SM
310 reply = Fy_or_n_p (Fconcat (3, prompt));
311 UNGCPRO;
312 if (NILP (reply))
e5aa79fa 313 return 0;
13d7dc77 314#endif
a154a4ef
SM
315
316 if (NILP (file))
317 Fsnarf_documentation (Vdoc_file_name);
318 else
319 Fload (file, Qt, Qt, Qt, Qnil);
e5aa79fa
SM
320
321 return 1;
a154a4ef
SM
322}
323
ee04dc54 324DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
335c5470
PJ
325 doc: /* Return the documentation string of FUNCTION.
326Unless a non-nil second argument RAW is given, the
327string is passed through `substitute-command-keys'. */)
5842a27b 328 (Lisp_Object function, Lisp_Object raw)
c6045832
JB
329{
330 Lisp_Object fun;
331 Lisp_Object funcar;
ee04dc54 332 Lisp_Object tem, doc;
e5aa79fa
SM
333 int try_reload = 1;
334
335 documentation:
c6045832 336
8d17fe0b 337 doc = Qnil;
177c0ea7 338
9191c8ae
GM
339 if (SYMBOLP (function)
340 && (tem = Fget (function, Qfunction_documentation),
341 !NILP (tem)))
342 return Fdocumentation_property (function, Qfunction_documentation, raw);
177c0ea7 343
a7f96a35 344 fun = Findirect_function (function, Qnil);
5b5f6883 345 if (SUBRP (fun))
c6045832 346 {
9191c8ae
GM
347 if (XSUBR (fun)->doc == 0)
348 return Qnil;
349 else if ((EMACS_INT) XSUBR (fun)->doc >= 0)
ee04dc54 350 doc = build_string (XSUBR (fun)->doc);
c6045832 351 else
87afdd65 352 doc = make_number ((EMACS_INT) XSUBR (fun)->doc);
5b5f6883
KH
353 }
354 else if (COMPILEDP (fun))
355 {
87afdd65 356 if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) <= COMPILED_DOC_STRING)
c6045832 357 return Qnil;
87afdd65 358 tem = AREF (fun, COMPILED_DOC_STRING);
e6d12642 359 if (STRINGP (tem))
ee04dc54 360 doc = tem;
700ea809 361 else if (NATNUMP (tem) || CONSP (tem))
87afdd65 362 doc = tem;
ee04dc54
RM
363 else
364 return Qnil;
5b5f6883
KH
365 }
366 else if (STRINGP (fun) || VECTORP (fun))
367 {
c6045832 368 return build_string ("Keyboard macro.");
5b5f6883
KH
369 }
370 else if (CONSP (fun))
371 {
c6045832 372 funcar = Fcar (fun);
e6d12642 373 if (!SYMBOLP (funcar))
2f0a47f9 374 xsignal1 (Qinvalid_function, fun);
502ddf23 375 else if (EQ (funcar, Qkeymap))
a3cec380 376 return build_string ("Prefix command (definition is a keymap associating keystrokes with commands).");
502ddf23
JB
377 else if (EQ (funcar, Qlambda)
378 || EQ (funcar, Qautoload))
c6045832 379 {
ae44f7a4
RS
380 Lisp_Object tem1;
381 tem1 = Fcdr (Fcdr (fun));
382 tem = Fcar (tem1);
e6d12642 383 if (STRINGP (tem))
ee04dc54 384 doc = tem;
ae44f7a4
RS
385 /* Handle a doc reference--but these never come last
386 in the function body, so reject them if they are last. */
87afdd65
SM
387 else if ((NATNUMP (tem) || (CONSP (tem) && INTEGERP (XCDR (tem))))
388 && !NILP (XCDR (tem1)))
389 doc = tem;
ee04dc54
RM
390 else
391 return Qnil;
c6045832 392 }
502ddf23 393 else if (EQ (funcar, Qmacro))
ee04dc54 394 return Fdocumentation (Fcdr (fun), raw);
5b5f6883
KH
395 else
396 goto oops;
397 }
398 else
399 {
400 oops:
2f0a47f9 401 xsignal1 (Qinvalid_function, fun);
c6045832 402 }
ee04dc54 403
db3534c3
JB
404 /* Check for an advised function. Its doc string
405 has an `ad-advice-info' text property. */
406 if (STRINGP (doc))
407 {
408 Lisp_Object innerfunc;
409 innerfunc = Fget_text_property (make_number (0),
410 intern ("ad-advice-info"),
411 doc);
412 if (! NILP (innerfunc))
413 doc = call1 (intern ("ad-make-advised-docstring"), innerfunc);
414 }
415
e5aa79fa
SM
416 /* If DOC is 0, it's typically because of a dumped file missing
417 from the DOC file (bug in src/Makefile.in). */
71cdb109
SM
418 if (EQ (doc, make_number (0)))
419 doc = Qnil;
68d8a8e1 420 if (INTEGERP (doc) || CONSP (doc))
a154a4ef
SM
421 {
422 Lisp_Object tem;
423 tem = get_doc_string (doc, 0, 0);
e5aa79fa 424 if (NILP (tem) && try_reload)
a154a4ef
SM
425 {
426 /* The file is newer, we need to reset the pointers. */
427 struct gcpro gcpro1, gcpro2;
428 GCPRO2 (function, raw);
e5aa79fa 429 try_reload = reread_doc_file (Fcar_safe (doc));
a154a4ef 430 UNGCPRO;
e5aa79fa
SM
431 if (try_reload)
432 {
433 try_reload = 0;
434 goto documentation;
435 }
a154a4ef
SM
436 }
437 else
438 doc = tem;
439 }
87afdd65 440
956ace37 441 if (NILP (raw))
441d75e5 442 doc = Fsubstitute_command_keys (doc);
ee04dc54 443 return doc;
c6045832
JB
444}
445
f6ee1260
GM
446DEFUN ("documentation-property", Fdocumentation_property,
447 Sdocumentation_property, 2, 3, 0,
335c5470
PJ
448 doc: /* Return the documentation string that is SYMBOL's PROP property.
449Third argument RAW omitted or nil means pass the result through
450`substitute-command-keys' if it is a string.
451
452This differs from `get' in that it can refer to strings stored in the
453`etc/DOC' file; and that it evaluates documentation properties that
454aren't strings. */)
5842a27b 455 (Lisp_Object symbol, Lisp_Object prop, Lisp_Object raw)
c6045832 456{
e5aa79fa 457 int try_reload = 1;
2f0b74ea 458 Lisp_Object tem;
c6045832 459
e5aa79fa 460 documentation_property:
177c0ea7 461
4acb738e 462 tem = Fget (symbol, prop);
44766095 463 if (EQ (tem, make_number (0)))
71cdb109 464 tem = Qnil;
68d8a8e1 465 if (INTEGERP (tem) || (CONSP (tem) && INTEGERP (XCDR (tem))))
a154a4ef
SM
466 {
467 Lisp_Object doc = tem;
468 tem = get_doc_string (tem, 0, 0);
e5aa79fa 469 if (NILP (tem) && try_reload)
a154a4ef
SM
470 {
471 /* The file is newer, we need to reset the pointers. */
472 struct gcpro gcpro1, gcpro2, gcpro3;
473 GCPRO3 (symbol, prop, raw);
e5aa79fa 474 try_reload = reread_doc_file (Fcar_safe (doc));
a154a4ef 475 UNGCPRO;
e5aa79fa
SM
476 if (try_reload)
477 {
478 try_reload = 0;
479 goto documentation_property;
480 }
a154a4ef
SM
481 }
482 }
f6ee1260
GM
483 else if (!STRINGP (tem))
484 /* Feval protects its argument. */
485 tem = Feval (tem);
177c0ea7 486
e6d12642 487 if (NILP (raw) && STRINGP (tem))
bbd7d5d3 488 tem = Fsubstitute_command_keys (tem);
992d176e 489 return tem;
c6045832
JB
490}
491\f
283e1184
JB
492/* Scanning the DOC files and placing docstring offsets into functions. */
493
494static void
971de7fb 495store_function_docstring (Lisp_Object fun, EMACS_INT offset)
b8ce688b 496/* Use EMACS_INT because we get offset from pointer subtraction. */
283e1184
JB
497{
498 fun = indirect_function (fun);
499
500 /* The type determines where the docstring is stored. */
501
502 /* Lisp_Subrs have a slot for it. */
e6d12642 503 if (SUBRP (fun))
283e1184
JB
504 XSUBR (fun)->doc = (char *) - offset;
505
506 /* If it's a lisp form, stick it in the form. */
507 else if (CONSP (fun))
508 {
509 Lisp_Object tem;
510
03699b14 511 tem = XCAR (fun);
283e1184
JB
512 if (EQ (tem, Qlambda) || EQ (tem, Qautoload))
513 {
514 tem = Fcdr (Fcdr (fun));
03699b14 515 if (CONSP (tem) && INTEGERP (XCAR (tem)))
d6d23852 516 XSETCAR (tem, make_number (offset));
283e1184
JB
517 }
518 else if (EQ (tem, Qmacro))
03699b14 519 store_function_docstring (XCDR (fun), offset);
283e1184
JB
520 }
521
522 /* Bytecode objects sometimes have slots for it. */
e6d12642 523 else if (COMPILEDP (fun))
283e1184
JB
524 {
525 /* This bytecode object must have a slot for the
526 docstring, since we've found a docstring for it. */
87afdd65 527 if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) > COMPILED_DOC_STRING)
3ae565b3 528 ASET (fun, COMPILED_DOC_STRING, make_number (offset));
283e1184
JB
529 }
530}
531
878bde49 532static const char buildobj[] = BUILDOBJ;
283e1184 533
c6045832 534DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
335c5470 535 1, 1, 0,
f4e25f94
RS
536 doc: /* Used during Emacs initialization to scan the `etc/DOC...' file.
537This searches the `etc/DOC...' file for doc strings and
538records them in function and variable definitions.
539The function takes one argument, FILENAME, a string;
540it specifies the file name (without a directory) of the DOC file.
541That file is found in `../etc' now; later, when the dumped Emacs is run,
98b6690a 542the same file name is found in the `doc-directory'. */)
5842a27b 543 (Lisp_Object filename)
c6045832
JB
544{
545 int fd;
546 char buf[1024 + 1];
84c9ce05
LMI
547 register EMACS_INT filled;
548 register EMACS_INT pos;
c6045832 549 register char *p, *end;
24109c98 550 Lisp_Object sym;
c6045832 551 char *name;
d87a9ab8 552 int skip_file = 0;
c6045832 553
b7826503 554 CHECK_STRING (filename);
c6045832 555
a154a4ef 556 if
c6045832 557#ifndef CANNOT_DUMP
a154a4ef 558 (!NILP (Vpurify_flag))
c6045832 559#else /* CANNOT_DUMP */
a154a4ef 560 (0)
c6045832 561#endif /* CANNOT_DUMP */
a154a4ef 562 {
d5db4077 563 name = (char *) alloca (SCHARS (filename) + 14);
a154a4ef
SM
564 strcpy (name, "../etc/");
565 }
566 else
567 {
568 CHECK_STRING (Vdoc_directory);
d5db4077
KR
569 name = (char *) alloca (SCHARS (filename)
570 + SCHARS (Vdoc_directory) + 1);
571 strcpy (name, SDATA (Vdoc_directory));
a154a4ef 572 }
d5db4077 573 strcat (name, SDATA (filename)); /*** Add this line ***/
c6045832 574
d87a9ab8
JD
575 /* Vbuild_files is nil when temacs is run, and non-nil after that. */
576 if (NILP (Vbuild_files))
577 {
878bde49 578 const char *beg, *end;
d87a9ab8 579
878bde49 580 for (beg = buildobj; *beg; beg = end)
d87a9ab8 581 {
84c9ce05 582 EMACS_INT len;
d87a9ab8
JD
583
584 while (*beg && isspace (*beg)) ++beg;
585
586 for (end = beg; *end && ! isspace (*end); ++end)
587 if (*end == '/') beg = end+1; /* skip directory part */
588
589 len = end - beg;
590 if (len > 4 && end[-4] == '.' && end[-3] == 'o')
591 len -= 2; /* Just take .o if it ends in .obj */
592
593 if (len > 0)
594 Vbuild_files = Fcons (make_string (beg, len), Vbuild_files);
595 }
a4ada374 596 Vbuild_files = Fpurecopy (Vbuild_files);
d87a9ab8
JD
597 }
598
68c45bf0 599 fd = emacs_open (name, O_RDONLY, 0);
c6045832
JB
600 if (fd < 0)
601 report_file_error ("Opening doc string file",
602 Fcons (build_string (name), Qnil));
603 Vdoc_file_name = filename;
604 filled = 0;
605 pos = 0;
606 while (1)
607 {
608 if (filled < 512)
68c45bf0 609 filled += emacs_read (fd, &buf[filled], sizeof buf - 1 - filled);
c6045832
JB
610 if (!filled)
611 break;
612
613 buf[filled] = 0;
614 p = buf;
615 end = buf + (filled < 512 ? filled : filled - 128);
616 while (p != end && *p != '\037') p++;
983b8302 617 /* p points to ^_Ffunctionname\n or ^_Vvarname\n or ^_Sfilename\n. */
c6045832
JB
618 if (p != end)
619 {
8966b757 620 end = strchr (p, '\n');
d87a9ab8
JD
621
622 /* See if this is a file name, and if it is a file in build-files. */
983b8302 623 if (p[1] == 'S')
d87a9ab8 624 {
983b8302
J
625 skip_file = 0;
626 if (end - p > 4 && end[-2] == '.'
627 && (end[-1] == 'o' || end[-1] == 'c'))
628 {
84c9ce05 629 EMACS_INT len = end - p - 2;
983b8302
J
630 char *fromfile = alloca (len + 1);
631 strncpy (fromfile, &p[2], len);
632 fromfile[len] = 0;
633 if (fromfile[len-1] == 'c')
634 fromfile[len-1] = 'o';
635
636 skip_file = NILP (Fmember (build_string (fromfile),
637 Vbuild_files));
638 }
d87a9ab8
JD
639 }
640
141199d1
RS
641 sym = oblookup (Vobarray, p + 2,
642 multibyte_chars_in_text (p + 2, end - p - 2),
643 end - p - 2);
11fb4bdb
SM
644 /* Check skip_file so that when a function is defined several
645 times in different files (typically, once in xterm, once in
646 w32term, ...), we only pay attention to the one that
647 matters. */
d87a9ab8 648 if (! skip_file && SYMBOLP (sym))
c6045832
JB
649 {
650 /* Attach a docstring to a variable? */
651 if (p[1] == 'V')
652 {
653 /* Install file-position as variable-documentation property
654 and make it negative for a user-variable
655 (doc starts with a `*'). */
656 Fput (sym, Qvariable_documentation,
657 make_number ((pos + end + 1 - buf)
658 * (end[1] == '*' ? -1 : 1)));
659 }
660
283e1184 661 /* Attach a docstring to a function? */
c6045832 662 else if (p[1] == 'F')
283e1184
JB
663 store_function_docstring (sym, pos + end + 1 - buf);
664
6b61353c
KH
665 else if (p[1] == 'S')
666 ; /* Just a source file name boundary marker. Ignore it. */
667
283e1184
JB
668 else
669 error ("DOC file invalid at position %d", pos);
c6045832
JB
670 }
671 }
672 pos += end - buf;
673 filled -= end - buf;
840b985a 674 memmove (buf, end, filled);
c6045832 675 }
68c45bf0 676 emacs_close (fd);
c6045832
JB
677 return Qnil;
678}
679\f
680DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
335c5470
PJ
681 Ssubstitute_command_keys, 1, 1, 0,
682 doc: /* Substitute key descriptions for command names in STRING.
c698360f
KS
683Substrings of the form \\=\\[COMMAND] replaced by either: a keystroke
684sequence that will invoke COMMAND, or "M-x COMMAND" if COMMAND is not
685on any keys.
335c5470 686Substrings of the form \\=\\{MAPVAR} are replaced by summaries
04bf6783 687\(made by `describe-bindings') of the value of MAPVAR, taken as a keymap.
335c5470
PJ
688Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR
689as the keymap for future \\=\\[COMMAND] substrings.
690\\=\\= quotes the following character and is discarded;
c698360f
KS
691thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.
692
2610bf68 693Returns original STRING if no substitutions were made. Otherwise,
c698360f 694a new string, without any text properties, is returned. */)
5842a27b 695 (Lisp_Object string)
c6045832
JB
696{
697 unsigned char *buf;
698 int changed = 0;
699 register unsigned char *strp;
700 register unsigned char *bufp;
84c9ce05
LMI
701 EMACS_INT idx;
702 EMACS_INT bsize;
665d3046 703 Lisp_Object tem;
c6045832
JB
704 Lisp_Object keymap;
705 unsigned char *start;
84c9ce05 706 EMACS_INT length, length_byte;
665d3046
JB
707 Lisp_Object name;
708 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
141199d1 709 int multibyte;
84c9ce05 710 EMACS_INT nchars;
c6045832 711
4acb738e 712 if (NILP (string))
c6045832
JB
713 return Qnil;
714
b7826503 715 CHECK_STRING (string);
665d3046
JB
716 tem = Qnil;
717 keymap = Qnil;
718 name = Qnil;
4acb738e 719 GCPRO4 (string, tem, keymap, name);
c6045832 720
141199d1
RS
721 multibyte = STRING_MULTIBYTE (string);
722 nchars = 0;
723
9a425dcb
RS
724 /* KEYMAP is either nil (which means search all the active keymaps)
725 or a specified local map (which means search just that and the
726 global map). If non-nil, it might come from Voverriding_local_map,
4acb738e 727 or from a \\<mapname> construct in STRING itself.. */
f73d1163
KH
728 keymap = current_kboard->Voverriding_terminal_local_map;
729 if (NILP (keymap))
730 keymap = Voverriding_local_map;
c6045832 731
d5db4077 732 bsize = SBYTES (string);
c6045832
JB
733 bufp = buf = (unsigned char *) xmalloc (bsize);
734
8a7bde3e 735 strp = SDATA (string);
d5db4077 736 while (strp < SDATA (string) + SBYTES (string))
c6045832
JB
737 {
738 if (strp[0] == '\\' && strp[1] == '=')
739 {
740 /* \= quotes the next character;
741 thus, to put in \[ without its special meaning, use \=\[. */
742 changed = 1;
141199d1
RS
743 strp += 2;
744 if (multibyte)
745 {
746 int len;
141199d1 747
62a6e103 748 STRING_CHAR_AND_LENGTH (strp, len);
141199d1
RS
749 if (len == 1)
750 *bufp = *strp;
751 else
72af86bd 752 memcpy (bufp, strp, len);
141199d1
RS
753 strp += len;
754 bufp += len;
755 nchars++;
756 }
757 else
758 *bufp++ = *strp++, nchars++;
c6045832
JB
759 }
760 else if (strp[0] == '\\' && strp[1] == '[')
761 {
84c9ce05 762 EMACS_INT start_idx;
a1d3a188 763 int follow_remap = 1;
b6c53774 764
c6045832
JB
765 changed = 1;
766 strp += 2; /* skip \[ */
767 start = strp;
d5db4077 768 start_idx = start - SDATA (string);
c6045832 769
8a7bde3e 770 while ((strp - SDATA (string)
d5db4077 771 < SBYTES (string))
c6045832
JB
772 && *strp != ']')
773 strp++;
141199d1
RS
774 length_byte = strp - start;
775
c6045832
JB
776 strp++; /* skip ] */
777
778 /* Save STRP in IDX. */
8a7bde3e 779 idx = strp - SDATA (string);
3584d95d 780 name = Fintern (make_string (start, length_byte), Qnil);
11f9d6e1 781
a1d3a188 782 do_remap:
a88a5372 783 tem = Fwhere_is_internal (name, keymap, Qt, Qnil, Qnil);
332e51c1 784
a1d3a188
KS
785 if (VECTORP (tem) && XVECTOR (tem)->size > 1
786 && EQ (AREF (tem, 0), Qremap) && SYMBOLP (AREF (tem, 1))
787 && follow_remap)
788 {
789 name = AREF (tem, 1);
790 follow_remap = 0;
791 goto do_remap;
792 }
793
11f9d6e1
GM
794 /* Note the Fwhere_is_internal can GC, so we have to take
795 relocation of string contents into account. */
d5db4077
KR
796 strp = SDATA (string) + idx;
797 start = SDATA (string) + start_idx;
c6045832 798
265a9e55 799 if (NILP (tem)) /* but not on any keys */
c6045832 800 {
84c9ce05 801 EMACS_INT offset = bufp - buf;
8d17fe0b
GM
802 buf = (unsigned char *) xrealloc (buf, bsize += 4);
803 bufp = buf + offset;
72af86bd 804 memcpy (bufp, "M-x ", 4);
c6045832 805 bufp += 4;
141199d1
RS
806 nchars += 4;
807 if (multibyte)
808 length = multibyte_chars_in_text (start, length_byte);
809 else
810 length = length_byte;
c6045832
JB
811 goto subst;
812 }
813 else
814 { /* function is on a key */
a1bfe073 815 tem = Fkey_description (tem, Qnil);
c6045832
JB
816 goto subst_string;
817 }
818 }
819 /* \{foo} is replaced with a summary of the keymap (symbol-value foo).
820 \<foo> just sets the keymap used for \[cmd]. */
821 else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<'))
822 {
823 struct buffer *oldbuf;
84c9ce05 824 EMACS_INT start_idx;
e679a3c1 825 /* This is for computing the SHADOWS arg for describe_map_tree. */
9a51747b 826 Lisp_Object active_maps = Fcurrent_active_maps (Qnil, Qnil);
e679a3c1 827 Lisp_Object earlier_maps;
c6045832
JB
828
829 changed = 1;
830 strp += 2; /* skip \{ or \< */
831 start = strp;
d5db4077 832 start_idx = start - SDATA (string);
c6045832 833
ccddfb9e 834 while ((strp - SDATA (string) < SBYTES (string))
c6045832
JB
835 && *strp != '}' && *strp != '>')
836 strp++;
141199d1
RS
837
838 length_byte = strp - start;
c6045832
JB
839 strp++; /* skip } or > */
840
841 /* Save STRP in IDX. */
8a7bde3e 842 idx = strp - SDATA (string);
c6045832
JB
843
844 /* Get the value of the keymap in TEM, or nil if undefined.
845 Do this while still in the user's current buffer
846 in case it is a local variable. */
141199d1 847 name = Fintern (make_string (start, length_byte), Qnil);
c6045832 848 tem = Fboundp (name);
265a9e55 849 if (! NILP (tem))
c6045832
JB
850 {
851 tem = Fsymbol_value (name);
265a9e55 852 if (! NILP (tem))
11f9d6e1 853 {
02067692
SM
854 tem = get_keymap (tem, 0, 1);
855 /* Note that get_keymap can GC. */
d5db4077
KR
856 strp = SDATA (string) + idx;
857 start = SDATA (string) + start_idx;
11f9d6e1 858 }
c6045832
JB
859 }
860
861 /* Now switch to a temp buffer. */
862 oldbuf = current_buffer;
863 set_buffer_internal (XBUFFER (Vprin1_to_string_buffer));
864
265a9e55 865 if (NILP (tem))
c6045832
JB
866 {
867 name = Fsymbol_name (name);
868 insert_string ("\nUses keymap \"");
141199d1 869 insert_from_string (name, 0, 0,
d5db4077
KR
870 SCHARS (name),
871 SBYTES (name), 1);
c6045832
JB
872 insert_string ("\", which is not currently defined.\n");
873 if (start[-1] == '<') keymap = Qnil;
874 }
875 else if (start[-1] == '<')
876 keymap = tem;
877 else
e679a3c1
RS
878 {
879 /* Get the list of active keymaps that precede this one.
880 If this one's not active, get nil. */
881 earlier_maps = Fcdr (Fmemq (tem, Freverse (active_maps)));
882 describe_map_tree (tem, 1, Fnreverse (earlier_maps),
883 Qnil, (char *)0, 1, 0, 0, 1);
884 }
c6045832
JB
885 tem = Fbuffer_string ();
886 Ferase_buffer ();
887 set_buffer_internal (oldbuf);
888
889 subst_string:
d5db4077
KR
890 start = SDATA (tem);
891 length = SCHARS (tem);
892 length_byte = SBYTES (tem);
c6045832 893 subst:
8d17fe0b 894 {
84c9ce05 895 EMACS_INT offset = bufp - buf;
8d17fe0b
GM
896 buf = (unsigned char *) xrealloc (buf, bsize += length_byte);
897 bufp = buf + offset;
72af86bd 898 memcpy (bufp, start, length_byte);
8d17fe0b
GM
899 bufp += length_byte;
900 nchars += length;
901 /* Check STRING again in case gc relocated it. */
d5db4077 902 strp = (unsigned char *) SDATA (string) + idx;
8d17fe0b 903 }
c6045832 904 }
141199d1
RS
905 else if (! multibyte) /* just copy other chars */
906 *bufp++ = *strp++, nchars++;
907 else
908 {
909 int len;
141199d1 910
62a6e103 911 STRING_CHAR_AND_LENGTH (strp, len);
141199d1
RS
912 if (len == 1)
913 *bufp = *strp;
914 else
72af86bd 915 memcpy (bufp, strp, len);
141199d1
RS
916 strp += len;
917 bufp += len;
918 nchars++;
919 }
c6045832
JB
920 }
921
922 if (changed) /* don't bother if nothing substituted */
cc5bf9eb 923 tem = make_string_from_bytes (buf, nchars, bufp - buf);
c6045832 924 else
4acb738e 925 tem = string;
9ac0d9e0 926 xfree (buf);
665d3046 927 RETURN_UNGCPRO (tem);
c6045832
JB
928}
929\f
dfcf069d 930void
971de7fb 931syms_of_doc (void)
c6045832 932{
d67b4f80 933 Qfunction_documentation = intern_c_string ("function-documentation");
9191c8ae 934 staticpro (&Qfunction_documentation);
177c0ea7 935
c6045832 936 DEFVAR_LISP ("internal-doc-file-name", &Vdoc_file_name,
335c5470 937 doc: /* Name of file containing documentation strings of built-in symbols. */);
c6045832
JB
938 Vdoc_file_name = Qnil;
939
d87a9ab8
JD
940 DEFVAR_LISP ("build-files", &Vbuild_files,
941 doc: /* A list of files used to build this Emacs binary. */);
942 Vbuild_files = Qnil;
943
c6045832
JB
944 defsubr (&Sdocumentation);
945 defsubr (&Sdocumentation_property);
946 defsubr (&Ssnarf_documentation);
947 defsubr (&Ssubstitute_command_keys);
948}
ccddfb9e
KH
949
950/* arch-tag: 56281d4d-6949-43e2-be2e-f6517de744ba
951 (do not change this comment) */