211
|
1 /* Random utility Lisp functions.
|
|
2 Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
|
|
3
|
|
4 This file is part of GNU Emacs.
|
|
5
|
|
6 GNU Emacs is free software; you can redistribute it and/or modify
|
|
7 it under the terms of the GNU General Public License as published by
|
|
8 the Free Software Foundation; either version 1, or (at your option)
|
|
9 any later version.
|
|
10
|
|
11 GNU Emacs is distributed in the hope that it will be useful,
|
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 GNU General Public License for more details.
|
|
15
|
|
16 You should have received a copy of the GNU General Public License
|
|
17 along with GNU Emacs; see the file COPYING. If not, write to
|
|
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
19
|
|
20
|
|
21 #include "config.h"
|
|
22
|
|
23 #ifdef LOAD_AVE_TYPE
|
|
24 #ifdef BSD
|
|
25 /* It appears param.h defines BSD and BSD4_3 in 4.3
|
|
26 and is not considerate enough to avoid bombing out
|
|
27 if they are already defined. */
|
|
28 #undef BSD
|
|
29 #ifdef BSD4_3
|
|
30 #undef BSD4_3
|
|
31 #define XBSD4_3 /* XBSD4_3 says BSD4_3 is supposed to be defined. */
|
|
32 #endif
|
|
33 #include <sys/param.h>
|
|
34 /* Now if BSD or BSD4_3 was defined and is no longer,
|
|
35 define it again. */
|
|
36 #ifndef BSD
|
|
37 #define BSD
|
|
38 #endif
|
|
39 #ifdef XBSD4_3
|
|
40 #ifndef BSD4_3
|
|
41 #define BSD4_3
|
|
42 #endif
|
|
43 #endif /* XBSD4_3 */
|
|
44 #endif /* BSD */
|
|
45 #ifndef VMS
|
|
46 #ifndef NLIST_STRUCT
|
|
47 #include <a.out.h>
|
|
48 #else /* NLIST_STRUCT */
|
|
49 #include <nlist.h>
|
|
50 #endif /* NLIST_STRUCT */
|
|
51 #endif /* not VMS */
|
|
52 #endif /* LOAD_AVE_TYPE */
|
|
53
|
350
|
54 #ifdef DGUX
|
|
55 #include <sys/dg_sys_info.h> /* for load average info - DJB */
|
|
56 #endif
|
|
57
|
211
|
58 /* Note on some machines this defines `vector' as a typedef,
|
|
59 so make sure we don't use that name in this file. */
|
|
60 #undef vector
|
|
61 #define vector *****
|
|
62
|
|
63 #ifdef NULL
|
|
64 #undef NULL
|
|
65 #endif
|
|
66 #include "lisp.h"
|
|
67 #include "commands.h"
|
|
68
|
|
69 #ifdef MULTI_SCREEN
|
|
70 #include "screen.h"
|
|
71 #endif
|
|
72
|
|
73 #include "buffer.h"
|
|
74
|
|
75 Lisp_Object Qstring_lessp;
|
|
76
|
|
77 DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0,
|
|
78 "Return the argument unchanged.")
|
|
79 (arg)
|
|
80 Lisp_Object arg;
|
|
81 {
|
|
82 return arg;
|
|
83 }
|
|
84
|
|
85 DEFUN ("random", Frandom, Srandom, 0, 1, 0,
|
|
86 "Return a pseudo-random number.\n\
|
|
87 On most systems all integers representable in Lisp are equally likely.\n\
|
|
88 This is 24 bits' worth.\n\
|
|
89 With argument N, return random number in interval [0,N).\n\
|
|
90 With argument t, set the random number seed from the current time and pid.")
|
|
91 (arg)
|
|
92 Lisp_Object arg;
|
|
93 {
|
|
94 int val;
|
|
95 extern long random ();
|
|
96 extern srandom ();
|
|
97 extern long time ();
|
|
98
|
|
99 if (EQ (arg, Qt))
|
|
100 srandom (getpid () + time (0));
|
|
101 val = random ();
|
|
102 if (XTYPE (arg) == Lisp_Int && XINT (arg) != 0)
|
|
103 {
|
|
104 /* Try to take our random number from the higher bits of VAL,
|
|
105 not the lower, since (says Gentzel) the low bits of `random'
|
|
106 are less random than the higher ones. */
|
|
107 val &= 0xfffffff; /* Ensure positive. */
|
|
108 val >>= 5;
|
|
109 if (XINT (arg) < 10000)
|
|
110 val >>= 6;
|
|
111 val %= XINT (arg);
|
|
112 }
|
|
113 return make_number (val);
|
|
114 }
|
|
115
|
|
116 /* Random data-structure functions */
|
|
117
|
|
118 DEFUN ("length", Flength, Slength, 1, 1, 0,
|
|
119 "Return the length of vector, list or string SEQUENCE.\n\
|
|
120 A byte-code function object is also allowed.")
|
|
121 (obj)
|
|
122 register Lisp_Object obj;
|
|
123 {
|
|
124 register Lisp_Object tail, val;
|
|
125 register int i;
|
|
126
|
|
127 retry:
|
|
128 if (XTYPE (obj) == Lisp_Vector || XTYPE (obj) == Lisp_String
|
|
129 || XTYPE (obj) == Lisp_Compiled)
|
|
130 return Farray_length (obj);
|
|
131 else if (CONSP (obj))
|
|
132 {
|
|
133 for (i = 0, tail = obj; !NULL(tail); i++)
|
|
134 {
|
|
135 QUIT;
|
|
136 tail = Fcdr (tail);
|
|
137 }
|
|
138
|
|
139 XFASTINT (val) = i;
|
|
140 return val;
|
|
141 }
|
|
142 else if (NULL(obj))
|
|
143 {
|
|
144 XFASTINT (val) = 0;
|
|
145 return val;
|
|
146 }
|
|
147 else
|
|
148 {
|
|
149 obj = wrong_type_argument (Qsequencep, obj);
|
|
150 goto retry;
|
|
151 }
|
|
152 }
|
|
153
|
|
154 DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0,
|
|
155 "T if two strings have identical contents.\n\
|
|
156 Case is significant.\n\
|
|
157 Symbols are also allowed; their print names are used instead.")
|
|
158 (s1, s2)
|
|
159 register Lisp_Object s1, s2;
|
|
160 {
|
|
161 if (XTYPE (s1) == Lisp_Symbol)
|
|
162 XSETSTRING (s1, XSYMBOL (s1)->name), XSETTYPE (s1, Lisp_String);
|
|
163 if (XTYPE (s2) == Lisp_Symbol)
|
|
164 XSETSTRING (s2, XSYMBOL (s2)->name), XSETTYPE (s2, Lisp_String);
|
|
165 CHECK_STRING (s1, 0);
|
|
166 CHECK_STRING (s2, 1);
|
|
167
|
|
168 if (XSTRING (s1)->size != XSTRING (s2)->size ||
|
|
169 bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size))
|
|
170 return Qnil;
|
|
171 return Qt;
|
|
172 }
|
|
173
|
|
174 DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0,
|
|
175 "T if first arg string is less than second in lexicographic order.\n\
|
|
176 Case is significant.\n\
|
|
177 Symbols are also allowed; their print names are used instead.")
|
|
178 (s1, s2)
|
|
179 register Lisp_Object s1, s2;
|
|
180 {
|
|
181 register int i;
|
|
182 register unsigned char *p1, *p2;
|
|
183 register int end;
|
|
184
|
|
185 if (XTYPE (s1) == Lisp_Symbol)
|
|
186 XSETSTRING (s1, XSYMBOL (s1)->name), XSETTYPE (s1, Lisp_String);
|
|
187 if (XTYPE (s2) == Lisp_Symbol)
|
|
188 XSETSTRING (s2, XSYMBOL (s2)->name), XSETTYPE (s2, Lisp_String);
|
|
189 CHECK_STRING (s1, 0);
|
|
190 CHECK_STRING (s2, 1);
|
|
191
|
|
192 p1 = XSTRING (s1)->data;
|
|
193 p2 = XSTRING (s2)->data;
|
|
194 end = XSTRING (s1)->size;
|
|
195 if (end > XSTRING (s2)->size)
|
|
196 end = XSTRING (s2)->size;
|
|
197
|
|
198 for (i = 0; i < end; i++)
|
|
199 {
|
|
200 if (p1[i] != p2[i])
|
|
201 return p1[i] < p2[i] ? Qt : Qnil;
|
|
202 }
|
|
203 return i < XSTRING (s2)->size ? Qt : Qnil;
|
|
204 }
|
|
205
|
|
206 static Lisp_Object concat ();
|
|
207
|
|
208 /* ARGSUSED */
|
|
209 Lisp_Object
|
|
210 concat2 (s1, s2)
|
|
211 Lisp_Object s1, s2;
|
|
212 {
|
|
213 #ifdef NO_ARG_ARRAY
|
|
214 Lisp_Object args[2];
|
|
215 args[0] = s1;
|
|
216 args[1] = s2;
|
|
217 return concat (2, args, Lisp_String, 0);
|
|
218 #else
|
|
219 return concat (2, &s1, Lisp_String, 0);
|
|
220 #endif /* NO_ARG_ARRAY */
|
|
221 }
|
|
222
|
|
223 DEFUN ("append", Fappend, Sappend, 0, MANY, 0,
|
|
224 "Concatenate all the arguments and make the result a list.\n\
|
|
225 The result is a list whose elements are the elements of all the arguments.\n\
|
|
226 Each argument may be a list, vector or string.\n\
|
|
227 The last argument is not copied if it is a list.")
|
|
228 (nargs, args)
|
|
229 int nargs;
|
|
230 Lisp_Object *args;
|
|
231 {
|
|
232 return concat (nargs, args, Lisp_Cons, 1);
|
|
233 }
|
|
234
|
|
235 DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
|
|
236 "Concatenate all the arguments and make the result a string.\n\
|
|
237 The result is a string whose elements are the elements of all the arguments.\n\
|
|
238 Each argument may be a string, a list of numbers, or a vector of numbers.")
|
|
239 (nargs, args)
|
|
240 int nargs;
|
|
241 Lisp_Object *args;
|
|
242 {
|
|
243 return concat (nargs, args, Lisp_String, 0);
|
|
244 }
|
|
245
|
|
246 DEFUN ("vconcat", Fvconcat, Svconcat, 0, MANY, 0,
|
|
247 "Concatenate all the arguments and make the result a vector.\n\
|
|
248 The result is a vector whose elements are the elements of all the arguments.\n\
|
|
249 Each argument may be a list, vector or string.")
|
|
250 (nargs, args)
|
|
251 int nargs;
|
|
252 Lisp_Object *args;
|
|
253 {
|
|
254 return concat (nargs, args, Lisp_Vector, 0);
|
|
255 }
|
|
256
|
|
257 DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
|
|
258 "Return a copy of a list, vector or string.\n\
|
|
259 The elements of a list or vector are not copied; they are shared\n\
|
|
260 with the original.")
|
|
261 (arg)
|
|
262 Lisp_Object arg;
|
|
263 {
|
|
264 if (NULL (arg)) return arg;
|
|
265 if (!CONSP (arg) && XTYPE (arg) != Lisp_Vector && XTYPE (arg) != Lisp_String)
|
|
266 arg = wrong_type_argument (Qsequencep, arg);
|
|
267 return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0);
|
|
268 }
|
|
269
|
|
270 static Lisp_Object
|
|
271 concat (nargs, args, target_type, last_special)
|
|
272 int nargs;
|
|
273 Lisp_Object *args;
|
|
274 enum Lisp_Type target_type;
|
|
275 int last_special;
|
|
276 {
|
|
277 Lisp_Object val;
|
|
278 Lisp_Object len;
|
|
279 register Lisp_Object tail;
|
|
280 register Lisp_Object this;
|
|
281 int toindex;
|
|
282 register int leni;
|
|
283 register int argnum;
|
|
284 Lisp_Object last_tail;
|
|
285 Lisp_Object prev;
|
|
286
|
|
287 /* In append, the last arg isn't treated like the others */
|
|
288 if (last_special && nargs > 0)
|
|
289 {
|
|
290 nargs--;
|
|
291 last_tail = args[nargs];
|
|
292 }
|
|
293 else
|
|
294 last_tail = Qnil;
|
|
295
|
|
296 for (argnum = 0; argnum < nargs; argnum++)
|
|
297 {
|
|
298 this = args[argnum];
|
|
299 if (!(CONSP (this) || NULL (this)
|
|
300 || XTYPE (this) == Lisp_Vector || XTYPE (this) == Lisp_String
|
|
301 || XTYPE (this) == Lisp_Compiled))
|
|
302 {
|
|
303 if (XTYPE (this) == Lisp_Int)
|
|
304 args[argnum] = Fint_to_string (this);
|
|
305 else
|
|
306 args[argnum] = wrong_type_argument (Qsequencep, this);
|
|
307 }
|
|
308 }
|
|
309
|
|
310 for (argnum = 0, leni = 0; argnum < nargs; argnum++)
|
|
311 {
|
|
312 this = args[argnum];
|
|
313 len = Flength (this);
|
|
314 leni += XFASTINT (len);
|
|
315 }
|
|
316
|
|
317 XFASTINT (len) = leni;
|
|
318
|
|
319 if (target_type == Lisp_Cons)
|
|
320 val = Fmake_list (len, Qnil);
|
|
321 else if (target_type == Lisp_Vector)
|
|
322 val = Fmake_vector (len, Qnil);
|
|
323 else
|
|
324 val = Fmake_string (len, len);
|
|
325
|
|
326 /* In append, if all but last arg are nil, return last arg */
|
|
327 if (target_type == Lisp_Cons && EQ (val, Qnil))
|
|
328 return last_tail;
|
|
329
|
|
330 if (CONSP (val))
|
|
331 tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */
|
|
332 else
|
|
333 toindex = 0;
|
|
334
|
|
335 prev = Qnil;
|
|
336
|
|
337 for (argnum = 0; argnum < nargs; argnum++)
|
|
338 {
|
|
339 Lisp_Object thislen;
|
|
340 int thisleni;
|
|
341 register int thisindex = 0;
|
|
342
|
|
343 this = args[argnum];
|
|
344 if (!CONSP (this))
|
|
345 thislen = Flength (this), thisleni = XINT (thislen);
|
|
346
|
|
347 while (1)
|
|
348 {
|
|
349 register Lisp_Object elt;
|
|
350
|
|
351 /* Fetch next element of `this' arg into `elt', or break if `this' is exhausted. */
|
|
352 if (NULL (this)) break;
|
|
353 if (CONSP (this))
|
|
354 elt = Fcar (this), this = Fcdr (this);
|
|
355 else
|
|
356 {
|
|
357 if (thisindex >= thisleni) break;
|
|
358 if (XTYPE (this) == Lisp_String)
|
|
359 XFASTINT (elt) = XSTRING (this)->data[thisindex++];
|
|
360 else
|
|
361 elt = XVECTOR (this)->contents[thisindex++];
|
|
362 }
|
|
363
|
|
364 /* Store into result */
|
|
365 if (toindex < 0)
|
|
366 {
|
|
367 XCONS (tail)->car = elt;
|
|
368 prev = tail;
|
|
369 tail = XCONS (tail)->cdr;
|
|
370 }
|
|
371 else if (XTYPE (val) == Lisp_Vector)
|
|
372 XVECTOR (val)->contents[toindex++] = elt;
|
|
373 else
|
|
374 {
|
|
375 while (XTYPE (elt) != Lisp_Int)
|
|
376 elt = wrong_type_argument (Qintegerp, elt);
|
|
377 {
|
|
378 #ifdef MASSC_REGISTER_BUG
|
|
379 /* Even removing all "register"s doesn't disable this bug!
|
|
380 Nothing simpler than this seems to work. */
|
|
381 unsigned char *p = & XSTRING (val)->data[toindex++];
|
|
382 *p = XINT (elt);
|
|
383 #else
|
|
384 XSTRING (val)->data[toindex++] = XINT (elt);
|
|
385 #endif
|
|
386 }
|
|
387 }
|
|
388 }
|
|
389 }
|
|
390 if (!NULL (prev))
|
|
391 XCONS (prev)->cdr = last_tail;
|
|
392
|
|
393 return val;
|
|
394 }
|
|
395
|
|
396 DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0,
|
|
397 "Return a copy of ALIST.\n\
|
|
398 This is an alist which represents the same mapping from objects to objects,\n\
|
|
399 but does not share the alist structure with ALIST.\n\
|
|
400 The objects mapped (cars and cdrs of elements of the alist)\n\
|
|
401 are shared, however.\n\
|
|
402 Elements of ALIST that are not conses are also shared.")
|
|
403 (alist)
|
|
404 Lisp_Object alist;
|
|
405 {
|
|
406 register Lisp_Object tem;
|
|
407
|
|
408 CHECK_LIST (alist, 0);
|
|
409 if (NULL (alist))
|
|
410 return alist;
|
|
411 alist = concat (1, &alist, Lisp_Cons, 0);
|
|
412 for (tem = alist; CONSP (tem); tem = XCONS (tem)->cdr)
|
|
413 {
|
|
414 register Lisp_Object car;
|
|
415 car = XCONS (tem)->car;
|
|
416
|
|
417 if (CONSP (car))
|
|
418 XCONS (tem)->car = Fcons (XCONS (car)->car, XCONS (car)->cdr);
|
|
419 }
|
|
420 return alist;
|
|
421 }
|
|
422
|
|
423 DEFUN ("substring", Fsubstring, Ssubstring, 2, 3, 0,
|
|
424 "Return a substring of STRING, starting at index FROM and ending before TO.\n\
|
|
425 TO may be nil or omitted; then the substring runs to the end of STRING.\n\
|
|
426 If FROM or TO is negative, it counts from the end.")
|
|
427 (string, from, to)
|
|
428 Lisp_Object string;
|
|
429 register Lisp_Object from, to;
|
|
430 {
|
|
431 CHECK_STRING (string, 0);
|
|
432 CHECK_NUMBER (from, 1);
|
|
433 if (NULL (to))
|
|
434 to = Flength (string);
|
|
435 else
|
|
436 CHECK_NUMBER (to, 2);
|
|
437
|
|
438 if (XINT (from) < 0)
|
|
439 XSETINT (from, XINT (from) + XSTRING (string)->size);
|
|
440 if (XINT (to) < 0)
|
|
441 XSETINT (to, XINT (to) + XSTRING (string)->size);
|
|
442 if (!(0 <= XINT (from) && XINT (from) <= XINT (to)
|
|
443 && XINT (to) <= XSTRING (string)->size))
|
|
444 args_out_of_range_3 (string, from, to);
|
|
445
|
|
446 return make_string (XSTRING (string)->data + XINT (from),
|
|
447 XINT (to) - XINT (from));
|
|
448 }
|
|
449
|
|
450 DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
|
|
451 "Take cdr N times on LIST, returns the result.")
|
|
452 (n, list)
|
|
453 Lisp_Object n;
|
|
454 register Lisp_Object list;
|
|
455 {
|
|
456 register int i, num;
|
|
457 CHECK_NUMBER (n, 0);
|
|
458 num = XINT (n);
|
|
459 for (i = 0; i < num && !NULL (list); i++)
|
|
460 {
|
|
461 QUIT;
|
|
462 list = Fcdr (list);
|
|
463 }
|
|
464 return list;
|
|
465 }
|
|
466
|
|
467 DEFUN ("nth", Fnth, Snth, 2, 2, 0,
|
|
468 "Return the Nth element of LIST.\n\
|
|
469 N counts from zero. If LIST is not that long, nil is returned.")
|
|
470 (n, list)
|
|
471 Lisp_Object n, list;
|
|
472 {
|
|
473 return Fcar (Fnthcdr (n, list));
|
|
474 }
|
|
475
|
|
476 DEFUN ("elt", Felt, Selt, 2, 2, 0,
|
|
477 "Return element of SEQUENCE at index N.")
|
|
478 (seq, n)
|
|
479 register Lisp_Object seq, n;
|
|
480 {
|
|
481 CHECK_NUMBER (n, 0);
|
|
482 while (1)
|
|
483 {
|
|
484 if (XTYPE (seq) == Lisp_Cons || NULL (seq))
|
|
485 return Fcar (Fnthcdr (n, seq));
|
|
486 else if (XTYPE (seq) == Lisp_String ||
|
|
487 XTYPE (seq) == Lisp_Vector)
|
|
488 return Faref (seq, n);
|
|
489 else
|
|
490 seq = wrong_type_argument (Qsequencep, seq);
|
|
491 }
|
|
492 }
|
|
493
|
|
494 DEFUN ("member", Fmember, Smember, 2, 2, 0,
|
|
495 "Return non-nil if ELT is an element of LIST. Comparison done with EQUAL.\n\
|
|
496 The value is actually the tail of LIST whose car is ELT.")
|
|
497 (elt, list)
|
|
498 register Lisp_Object elt;
|
|
499 Lisp_Object list;
|
|
500 {
|
|
501 register Lisp_Object tail;
|
|
502 for (tail = list; !NULL (tail); tail = Fcdr (tail))
|
|
503 {
|
|
504 register Lisp_Object tem;
|
|
505 tem = Fcar (tail);
|
|
506 if (! NULL (Fequal (elt, tem)))
|
|
507 return tail;
|
|
508 QUIT;
|
|
509 }
|
|
510 return Qnil;
|
|
511 }
|
|
512
|
|
513 DEFUN ("memq", Fmemq, Smemq, 2, 2, 0,
|
|
514 "Return non-nil if ELT is an element of LIST. Comparison done with EQ.\n\
|
|
515 The value is actually the tail of LIST whose car is ELT.")
|
|
516 (elt, list)
|
|
517 register Lisp_Object elt;
|
|
518 Lisp_Object list;
|
|
519 {
|
|
520 register Lisp_Object tail;
|
|
521 for (tail = list; !NULL (tail); tail = Fcdr (tail))
|
|
522 {
|
|
523 register Lisp_Object tem;
|
|
524 tem = Fcar (tail);
|
|
525 if (EQ (elt, tem)) return tail;
|
|
526 QUIT;
|
|
527 }
|
|
528 return Qnil;
|
|
529 }
|
|
530
|
|
531 DEFUN ("assq", Fassq, Sassq, 2, 2, 0,
|
|
532 "Return non-nil if ELT is `eq' to the car of an element of LIST.\n\
|
|
533 The value is actually the element of LIST whose car is ELT.\n\
|
|
534 Elements of LIST that are not conses are ignored.")
|
|
535 (key, list)
|
|
536 register Lisp_Object key;
|
|
537 Lisp_Object list;
|
|
538 {
|
|
539 register Lisp_Object tail;
|
|
540 for (tail = list; !NULL (tail); tail = Fcdr (tail))
|
|
541 {
|
|
542 register Lisp_Object elt, tem;
|
|
543 elt = Fcar (tail);
|
|
544 if (!CONSP (elt)) continue;
|
|
545 tem = Fcar (elt);
|
|
546 if (EQ (key, tem)) return elt;
|
|
547 QUIT;
|
|
548 }
|
|
549 return Qnil;
|
|
550 }
|
|
551
|
|
552 /* Like Fassq but never report an error and do not allow quits.
|
|
553 Use only on lists known never to be circular. */
|
|
554
|
|
555 Lisp_Object
|
|
556 assq_no_quit (key, list)
|
|
557 register Lisp_Object key;
|
|
558 Lisp_Object list;
|
|
559 {
|
|
560 register Lisp_Object tail;
|
|
561 for (tail = list; CONSP (tail); tail = Fcdr (tail))
|
|
562 {
|
|
563 register Lisp_Object elt, tem;
|
|
564 elt = Fcar (tail);
|
|
565 if (!CONSP (elt)) continue;
|
|
566 tem = Fcar (elt);
|
|
567 if (EQ (key, tem)) return elt;
|
|
568 }
|
|
569 return Qnil;
|
|
570 }
|
|
571
|
|
572 DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0,
|
|
573 "Return non-nil if ELT is `equal' to the car of an element of LIST.\n\
|
|
574 The value is actually the element of LIST whose car is ELT.")
|
|
575 (key, list)
|
|
576 register Lisp_Object key;
|
|
577 Lisp_Object list;
|
|
578 {
|
|
579 register Lisp_Object tail;
|
|
580 for (tail = list; !NULL (tail); tail = Fcdr (tail))
|
|
581 {
|
|
582 register Lisp_Object elt, tem;
|
|
583 elt = Fcar (tail);
|
|
584 if (!CONSP (elt)) continue;
|
|
585 tem = Fequal (Fcar (elt), key);
|
|
586 if (!NULL (tem)) return elt;
|
|
587 QUIT;
|
|
588 }
|
|
589 return Qnil;
|
|
590 }
|
|
591
|
|
592 DEFUN ("rassq", Frassq, Srassq, 2, 2, 0,
|
|
593 "Return non-nil if ELT is `eq' to the cdr of an element of LIST.\n\
|
|
594 The value is actually the element of LIST whose cdr is ELT.")
|
|
595 (key, list)
|
|
596 register Lisp_Object key;
|
|
597 Lisp_Object list;
|
|
598 {
|
|
599 register Lisp_Object tail;
|
|
600 for (tail = list; !NULL (tail); tail = Fcdr (tail))
|
|
601 {
|
|
602 register Lisp_Object elt, tem;
|
|
603 elt = Fcar (tail);
|
|
604 if (!CONSP (elt)) continue;
|
|
605 tem = Fcdr (elt);
|
|
606 if (EQ (key, tem)) return elt;
|
|
607 QUIT;
|
|
608 }
|
|
609 return Qnil;
|
|
610 }
|
|
611
|
|
612 DEFUN ("delq", Fdelq, Sdelq, 2, 2, 0,
|
|
613 "Delete by side effect any occurrences of ELT as a member of LIST.\n\
|
|
614 The modified LIST is returned. Comparison is done with `eq'.\n\
|
|
615 If the first member of LIST is ELT, there is no way to remove it by side effect;\n\
|
|
616 therefore, write `(setq foo (delq element foo))'\n\
|
|
617 to be sure of changing the value of `foo'.")
|
|
618 (elt, list)
|
|
619 register Lisp_Object elt;
|
|
620 Lisp_Object list;
|
|
621 {
|
|
622 register Lisp_Object tail, prev;
|
|
623 register Lisp_Object tem;
|
|
624
|
|
625 tail = list;
|
|
626 prev = Qnil;
|
|
627 while (!NULL (tail))
|
|
628 {
|
|
629 tem = Fcar (tail);
|
|
630 if (EQ (elt, tem))
|
|
631 {
|
|
632 if (NULL (prev))
|
|
633 list = Fcdr (tail);
|
|
634 else
|
|
635 Fsetcdr (prev, Fcdr (tail));
|
|
636 }
|
|
637 else
|
|
638 prev = tail;
|
|
639 tail = Fcdr (tail);
|
|
640 QUIT;
|
|
641 }
|
|
642 return list;
|
|
643 }
|
|
644
|
|
645 DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0,
|
|
646 "Reverse LIST by modifying cdr pointers.\n\
|
|
647 Returns the beginning of the reversed list.")
|
|
648 (list)
|
|
649 Lisp_Object list;
|
|
650 {
|
|
651 register Lisp_Object prev, tail, next;
|
|
652
|
|
653 if (NULL (list)) return list;
|
|
654 prev = Qnil;
|
|
655 tail = list;
|
|
656 while (!NULL (tail))
|
|
657 {
|
|
658 QUIT;
|
|
659 next = Fcdr (tail);
|
|
660 Fsetcdr (tail, prev);
|
|
661 prev = tail;
|
|
662 tail = next;
|
|
663 }
|
|
664 return prev;
|
|
665 }
|
|
666
|
|
667 DEFUN ("reverse", Freverse, Sreverse, 1, 1, 0,
|
|
668 "Reverse LIST, copying. Returns the beginning of the reversed list.\n\
|
|
669 See also the function `nreverse', which is used more often.")
|
|
670 (list)
|
|
671 Lisp_Object list;
|
|
672 {
|
|
673 Lisp_Object length;
|
|
674 register Lisp_Object *vec;
|
|
675 register Lisp_Object tail;
|
|
676 register int i;
|
|
677
|
|
678 length = Flength (list);
|
|
679 vec = (Lisp_Object *) alloca (XINT (length) * sizeof (Lisp_Object));
|
|
680 for (i = XINT (length) - 1, tail = list; i >= 0; i--, tail = Fcdr (tail))
|
|
681 vec[i] = Fcar (tail);
|
|
682
|
|
683 return Flist (XINT (length), vec);
|
|
684 }
|
|
685
|
|
686 Lisp_Object merge ();
|
|
687
|
|
688 DEFUN ("sort", Fsort, Ssort, 2, 2, 0,
|
|
689 "Sort LIST, stably, comparing elements using PREDICATE.\n\
|
|
690 Returns the sorted list. LIST is modified by side effects.\n\
|
|
691 PREDICATE is called with two elements of LIST, and should return T\n\
|
|
692 if the first element is \"less\" than the second.")
|
|
693 (list, pred)
|
|
694 Lisp_Object list, pred;
|
|
695 {
|
|
696 Lisp_Object front, back;
|
|
697 register Lisp_Object len, tem;
|
|
698 struct gcpro gcpro1, gcpro2;
|
|
699 register int length;
|
|
700
|
|
701 front = list;
|
|
702 len = Flength (list);
|
|
703 length = XINT (len);
|
|
704 if (length < 2)
|
|
705 return list;
|
|
706
|
|
707 XSETINT (len, (length / 2) - 1);
|
|
708 tem = Fnthcdr (len, list);
|
|
709 back = Fcdr (tem);
|
|
710 Fsetcdr (tem, Qnil);
|
|
711
|
|
712 GCPRO2 (front, back);
|
|
713 front = Fsort (front, pred);
|
|
714 back = Fsort (back, pred);
|
|
715 UNGCPRO;
|
|
716 return merge (front, back, pred);
|
|
717 }
|
|
718
|
|
719 Lisp_Object
|
|
720 merge (org_l1, org_l2, pred)
|
|
721 Lisp_Object org_l1, org_l2;
|
|
722 Lisp_Object pred;
|
|
723 {
|
|
724 Lisp_Object value;
|
|
725 register Lisp_Object tail;
|
|
726 Lisp_Object tem;
|
|
727 register Lisp_Object l1, l2;
|
|
728 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
|
|
729
|
|
730 l1 = org_l1;
|
|
731 l2 = org_l2;
|
|
732 tail = Qnil;
|
|
733 value = Qnil;
|
|
734
|
|
735 /* It is sufficient to protect org_l1 and org_l2.
|
|
736 When l1 and l2 are updated, we copy the new values
|
|
737 back into the org_ vars. */
|
|
738 GCPRO4 (org_l1, org_l2, pred, value);
|
|
739
|
|
740 while (1)
|
|
741 {
|
|
742 if (NULL (l1))
|
|
743 {
|
|
744 UNGCPRO;
|
|
745 if (NULL (tail))
|
|
746 return l2;
|
|
747 Fsetcdr (tail, l2);
|
|
748 return value;
|
|
749 }
|
|
750 if (NULL (l2))
|
|
751 {
|
|
752 UNGCPRO;
|
|
753 if (NULL (tail))
|
|
754 return l1;
|
|
755 Fsetcdr (tail, l1);
|
|
756 return value;
|
|
757 }
|
|
758 tem = call2 (pred, Fcar (l2), Fcar (l1));
|
|
759 if (NULL (tem))
|
|
760 {
|
|
761 tem = l1;
|
|
762 l1 = Fcdr (l1);
|
|
763 org_l1 = l1;
|
|
764 }
|
|
765 else
|
|
766 {
|
|
767 tem = l2;
|
|
768 l2 = Fcdr (l2);
|
|
769 org_l2 = l2;
|
|
770 }
|
|
771 if (NULL (tail))
|
|
772 value = tem;
|
|
773 else
|
|
774 Fsetcdr (tail, tem);
|
|
775 tail = tem;
|
|
776 }
|
|
777 }
|
|
778
|
|
779 DEFUN ("get", Fget, Sget, 2, 2, 0,
|
|
780 "Return the value of SYMBOL's PROPNAME property.\n\
|
|
781 This is the last VALUE stored with `(put SYMBOL PROPNAME VALUE)'.")
|
|
782 (sym, prop)
|
|
783 Lisp_Object sym;
|
|
784 register Lisp_Object prop;
|
|
785 {
|
|
786 register Lisp_Object tail;
|
|
787 for (tail = Fsymbol_plist (sym); !NULL (tail); tail = Fcdr (Fcdr (tail)))
|
|
788 {
|
|
789 register Lisp_Object tem;
|
|
790 tem = Fcar (tail);
|
|
791 if (EQ (prop, tem))
|
|
792 return Fcar (Fcdr (tail));
|
|
793 }
|
|
794 return Qnil;
|
|
795 }
|
|
796
|
|
797 DEFUN ("put", Fput, Sput, 3, 3, 0,
|
|
798 "Store SYMBOL's PROPNAME property with value VALUE.\n\
|
|
799 It can be retrieved with `(get SYMBOL PROPNAME)'.")
|
|
800 (sym, prop, val)
|
|
801 Lisp_Object sym;
|
|
802 register Lisp_Object prop;
|
|
803 Lisp_Object val;
|
|
804 {
|
|
805 register Lisp_Object tail, prev;
|
|
806 Lisp_Object newcell;
|
|
807 prev = Qnil;
|
|
808 for (tail = Fsymbol_plist (sym); !NULL (tail); tail = Fcdr (Fcdr (tail)))
|
|
809 {
|
|
810 register Lisp_Object tem;
|
|
811 tem = Fcar (tail);
|
|
812 if (EQ (prop, tem))
|
|
813 return Fsetcar (Fcdr (tail), val);
|
|
814 prev = tail;
|
|
815 }
|
|
816 newcell = Fcons (prop, Fcons (val, Qnil));
|
|
817 if (NULL (prev))
|
|
818 Fsetplist (sym, newcell);
|
|
819 else
|
|
820 Fsetcdr (Fcdr (prev), newcell);
|
|
821 return val;
|
|
822 }
|
|
823
|
|
824 DEFUN ("equal", Fequal, Sequal, 2, 2, 0,
|
|
825 "T if two Lisp objects have similar structure and contents.\n\
|
|
826 They must have the same data type.\n\
|
|
827 Conses are compared by comparing the cars and the cdrs.\n\
|
|
828 Vectors and strings are compared element by element.\n\
|
|
829 Numbers are compared by value. Symbols must match exactly.")
|
|
830 (o1, o2)
|
|
831 register Lisp_Object o1, o2;
|
|
832 {
|
|
833 do_cdr:
|
|
834 QUIT;
|
|
835 if (XTYPE (o1) != XTYPE (o2)) return Qnil;
|
|
836 if (XINT (o1) == XINT (o2)) return Qt;
|
|
837 if (XTYPE (o1) == Lisp_Cons)
|
|
838 {
|
|
839 Lisp_Object v1;
|
|
840 v1 = Fequal (Fcar (o1), Fcar (o2));
|
|
841 if (NULL (v1))
|
|
842 return v1;
|
|
843 o1 = Fcdr (o1), o2 = Fcdr (o2);
|
|
844 goto do_cdr;
|
|
845 }
|
|
846 if (XTYPE (o1) == Lisp_Marker)
|
|
847 {
|
|
848 return (XMARKER (o1)->buffer == XMARKER (o2)->buffer
|
|
849 && XMARKER (o1)->bufpos == XMARKER (o2)->bufpos)
|
|
850 ? Qt : Qnil;
|
|
851 }
|
|
852 if (XTYPE (o1) == Lisp_Vector)
|
|
853 {
|
|
854 register int index;
|
|
855 if (XVECTOR (o1)->size != XVECTOR (o2)->size)
|
|
856 return Qnil;
|
|
857 for (index = 0; index < XVECTOR (o1)->size; index++)
|
|
858 {
|
|
859 Lisp_Object v, v1, v2;
|
|
860 v1 = XVECTOR (o1)->contents [index];
|
|
861 v2 = XVECTOR (o2)->contents [index];
|
|
862 v = Fequal (v1, v2);
|
|
863 if (NULL (v)) return v;
|
|
864 }
|
|
865 return Qt;
|
|
866 }
|
|
867 if (XTYPE (o1) == Lisp_String)
|
|
868 {
|
|
869 if (XSTRING (o1)->size != XSTRING (o2)->size)
|
|
870 return Qnil;
|
|
871 if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data, XSTRING (o1)->size))
|
|
872 return Qnil;
|
|
873 return Qt;
|
|
874 }
|
|
875 return Qnil;
|
|
876 }
|
|
877
|
|
878 DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
|
|
879 "Store each element of ARRAY with ITEM. ARRAY is a vector or string.")
|
|
880 (array, item)
|
|
881 Lisp_Object array, item;
|
|
882 {
|
|
883 register int size, index, charval;
|
|
884 retry:
|
|
885 if (XTYPE (array) == Lisp_Vector)
|
|
886 {
|
|
887 register Lisp_Object *p = XVECTOR (array)->contents;
|
|
888 size = XVECTOR (array)->size;
|
|
889 for (index = 0; index < size; index++)
|
|
890 p[index] = item;
|
|
891 }
|
|
892 else if (XTYPE (array) == Lisp_String)
|
|
893 {
|
|
894 register unsigned char *p = XSTRING (array)->data;
|
|
895 CHECK_NUMBER (item, 1);
|
|
896 charval = XINT (item);
|
|
897 size = XSTRING (array)->size;
|
|
898 for (index = 0; index < size; index++)
|
|
899 p[index] = charval;
|
|
900 }
|
|
901 else
|
|
902 {
|
|
903 array = wrong_type_argument (Qarrayp, array);
|
|
904 goto retry;
|
|
905 }
|
|
906 return array;
|
|
907 }
|
|
908
|
|
909 /* ARGSUSED */
|
|
910 Lisp_Object
|
|
911 nconc2 (s1, s2)
|
|
912 Lisp_Object s1, s2;
|
|
913 {
|
|
914 #ifdef NO_ARG_ARRAY
|
|
915 Lisp_Object args[2];
|
|
916 args[0] = s1;
|
|
917 args[1] = s2;
|
|
918 return Fnconc (2, args);
|
|
919 #else
|
|
920 return Fnconc (2, &s1);
|
|
921 #endif /* NO_ARG_ARRAY */
|
|
922 }
|
|
923
|
|
924 DEFUN ("nconc", Fnconc, Snconc, 0, MANY, 0,
|
|
925 "Concatenate any number of lists by altering them.\n\
|
|
926 Only the last argument is not altered, and need not be a list.")
|
|
927 (nargs, args)
|
|
928 int nargs;
|
|
929 Lisp_Object *args;
|
|
930 {
|
|
931 register int argnum;
|
|
932 register Lisp_Object tail, tem, val;
|
|
933
|
|
934 val = Qnil;
|
|
935
|
|
936 for (argnum = 0; argnum < nargs; argnum++)
|
|
937 {
|
|
938 tem = args[argnum];
|
|
939 if (NULL (tem)) continue;
|
|
940
|
|
941 if (NULL (val))
|
|
942 val = tem;
|
|
943
|
|
944 if (argnum + 1 == nargs) break;
|
|
945
|
|
946 if (!CONSP (tem))
|
|
947 tem = wrong_type_argument (Qlistp, tem);
|
|
948
|
|
949 while (CONSP (tem))
|
|
950 {
|
|
951 tail = tem;
|
|
952 tem = Fcdr (tail);
|
|
953 QUIT;
|
|
954 }
|
|
955
|
|
956 tem = args[argnum + 1];
|
|
957 Fsetcdr (tail, tem);
|
|
958 if (NULL (tem))
|
|
959 args[argnum + 1] = tail;
|
|
960 }
|
|
961
|
|
962 return val;
|
|
963 }
|
|
964
|
|
965 /* This is the guts of all mapping functions.
|
|
966 Apply fn to each element of seq, one by one,
|
|
967 storing the results into elements of vals, a C vector of Lisp_Objects.
|
|
968 leni is the length of vals, which should also be the length of seq. */
|
|
969
|
|
970 static void
|
|
971 mapcar1 (leni, vals, fn, seq)
|
|
972 int leni;
|
|
973 Lisp_Object *vals;
|
|
974 Lisp_Object fn, seq;
|
|
975 {
|
|
976 register Lisp_Object tail;
|
|
977 Lisp_Object dummy;
|
|
978 register int i;
|
|
979 struct gcpro gcpro1, gcpro2, gcpro3;
|
|
980
|
|
981 /* Don't let vals contain any garbage when GC happens. */
|
|
982 for (i = 0; i < leni; i++)
|
|
983 vals[i] = Qnil;
|
|
984
|
|
985 GCPRO3 (dummy, fn, seq);
|
|
986 gcpro1.var = vals;
|
|
987 gcpro1.nvars = leni;
|
|
988 /* We need not explicitly protect `tail' because it is used only on lists, and
|
|
989 1) lists are not relocated and 2) the list is marked via `seq' so will not be freed */
|
|
990
|
|
991 if (XTYPE (seq) == Lisp_Vector)
|
|
992 {
|
|
993 for (i = 0; i < leni; i++)
|
|
994 {
|
|
995 dummy = XVECTOR (seq)->contents[i];
|
|
996 vals[i] = call1 (fn, dummy);
|
|
997 }
|
|
998 }
|
|
999 else if (XTYPE (seq) == Lisp_String)
|
|
1000 {
|
|
1001 for (i = 0; i < leni; i++)
|
|
1002 {
|
|
1003 XFASTINT (dummy) = XSTRING (seq)->data[i];
|
|
1004 vals[i] = call1 (fn, dummy);
|
|
1005 }
|
|
1006 }
|
|
1007 else /* Must be a list, since Flength did not get an error */
|
|
1008 {
|
|
1009 tail = seq;
|
|
1010 for (i = 0; i < leni; i++)
|
|
1011 {
|
|
1012 vals[i] = call1 (fn, Fcar (tail));
|
|
1013 tail = Fcdr (tail);
|
|
1014 }
|
|
1015 }
|
|
1016
|
|
1017 UNGCPRO;
|
|
1018 }
|
|
1019
|
|
1020 DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
|
|
1021 "Apply FN to each element of SEQ, and concat the results as strings.\n\
|
|
1022 In between each pair of results, stick in SEP.\n\
|
|
1023 Thus, \" \" as SEP results in spaces between the values return by FN.")
|
|
1024 (fn, seq, sep)
|
|
1025 Lisp_Object fn, seq, sep;
|
|
1026 {
|
|
1027 Lisp_Object len;
|
|
1028 register int leni;
|
|
1029 int nargs;
|
|
1030 register Lisp_Object *args;
|
|
1031 register int i;
|
|
1032 struct gcpro gcpro1;
|
|
1033
|
|
1034 len = Flength (seq);
|
|
1035 leni = XINT (len);
|
|
1036 nargs = leni + leni - 1;
|
|
1037 if (nargs < 0) return build_string ("");
|
|
1038
|
|
1039 args = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object));
|
|
1040
|
|
1041 GCPRO1 (sep);
|
|
1042 mapcar1 (leni, args, fn, seq);
|
|
1043 UNGCPRO;
|
|
1044
|
|
1045 for (i = leni - 1; i >= 0; i--)
|
|
1046 args[i + i] = args[i];
|
|
1047
|
|
1048 for (i = 1; i < nargs; i += 2)
|
|
1049 args[i] = sep;
|
|
1050
|
|
1051 return Fconcat (nargs, args);
|
|
1052 }
|
|
1053
|
|
1054 DEFUN ("mapcar", Fmapcar, Smapcar, 2, 2, 0,
|
|
1055 "Apply FUNCTION to each element of SEQUENCE, and make a list of the results.\n\
|
|
1056 The result is a list just as long as SEQUENCE.\n\
|
|
1057 SEQUENCE may be a list, a vector or a string.")
|
|
1058 (fn, seq)
|
|
1059 Lisp_Object fn, seq;
|
|
1060 {
|
|
1061 register Lisp_Object len;
|
|
1062 register int leni;
|
|
1063 register Lisp_Object *args;
|
|
1064
|
|
1065 len = Flength (seq);
|
|
1066 leni = XFASTINT (len);
|
|
1067 args = (Lisp_Object *) alloca (leni * sizeof (Lisp_Object));
|
|
1068
|
|
1069 mapcar1 (leni, args, fn, seq);
|
|
1070
|
|
1071 return Flist (leni, args);
|
|
1072 }
|
|
1073
|
|
1074 /* Anything that calls this function must protect from GC! */
|
|
1075
|
|
1076 DEFUN ("y-or-n-p", Fy_or_n_p, Sy_or_n_p, 1, 1, 0,
|
|
1077 "Ask user a \"y or n\" question. Return t if answer is \"y\".\n\
|
|
1078 No confirmation of the answer is requested; a single character is enough.\n\
|
|
1079 Also accepts Space to mean yes, or Delete to mean no.")
|
|
1080 (prompt)
|
|
1081 Lisp_Object prompt;
|
|
1082 {
|
|
1083 register Lisp_Object obj;
|
|
1084 register int ans;
|
|
1085 Lisp_Object xprompt;
|
|
1086 Lisp_Object args[2];
|
|
1087 int ocech = cursor_in_echo_area;
|
|
1088 struct gcpro gcpro1, gcpro2;
|
|
1089
|
|
1090 CHECK_STRING (prompt, 0);
|
|
1091 xprompt = prompt;
|
|
1092 GCPRO2 (prompt, xprompt);
|
|
1093
|
|
1094 while (1)
|
|
1095 {
|
|
1096 message ("%s(y or n) ", XSTRING (xprompt)->data);
|
|
1097 cursor_in_echo_area = 1;
|
|
1098
|
|
1099 obj = read_char (0);
|
|
1100 if (XTYPE (obj) == Lisp_Int)
|
|
1101 ans = XINT (obj);
|
|
1102 else
|
|
1103 continue;
|
|
1104
|
|
1105 cursor_in_echo_area = -1;
|
|
1106 message ("%s(y or n) %c", XSTRING (xprompt)->data, ans);
|
|
1107 cursor_in_echo_area = ocech;
|
|
1108 /* Accept a C-g or C-] (abort-recursive-edit) as quit requests. */
|
|
1109 if (ans == 7 || ans == '\035')
|
|
1110 Vquit_flag = Qt;
|
|
1111 QUIT;
|
|
1112 if (ans >= 0)
|
|
1113 ans = DOWNCASE (ans);
|
|
1114 if (ans == 'y' || ans == ' ')
|
|
1115 { ans = 'y'; break; }
|
|
1116 if (ans == 'n' || ans == 127)
|
|
1117 break;
|
|
1118
|
|
1119 Fding (Qnil);
|
|
1120 Fdiscard_input ();
|
|
1121 if (EQ (xprompt, prompt))
|
|
1122 {
|
|
1123 args[0] = build_string ("Please answer y or n. ");
|
|
1124 args[1] = prompt;
|
|
1125 xprompt = Fconcat (2, args);
|
|
1126 }
|
|
1127 }
|
|
1128 UNGCPRO;
|
|
1129 return (ans == 'y' ? Qt : Qnil);
|
|
1130 }
|
|
1131
|
|
1132 /* This is how C code calls `yes-or-no-p' and allows the user
|
|
1133 to redefined it.
|
|
1134
|
|
1135 Anything that calls this function must protect from GC! */
|
|
1136
|
|
1137 Lisp_Object
|
|
1138 do_yes_or_no_p (prompt)
|
|
1139 Lisp_Object prompt;
|
|
1140 {
|
|
1141 return call1 (intern ("yes-or-no-p"), prompt);
|
|
1142 }
|
|
1143
|
|
1144 /* Anything that calls this function must protect from GC! */
|
|
1145
|
|
1146 DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0,
|
|
1147 "Ask user a yes or no question. Return t if answer is yes.\n\
|
|
1148 The user must confirm the answer with a newline,\n\
|
|
1149 and can rub it out if not confirmed.")
|
|
1150 (prompt)
|
|
1151 Lisp_Object prompt;
|
|
1152 {
|
|
1153 register Lisp_Object ans;
|
|
1154 Lisp_Object args[2];
|
|
1155 struct gcpro gcpro1;
|
|
1156
|
|
1157 CHECK_STRING (prompt, 0);
|
|
1158
|
|
1159 args[0] = prompt;
|
|
1160 args[1] = build_string ("(yes or no) ");
|
|
1161 prompt = Fconcat (2, args);
|
|
1162
|
|
1163 GCPRO1 (prompt);
|
|
1164 while (1)
|
|
1165 {
|
|
1166 ans = Fdowncase (read_minibuf (Vminibuffer_local_map,
|
|
1167 Qnil, prompt, Qnil, 0));
|
|
1168 if (XSTRING (ans)->size == 3 && !strcmp (XSTRING (ans)->data, "yes"))
|
|
1169 {
|
|
1170 UNGCPRO;
|
|
1171 return Qt;
|
|
1172 }
|
|
1173 if (XSTRING (ans)->size == 2 && !strcmp (XSTRING (ans)->data, "no"))
|
|
1174 {
|
|
1175 UNGCPRO;
|
|
1176 return Qnil;
|
|
1177 }
|
|
1178
|
|
1179 Fding (Qnil);
|
|
1180 Fdiscard_input ();
|
|
1181 message ("Please answer yes or no.");
|
|
1182 Fsleep_for (make_number (2));
|
|
1183 }
|
|
1184 UNGCPRO;
|
|
1185 }
|
|
1186
|
|
1187 /* Avoid static vars inside a function since in HPUX they dump as pure. */
|
350
|
1188 #ifdef DGUX
|
|
1189 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
|
|
1190
|
|
1191 #else /* Not DGUX */
|
|
1192
|
211
|
1193 static int ldav_initialized;
|
|
1194 static int ldav_channel;
|
|
1195 #ifdef LOAD_AVE_TYPE
|
|
1196 #ifndef VMS
|
|
1197 static struct nlist ldav_nl[2];
|
|
1198 #endif /* VMS */
|
|
1199 #endif /* LOAD_AVE_TYPE */
|
|
1200
|
|
1201 #define channel ldav_channel
|
|
1202 #define initialized ldav_initialized
|
|
1203 #define nl ldav_nl
|
350
|
1204 #endif /* Not DGUX */
|
211
|
1205
|
|
1206 DEFUN ("load-average", Fload_average, Sload_average, 0, 0, 0,
|
|
1207 "Return list of 1 minute, 5 minute and 15 minute load averages.\n\
|
|
1208 Each of the three load averages is multiplied by 100,\n\
|
|
1209 then converted to integer.")
|
|
1210 ()
|
|
1211 {
|
350
|
1212 #ifdef DGUX
|
|
1213 /* perhaps there should be a "sys_load_avg" call in sysdep.c?! - DJB */
|
|
1214 load_info.one_minute = 0.0; /* just in case there is an error */
|
|
1215 load_info.five_minute = 0.0;
|
|
1216 load_info.fifteen_minute = 0.0;
|
|
1217 dg_sys_info (&load_info, DG_SYS_INFO_LOAD_INFO_TYPE,
|
|
1218 DG_SYS_INFO_LOAD_VERSION_0);
|
|
1219
|
|
1220 return Fcons (make_number ((int)(load_info.one_minute * 100.0)),
|
|
1221 Fcons (make_number ((int)(load_info.five_minute * 100.0)),
|
|
1222 Fcons (make_number ((int)(load_info.fifteen_minute * 100.0)),
|
|
1223 Qnil)));
|
|
1224 #else /* not DGUX */
|
211
|
1225 #ifndef LOAD_AVE_TYPE
|
|
1226 error ("load-average not implemented for this operating system");
|
|
1227
|
|
1228 #else /* LOAD_AVE_TYPE defined */
|
|
1229
|
|
1230 LOAD_AVE_TYPE load_ave[3];
|
|
1231 #ifdef VMS
|
|
1232 #ifndef eunice
|
|
1233 #include <iodef.h>
|
|
1234 #include <descrip.h>
|
|
1235 #else
|
|
1236 #include <vms/iodef.h>
|
|
1237 struct {int dsc$w_length; char *dsc$a_pointer;} descriptor;
|
|
1238 #endif /* eunice */
|
|
1239 #endif /* VMS */
|
|
1240
|
|
1241 /* If this fails for any reason, we can return (0 0 0) */
|
|
1242 load_ave[0] = 0.0; load_ave[1] = 0.0; load_ave[2] = 0.0;
|
|
1243
|
|
1244 #ifdef VMS
|
|
1245 /*
|
|
1246 * VMS specific code -- read from the Load Ave driver
|
|
1247 */
|
|
1248
|
|
1249 /*
|
|
1250 * Ensure that there is a channel open to the load ave device
|
|
1251 */
|
|
1252 if (initialized == 0)
|
|
1253 {
|
|
1254 /* Attempt to open the channel */
|
|
1255 #ifdef eunice
|
|
1256 descriptor.size = 18;
|
|
1257 descriptor.ptr = "$$VMS_LOAD_AVERAGE";
|
|
1258 #else
|
|
1259 $DESCRIPTOR(descriptor, "LAV0:");
|
|
1260 #endif
|
|
1261 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
|
|
1262 initialized = 1;
|
|
1263 }
|
|
1264 /*
|
|
1265 * Read the load average vector
|
|
1266 */
|
|
1267 if (initialized)
|
|
1268 {
|
|
1269 if (!(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
|
|
1270 load_ave, 12, 0, 0, 0, 0)
|
|
1271 & 1))
|
|
1272 {
|
|
1273 sys$dassgn (channel);
|
|
1274 initialized = 0;
|
|
1275 }
|
|
1276 }
|
|
1277 #else /* not VMS */
|
|
1278 /*
|
|
1279 * 4.2BSD UNIX-specific code -- read _avenrun from /dev/kmem
|
|
1280 */
|
|
1281
|
|
1282 /*
|
|
1283 * Make sure we have the address of _avenrun
|
|
1284 */
|
|
1285 if (nl[0].n_value == 0)
|
|
1286 {
|
|
1287 /*
|
|
1288 * Get the address of _avenrun
|
|
1289 */
|
|
1290 #ifndef NLIST_STRUCT
|
|
1291 strcpy (nl[0].n_name, LDAV_SYMBOL);
|
|
1292 nl[1].n_zeroes = 0;
|
|
1293 #else /* NLIST_STRUCT */
|
|
1294 #ifdef convex
|
|
1295 nl[0].n_un.n_name = LDAV_SYMBOL;
|
|
1296 nl[1].n_un.n_name = 0;
|
|
1297 #else /* not convex */
|
|
1298 nl[0].n_name = LDAV_SYMBOL;
|
|
1299 nl[1].n_name = 0;
|
|
1300 #endif /* not convex */
|
|
1301 #endif /* NLIST_STRUCT */
|
|
1302
|
|
1303 nlist (KERNEL_FILE, nl);
|
|
1304
|
|
1305 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
|
|
1306 FIXUP_KERNEL_SYMBOL_ADDR (nl);
|
|
1307 #endif /* FIXUP_KERNEL_SYMBOL_ADDR */
|
|
1308 }
|
|
1309 /*
|
|
1310 * Make sure we have /dev/kmem open
|
|
1311 */
|
|
1312 if (initialized == 0)
|
|
1313 {
|
|
1314 /*
|
|
1315 * Open /dev/kmem
|
|
1316 */
|
|
1317 channel = open ("/dev/kmem", 0);
|
|
1318 if (channel >= 0) initialized = 1;
|
|
1319 }
|
|
1320 /*
|
|
1321 * If we can, get the load ave values
|
|
1322 */
|
|
1323 if ((nl[0].n_value != 0) && (initialized != 0))
|
|
1324 {
|
|
1325 /*
|
|
1326 * Seek to the correct address
|
|
1327 */
|
|
1328 lseek (channel, (long) nl[0].n_value, 0);
|
|
1329 if (read (channel, load_ave, sizeof load_ave)
|
|
1330 != sizeof(load_ave))
|
|
1331 {
|
|
1332 close (channel);
|
|
1333 initialized = 0;
|
|
1334 }
|
|
1335 }
|
|
1336 #endif /* not VMS */
|
|
1337
|
|
1338 /*
|
|
1339 * Return the list of load average values
|
|
1340 */
|
|
1341 return Fcons (make_number (LOAD_AVE_CVT (load_ave[0])),
|
|
1342 Fcons (make_number (LOAD_AVE_CVT (load_ave[1])),
|
|
1343 Fcons (make_number (LOAD_AVE_CVT (load_ave[2])),
|
|
1344 Qnil)));
|
|
1345 #endif /* LOAD_AVE_TYPE */
|
350
|
1346 #endif /* not DGUX */
|
211
|
1347 }
|
|
1348
|
|
1349 #undef channel
|
|
1350 #undef initialized
|
|
1351 #undef nl
|
|
1352
|
|
1353 Lisp_Object Vfeatures;
|
|
1354
|
|
1355 DEFUN ("featurep", Ffeaturep, Sfeaturep, 1, 1, 0,
|
|
1356 "Returns t if FEATURE is present in this Emacs.\n\
|
|
1357 Use this to conditionalize execution of lisp code based on the presence or\n\
|
|
1358 absence of emacs or environment extensions.\n\
|
|
1359 Use `provide' to declare that a feature is available.\n\
|
|
1360 This function looks at the value of the variable `features'.")
|
|
1361 (feature)
|
|
1362 Lisp_Object feature;
|
|
1363 {
|
|
1364 register Lisp_Object tem;
|
|
1365 CHECK_SYMBOL (feature, 0);
|
|
1366 tem = Fmemq (feature, Vfeatures);
|
|
1367 return (NULL (tem)) ? Qnil : Qt;
|
|
1368 }
|
|
1369
|
|
1370 DEFUN ("provide", Fprovide, Sprovide, 1, 1, 0,
|
|
1371 "Announce that FEATURE is a feature of the current Emacs.")
|
|
1372 (feature)
|
|
1373 Lisp_Object feature;
|
|
1374 {
|
|
1375 register Lisp_Object tem;
|
|
1376 CHECK_SYMBOL (feature, 0);
|
|
1377 if (!NULL (Vautoload_queue))
|
|
1378 Vautoload_queue = Fcons (Fcons (Vfeatures, Qnil), Vautoload_queue);
|
|
1379 tem = Fmemq (feature, Vfeatures);
|
|
1380 if (NULL (tem))
|
|
1381 Vfeatures = Fcons (feature, Vfeatures);
|
|
1382 return feature;
|
|
1383 }
|
|
1384
|
|
1385 DEFUN ("require", Frequire, Srequire, 1, 2, 0,
|
|
1386 "If feature FEATURE is not loaded, load it from FILENAME.\n\
|
|
1387 If FEATURE is not a member of the list `features', then the feature\n\
|
|
1388 is not loaded; so load the file FILENAME.\n\
|
|
1389 If FILENAME is omitted, the printname of FEATURE is used as the file name.")
|
|
1390 (feature, file_name)
|
|
1391 Lisp_Object feature, file_name;
|
|
1392 {
|
|
1393 register Lisp_Object tem;
|
|
1394 CHECK_SYMBOL (feature, 0);
|
|
1395 tem = Fmemq (feature, Vfeatures);
|
|
1396 if (NULL (tem))
|
|
1397 {
|
|
1398 int count = specpdl_ptr - specpdl;
|
|
1399
|
|
1400 /* Value saved here is to be restored into Vautoload_queue */
|
|
1401 record_unwind_protect (un_autoload, Vautoload_queue);
|
|
1402 Vautoload_queue = Qt;
|
|
1403
|
|
1404 Fload (NULL (file_name) ? Fsymbol_name (feature) : file_name,
|
|
1405 Qnil, Qt, Qnil);
|
|
1406
|
|
1407 tem = Fmemq (feature, Vfeatures);
|
|
1408 if (NULL (tem))
|
|
1409 error ("Required feature %s was not provided",
|
|
1410 XSYMBOL (feature)->name->data );
|
|
1411
|
|
1412 /* Once loading finishes, don't undo it. */
|
|
1413 Vautoload_queue = Qt;
|
|
1414 feature = unbind_to (count, feature);
|
|
1415 }
|
|
1416 return feature;
|
|
1417 }
|
|
1418
|
|
1419 syms_of_fns ()
|
|
1420 {
|
|
1421 Qstring_lessp = intern ("string-lessp");
|
|
1422 staticpro (&Qstring_lessp);
|
|
1423
|
|
1424 DEFVAR_LISP ("features", &Vfeatures,
|
|
1425 "A list of symbols which are the features of the executing emacs.\n\
|
|
1426 Used by `featurep' and `require', and altered by `provide'.");
|
|
1427 Vfeatures = Qnil;
|
|
1428
|
|
1429 defsubr (&Sidentity);
|
|
1430 defsubr (&Srandom);
|
|
1431 defsubr (&Slength);
|
|
1432 defsubr (&Sstring_equal);
|
|
1433 defsubr (&Sstring_lessp);
|
|
1434 defsubr (&Sappend);
|
|
1435 defsubr (&Sconcat);
|
|
1436 defsubr (&Svconcat);
|
|
1437 defsubr (&Scopy_sequence);
|
|
1438 defsubr (&Scopy_alist);
|
|
1439 defsubr (&Ssubstring);
|
|
1440 defsubr (&Snthcdr);
|
|
1441 defsubr (&Snth);
|
|
1442 defsubr (&Selt);
|
|
1443 defsubr (&Smember);
|
|
1444 defsubr (&Smemq);
|
|
1445 defsubr (&Sassq);
|
|
1446 defsubr (&Sassoc);
|
|
1447 defsubr (&Srassq);
|
|
1448 defsubr (&Sdelq);
|
|
1449 defsubr (&Snreverse);
|
|
1450 defsubr (&Sreverse);
|
|
1451 defsubr (&Ssort);
|
|
1452 defsubr (&Sget);
|
|
1453 defsubr (&Sput);
|
|
1454 defsubr (&Sequal);
|
|
1455 defsubr (&Sfillarray);
|
|
1456 defsubr (&Snconc);
|
|
1457 defsubr (&Smapcar);
|
|
1458 defsubr (&Smapconcat);
|
|
1459 defsubr (&Sy_or_n_p);
|
|
1460 defsubr (&Syes_or_no_p);
|
|
1461 defsubr (&Sload_average);
|
|
1462 defsubr (&Sfeaturep);
|
|
1463 defsubr (&Srequire);
|
|
1464 defsubr (&Sprovide);
|
|
1465 }
|