|
|
1.1 root 1: /* Record indices of function doc strings stored in a file.
2: Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is distributed in the hope that it will be useful,
7: but WITHOUT ANY WARRANTY. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing. Refer to the GNU Emacs General Public
11: License for full details.
12:
13: Everyone is granted permission to copy, modify and redistribute
14: GNU Emacs, but only under the conditions described in the
15: GNU Emacs General Public License. A copy of this license is
16: supposed to have been given to you along with GNU Emacs so you
17: can know your rights and responsibilities. It should be in a
18: file named COPYING. Among other things, the copyright notice
19: and this notice must be preserved on all copies. */
20:
21:
22: #include "config.h"
23: #include "lisp.h"
24: #include "buffer.h"
25:
26: #include <sys/types.h>
27: #include <sys/file.h> /* Must be after sys/types.h for USG and BSD4_1*/
28:
29: #ifdef USG5
30: #include <fcntl.h>
31: #endif
32:
33: #ifndef O_RDONLY
34: #define O_RDONLY 0
35: #endif
36:
37: Lisp_Object Vdoc_file_name;
38:
39: Lisp_Object
40: get_doc_string (filepos)
41: long filepos;
42: {
43: char buf[512 * 32 + 1];
44: register int fd;
45: register char *name;
46: register char *p, *p1;
47: register int count;
48: extern char *index ();
49:
50: if (XTYPE (Vexec_directory) != Lisp_String
51: || XTYPE (Vdoc_file_name) != Lisp_String)
52: return Qnil;
53:
54: name = (char *) alloca (XSTRING (Vexec_directory)->size
55: + XSTRING (Vdoc_file_name)->size + 8);
56: strcpy (name, XSTRING (Vexec_directory)->data);
57: strcat (name, XSTRING (Vdoc_file_name)->data);
58: #ifdef VMS
59: #ifndef VMS4_4
60: /* For VMS versions with limited file name syntax,
61: convert the name to something VMS will allow. */
62: p = name;
63: while (*p)
64: {
65: if (*p == '-')
66: *p = '_';
67: p++;
68: }
69: #endif /* not VMS4_4 */
70: #ifdef VMS4_4
71: strcpy (name, sys_translate_unix (name));
72: #endif /* VMS4_4 */
73: #endif /* VMS */
74:
75: fd = open (name, O_RDONLY, 0);
76: if (fd < 0)
77: error ("Cannot open doc string file \"%s\"", name);
78: if (0 > lseek (fd, filepos, 0))
79: {
80: close (fd);
81: error ("Position %ld out of range in doc string file \"%s\"",
82: filepos, name);
83: }
84: p = buf;
85: while (p != buf + sizeof buf - 1)
86: {
87: count = read (fd, p, 512);
88: p[count] = 0;
89: if (!count)
90: break;
91: p1 = index (p, '\037');
92: if (p1)
93: {
94: *p1 = 0;
95: p = p1;
96: break;
97: }
98: p += count;
99: }
100: close (fd);
101: return make_string (buf, p - buf);
102: }
103:
104: DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 1, 0,
105: "Return the documentation string of FUNCTION.")
106: (fun1)
107: Lisp_Object fun1;
108: {
109: Lisp_Object fun;
110: Lisp_Object funcar;
111: Lisp_Object tem;
112:
113: fun = fun1;
114: while (XTYPE (fun) == Lisp_Symbol)
115: fun = Fsymbol_function (fun);
116: if (XTYPE (fun) == Lisp_Subr)
117: {
118: if (XSUBR (fun)->doc == 0) return Qnil;
119: if ((int) XSUBR (fun)->doc >= 0)
120: return Fsubstitute_command_keys (build_string (XSUBR (fun)->doc));
121: return Fsubstitute_command_keys (get_doc_string (- (int) XSUBR (fun)->doc));
122: }
123: if (XTYPE (fun) == Lisp_Vector)
124: return build_string ("Prefix command (definition is a Lisp vector of subcommands).");
125: if (XTYPE (fun) == Lisp_String)
126: return build_string ("Keyboard macro.");
127: if (!CONSP (fun))
128: return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
129: funcar = Fcar (fun);
130: if (XTYPE (funcar) != Lisp_Symbol)
131: return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
132: if (XSYMBOL (funcar) == XSYMBOL (Qkeymap))
133: return build_string ("Prefix command (definition is a list whose cdr is an alist of subcommands.)");
134: if (XSYMBOL (funcar) == XSYMBOL (Qlambda)
135: || XSYMBOL (funcar) == XSYMBOL (Qautoload))
136: {
137: tem = Fcar (Fcdr (Fcdr (fun)));
138: if (XTYPE (tem) == Lisp_String)
139: return Fsubstitute_command_keys (tem);
140: if (XTYPE (tem) == Lisp_Int && XINT (tem) >= 0)
141: return Fsubstitute_command_keys (get_doc_string (XFASTINT (tem)));
142: return Qnil;
143: }
144: if (XSYMBOL (funcar) == XSYMBOL (Qmocklisp))
145: return Qnil;
146: if (XSYMBOL (funcar) == XSYMBOL (Qmacro))
147: return Fdocumentation (Fcdr (fun));
148: else
149: return Fsignal (Qinvalid_function, Fcons (fun, Qnil));
150: }
151:
152: DEFUN ("documentation-property", Fdocumentation_property,
153: Sdocumentation_property, 2, 2, 0,
154: "Return the documentation string that is SYMBOL's PROP property.\n\
155: This differs from using `get' only in that it can refer to strings\n\
156: stored in the etc/DOC file.")
157: (sym, prop)
158: Lisp_Object sym, prop;
159: {
160: register Lisp_Object tem;
161:
162: tem = Fget (sym, prop);
163: if (XTYPE (tem) == Lisp_Int)
164: tem = get_doc_string (XINT (tem) > 0 ? XINT (tem) : - XINT (tem));
165: return Fsubstitute_command_keys (tem);
166: }
167:
168: DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
169: 1, 1, 0,
170: "Used during Emacs initialization, before dumping runnable Emacs,\n\
171: to find pointers to doc strings stored in etc/DOC... and\n\
172: record them in function definitions.\n\
173: One arg, FILENAME, a string which does not include a directory.\n\
174: The file is found in ../etc now; found in the exec-directory\n\
175: when doc strings are referred to later in the dumped Emacs.")
176: (filename)
177: Lisp_Object filename;
178: {
179: int fd;
180: char buf[1024 + 1];
181: register int filled;
182: register int pos;
183: register char *p, *end;
184: Lisp_Object sym, fun, tem;
185: char *name;
186: extern char *index ();
187:
188: CHECK_STRING (filename, 0);
189:
190: #ifndef CANNOT_DUMP
191: name = (char *) alloca (XSTRING (filename)->size + 8);
192: strcpy (name, "../etc/");
193: #else /* CANNOT_DUMP */
194: CHECK_STRING (Vexec_directory, 0);
195: name = (char *) alloca (XSTRING (filename)->size +
196: XSTRING (Vexec_directory)->size + 1);
197: strcpy (name, XSTRING (Vexec_directory)->data);
198: #endif /* CANNOT_DUMP */
199: strcat (name, XSTRING (filename)->data); /*** Add this line ***/
200: #ifdef VMS
201: #ifndef VMS4_4
202: /* For VMS versions with limited file name syntax,
203: convert the name to something VMS will allow. */
204: p = name;
205: while (*p)
206: {
207: if (*p == '-')
208: *p = '_';
209: p++;
210: }
211: #endif /* not VMS4_4 */
212: #ifdef VMS4_4
213: strcpy (name, sys_translate_unix (name));
214: #endif /* VMS4_4 */
215: #endif /* VMS */
216:
217: fd = open (name, O_RDONLY, 0);
218: if (fd < 0)
219: report_file_error ("Opening doc string file",
220: Fcons (build_string (name), Qnil));
221: Vdoc_file_name = filename;
222: filled = 0;
223: pos = 0;
224: while (1)
225: {
226: if (filled < 512)
227: filled += read (fd, &buf[filled], sizeof buf - 1 - filled);
228: if (!filled)
229: break;
230:
231: buf[filled] = 0;
232: p = buf;
233: end = buf + (filled < 512 ? filled : filled - 128);
234: while (p != end && *p != '\037') p++;
235: /* p points to ^_Ffunctionname\n or ^_Vvarname\n. */
236: if (p != end)
237: {
238: end = index (p, '\n');
239: sym = oblookup (Vobarray, p + 2, end - p - 2);
240: if (XTYPE (sym) == Lisp_Symbol)
241: {
242: if (p[1] == 'V')
243: {
244: /* Install file-position as variable-documentation property
245: and make it negative for a user-variable
246: (doc starts with a `*'). */
247: Fput (sym, Qvariable_documentation,
248: make_number ((pos + end + 1 - buf)
249: * (end[1] == '*' ? -1 : 1)));
250: }
251: else if (p[1] == 'F')
252: {
253: fun = XSYMBOL (sym)->function;
254: if (XTYPE (fun) == Lisp_Subr)
255: XSUBR (fun)->doc = (char *) - (pos + end + 1 - buf);
256: else if (CONSP (fun))
257: {
258: tem = XCONS (fun)->car;
259: if (EQ (tem, Qlambda) || EQ (tem, Qautoload))
260: {
261: tem = Fcdr (Fcdr (fun));
262: if (CONSP (tem) &&
263: XTYPE (XCONS (tem)->car) == Lisp_Int)
264: XFASTINT (XCONS (tem)->car) = (pos + end + 1 - buf);
265: }
266: }
267: }
268: else error ("DOC file invalid at position %d", pos);
269: }
270: }
271: pos += end - buf;
272: filled -= end - buf;
273: bcopy (end, buf, filled);
274: }
275: close (fd);
276: return Qnil;
277: }
278:
279: DEFUN ("substitute-command-keys", Fsubstitute_command_keys,
280: Ssubstitute_command_keys, 1, 1, 0,
281: "Return the STRING with substrings of the form \\=\\[COMMAND]\n\
282: replaced by either: a keystroke sequence that will invoke COMMAND,\n\
283: or \"M-x COMMAND\" if COMMAND is not on any keys.\n\
284: Substrings of the form \\=\\{MAPVAR} are replaced by summaries\n\
285: \(made by describe-bindings) of the value of MAPVAR, taken as a keymap.\n\
286: Substrings of the form \\=\\<MAPVAR> specify to use the value of MAPVAR\n\
287: as the keymap for future \\=\\[COMMAND] substrings.\n\
288: \\=\\= quotes the following character and is discarded;\n\
289: thus, \\=\\=\\=\\= puts \\=\\= into the output, and \\=\\=\\=\\[ puts \\=\\[ into the output.")
290: (str)
291: Lisp_Object str;
292: {
293: unsigned char *buf;
294: int changed = 0;
295: register unsigned char *strp;
296: register unsigned char *bufp;
297: register unsigned char *send;
298: int bsize;
299: unsigned char *new;
300: register Lisp_Object tem;
301: Lisp_Object keymap;
302: unsigned char *start;
303: int length;
304:
305: if (NULL (str))
306: return Qnil;
307:
308: CHECK_STRING (str, 0);
309: strp = (unsigned char *) XSTRING (str)->data;
310: send = strp + XSTRING (str)->size;
311:
312: keymap = bf_cur->keymap;
313:
314: bsize = XSTRING (str)->size;
315: bufp = buf = (unsigned char *) xmalloc (bsize);
316:
317: while (strp < send)
318: {
319: if (strp[0] == '\\' && strp[1] == '=')
320: {
321: /* \= quotes the next character;
322: thus, to put in \[ without its special meaning, use \=\[. */
323: changed = 1;
324: *bufp++ = strp[2];
325: strp += 3;
326: }
327: else if (strp[0] == '\\' && strp[1] == '[')
328: {
329: changed = 1;
330: strp += 2; /* skip \[ */
331: start = strp;
332:
333: while (strp < send && *strp != ']')
334: strp++;
335: length = strp - start;
336: strp++; /* skip ] */
337:
338: tem = Fintern (make_string (start, length), Qnil);
339: tem = Fwhere_is_internal (tem, keymap, Qt);
340:
341: if (NULL (tem)) /* but not on any keys */
342: {
343: new = (unsigned char *) xrealloc (buf, bsize += 4);
344: bufp += new - buf;
345: buf = new;
346: bcopy ("M-x ", bufp, 4);
347: bufp += 4;
348: goto subst;
349: }
350: else
351: { /* function is on a key */
352: tem = Fkey_description (tem);
353: goto subst_string;
354: }
355: }
356: /* \{foo} is replaced with a summary of the keymap (symeval foo).
357: \<foo> just sets the keymap used for \[cmd]. */
358: else if (strp[0] == '\\' && (strp[1] == '{' || strp[1] == '<'))
359: {
360: struct buffer *oldbuf;
361: Lisp_Object name;
362:
363: changed = 1;
364: strp += 2; /* skip \{ or \< */
365: start = strp;
366:
367: while (strp < send && *strp != '}' && *strp != '>')
368: strp++;
369: length = strp - start;
370: strp++; /* skip } or > */
371:
372: oldbuf = bf_cur;
373: SetBfp (XBUFFER (Vprin1_to_string_buffer));
374: name = Fintern (make_string (start, length), Qnil);
375: if ((tem = (Fboundp (name)), NULL (tem)) ||
376: (tem = (Fsymbol_value (name)), NULL (tem)) ||
377: (tem = (get_keymap_1 (tem, 0)), NULL (tem)))
378: {
379: name = Fsymbol_name (name);
380: InsStr ("\nUses keymap \"");
381: InsCStr (XSTRING (name)->data, XSTRING (name)->size);
382: InsStr ("\", which is not currently defined.\n");
383: if (start[-1] == '<') keymap = Qnil;
384: }
385: else if (start[-1] == '<')
386: keymap = tem;
387: else
388: describe_map_tree (tem, 1, Qnil);
389: tem = Fbuffer_string ();
390: Ferase_buffer ();
391: SetBfp (oldbuf);
392:
393: subst_string:
394: start = XSTRING (tem)->data;
395: length = XSTRING (tem)->size;
396: subst:
397: new = (unsigned char *) xrealloc (buf, bsize += length);
398: bufp += new - buf;
399: buf = new;
400: bcopy (start, bufp, length);
401: bufp += length;
402: }
403: else /* just copy other chars */
404: *bufp++ = *strp++;
405: }
406:
407: if (changed) /* don't bother if nothing substituted */
408: tem = make_string (buf, bufp - buf);
409: else
410: tem = str;
411: free (buf);
412: return tem;
413: }
414:
415: syms_of_doc ()
416: {
417: staticpro (&Vdoc_file_name);
418: Vdoc_file_name = Qnil;
419:
420: defsubr (&Sdocumentation);
421: defsubr (&Sdocumentation_property);
422: defsubr (&Ssnarf_documentation);
423: defsubr (&Ssubstitute_command_keys);
424: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.