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