1 // fns1.cpp Copyright (C) 1989-2021 Codemist
2
3 //
4 // Basic functions part 1.
5 //
6
7 /**************************************************************************
8 * Copyright (C) 2021, Codemist. A C Norman *
9 * *
10 * Redistribution and use in source and binary forms, with or without *
11 * modification, are permitted provided that the following conditions are *
12 * met: *
13 * *
14 * * Redistributions of source code must retain the relevant *
15 * copyright notice, this list of conditions and the following *
16 * disclaimer. *
17 * * Redistributions in binary form must reproduce the above *
18 * copyright notice, this list of conditions and the following *
19 * disclaimer in the documentation and/or other materials provided *
20 * with the distribution. *
21 * *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
26 * COPYRIGHT OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
31 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
32 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
33 * DAMAGE. *
34 *************************************************************************/
35
36 // $Id: fns1.cpp 5736 2021-03-16 10:41:22Z arthurcnorman $
37
38
39 #include "headers.h"
40
41 #ifndef WIN32
42 #include <dlfcn.h>
43 #endif
44
45 /*!!! csl
46 */
47
48 /*****************************************************************************/
49 // Some basic functions
50 /*****************************************************************************/
51
52 // For some debugging purposes it is noce to have a counter...
53
54 static uintptr_t countup_counter = 0;
55
Lcount_up(LispObject)56 LispObject Lcount_up(LispObject)
57 { return fixnum_of_int(countup_counter++);
58 }
59
integerp(LispObject p)60 LispObject integerp(LispObject p)
61 { if (is_fixnum(p) || (is_numbers(p) &&
62 is_bignum(p))) return lisp_true;
63 else return nil;
64 }
65
66 //****************************************************************************
67 //****************************************************************************
68 //** Lisp-callable versions various things **
69 //****************************************************************************
70 //****************************************************************************
71
72 // The set of car/cdr combinations here seem pretty dull, but they
73 // are fairly important for performance...
74
75 /*! fns [car] \item [{\ttfamily car} {\itshape expr}] \index{{\ttfamily car} {\itshape expr}} ~\newline
76 * For a non-empty list the function {\ttfamily car} will return the
77 * first element. For a dotted pair (created using {\ttfamily cons})
78 * it extracts the first component. This is the fundamental low-level
79 * data structure access function in Lisp. See {\ttfamily cdr} for the
80 * function that returns the tail or a list or the second component of
81 * a dotted pair. In CSL any attempt to take {\ttfamily car} of an atom
82 * should be detected and will be treated as an error. If CSL had been
83 * compiled in Common Lisp mode (which is now not probable) a special
84 * exemption would apply and {\ttfamily car} and {\ttfamily cdr} of the
85 * empty lisp {\ttfamily nil} would be {\ttfamily nil}.
86 */
87
Lcar(LispObject,LispObject a)88 LispObject Lcar(LispObject, LispObject a)
89 { if (!car_legal(a)) return onevalue(carerror(a));
90 else return onevalue(car(a));
91 }
92
93 // (car* a) = (car a) if a is non-atomic, but just a otherwise.
94
95 /*! fns [car*] \item[{\ttfamily car!*} {\itshape expr}] \index{{\ttfamily car"!*} {\itshape expr}} ~\newline
96 * This function behaves like {\ttfamily car} except that if its argument
97 * is atomic then the argument is returned unaltered rather than that case
98 * being treated as an error.
99 */
100
Lcar_star(LispObject,LispObject a)101 LispObject Lcar_star(LispObject, LispObject a)
102 { if (!car_legal(a)) return onevalue(a);
103 else return onevalue(car(a));
104 }
105
106 /*! fns [cdr] \item [{\ttfamily cdr} {\itshape expr}] \index{{\ttfamily cdr} {\itshape expr}} ~\newline
107 * See {\ttfamily car}.
108 */
109
Lcdr(LispObject,LispObject a)110 LispObject Lcdr(LispObject, LispObject a)
111 { if (!car_legal(a)) return onevalue(cdrerror(a));
112 else return onevalue(cdr(a));
113 }
114
115 /*! fns [caar] \item [{\ttfamily caar \ldots cddddr} {\itshape expr}] \index{{\ttfamily caar \ldots cddddr} {\itshape expr}} ~\newline
116 * Names that start with {\ttfamily c}, then have a sequence of
117 * {\ttfamily a} or {\ttfamily d}s and finally {\ttfamily r} provide
118 * shorthand functions for chains of uses of {\ttfamily car} and
119 * {\ttfamily cdr}. Thus for instance
120 * {\ttfamily (cadar x)} has the same meaning as
121 * {\ttfamily (car (cdr (car x)))}.
122 */
123
Lcaar(LispObject,LispObject a)124 LispObject Lcaar(LispObject, LispObject a)
125 { if (!car_legal(a)) return onevalue(carerror(a));
126 else a = car(a);
127 if (!car_legal(a)) return onevalue(carerror(a));
128 else return onevalue(car(a));
129 }
130
131 /*! fns [cadr] \item [{\ttfamily cadr} {\itshape expr}] \index{{\ttfamily cadr} {\itshape expr}} ~\newline
132 * see {\ttfamily caar} and {\ttfamily second}.
133 */
134
Lcadr(LispObject,LispObject a)135 LispObject Lcadr(LispObject, LispObject a)
136 { if (!car_legal(a)) return onevalue(cdrerror(a));
137 else a = cdr(a);
138 if (!car_legal(a)) return onevalue(carerror(a));
139 else return onevalue(car(a));
140 }
141
142 /*! fns [cdar] \item[{\ttfamily cdar} {\itshape expr}] \index{{\ttfamily cdar} {\itshape expr}} ~\newline
143 * see {\ttfamily caar}.
144 */
145
Lcdar(LispObject,LispObject a)146 LispObject Lcdar(LispObject, LispObject a)
147 { if (!car_legal(a)) return onevalue(carerror(a));
148 else a = car(a);
149 if (!car_legal(a)) return onevalue(cdrerror(a));
150 else return onevalue(cdr(a));
151 }
152
153 /*! fns [cddr] \item[{\ttfamily cddr} {\itshape expr}] \index{{\ttfamily cddr} {\itshape expr}} ~\newline
154 * see {\ttfamily caar}.
155 */
156
Lcddr(LispObject,LispObject a)157 LispObject Lcddr(LispObject, LispObject a)
158 { if (!car_legal(a)) return onevalue(cdrerror(a));
159 else a = cdr(a);
160 if (!car_legal(a)) return onevalue(cdrerror(a));
161 else return onevalue(cdr(a));
162 }
163
164 /*! fns [caaar] \item[{\ttfamily caaar} {\itshape expr}] \index{{\ttfamily caaar} {\itshape expr}} ~\newline
165 * see {\ttfamily caar}.
166 */
167
Lcaaar(LispObject,LispObject a)168 LispObject Lcaaar(LispObject, LispObject a)
169 { if (!car_legal(a)) return onevalue(carerror(a));
170 else a = car(a);
171 if (!car_legal(a)) return onevalue(carerror(a));
172 else a = car(a);
173 if (!car_legal(a)) return onevalue(carerror(a));
174 else return onevalue(car(a));
175 }
176
177 /*! fns [caadr] \item[{\ttfamily caadr} {\itshape expr}] \index{{\ttfamily caadr} {\itshape expr}} ~\newline
178 * see {\ttfamily caar}.
179 */
180
Lcaadr(LispObject,LispObject a)181 LispObject Lcaadr(LispObject, LispObject a)
182 { if (!car_legal(a)) return onevalue(cdrerror(a));
183 else a = cdr(a);
184 if (!car_legal(a)) return onevalue(carerror(a));
185 else a = car(a);
186 if (!car_legal(a)) return onevalue(carerror(a));
187 else return onevalue(car(a));
188 }
189
190 /*! fns [cadar] \item[{\ttfamily cadar} {\itshape expr}] \index{{\ttfamily cadar} {\itshape expr}} ~\newline
191 * see {\ttfamily caar}.
192 */
193
Lcadar(LispObject,LispObject a)194 LispObject Lcadar(LispObject, LispObject a)
195 { if (!car_legal(a)) return onevalue(carerror(a));
196 else a = car(a);
197 if (!car_legal(a)) return onevalue(cdrerror(a));
198 else a = cdr(a);
199 if (!car_legal(a)) return onevalue(carerror(a));
200 else return onevalue(car(a));
201 }
202
203 /*! fns [caddr] \item[{\ttfamily caddr} {\itshape expr}] \index{{\ttfamily caddr} {\itshape expr}} ~\newline
204 * see {\ttfamily caar} and {\ttfamily third}.
205 */
206
Lcaddr(LispObject,LispObject a)207 LispObject Lcaddr(LispObject, LispObject a)
208 { if (!car_legal(a)) return onevalue(cdrerror(a));
209 else a = cdr(a);
210 if (!car_legal(a)) return onevalue(cdrerror(a));
211 else a = cdr(a);
212 if (!car_legal(a)) return onevalue(carerror(a));
213 else return onevalue(car(a));
214 }
215
216 /*! fns [cdaar] \item[{\ttfamily cdaar} {\itshape expr}] \index{{\ttfamily cdaar} {\itshape expr}} ~\newline
217 * see {\ttfamily caar}.
218 */
219
Lcdaar(LispObject,LispObject a)220 LispObject Lcdaar(LispObject, LispObject a)
221 { if (!car_legal(a)) return onevalue(carerror(a));
222 else a = car(a);
223 if (!car_legal(a)) return onevalue(carerror(a));
224 else a = car(a);
225 if (!car_legal(a)) return onevalue(cdrerror(a));
226 else return onevalue(cdr(a));
227 }
228
229 /*! fns [cdadr] \item[{\ttfamily cdadr} {\itshape expr}] \index{{\ttfamily cdadr} {\itshape expr}} ~\newline
230 * see {\ttfamily caar}.
231 */
232
Lcdadr(LispObject,LispObject a)233 LispObject Lcdadr(LispObject, LispObject a)
234 { if (!car_legal(a)) return onevalue(cdrerror(a));
235 else a = cdr(a);
236 if (!car_legal(a)) return onevalue(carerror(a));
237 else a = car(a);
238 if (!car_legal(a)) return onevalue(cdrerror(a));
239 else return onevalue(cdr(a));
240 }
241
242 /*! fns [cddar] \item[{\ttfamily cddar} {\itshape expr}] \index{{\ttfamily cddar} {\itshape expr}} ~\newline
243 * see {\ttfamily caar}.
244 */
245
Lcddar(LispObject,LispObject a)246 LispObject Lcddar(LispObject, LispObject a)
247 { if (!car_legal(a)) return onevalue(carerror(a));
248 else a = car(a);
249 if (!car_legal(a)) return onevalue(cdrerror(a));
250 else a = cdr(a);
251 if (!car_legal(a)) return onevalue(cdrerror(a));
252 else return onevalue(cdr(a));
253 }
254
255 /*! fns [cdddr] \item[{\ttfamily cdddr} {\itshape expr}] \index{{\ttfamily cdddr} {\itshape expr}} ~\newline
256 * see {\ttfamily caar}.
257 */
258
Lcdddr(LispObject,LispObject a)259 LispObject Lcdddr(LispObject, LispObject a)
260 { if (!car_legal(a)) return onevalue(cdrerror(a));
261 else a = cdr(a);
262 if (!car_legal(a)) return onevalue(cdrerror(a));
263 else a = cdr(a);
264 if (!car_legal(a)) return onevalue(cdrerror(a));
265 else return onevalue(cdr(a));
266 }
267
268 /*! fns [caaaar] \item[{\ttfamily caaaar} {\itshape expr}] \index{{\ttfamily caaaar} {\itshape expr}} ~\newline
269 * see {\ttfamily caar}.
270 */
271
Lcaaaar(LispObject,LispObject a)272 LispObject Lcaaaar(LispObject, LispObject a)
273 { if (!car_legal(a)) return onevalue(carerror(a));
274 else a = car(a);
275 if (!car_legal(a)) return onevalue(carerror(a));
276 else a = car(a);
277 if (!car_legal(a)) return onevalue(carerror(a));
278 else a = car(a);
279 if (!car_legal(a)) return onevalue(carerror(a));
280 else return onevalue(car(a));
281 }
282
283 /*! fns [caaadr] \item[{\ttfamily caaadr} {\itshape expr}] \index{{\ttfamily caaadr} {\itshape expr}} ~\newline
284 * see {\ttfamily caar}.
285 */
286
Lcaaadr(LispObject,LispObject a)287 LispObject Lcaaadr(LispObject, LispObject a)
288 { if (!car_legal(a)) return onevalue(cdrerror(a));
289 else a = cdr(a);
290 if (!car_legal(a)) return onevalue(carerror(a));
291 else a = car(a);
292 if (!car_legal(a)) return onevalue(carerror(a));
293 else a = car(a);
294 if (!car_legal(a)) return onevalue(carerror(a));
295 else return onevalue(car(a));
296 }
297
298 /*! fns [caadar] \item[{\ttfamily caadar} {\itshape expr}] \index{{\ttfamily caadar} {\itshape expr}} ~\newline
299 * see {\ttfamily caar}.
300 */
301
Lcaadar(LispObject,LispObject a)302 LispObject Lcaadar(LispObject, LispObject a)
303 { if (!car_legal(a)) return onevalue(carerror(a));
304 else a = car(a);
305 if (!car_legal(a)) return onevalue(cdrerror(a));
306 else a = cdr(a);
307 if (!car_legal(a)) return onevalue(carerror(a));
308 else a = car(a);
309 if (!car_legal(a)) return onevalue(carerror(a));
310 else return onevalue(car(a));
311 }
312
313 /*! fns [caaddr] \item[{\ttfamily caaddr} {\itshape expr}] \index{{\ttfamily caaddr} {\itshape expr}} ~\newline
314 * see {\ttfamily caar}.
315 */
316
Lcaaddr(LispObject,LispObject a)317 LispObject Lcaaddr(LispObject, LispObject a)
318 { if (!car_legal(a)) return onevalue(cdrerror(a));
319 else a = cdr(a);
320 if (!car_legal(a)) return onevalue(cdrerror(a));
321 else a = cdr(a);
322 if (!car_legal(a)) return onevalue(carerror(a));
323 else a = car(a);
324 if (!car_legal(a)) return onevalue(carerror(a));
325 else return onevalue(car(a));
326 }
327
328 /*! fns [cadaar] \item[{\ttfamily cadaar} {\itshape expr}] \index{{\ttfamily cadaar} {\itshape expr}} ~\newline
329 * see {\ttfamily caar}.
330 */
331
Lcadaar(LispObject,LispObject a)332 LispObject Lcadaar(LispObject, LispObject a)
333 { if (!car_legal(a)) return onevalue(carerror(a));
334 else a = car(a);
335 if (!car_legal(a)) return onevalue(carerror(a));
336 else a = car(a);
337 if (!car_legal(a)) return onevalue(cdrerror(a));
338 else a = cdr(a);
339 if (!car_legal(a)) return onevalue(carerror(a));
340 else return onevalue(car(a));
341 }
342
343 /*! fns [cadadr] \item[{\ttfamily cadadr} {\itshape expr}] \index{{\ttfamily cadadr} {\itshape expr}} ~\newline
344 * see {\ttfamily caar}.
345 */
346
Lcadadr(LispObject,LispObject a)347 LispObject Lcadadr(LispObject, LispObject a)
348 { if (!car_legal(a)) return onevalue(cdrerror(a));
349 else a = cdr(a);
350 if (!car_legal(a)) return onevalue(carerror(a));
351 else a = car(a);
352 if (!car_legal(a)) return onevalue(cdrerror(a));
353 else a = cdr(a);
354 if (!car_legal(a)) return onevalue(carerror(a));
355 else return onevalue(car(a));
356 }
357
358 /*! fns [caddar] \item[{\ttfamily caddar} {\itshape expr}] \index{{\ttfamily caddar} {\itshape expr}} ~\newline
359 * see {\ttfamily caar}.
360 */
361
Lcaddar(LispObject,LispObject a)362 LispObject Lcaddar(LispObject, LispObject a)
363 { if (!car_legal(a)) return onevalue(carerror(a));
364 else a = car(a);
365 if (!car_legal(a)) return onevalue(cdrerror(a));
366 else a = cdr(a);
367 if (!car_legal(a)) return onevalue(cdrerror(a));
368 else a = cdr(a);
369 if (!car_legal(a)) return onevalue(carerror(a));
370 else return onevalue(car(a));
371 }
372
373 /*! fns [cadddr] \item[{\ttfamily cadddr} {\itshape expr}] \index{{\ttfamily cadddr} {\itshape expr}} ~\newline
374 * see {\ttfamily caar} and {\ttfamily fourth}.
375 */
376
Lcadddr(LispObject,LispObject a)377 LispObject Lcadddr(LispObject, LispObject a)
378 { if (!car_legal(a)) return onevalue(cdrerror(a));
379 else a = cdr(a);
380 if (!car_legal(a)) return onevalue(cdrerror(a));
381 else a = cdr(a);
382 if (!car_legal(a)) return onevalue(cdrerror(a));
383 else a = cdr(a);
384 if (!car_legal(a)) return onevalue(carerror(a));
385 else return onevalue(car(a));
386 }
387
388 /*! fns [cdaaar] \item[{\ttfamily cdaaar} {\itshape expr}] \index{{\ttfamily cdaaar} {\itshape expr}} ~\newline
389 * see {\ttfamily caar}.
390 */
391
Lcdaaar(LispObject,LispObject a)392 LispObject Lcdaaar(LispObject, LispObject a)
393 { if (!car_legal(a)) return onevalue(carerror(a));
394 else a = car(a);
395 if (!car_legal(a)) return onevalue(carerror(a));
396 else a = car(a);
397 if (!car_legal(a)) return onevalue(carerror(a));
398 else a = car(a);
399 if (!car_legal(a)) return onevalue(cdrerror(a));
400 else return onevalue(cdr(a));
401 }
402
403 /*! fns [cdaadr] \item[{\ttfamily cdaadr} {\itshape expr}] \index{{\ttfamily cdaadr} {\itshape expr}} ~\newline
404 * see {\ttfamily caar}.
405 */
406
Lcdaadr(LispObject,LispObject a)407 LispObject Lcdaadr(LispObject, LispObject a)
408 { if (!car_legal(a)) return onevalue(cdrerror(a));
409 else a = cdr(a);
410 if (!car_legal(a)) return onevalue(carerror(a));
411 else a = car(a);
412 if (!car_legal(a)) return onevalue(carerror(a));
413 else a = car(a);
414 if (!car_legal(a)) return onevalue(cdrerror(a));
415 else return onevalue(cdr(a));
416 }
417
418 /*! fns [cdadar] \item[{\ttfamily cdadar} {\itshape expr}] \index{{\ttfamily cdadar} {\itshape expr}} ~\newline
419 * see {\ttfamily caar}.
420 */
421
Lcdadar(LispObject,LispObject a)422 LispObject Lcdadar(LispObject, LispObject a)
423 { if (!car_legal(a)) return onevalue(carerror(a));
424 else a = car(a);
425 if (!car_legal(a)) return onevalue(cdrerror(a));
426 else a = cdr(a);
427 if (!car_legal(a)) return onevalue(carerror(a));
428 else a = car(a);
429 if (!car_legal(a)) return onevalue(cdrerror(a));
430 else return onevalue(cdr(a));
431 }
432
433 /*! fns [cdaddr] \item[{\ttfamily cdaddr} {\itshape expr}] \index{{\ttfamily cdaddr} {\itshape expr}} ~\newline
434 * see {\ttfamily caar}.
435 */
436
Lcdaddr(LispObject,LispObject a)437 LispObject Lcdaddr(LispObject, LispObject a)
438 { if (!car_legal(a)) return onevalue(cdrerror(a));
439 else a = cdr(a);
440 if (!car_legal(a)) return onevalue(cdrerror(a));
441 else a = cdr(a);
442 if (!car_legal(a)) return onevalue(carerror(a));
443 else a = car(a);
444 if (!car_legal(a)) return onevalue(cdrerror(a));
445 else return onevalue(cdr(a));
446 }
447
448 /*! fns [cddaar] \item[{\ttfamily cddaar} {\itshape expr}] \index{{\ttfamily cddaar} {\itshape expr}} ~\newline
449 * see {\ttfamily caar}.
450 */
451
Lcddaar(LispObject,LispObject a)452 LispObject Lcddaar(LispObject, LispObject a)
453 { if (!car_legal(a)) return onevalue(carerror(a));
454 else a = car(a);
455 if (!car_legal(a)) return onevalue(carerror(a));
456 else a = car(a);
457 if (!car_legal(a)) return onevalue(cdrerror(a));
458 else a = cdr(a);
459 if (!car_legal(a)) return onevalue(cdrerror(a));
460 else return onevalue(cdr(a));
461 }
462
463 /*! fns [cddadr] \item[{\ttfamily cddadr} {\itshape expr}] \index{{\ttfamily cddadr} {\itshape expr}} ~\newline
464 * see {\ttfamily caar}.
465 */
466
Lcddadr(LispObject,LispObject a)467 LispObject Lcddadr(LispObject, LispObject a)
468 { if (!car_legal(a)) return onevalue(cdrerror(a));
469 else a = cdr(a);
470 if (!car_legal(a)) return onevalue(carerror(a));
471 else a = car(a);
472 if (!car_legal(a)) return onevalue(cdrerror(a));
473 else a = cdr(a);
474 if (!car_legal(a)) return onevalue(cdrerror(a));
475 else return onevalue(cdr(a));
476 }
477
478 /*! fns [cdddar] \item[{\ttfamily cdddar} {\itshape expr}] \index{{\ttfamily cdddar} {\itshape expr}} ~\newline
479 * see {\ttfamily caar}.
480 */
481
Lcdddar(LispObject,LispObject a)482 LispObject Lcdddar(LispObject, LispObject a)
483 { if (!car_legal(a)) return onevalue(carerror(a));
484 else a = car(a);
485 if (!car_legal(a)) return onevalue(cdrerror(a));
486 else a = cdr(a);
487 if (!car_legal(a)) return onevalue(cdrerror(a));
488 else a = cdr(a);
489 if (!car_legal(a)) return onevalue(cdrerror(a));
490 else return onevalue(cdr(a));
491 }
492
493 /*! fns [cddddr] \item[{\ttfamily cddddr} {\itshape expr}] \index{{\ttfamily cddddr} {\itshape expr}} ~\newline
494 * see {\ttfamily caar}.
495 */
496
Lcddddr(LispObject,LispObject a)497 LispObject Lcddddr(LispObject, LispObject a)
498 { if (!car_legal(a)) return onevalue(cdrerror(a));
499 else a = cdr(a);
500 if (!car_legal(a)) return onevalue(cdrerror(a));
501 else a = cdr(a);
502 if (!car_legal(a)) return onevalue(cdrerror(a));
503 else a = cdr(a);
504 if (!car_legal(a)) return onevalue(cdrerror(a));
505 else return onevalue(cdr(a));
506 }
507
508 /*! fns [rplaca] \item[{\ttfamily rplaca} {\itshape expr}] \index{{\ttfamily rplaca} {\itshape expr}} ~\newline
509 * This is a destructive function in that it alters the data structure
510 * that it is given as its first argument by updating its {\ttfamily car}
511 * component. The result is the updated object. See {\ttfamily rplacd}
512 * for the corresponding function for updating the {\ttfamily cdr} component.
513 */
514
Lrplaca(LispObject,LispObject a,LispObject b)515 LispObject Lrplaca(LispObject, LispObject a, LispObject b)
516 { if (!consp(a)) return error(1, err_bad_rplac, a);
517 write_barrier(caraddr(a), b);
518 return onevalue(a);
519 }
520
521 /*! fns [rplacd] \item [{\ttfamily rplacd} {\itshape expr}] \index{{\ttfamily rplacd} {\itshape expr}} ~\newline
522 * See {\ttfamily rplaca}
523 */
524
Lrplacd(LispObject,LispObject a,LispObject b)525 LispObject Lrplacd(LispObject, LispObject a, LispObject b)
526 { if (!consp(a)) return error(1, err_bad_rplac, a);
527 write_barrier(cdraddr(a), b);
528 return onevalue(a);
529 }
530
Lsymbolp(LispObject env,LispObject a)531 LispObject Lsymbolp(LispObject env, LispObject a)
532 { return onevalue(Lispify_predicate(symbolp(a)));
533 }
534
Latom(LispObject env,LispObject a)535 LispObject Latom(LispObject env, LispObject a)
536 { return onevalue(Lispify_predicate(!consp(a)));
537 }
538
Lconsp(LispObject env,LispObject a)539 LispObject Lconsp(LispObject env, LispObject a)
540 { return onevalue(Lispify_predicate(consp(a)));
541 }
542
Lconstantp(LispObject env,LispObject a)543 LispObject Lconstantp(LispObject env, LispObject a)
544 // This version is as required for Standard Lisp - it is inadequate
545 // for Common Lisp.
546 {
547 // Standard Lisp requires that I report that "Function Pointers" are
548 // "constant" here. It is not at all clear that I have a way of
549 // doing that. I will go some way by ensuring that code-vectors are
550 // reported as constant.
551 return onevalue(Lispify_predicate(
552 a == nil || a == lisp_true ||
553 is_char(a) ||
554 is_number(a) ||
555 is_vector(a) ||
556 is_bps(a)));
557 }
558
Lidentity(LispObject,LispObject a)559 LispObject Lidentity(LispObject, LispObject a)
560 { return onevalue(a);
561 }
562
Llistp(LispObject env,LispObject a)563 LispObject Llistp(LispObject env, LispObject a)
564 { return onevalue(Lispify_predicate(is_cons(a)));
565 }
566
Lnumberp(LispObject env,LispObject a)567 LispObject Lnumberp(LispObject env, LispObject a)
568 { return onevalue(Lispify_predicate(is_number(a)));
569 }
570
Lintegerp(LispObject,LispObject a)571 LispObject Lintegerp(LispObject, LispObject a)
572 { return onevalue(integerp(a));
573 }
574
Leq_safe(LispObject env,LispObject a)575 LispObject Leq_safe(LispObject env, LispObject a)
576 {
577 // True if you can safely use EQ tests to check equality. Thus true for
578 // things that are represented in "immediate" form... and ALSO of nil
579 // and all other symbols.
580 return onevalue(symbolp(a) ||
581 is_fixnum(a) ||
582 is_sfloat(a) ||
583 is_odds(a) ? lisp_true : nil);
584 }
585
Lfixp(LispObject env,LispObject a)586 LispObject Lfixp(LispObject env, LispObject a)
587 {
588 #ifdef COMMON
589 return onevalue(is_fixnum(a) ? lisp_true : nil);
590 #else
591 // Standard Lisp defines fixp to say yes to bignums as well as
592 // fixnums. The code here is as in intergerp.
593 if (is_fixnum(a)) return onevalue(lisp_true);
594 else if (is_numbers(a))
595 { Header h = *reinterpret_cast<Header *>(reinterpret_cast<char *>
596 (a) - TAG_NUMBERS);
597 if (type_of_header(h) == TYPE_BIGNUM) return onevalue(lisp_true);
598 else return onevalue(nil);
599 }
600 else return onevalue(nil);
601 #endif
602 }
603
Lfloatp(LispObject env,LispObject p)604 LispObject Lfloatp(LispObject env, LispObject p)
605 { if (is_bfloat(p)) return onevalue(lisp_true);
606 else if (is_sfloat(p)) return onevalue(lisp_true);
607 else return onevalue(nil);
608 }
609
Lshort_floatp(LispObject env,LispObject p)610 static LispObject Lshort_floatp(LispObject env, LispObject p)
611 { if (is_sfloat(p) &&
612 (!SIXTY_FOUR_BIT ||
613 ((p & XTAG_FLOAT32) == 0))) return onevalue(lisp_true);
614 else return onevalue(nil);
615 }
616
Lsingle_floatp(LispObject env,LispObject p)617 static LispObject Lsingle_floatp(LispObject env, LispObject p)
618 { int tag = TAG_BITS & static_cast<int>(p);
619 if (SIXTY_FOUR_BIT &&
620 is_sfloat(p) &&
621 (p & XTAG_FLOAT32) != 0) return onevalue(lisp_true);
622 if (tag == TAG_BOXFLOAT &&
623 type_of_header(flthdr(p)) == TYPE_SINGLE_FLOAT)
624 return onevalue(lisp_true);
625 else return onevalue(nil);
626 }
627
Ldouble_floatp(LispObject env,LispObject p)628 static LispObject Ldouble_floatp(LispObject env, LispObject p)
629 { int tag = TAG_BITS & static_cast<int>(p);
630 if (tag == TAG_BOXFLOAT &&
631 type_of_header(flthdr(p)) == TYPE_DOUBLE_FLOAT)
632 return onevalue(lisp_true);
633 else return onevalue(nil);
634 }
635
Llong_floatp(LispObject env,LispObject p)636 static LispObject Llong_floatp(LispObject env, LispObject p)
637 { int tag = TAG_BITS & static_cast<int>(p);
638 if (tag == TAG_BOXFLOAT &&
639 type_of_header(flthdr(p)) == TYPE_LONG_FLOAT)
640 return onevalue(lisp_true);
641 else return onevalue(nil);
642 }
643
Lmantissa_bits(LispObject env,LispObject p)644 static LispObject Lmantissa_bits(LispObject env, LispObject p)
645 { if (Ldouble_floatp(env,
646 p) != nil) return onevalue(fixnum_of_int(53));
647 if (Lsingle_floatp(env, p) != nil) return onevalue(fixnum_of_int(24));
648 if (Lshort_floatp(env, p) != nil) return onevalue(fixnum_of_int(20));
649 if (Llong_floatp(env, p) != nil) return onevalue(fixnum_of_int(113));
650 return onevalue(nil);
651 }
652
Lrationalp(LispObject env,LispObject a)653 LispObject Lrationalp(LispObject env, LispObject a)
654 { return onevalue(
655 Lispify_predicate(
656 is_fixnum(a) ||
657 (is_numbers(a) &&
658 (is_bignum(a) || is_ratio(a)))));
659 }
660
Lcomplexp(LispObject env,LispObject a)661 LispObject Lcomplexp(LispObject env, LispObject a)
662 { return onevalue(Lispify_predicate(is_numbers(a) &&
663 is_complex(a)));
664 }
665
complex_stringp(LispObject a)666 bool complex_stringp(LispObject a)
667 // true if the arg is a string, but NOT a simple string. In general
668 // when this is true simplify_string() will then be called to do
669 // an adjustment.
670 { Header h;
671 LispObject w;
672 if (!is_vector(a)) return false;
673 h = vechdr(a);
674 if (type_of_header(h) != TYPE_ARRAY) return false;
675 // Note that the cheery Common Lisp Committee decided the abolish the
676 // separate type 'string-char, so the test here is maybe dubious...
677 else if (static_cast<LispObject>(elt(a,
678 0)) != string_char_sym) return false;
679 w = elt(a, 1);
680 if (!consp(w) || consp(cdr(w))) return false;
681 else return true;
682 }
683
Lwarn_about_protected_symbols(LispObject env,LispObject a)684 LispObject Lwarn_about_protected_symbols(LispObject env, LispObject a)
685 { LispObject retval = Lispify_predicate(
686 warn_about_protected_symbols);
687 warn_about_protected_symbols = (a != nil);
688 return onevalue(retval);
689 }
690
Lprotect_symbols(LispObject env,LispObject a)691 LispObject Lprotect_symbols(LispObject env, LispObject a)
692 { LispObject retval = Lispify_predicate(symbol_protect_flag);
693 symbol_protect_flag = (a != nil);
694 return onevalue(retval);
695 }
696
stringp(LispObject a)697 bool stringp(LispObject a)
698 // True if arg is a simple OR a general string
699 { Header h;
700 LispObject w;
701 if (!is_vector(a)) return false;
702 h = vechdr(a);
703 if (is_string_header(h)) return true;
704 else if (type_of_header(h) != TYPE_ARRAY) return false;
705 // Beware abolition of 'string-char
706 else if (static_cast<LispObject>(elt(a,
707 0)) != string_char_sym) return false;
708 w = elt(a, 1);
709 if (!consp(w) || consp(cdr(w))) return false;
710 else return true;
711 }
712
Lstringp(LispObject env,LispObject a)713 LispObject Lstringp(LispObject env, LispObject a)
714 // simple-string-p
715 { if (!(is_vector(a)) || !is_string(a)) return onevalue(nil);
716 else return onevalue(lisp_true);
717 }
718
719 // Common Lisp has "complicated strings" which may have fill pointers,
720 // indirection to their contents and basically be unnecessary generalisations
721 // of what one really uses.
722
Lc_stringp(LispObject env,LispObject a)723 static LispObject Lc_stringp(LispObject env, LispObject a)
724 { return onevalue(Lispify_predicate(stringp(a)));
725 }
726
Lhash_table_p(LispObject env,LispObject a)727 LispObject Lhash_table_p(LispObject env, LispObject a)
728 // hash-table-p
729 { if (!(is_vector(a)) || type_of_header(vechdr(a)) != TYPE_HASH)
730 return onevalue(nil);
731 else return onevalue(lisp_true);
732 }
733
Lsimple_bit_vector_p(LispObject env,LispObject a)734 static LispObject Lsimple_bit_vector_p(LispObject env,
735 LispObject a)
736 // simple-bit-vector-p
737 { if (!(is_vector(a))) return onevalue(nil);
738 else return onevalue(Lispify_predicate(is_bitvec_header(vechdr(a))));
739 }
740
Lsimple_vectorp(LispObject env,LispObject a)741 LispObject Lsimple_vectorp(LispObject env, LispObject a)
742 // simple-vector-p
743 { if (!(is_vector(a))) return onevalue(nil);
744 else return onevalue(Lispify_predicate(
745 type_of_header(vechdr(a))==TYPE_SIMPLE_VEC));
746 }
747
Lbpsp(LispObject env,LispObject a)748 LispObject Lbpsp(LispObject env, LispObject a)
749 { if (!(is_bps(a))) return onevalue(nil);
750 else return onevalue(lisp_true);
751 }
752
Lthreevectorp(LispObject env,LispObject a)753 LispObject Lthreevectorp(LispObject env, LispObject a)
754 // This is useful for REDUCE - it checks if something is a vector
755 // of size 3!
756 { if (!(is_vector(a))) return onevalue(nil);
757 // The "pack_hdrlength(4*CELL/4)" is because I want a vector
758 // with 1 cell of header and 3 of data. So the 4*CELL deals with with that
759 // but gives a size expressed in bytes. The "/4" then converts that to a
760 // count expressed in 32-bit words which is what pach_hdrlength requires.
761 return onevalue(Lispify_predicate(
762 vechdr(a) == (TAG_HDR_IMMED + TYPE_SIMPLE_VEC +
763 pack_hdrlength(4*CELL/4))));
764 }
765
Larrayp(LispObject env,LispObject a)766 static LispObject Larrayp(LispObject env, LispObject a)
767 { Header h;
768 if (!(is_vector(a))) return onevalue(nil);
769 h = vechdr(a);
770 // I could consider accepting TYPE_VEC16 and TYPE_VEC32 etc here...
771 //
772 // Note that the suggestion that a string is an array is a real problem
773 // in a world that believes in Unicode...
774 if (type_of_header(h)==TYPE_ARRAY ||
775 is_string_header(h) ||
776 type_of_header(h)==TYPE_SIMPLE_VEC ||
777 is_bitvec_header(h)) return onevalue(lisp_true);
778 else return onevalue(nil);
779 }
780
Lcomplex_arrayp(LispObject env,LispObject a)781 static LispObject Lcomplex_arrayp(LispObject env, LispObject a)
782 { if (!(is_vector(a))) return onevalue(nil);
783 else return onevalue(Lispify_predicate(
784 type_of_header(vechdr(a))==TYPE_ARRAY));
785 }
786
Lconvert_to_array(LispObject env,LispObject a)787 static LispObject Lconvert_to_array(LispObject env, LispObject a)
788 { if (!(is_basic_vector(a))) return onevalue(nil);
789 setvechdr(a, TYPE_ARRAY + (vechdr(a) & ~header_mask));
790 return onevalue(a);
791 }
792
Lstructp(LispObject env,LispObject a)793 static LispObject Lstructp(LispObject env, LispObject a)
794 // structp
795 { if (!(is_basic_vector(a))) return onevalue(nil);
796 else return onevalue(Lispify_predicate(
797 type_of_header(vechdr(a))==TYPE_STRUCTURE));
798 }
799
Lconvert_to_struct(LispObject env,LispObject a)800 static LispObject Lconvert_to_struct(LispObject env, LispObject a)
801 { if (!(is_basic_vector(a))) return onevalue(nil);
802 setvechdr(a, TYPE_STRUCTURE + (vechdr(a) & ~header_mask));
803 return onevalue(a);
804 }
805
Llist_2(LispObject env,LispObject a,LispObject b)806 LispObject Llist_2(LispObject env, LispObject a, LispObject b)
807 { a = list2(a, b);
808 return onevalue(a);
809 }
810
Lmkquote(LispObject env,LispObject a)811 LispObject Lmkquote(LispObject env, LispObject a)
812 { a = list2(quote_symbol, a);
813 return onevalue(a);
814 }
815
Llist_2star(LispObject env,LispObject a,LispObject b,LispObject c)816 LispObject Llist_2star(LispObject env, LispObject a, LispObject b,
817 LispObject c)
818 { return onevalue(list2star(a,b,c));
819 }
820
Llist_2starrev(LispObject env,LispObject a,LispObject b,LispObject c)821 LispObject Llist_2starrev(LispObject env, LispObject a, LispObject b,
822 LispObject c)
823 { return onevalue(list2starrev(a,b,c));
824 }
825
Lacons(LispObject env,LispObject a,LispObject b,LispObject c)826 LispObject Lacons(LispObject env, LispObject a, LispObject b,
827 LispObject c)
828 { return onevalue(acons(a, b, c));
829 }
830
Llist_3(LispObject env,LispObject a,LispObject b,LispObject c)831 LispObject Llist_3(LispObject env, LispObject a, LispObject b,
832 LispObject c)
833 { return onevalue(list3(a, b, c));
834 }
835
Llist_3rev(LispObject env,LispObject a,LispObject b,LispObject c)836 LispObject Llist_3rev(LispObject env, LispObject a, LispObject b,
837 LispObject c)
838 { return onevalue(list3rev(a, b, c));
839 }
840
Llist_3star(LispObject,LispObject a,LispObject b,LispObject c,LispObject a4up)841 LispObject Llist_3star(LispObject, LispObject a, LispObject b,
842 LispObject c, LispObject a4up)
843 { if (cdr(a4up) != nil) return aerror("too many arrguments for list3*");
844 LispObject d = car(a4up);
845 return onevalue(list3star(a,b,c,d));
846 }
847
Llist_4(LispObject env,LispObject a,LispObject b,LispObject c,LispObject a4up)848 LispObject Llist_4(LispObject env, LispObject a, LispObject b,
849 LispObject c, LispObject a4up)
850 { if (cdr(a4up) != nil) return aerror("too many arguments for list4");
851 LispObject d = car(a4up);
852 return onevalue(list4(a,b,c,d));
853 }
854
855
Llist_4up(LispObject env,LispObject a,LispObject b,LispObject c,LispObject a4up)856 LispObject Llist_4up(LispObject env, LispObject a, LispObject b,
857 LispObject c, LispObject a4up)
858 { return onevalue(list3star(a, b, c, a4up));
859 }
860
Lliststar_4up(LispObject env,LispObject a,LispObject b,LispObject c,LispObject a4up)861 LispObject Lliststar_4up(LispObject env, LispObject a, LispObject b,
862 LispObject c, LispObject a4up)
863 { LispObject r= nil, w;
864 while (a4up != nil)
865 { w = cdr(a4up);
866 write_barrier(cdraddr(a4up), r);
867 r = a4up;
868 a4up = w;
869 }
870 a4up = car(r);
871 r = cdr(r);
872 while (r != nil)
873 { w = cdr(r);
874 write_barrier(cdraddr(r), a4up);
875 a4up = r;
876 r = w;
877 }
878 return onevalue(list3star(a, b, c, a4up));
879 }
880
Lpair(LispObject env,LispObject a,LispObject b)881 LispObject Lpair(LispObject env, LispObject a, LispObject b)
882 { LispObject r = nil;
883 while (consp(a) && consp(b))
884 { Save save(a, b);
885 r = acons(car(a), car(b), r);
886 save.restore(a, b);
887 a = cdr(a);
888 b = cdr(b);
889 }
890 a = nil;
891 while (r != nil)
892 { b = cdr(r);
893 write_barrier(cdraddr(r), a);
894 a = r;
895 r = b;
896 }
897 return onevalue(a);
898 }
899
900
membercount(LispObject a,LispObject b)901 static size_t membercount(LispObject a, LispObject b)
902 // Counts how many times a is a member of the list b
903 { size_t r = 0;
904 if (is_symbol(a) || is_fixnum(a))
905 { while (consp(b))
906 { if (a == car(b)) r++;
907 b = cdr(b);
908 }
909 return r;
910 }
911 while (consp(b))
912 { LispObject cb = car(b);
913 if (equal(a, cb)) r++;
914 if (exceptionPending()) break;
915 b = cdr(b);
916 }
917 return r;
918 }
919
920 // INTERSECTION(A,B)
921 // The result will have its items in the order that they occur in A.
922 // If lists A and B contain duplicate items these will appear in the
923 // output if and only if the items involved are duplicated in both
924 // input lists.
925
Lintersect(LispObject env,LispObject a,LispObject b)926 LispObject Lintersect(LispObject env, LispObject a, LispObject b)
927 { LispObject w;
928 RealSave save(a, b, nil);
929 LispObject &aa = save.val(1);
930 LispObject &bb = save.val(2);
931 LispObject &rr = save.val(3);
932 while (consp(aa))
933 { w = Lmember(nil, car(aa), bb);
934 errexit();
935 // Here I ignore any item in a that is not also in b
936 if (w != nil)
937 { size_t n1 = membercount(car(aa), rr);
938 errexit();
939 // Here I want to arrange that items only appear in the result list multiple
940 // times if they occur multiple times in BOTH the input lists.
941 if (n1 != 0)
942 { size_t n2 = membercount(car(aa), bb);
943 if (n2 > n1) n1 = 0;
944 }
945 if (n1 == 0)
946 { rr = cons(car(aa), rr);
947 errexit();
948 }
949 }
950 aa = cdr(aa);
951 }
952 aa = nil;
953 while (consp(rr))
954 { bb = rr;
955 rr = cdr(rr);
956 write_barrier(cdraddr(bb), aa);
957 aa = bb;
958 }
959 return onevalue(aa);
960 }
961
962 // If you have two lists where all items in both lists are just symbols
963 // then I can form the intersection in deterministic linear time using a
964 // tag bit in symbol headers.
965
966 class tidy_intersect
967 { LispObject *b;
968 public:
tidy_intersect(LispObject * bb)969 tidy_intersect(LispObject *bb)
970 { b = bb;
971 }
~tidy_intersect()972 ~tidy_intersect()
973 { LispObject w = *b;
974 while (consp(w))
975 {
976 #ifdef DEBUG
977 LispObject ss = car(w);
978 if (!is_symbol(ss)) my_abort("Not a symbol in tidy_intersection");
979 #endif
980 setheader(car(w),
981 qheader(car(w)) & ~static_cast<Header>(SYM_TAGGED));
982 w = cdr(w);
983 }
984 }
985 };
986
Lintersect_symlist(LispObject env,LispObject a,LispObject b)987 LispObject Lintersect_symlist(LispObject env, LispObject a,
988 LispObject b)
989 { LispObject r = nil, w;
990 // First tag all the symbols in the list b. Any items that are not
991 // symbols just get ignored.
992 for (w = b; consp(w); w = cdr(w))
993 { LispObject x = car(w);
994 if (is_symbol(x)) setheader(x, qheader(x) | SYM_TAGGED);
995 }
996 // Now for each item in (a) push it onto a result list (r) if it a
997 // symbol that is tagged, i.e. if it was present in b.
998 RealSave save(b);
999 // LispObject &bb = save.val(1);
1000 { tidy_intersect tidy(&stack[0]);
1001 while (consp(a))
1002 { LispObject x = car(a);
1003 if (is_symbol(x) && (qheader(x) & SYM_TAGGED))
1004 { Save save1(a);
1005 r = cons(x, r);
1006 save1.restore(a);
1007 }
1008 a = cdr(a);
1009 }
1010 }
1011 // The above built up the result in reversed order, so I fix that here.
1012 a = nil;
1013 while (consp(r))
1014 { b = r;
1015 r = cdr(r);
1016 write_barrier(cdraddr(b), a);
1017 a = b;
1018 }
1019 return onevalue(a);
1020 }
1021
1022 // UNION(A, B)
1023 // This works by consing onto the front of B each element of A that
1024 // is not already in B. Thus items in A (but not already in B) get
1025 // added in reversed order. Duplicates in B remain there, and but
1026 // duplicates in A are dropped.
Lunion(LispObject env,LispObject a,LispObject b)1027 LispObject Lunion(LispObject env, LispObject a, LispObject b)
1028 { while (consp(a))
1029 { LispObject c;
1030 { Save save(a, b);
1031 c = Lmember(nil, car(a), b);
1032 errexit();
1033 save.restore(a, b);
1034 }
1035 if (c == nil)
1036 { Save save(a);
1037 b = cons(car(a), b);
1038 errexit();
1039 save.restore(a);
1040 }
1041 a = cdr(a);
1042 }
1043 return onevalue(b);
1044 }
1045
1046 // union-symlist expects both arguments to be lists of symbols, and on that
1047 // basis can run in linear time.
1048
1049 class tidy_union
1050 { LispObject *b;
1051 public:
tidy_union(LispObject * bb)1052 tidy_union(LispObject *bb)
1053 { b = bb;
1054 }
~tidy_union()1055 ~tidy_union()
1056 { LispObject w = *b;
1057 while (consp(w))
1058 {
1059 #ifdef DEBUG
1060 LispObject ss = car(w);
1061 if (!is_symbol(ss)) my_abort("Not a symbol in tidy_union");
1062 #endif
1063 setheader(car(w),
1064 qheader(car(w)) & ~static_cast<Header>(SYM_TAGGED));
1065 w = cdr(w);
1066 }
1067 }
1068 };
1069
Lunion_symlist(LispObject env,LispObject a,LispObject b)1070 LispObject Lunion_symlist(LispObject env, LispObject a, LispObject b)
1071 { LispObject r = nil, w;
1072 // First tag all the symbols in the list b. Any items that are not
1073 // symbols just ignored.
1074 for (w = b; consp(w); w = cdr(w))
1075 { LispObject x = car(w);
1076 if (is_symbol(x)) setheader(x, qheader(x) | SYM_TAGGED);
1077 }
1078 // Now for each item in a push it onto a result list (r) if it a
1079 // symbol that is NOT tagged, i.e. if it was not present in b.
1080 RealSave save(b);
1081 // LispObject bb = save.val(1);
1082 // I want to be able to traverse the list (b) at the end of this
1083 // clearing tag bits. And this must be GC safe, so I save b on the
1084 // stack. The destructor for the tidy_union must then access this and
1085 // do its work, but its private data must be an address of the stack
1086 // item not a LispObject (because the GC will not look at its internal
1087 // state. I pass a very explicit stack address here because trying to be
1088 // more abstract about things pushed too hard against edges of my C++
1089 // understanding!
1090 { tidy_union tidy(&stack[0]);
1091 while (consp(a))
1092 { LispObject x = car(a);
1093 if (is_symbol(x) && (qheader(x) & SYM_TAGGED) == 0)
1094 { Save save1(a);
1095 r = cons(x, r);
1096 errexit();
1097 save1.restore(a);
1098 }
1099 a = cdr(a);
1100 }
1101 }
1102 // What I now have is a reversed list of new items in r, and the existing
1103 // list b. So reverse r onto the front of b.
1104 save.restore(b);
1105 while (consp(r))
1106 { a = r;
1107 r = cdr(r);
1108 write_barrier(cdraddr(a), b);
1109 b = a;
1110 }
1111 return onevalue(b);
1112 }
1113
1114
Lenable_errorset(LispObject env,LispObject a,LispObject b)1115 LispObject Lenable_errorset(LispObject env, LispObject a,
1116 LispObject b)
1117 { LispObject r = cons(fixnum_of_int(errorset_min),
1118 fixnum_of_int(errorset_max));
1119 if (a == nil || a == fixnum_of_int(0)) errorset_min = 0;
1120 else if (a == fixnum_of_int(1)) errorset_min = 1;
1121 else if (a == fixnum_of_int(2)) errorset_min = 2;
1122 else if (a == fixnum_of_int(3) || a == lisp_true) errorset_min = 3;
1123 if (b == nil || b == fixnum_of_int(0)) errorset_max = 0;
1124 else if (b == fixnum_of_int(1)) errorset_max = 1;
1125 else if (b == fixnum_of_int(2)) errorset_max = 2;
1126 else if (b == fixnum_of_int(3) || b == lisp_true) errorset_max = 3;
1127 // I increase the max to be at least as high as the indicated min
1128 if (errorset_min > errorset_max) errorset_max = errorset_min;
1129 // I also arrange that the current state is within the specified range
1130 switch (errorset_min)
1131 { case 0: break;
1132 case 1: miscflags |= HEADLINE_FLAG;
1133 break;
1134 case 2: miscflags |= HEADLINE_FLAG | FNAME_FLAG;
1135 break;
1136 default: // case 3:
1137 miscflags |= BACKTRACE_MSG_BITS;
1138 break;
1139 }
1140 switch (errorset_max)
1141 { case 0: miscflags &= ~BACKTRACE_MSG_BITS;
1142 break;
1143 case 1: miscflags &= ~(FNAME_FLAG | ARGS_FLAG);
1144 break;
1145 case 2: miscflags &= ~ARGS_FLAG;
1146 break;
1147 default: // case 3:
1148 break;
1149 }
1150 return r;
1151 }
1152
Lenable_backtrace(LispObject env,LispObject a)1153 LispObject Lenable_backtrace(LispObject env, LispObject a)
1154 {
1155 // (enable-backtrace nil) errors silent unless ALWAYS_NOISY set
1156 // (enable-backtrace 0) ditto
1157 // (enable-backtrace 1) show 1-line messaqe on error
1158 // (enable-backtrace 2) show function names but not args in B/T
1159 // (enable-backtrace 3) show functions and args
1160 // (enable-backtrace t) ditto
1161 // otherwise just return previous setting
1162 int32_t n = miscflags;
1163 miscflags &= ~BACKTRACE_MSG_BITS;
1164 if (a == nil || a == fixnum_of_int(0)) /* nothing */;
1165 else if (a == fixnum_of_int(1))
1166 miscflags |= HEADLINE_FLAG;
1167 else if (a == fixnum_of_int(2))
1168 miscflags |= HEADLINE_FLAG | FNAME_FLAG;
1169 else if (a == lisp_true || a == fixnum_of_int(3))
1170 miscflags |= BACKTRACE_MSG_BITS;
1171 else miscflags = n; // Otherwise have no effect
1172 return onevalue(fixnum_of_int(miscflags & ARGS_FLAG ? 3 :
1173 miscflags & FNAME_FLAG ? 2 :
1174 miscflags & HEADLINE_FLAG ? 1 :
1175 0));
1176 }
1177
Lunwind(LispObject env)1178 LispObject Lunwind(LispObject env)
1179 { exit_reason = (miscflags & ARGS_FLAG) ? UNWIND_ERROR :
1180 (miscflags & FNAME_FLAG) ? UNWIND_FNAME :
1181 UNWIND_UNWIND;
1182 exit_count = 0;
1183 exit_tag = nil;
1184 THROW(LispError);
1185 }
1186
1187 // If the variable *break-function* has as its value a symbol, and that
1188 // symbol names a function, then the function concerned will be called
1189 // with one argument after the headline for the diagnostic. When it returns
1190 // the system will unwind in the usual manner.
1191
error_N(LispObject args)1192 LispObject error_N(LispObject args)
1193 { LispObject w;
1194 errexit(); // because constructing argument may have failed
1195 errors_now++;
1196 if (errors_limit >= 0 && errors_now > errors_limit)
1197 return resource_exceeded();
1198 #ifdef COMMON
1199 { Save save(args);
1200 LispObject a1 = car(args);
1201 args = cdr(args);
1202 // I will use FORMAT to handle error messages provided the first arg
1203 // to error had been a string and also provided (for bootstrapping) that
1204 // the function FORMAT seems to be defined.
1205 if (qfn1(format_symbol) == undefined_1 ||
1206 !stringp(a1)) loop_print_error(cons(a1, args));
1207 else Lapply_3(nil, format_symbol, qvalue(error_output), a1, args);
1208 err_printf("\n");
1209 save.restore(args);
1210 qvalue(emsg_star) = args; // "Error message" in CL world
1211 exit_value = fixnum_of_int(0); // "Error number" in CL world
1212 }
1213 #else
1214 if (miscflags & HEADLINE_FLAG)
1215 { RealSave save(args, cdr(args));
1216 err_printf("\n+++ error: ");
1217 errexit();
1218 loop_print_error(save.val(1));
1219 errexit();
1220 while (is_cons(save.val(2)))
1221 { err_printf(" ");
1222 errexit();
1223 loop_print_error(car(save.val(2)));
1224 errexit();
1225 save.val(2) = cdr(save.val(2));
1226 }
1227 err_printf("\n");
1228 errexit();
1229 args = save.val(1);
1230 }
1231 // So if you go (error n A B C) the output should be
1232 // +++ error n A B C
1233 // and emsg!* gets set to A, while an errorset that catches this will get n.
1234 LispObject msg = nil;
1235 if (is_cons(cdr(args))) msg = car(cdr(args));
1236 setvalue(emsg_star, msg); // "Error message" in SL world
1237 exit_value = car(args); // "Error number" in SL world
1238 #endif
1239 if ((w = qvalue(break_function)) != nil &&
1240 symbolp(w) &&
1241 qfn1(w) != undefined_1)
1242 { (*qfn1(w))(qenv(w), qvalue(emsg_star));
1243 }
1244 exit_reason = (miscflags & ARGS_FLAG) ? UNWIND_ERROR :
1245 (miscflags & FNAME_FLAG) ? UNWIND_FNAME :
1246 UNWIND_UNWIND;
1247 exit_count = 0;
1248 exit_tag = nil;
1249 THROW(LispError);
1250 }
1251
Lerror_1(LispObject env,LispObject a1)1252 LispObject Lerror_1(LispObject env, LispObject a1)
1253 { return error_N(ncons(a1));
1254 }
1255
Lerror_2(LispObject env,LispObject a1,LispObject a2)1256 LispObject Lerror_2(LispObject env, LispObject a1,
1257 LispObject a2)
1258 { return error_N(list2(a1, a2));
1259 }
1260
Lerror_3(LispObject env,LispObject a1,LispObject a2,LispObject a3)1261 LispObject Lerror_3(LispObject env, LispObject a1,
1262 LispObject a2, LispObject a3)
1263 { return error_N(list3(a1, a2, a3));
1264 }
1265
Lerror_4up(LispObject env,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)1266 LispObject Lerror_4up(LispObject env, LispObject a1,
1267 LispObject a2,
1268 LispObject a3, LispObject a4up)
1269 { return error_N(list3star(a1, a2, a3, a4up));
1270 }
1271
Lerror_0(LispObject env)1272 LispObject Lerror_0(LispObject env)
1273 {
1274 // Silently provoked error - unwind to surrounding errorset level. Note that
1275 // this will NEVER enter a user-provided break loop...
1276 // Also note that (enable-errorset) can set a lower limit to noise levels
1277 // that can result in the error here NOT being silent!
1278 errors_now++;
1279 if (errors_limit >= 0 && errors_now > errors_limit)
1280 resource_exceeded();
1281 switch (errorset_min)
1282 { case 0: miscflags &= ~BACKTRACE_MSG_BITS;
1283 break;
1284 case 1: miscflags &= ~(FNAME_FLAG | ARGS_FLAG);
1285 break;
1286 case 2: miscflags &= ~ARGS_FLAG;
1287 default:break;
1288 }
1289 exit_reason = (miscflags & ARGS_FLAG) ? UNWIND_ERROR :
1290 (miscflags & FNAME_FLAG) ? UNWIND_FNAME :
1291 UNWIND_UNWIND;
1292 exit_value = exit_tag = nil;
1293 exit_count = 0;
1294 THROW(LispError);
1295 }
1296
Lmake_special(LispObject,LispObject a)1297 LispObject Lmake_special(LispObject, LispObject a)
1298 { if (!symbolp(a)) return aerror1("make-special", a);
1299 if ((qheader(a) & SYM_GLOBAL_VAR) != 0)
1300 return aerror1(
1301 "Variable is global or keyword so can not become fluid", a);
1302 setheader(a, qheader(a) | SYM_SPECIAL_VAR);
1303 return onevalue(a);
1304 }
1305
Lmake_global(LispObject,LispObject a)1306 LispObject Lmake_global(LispObject, LispObject a)
1307 { if (!symbolp(a)) return aerror("make-global");
1308 if ((qheader(a) & SYM_SPECIAL_VAR) != 0)
1309 return aerror1(
1310 "Variable is fluid or keyword so can not become global", a);
1311 setheader(a, qheader(a) | SYM_GLOBAL_VAR);
1312 return onevalue(a);
1313 }
1314
Lmake_keyword(LispObject,LispObject a)1315 LispObject Lmake_keyword(LispObject, LispObject a)
1316 { if (!symbolp(a)) return aerror("make-keyword");
1317 if ((qheader(a) & (SYM_GLOBAL_VAR | SYM_SPECIAL_VAR)) != 0)
1318 return aerror1(
1319 "Variable is fluid or global so can not become keyword", a);
1320 setheader(a, qheader(a) | (SYM_SPECIAL_VAR | SYM_GLOBAL_VAR));
1321 setvalue(a, a); // value is itself.
1322 return onevalue(a);
1323 }
1324
1325 // All the "unmake" functions leave the symbol as a normal one that is
1326 // neither fluid, global nor keyword.
1327
Lunmake_special(LispObject env,LispObject a)1328 LispObject Lunmake_special(LispObject env, LispObject a)
1329 { if (!symbolp(a)) return onevalue(nil);
1330 setheader(a, qheader(a) & ~(SYM_SPECIAL_VAR | SYM_GLOBAL_VAR));
1331 return onevalue(a);
1332 }
1333
Lunmake_global(LispObject env,LispObject a)1334 LispObject Lunmake_global(LispObject env, LispObject a)
1335 { if (!symbolp(a)) return onevalue(nil);
1336 setheader(a, qheader(a) & ~(SYM_SPECIAL_VAR | SYM_GLOBAL_VAR));
1337 return onevalue(a);
1338 }
1339
Lunmake_keyword(LispObject env,LispObject a)1340 LispObject Lunmake_keyword(LispObject env, LispObject a)
1341 { if (!symbolp(a)) return onevalue(nil);
1342 setheader(a, qheader(a) & ~(SYM_SPECIAL_VAR | SYM_GLOBAL_VAR));
1343 return onevalue(a);
1344 }
1345
Lsymbol_specialp(LispObject env,LispObject a)1346 LispObject Lsymbol_specialp(LispObject env, LispObject a)
1347 { if (!symbolp(a)) return onevalue(nil);
1348 else if ((qheader(a) & (SYM_SPECIAL_VAR | SYM_GLOBAL_VAR)) ==
1349 SYM_SPECIAL_VAR) return onevalue(lisp_true);
1350 else return onevalue(nil);
1351 }
1352
Lsymbol_globalp(LispObject env,LispObject a)1353 LispObject Lsymbol_globalp(LispObject env, LispObject a)
1354 { if (!symbolp(a)) return onevalue(nil);
1355 else if ((qheader(a) & (SYM_SPECIAL_VAR | SYM_GLOBAL_VAR)) ==
1356 SYM_GLOBAL_VAR) return onevalue(lisp_true);
1357 else return onevalue(nil);
1358 }
1359
Lsymbol_keywordp(LispObject env,LispObject a)1360 LispObject Lsymbol_keywordp(LispObject env, LispObject a)
1361 { if (!symbolp(a)) return onevalue(nil);
1362 else if ((qheader(a) & (SYM_SPECIAL_VAR | SYM_GLOBAL_VAR)) ==
1363 (SYM_SPECIAL_VAR | SYM_GLOBAL_VAR))
1364 return onevalue(lisp_true);
1365 else return onevalue(nil);
1366 }
1367
Lboundp(LispObject env,LispObject a)1368 LispObject Lboundp(LispObject env, LispObject a)
1369 { if (!symbolp(a)) return onevalue(nil);
1370 // In COMMON Lisp it seems that this is intended to just check if the
1371 // value cell in a shallow-bound implementation contains some marker value
1372 // that stands for "junk". In Standard Lisp mode I deem that variables
1373 // that have not been declared fluid are unbound. Seems to me like a
1374 // classical mix-up between the concept of binding and of having some
1375 // particular value... Oh well.
1376 //
1377 // (September 2010) I just changed that so that a name that is not fluid
1378 // but that has been given a value (using SET or SETQ I expect) is counted
1379 // as "bound". This probably matches what PSL does and this function is
1380 // also probably used by few enough people that this will not lead to
1381 // too many bugs even though it is an incompatible change in behavior.
1382 #if 0
1383 else if ((qheader(a) & (SYM_SPECIAL_VAR|SYM_GLOBAL_VAR)) == 0)
1384 return onevalue(nil);
1385 #endif
1386 else if (qvalue(a) == unset_var) return onevalue(nil); // no value yet
1387 else return onevalue(lisp_true);
1388 }
1389
Lsymbol_value(LispObject,LispObject a)1390 LispObject Lsymbol_value(LispObject, LispObject a)
1391 { if (!symbolp(a)) return onevalue(a);
1392 else return onevalue(qvalue(a));
1393 }
1394
Lset(LispObject env,LispObject a,LispObject b)1395 LispObject Lset(LispObject env, LispObject a, LispObject b)
1396 { if (!symbolp(a) || a == nil || a == lisp_true) return aerror("set");
1397 setvalue(a, b);
1398 return onevalue(b);
1399 }
1400
Lmakeunbound(LispObject env,LispObject a)1401 LispObject Lmakeunbound(LispObject env, LispObject a)
1402 { if (!symbolp(a) || a == nil ||
1403 a == lisp_true) return aerror("makeunbound");
1404 setvalue(a, unset_var);
1405 return onevalue(a);
1406 }
1407
Lsymbol_function(LispObject env,LispObject a)1408 LispObject Lsymbol_function(LispObject env, LispObject a)
1409 { no_args *f0;
1410 one_arg *f1;
1411 two_args *f2;
1412 three_args *f3;
1413 fourup_args *f4up;
1414 if (!symbolp(a)) return onevalue(nil);
1415 f0 = qfn0(a);
1416 f1 = qfn1(a);
1417 f2 = qfn2(a);
1418 f3 = qfn3(a);
1419 f4up = qfn4up(a);
1420 if ((qheader(a) & (SYM_SPECIAL_FORM | SYM_MACRO)) != 0 ||
1421 (f0 == undefined_0 && f1 == undefined_1 && f2 == undefined_2 &&
1422 f3 == undefined_3 && f4up == undefined_4up)) return onevalue(nil);
1423 else if (f0 == interpreted_0 ||
1424 f1 == interpreted_1 ||
1425 f2 == interpreted_2 ||
1426 f3 == interpreted_3 ||
1427 f4up == interpreted_4up)
1428 return onevalue(cons(lambda, qenv(a)));
1429 else if (f0 == funarged_0 ||
1430 f1 == funarged_1 ||
1431 f2 == funarged_2 ||
1432 f3 == funarged_3 ||
1433 f4up == funarged_4up)
1434 return onevalue(cons(funarg, qenv(a)));
1435 else
1436 { LispObject b = get(a, work_symbol, nil);
1437 // If I have already manufactured a code pointer for this function I
1438 // can find it on the property list - in that case I will re-use it.
1439 while (b != nil)
1440 { LispObject c = car(b);
1441 if ((qheader(c) & (SYM_C_DEF | SYM_CODEPTR)) ==
1442 (SYM_CODEPTR | (qheader(a) & SYM_C_DEF)))
1443 return onevalue(c);
1444 b = cdr(b);
1445 }
1446 { Save save(a);
1447 // To carry a code-pointer I manufacture a sort of gensym, flagging
1448 // it in its header as a "code pointer object" and sticking the required
1449 // definition in with it. I need to link this to the originating
1450 // definition in some cases to allow for preserve/restart problems wrt
1451 // the initialisation of function addresses that refer to C code.
1452 // I make the carrier using GENSYM1, but need to clear the gensym flag bit
1453 // to show I have a regular name for the object, and that I will not need
1454 // to append a serial number later on. In Common Lisp mode I let the name
1455 // of the gensym be just the name of the function, while in Standard Lisp
1456 // mode I will append a numeric suffix. I do this because in Common Lisp
1457 // mode the thing will print as (say) #:apply which is visibly different
1458 // from the name 'apply of the base function, while in Standard Lisp a name
1459 // like apply775 is needed to make the distinction (easily) visible.
1460 get_pname(a); // to do with unprinted gensyms.
1461 errexit();
1462 #ifdef COMMON
1463 b = Lgensym2(nil, a);
1464 #else
1465 b = Lgensym0(nil, a, "#code");
1466 #endif
1467 errexit();
1468 save.restore(a);
1469 }
1470 qfn0(b) = qfn0(a);
1471 qfn1(b) = qfn1(a);
1472 qfn2(b) = qfn2(a);
1473 qfn3(b) = qfn3(a);
1474 qfn4up(b) = qfn4up(a);
1475 setenv(b, qenv(a));
1476 #ifdef COMMON
1477 // in Common Lisp mode gensyms that are "unprinted" are not special
1478 setheader(b, qheader(b) ^ (SYM_ANY_GENSYM | SYM_CODEPTR));
1479 #else
1480 setheader(b, qheader(b) ^ (SYM_UNPRINTED_GENSYM | SYM_ANY_GENSYM |
1481 SYM_CODEPTR));
1482 #endif
1483 if ((qheader(a) & SYM_C_DEF) != 0)
1484 { LispObject c, w;
1485 c = get(a, unset_var, nil);
1486 if (c == nil) c = a;
1487 { RealSave save(a, b);
1488 { RealSave save1(c);
1489 setheader(b, qheader(b) | SYM_C_DEF);
1490 putprop(b, unset_var, c);
1491 errexit();
1492 c = save.val(2);
1493 w = get(c, work_symbol, nil);
1494 errexit();
1495 w = cons(b, w);
1496 errexit();
1497 save1.restore(c);
1498 }
1499 putprop(c, work_symbol, w);
1500 errexit();
1501 save.restore(a, b);
1502 }
1503 }
1504 return onevalue(b);
1505 }
1506 }
1507
Lspecial_form_p(LispObject env,LispObject a)1508 LispObject Lspecial_form_p(LispObject env, LispObject a)
1509 { if (!symbolp(a)) return onevalue(nil);
1510 else if ((qheader(a) & SYM_SPECIAL_FORM) != 0) return onevalue(
1511 lisp_true);
1512 else return onevalue(nil);
1513 }
1514
Lcodep(LispObject env,LispObject a)1515 LispObject Lcodep(LispObject env, LispObject a)
1516 // This responds TRUE for the special pseudo-symbols that are used to
1517 // carry compiled code objects. It returns NIL on the symbols that
1518 // are normally used by the user.
1519 { if (!symbolp(a)) return onevalue(nil);
1520 if ((qheader(a) & (SYM_CODEPTR | SYM_C_DEF)) == SYM_CODEPTR)
1521 return onevalue(lisp_true);
1522 else return onevalue(nil);
1523 }
1524
get_basic_vector_init(size_t n,LispObject k)1525 LispObject get_basic_vector_init(size_t n, LispObject k)
1526 { LispObject p;
1527 { Save save(k);
1528 p = get_basic_vector(TAG_VECTOR, TYPE_SIMPLE_VEC, n);
1529 errexit();
1530 save.restore(k);
1531 }
1532 n = n/CELL - 1;
1533 for (size_t i=0; i<n; i++)
1534 basic_elt(p, i) = k;
1535 return p;
1536 }
1537
1538 // I make big vectors out of chunks each of which are vectors using
1539 // (up to) a megabyte.
1540 // Well there is a delicacy in that if one of that size is created on a
1541 // 32 bit system and dumped, and the image is then reloaded on a 64
1542 // bit system then the vector will consume around 2 Mbytes. I do not
1543 // believe that this can cause trouble.
1544 // I can have two levels of structure, and by the time the index level
1545 // is at maximum size (128K entries on a 64-bit system) size I will have
1546 // a table with 128K*128K = 16G slots in it and occupying 128 Gbytes.
1547 // At present (2018) I view the limits there are such that they will
1548 // not embarass me for some while. My belief is that allocating space in
1549 // chunks like this is going to be more friendly as regards memory
1550 // fragmentation than just using huge contiguous blocks.
1551
1552 //#define LOG2_VECTOR_CHUNK_BYTES 20 // in externs.h ...
1553 //#define VECTOR_CHUNK_BYTES ((size_t)(1<<LOG2_VECTOR_CHUNK_BYTES))
1554
1555 // I use zero to mark entries here that are not in use. As far as a
1556 // LispObject is concerned that is a pointer to a CONS cell but at
1557 // address zero, which should not arise. And anyway I am only going
1558 // to put references to vectors here and this array will be cleared by the
1559 // garbage collector rather than being scanned. Every vector put in
1560 // here should have tag TAG_VECTOR and type TYPE_SIMPLE_VEC
1561
1562 LispObject free_vectors[LOG2_VECTOR_CHUNK_BYTES+1] = {0};
1563
1564 // This will recover a saved vector if one is available. Its argument is
1565 // the size of the vector including its header word, but as far as powers
1566 // of 2 go I look at the size of the data part only.
1567
gvector(int tag,int type,size_t size)1568 static LispObject gvector(int tag, int type, size_t size)
1569 { STACK_SANITY;
1570 // I will never let odd sized vectors participate in this recycling
1571 // process.
1572 if (size%CELL != 0) return get_basic_vector(tag, type, size);
1573 size_t n = size/CELL - 1; // size in words of data part in cells.
1574 if (is_power_of_two(n)) // special if size is a power of 2.
1575 { int i = intlog2(n); // identify what power of 2 we have.
1576 LispObject r;
1577 if (i <= LOG2_VECTOR_CHUNK_BYTES &&
1578 (r = free_vectors[i]) != 0)
1579 { free_vectors[i] = basic_elt(r, 0);
1580 basic_elt(r, 0) = nil; // Just to be tidy!
1581 // reset type field
1582 setvechdr(r, type + (size << (Tw+5)) + TAG_HDR_IMMED);
1583 // I am going to claim that this is a recycled vector, and if I am on a 32-bit
1584 // system and it had a padder word at the end to bring its size up to a
1585 // multiple of 8 bytes then that word was tidily zeroed out when I first
1586 // created it, and nothing should have messed with it since - so I should not
1587 // need to do anything special here to maintain that tidy state.
1588 return r - TAG_VECTOR + tag;
1589 }
1590 }
1591 // If there is no saved vector then allocate a new one. Note that when
1592 // called from here this will be a smallish vector.
1593 return get_basic_vector(tag, type, size);
1594 }
1595
get_vector(int tag,int type,size_t n)1596 LispObject get_vector(int tag, int type, size_t n)
1597 { LispObject v;
1598 // A major ugliness here is that I need to support huge vectors.
1599 // To achieve this I will handle big cases using a vector of vectors, with
1600 // the higher level vector tagged as a INDEXVEC and the lower level vectors
1601 // each modestly sized.
1602 // So:
1603 // A vector of size up to VECTOR_CHUNK_BYTES will be represented
1604 // naturally as a single block of memory. That is the size of the DATA
1605 // not including the header cell.
1606 // Larger vectors will have an INDEXVEC most of whose contents are
1607 // vectors of size VECTOR_CHUNK_BYTES but where the final item
1608 // may be smaller.
1609 if (n-CELL > VECTOR_CHUNK_BYTES)
1610 {
1611 // If the number size is exactly a multiple of the chunk size I will not
1612 // need a special shorter final vector.
1613 size_t chunks = (n - CELL + VECTOR_CHUNK_BYTES -
1614 1)/VECTOR_CHUNK_BYTES;
1615 size_t i;
1616 // The final chunk will be full size if I have a neat multiple of
1617 // VECTOR_CHUNK_BYTES, otherwise smaller.
1618 size_t last_size = (n - CELL) % VECTOR_CHUNK_BYTES;
1619 if (last_size == 0) last_size = VECTOR_CHUNK_BYTES;
1620 v = gvector(TAG_VECTOR, TYPE_INDEXVEC, CELL*(chunks+1));
1621 errexit();
1622 // Note that this index vector will be around while the various sub
1623 // vectors are allocated, so I need to make it GC safe...
1624 for (i=0; i<chunks; i++)
1625 basic_elt(v, i) = nil;
1626 for (i=0; i<chunks; i++)
1627 { LispObject v1;
1628 int k = i==chunks-1 ? last_size : VECTOR_CHUNK_BYTES;
1629 { Save save(v);
1630 v1 = gvector(tag, type, k+CELL);
1631 errexit();
1632 save.restore(v);
1633 }
1634 // The vector here will be active as later chunks are allocated, so it needs
1635 // to be GC safe.
1636 if (!vector_holds_binary(v1))
1637 { size_t k1 = k/CELL;
1638 for (size_t j=0; j<k1; j++)
1639 basic_elt(v1, j) = nil;
1640 }
1641 basic_elt(v, i) = v1;
1642 }
1643 }
1644 else v = gvector(tag, type, n);
1645 return v;
1646 }
1647
1648
reduce_vector_size(LispObject v,size_t len)1649 LispObject reduce_vector_size(LispObject v, size_t len)
1650 { if (is_basic_vector(v)) return reduce_basic_vector_size(v, len);
1651 // Maybe the shorter vector will fit entirely within the first chunk of
1652 // the general one.
1653 if (len <= VECTOR_CHUNK_BYTES+CELL)
1654 return reduce_basic_vector_size(basic_elt(v, 0), len);
1655 // Work out how many chunks the smaller vector will need, and how large
1656 // its last chunk will end up.
1657 size_t chunks = (len - CELL + VECTOR_CHUNK_BYTES -
1658 1)/VECTOR_CHUNK_BYTES;
1659 size_t last_size = (len - CELL) % VECTOR_CHUNK_BYTES;
1660 if (last_size == 0) last_size = VECTOR_CHUNK_BYTES;
1661 len = CELL*(chunks+1);
1662 // Shorten the index vector...
1663 setvechdr(v, TYPE_INDEXVEC + (len << (Tw+5)) + TAG_HDR_IMMED);
1664 // ... and truncate what is now the last chunk.
1665 reduce_basic_vector_size(basic_elt(v, chunks-1), last_size+CELL);
1666 return v;
1667 }
1668
get_vector_init(size_t n,LispObject val)1669 LispObject get_vector_init(size_t n, LispObject val)
1670 { LispObject p;
1671 Save save(val);
1672 p = get_vector(TAG_VECTOR, TYPE_SIMPLE_VEC, n);
1673 errexit();
1674 save.restore(val);
1675 n = n/CELL - 1;
1676 while (n != 0)
1677 { n--;
1678 elt(p, n) = val;
1679 }
1680 return p;
1681 }
1682
Lstop1(LispObject env,LispObject code)1683 LispObject Lstop1(LispObject env, LispObject code)
1684 { if (!is_fixnum(code)) return aerror("stop");
1685 if (Lposn(nil) != fixnum_of_int(0)) Lterpri(nil);
1686 exit_value = code;
1687 exit_tag = fixnum_of_int(0); // Flag to say "stop"
1688 exit_reason = UNWIND_RESTART;
1689 exit_count = 1;
1690 THROW(LispRestart);
1691 }
1692
Lstop0(LispObject env)1693 LispObject Lstop0(LispObject env)
1694 { return Lstop1(env, fixnum_of_int(0));
1695 }
1696
1697 uint64_t base_time;
1698 uint64_t gc_time;
1699 std::chrono::high_resolution_clock::time_point base_walltime;
1700
Ltime(LispObject env)1701 LispObject Ltime(LispObject env)
1702 { uint64_t t0 = read_clock() - base_time;
1703 LispObject r = make_lisp_unsigned64(t0/1000);
1704 return onevalue(r);
1705 }
1706
Lwalltime(LispObject env)1707 LispObject Lwalltime(LispObject env)
1708 { using namespace std::chrono;
1709 high_resolution_clock::time_point t0 = high_resolution_clock::now();
1710 duration<double> span =
1711 duration_cast<duration<double>>(t0 - base_walltime);
1712 LispObject r = make_lisp_unsigned64((uint64_t)(1000.0*span.count()));
1713 return onevalue(r);
1714 }
1715
Lgctime(LispObject env)1716 LispObject Lgctime(LispObject env)
1717 { LispObject r = make_lisp_unsigned64(gc_time/1000);
1718 return onevalue(r);
1719 }
1720
Ldecoded_time(LispObject env)1721 LispObject Ldecoded_time(LispObject env)
1722 { std::time_t t0 = std::time(nullptr);
1723 // tm_sec -- seconds 0..59
1724 // tm_min -- minutes 0..59
1725 // tm_hour -- hour of day 0..23
1726 // tm_mday -- day of month 1..31
1727 // tm_mon -- month 0..11
1728 // tm_year -- years since 1900
1729 // tm_wday -- day of week, 0..6 (Sunday..Saturday)
1730 // tm_yday -- day of year, 0..365
1731 // tm_isdst -- >0 if daylight savings time
1732 // -- ==0 if not DST
1733 // -- <0 if don't know
1734 struct std::tm *tbuf = std::localtime(&t0);
1735 LispObject r, *p = &mv_2;
1736 int w;
1737 r = fixnum_of_int(tbuf->tm_sec);
1738 *p++ = fixnum_of_int(tbuf->tm_min);
1739 *p++ = fixnum_of_int(tbuf->tm_hour);
1740 *p++ = fixnum_of_int(tbuf->tm_mday);
1741 *p++ = fixnum_of_int(tbuf->tm_mon+1);
1742 *p++ = fixnum_of_int(tbuf->tm_year+1900);
1743 w = tbuf->tm_wday;
1744 *p++ = fixnum_of_int(w == 0 ? 6 : w-1);
1745 *p++ = tbuf->tm_isdst > 0 ? lisp_true : nil;
1746 *p++ = fixnum_of_int(0); // Time zone info not available?
1747 // Until and unless I implement multiple values in Standard Lisp mode this
1748 // function will count as a bit silly in that most of its results will
1749 // be just lost!
1750 return nvalues(r, 9);
1751 }
1752
1753 // (date) "14-May-2013"
1754 // (date!-and!-time) "Tue May 14 09:52:45 2013"
1755 //
1756 // Then (date t) and (date!-and!-time t) flip formats (well actually any
1757 // argument will suffice).
1758
Ldate(LispObject env)1759 LispObject Ldate(LispObject env)
1760 { LispObject w;
1761 std::time_t t = std::time(nullptr);
1762 char today[32];
1763 char today1[32];
1764 std::strcpy(today, std::ctime(&t));
1765 // e.g. "Sun Sep 16 01:03:52 1973\n"
1766 // 012345678901234567890123
1767 today[24] = 0; // loses final '\n'
1768 today1[0] = today[8]==' ' ? '0' : today[8];
1769 today1[1] = today[9];
1770 today1[2] = '-';
1771 today1[3] = today[4];
1772 today1[4] = today[5];
1773 today1[5] = today[6];
1774 today1[6] = '-';
1775 today1[7] = today[20];
1776 today1[8] = today[21];
1777 today1[9] = today[22];
1778 today1[10] = today[23];
1779 today1[11] = 0; // Now as in 03-Apr-2009
1780 w = make_string(today1);
1781 return onevalue(w);
1782 }
1783
Ldate1(LispObject env,LispObject a1)1784 LispObject Ldate1(LispObject env, LispObject a1)
1785 { LispObject w;
1786 std::time_t t = std::time(nullptr);
1787 char today[32];
1788 std::strcpy(today, std::ctime(&t));
1789 // e.g. "Sun Sep 16 01:03:52 1973\n"
1790 today[24] = 0; // loses final '\n'
1791 w = make_string(today);
1792 return onevalue(w);
1793 }
1794
Ldate_and_time(LispObject env)1795 LispObject Ldate_and_time(LispObject env)
1796 { LispObject w;
1797 std::time_t t = std::time(nullptr);
1798 char today[32];
1799 std::strcpy(today, std::ctime(&t));
1800 // e.g. "Sun Sep 16 01:03:52 1973\n"
1801 today[24] = 0; // loses final '\n'
1802 w = make_string(today);
1803 return onevalue(w);
1804 }
1805
Ldate_and_time1(LispObject env,LispObject a1)1806 LispObject Ldate_and_time1(LispObject env, LispObject a1)
1807 { LispObject w;
1808 std::time_t t = std::time(nullptr);
1809 char today[32], today1[32];
1810 std::strcpy(today, std::ctime(
1811 &t)); // e.g. "Sun Sep 16 01:03:52 1973\n"
1812 // 012345678901234567890123
1813 today[24] = 0; // loses final '\n'
1814 today1[0] = today[8]==' ' ? '0' : today[8];
1815 today1[1] = today[9];
1816 today1[2] = '-';
1817 today1[3] = today[4];
1818 today1[4] = today[5];
1819 today1[5] = today[6];
1820 today1[6] = '-';
1821 today1[7] = today[22];
1822 today1[8] = today[23];
1823 today1[9] = 0; // Now as in 03-Apr-09
1824 w = make_string(today1);
1825 return onevalue(w);
1826 }
1827
Ldatestamp(LispObject env)1828 LispObject Ldatestamp(LispObject env)
1829 // Returns date-stamp integer, which on many systems will be the
1830 // number of seconds between 1970.0.0 and now, but which could be
1831 // pretty-well almost any other thing, as per the C "time_t" type.
1832 // I do not allow for time-zones etc here either!
1833 { std::time_t t = std::time(nullptr);
1834 return onevalue(make_lisp_integer64((int64_t)t));
1835 }
1836
Ltimeofday(LispObject env)1837 LispObject Ltimeofday(LispObject env)
1838 // This is like datestamp, in that it returns information about the
1839 // current real time. However it returns a pair of two values, the
1840 // first being in seconds and the second (when available) being in
1841 // microseconds.
1842 { LispObject w;
1843 std::time_t t = std::time(nullptr);
1844 // Note that if this is a 32-bit value it will wrap in 2038. Probably some
1845 // other API should be used here!
1846 uint64_t n = (uint64_t)t;
1847 uint32_t un =
1848 0; // will be for microseconds, so value will be 0-999999
1849 #ifdef HAVE_SYS_TIME_H
1850 #ifdef HAVE_GETTIMEOFDAY
1851 // If more precise information is available then use it
1852 struct timeval tv;
1853 gettimeofday(&tv, nullptr);
1854 n = (uint64_t)tv.tv_sec;
1855 un = (uint32_t)tv.tv_usec;
1856 #endif
1857 #endif
1858 w = make_lisp_unsigned64(n);
1859 errexit();
1860 return onevalue(cons(w, fixnum_of_int(un)));
1861 }
1862
1863 // This will be the header for a string of length exactly 24. It is
1864 // used because a valid date will be a string of just that length.
1865
1866 #define STR24HDR (TAG_HDR_IMMED+TYPE_STRING_4+((24+CELL)<<(Tw+5)))
1867
getint(char * p,int len)1868 static int getint(char *p, int len)
1869 { int r = 0;
1870 while (len-- != 0)
1871 { int c = *p++;
1872 if (c == ' ') c = '0';
1873 r = 10*r + (c - '0');
1874 }
1875 return r;
1876 }
1877
getmon(char * s)1878 static int getmon(char *s)
1879 { int c1 = s[0], c2 = s[1], c3 = s[2], r = -1, w;
1880 const char *m = "janfebmaraprmayjunjulaugsepoctnovdec";
1881 if (std::isupper(c1)) c1 = std::tolower(c1);
1882 if (std::isupper(c2)) c2 = std::tolower(c2);
1883 if (std::isupper(c3)) c3 = std::tolower(c3);
1884 for (w=0; w<12; w++)
1885 { if (c1==m[0] && c2==m[1] && c3==m[2])
1886 { r = w;
1887 break;
1888 }
1889 m += 3;
1890 }
1891 return r;
1892 }
1893
Ldatelessp(LispObject env,LispObject a,LispObject b)1894 static LispObject Ldatelessp(LispObject env, LispObject a,
1895 LispObject b)
1896 // This is maybe a bit of an abomination! The functions (date) and
1897 // (filedate "filename") [and also (modulep 'modulename)] return times
1898 // as strings of 24 characters. This function decodes these and
1899 // sorts out which time is earlier. The alternative would be to provide
1900 // a collection of functions that returned coded times (as in C "time_t"),
1901 // but I have greater doubts about making those utterly portable, while the
1902 // textual arrangement used here seems fairly robust (until you start
1903 // worrying about carrying a portable machine across time zones or switching
1904 // to daylight savings time).
1905 { char *aa, *bb;
1906 bool res;
1907 int wa, wb;
1908 if (!is_vector(a) || !is_vector(b) ||
1909 vechdr(a) != STR24HDR ||
1910 vechdr(b) != STR24HDR) return aerror2("datelessp", a, b);
1911 aa = reinterpret_cast<char *>(a) + (CELL - TAG_VECTOR);
1912 bb = reinterpret_cast<char *>(b) + (CELL - TAG_VECTOR);
1913 // Layout is eg. "Wed May 12 15:50:23 1993"
1914 // 012345678901234567890123
1915 // Note that the year is 4 digits so that the year 2000 should hold
1916 // no special terrors JUST here.
1917 if ((wa = getint(aa+20, 4)) != (wb = getint(bb+20, 4))) res = wa < wb;
1918 else if ((wa = getmon(aa+4)) != (wb = getmon(bb+4))) res = wa < wb;
1919 else if ((wa = getint(aa+8, 2)) != (wb = getint(bb+8,
1920 2))) res = wa < wb;
1921 else if ((wa = getint(aa+11, 2)) != (wb = getint(bb+11,
1922 2))) res = wa < wb;
1923 else if ((wa = getint(aa+14, 2)) != (wb = getint(bb+14,
1924 2))) res = wa < wb;
1925 else if ((wa = getint(aa+17, 2)) != (wb = getint(bb+17,
1926 2))) res = wa < wb;
1927 else res = false;
1928 return onevalue(Lispify_predicate(res));
1929 }
1930
Lrepresentation1(LispObject env,LispObject a)1931 LispObject Lrepresentation1(LispObject env, LispObject a)
1932 // Intended for debugging, and use with indirect (q.v.)
1933 { a = make_lisp_integer64((intptr_t)a);
1934 return onevalue(a);
1935 }
1936
Lrepresentation2(LispObject env,LispObject a,LispObject b)1937 LispObject Lrepresentation2(LispObject env, LispObject a,
1938 LispObject b)
1939 // Intended for debugging, and use with indirect (q.v.). arg2, if
1940 // present and non-nil makes this more verbose. If arg2 is numeric it
1941 // prints slightly less than if it is other non-nil things!
1942 { if (SIXTY_FOUR_BIT)
1943 { if (b != nil)
1944 { if (!is_fixnum(b))
1945 trace_printf("R = %.16" PRIx64 " ", (uint64_t)a);
1946 if (is_numbers(a) && is_bignum(a))
1947 { size_t len = (length_of_header(numhdr(a))-CELL)/4;
1948 for (size_t i=len; i>0; i--)
1949 trace_printf("%.8x ", (uint32_t)bignum_digits(a)[i-1]);
1950 }
1951 if (is_numbers(a) && is_new_bignum(a))
1952 { size_t len = (length_of_header(numhdr(a))-8)/8;
1953 for (size_t i=len; i>0; i--)
1954 trace_printf("%.8x ", (uint64_t)new_bignum_digits(a)[i-1]);
1955 }
1956 else if (is_fixnum(a))
1957 trace_printf("#%cFIX:%" PRIx64, ((intptr_t)a>=0 ? 'p' : 'n'),
1958 int_of_fixnum(a));
1959 trace_printf("\n");
1960 }
1961 a = make_lisp_integer64((intptr_t)a);
1962 return onevalue(a);
1963 }
1964 else
1965 { if (b != nil)
1966 { if (!is_fixnum(b))
1967 trace_printf("R = %.8lx ", static_cast<long>(
1968 static_cast<uint32_t>(a)));
1969 if (is_numbers(a) && is_bignum(a))
1970 { size_t len = (length_of_header(numhdr(a))-CELL)/4;
1971 for (size_t i=len; i>0; i--)
1972 trace_printf("%.8x ", (uint32_t)bignum_digits(a)[i-1]);
1973 }
1974 trace_printf("\n");
1975 }
1976 a = make_lisp_integer32((int32_t)a);
1977 return onevalue(a);
1978 }
1979 }
1980
Lindirect(LispObject,LispObject a)1981 LispObject Lindirect(LispObject, LispObject a)
1982 { return onevalue(*reinterpret_cast<LispObject *>(
1983 static_cast<intptr_t>(sixty_four_bits(a))));
1984 }
1985
1986 #ifndef WITHOUT_FFI
1987
1988 // A basic foreign function interface...
1989
1990
1991 // (setq libobject (open!-foreign!-library "libraryname"))
1992 // On windows ".dll" is appended, on other systems ".so", unless there is
1993 // already a suffix. Returns nil if the library can not be accessed.
1994 //
1995 // I will not (for now) provide a call to close the library - it should be
1996 // closed when the system exits.
1997
Lopen_foreign_library(LispObject env,LispObject name)1998 LispObject Lopen_foreign_library(LispObject env, LispObject name)
1999 {
2000 #ifdef WIN32
2001 HANDLE a;
2002 #else
2003 void *a;
2004 #endif
2005 LispObject r;
2006 char libname[LONGEST_LEGAL_FILENAME];
2007 size_t len = 0;
2008 const char *w;
2009 char *w2, *w1 = nullptr;
2010 std::memset(libname, 0, sizeof(libname));
2011 w = get_string_data(name, "find-foreign-library", len);
2012 if (len > sizeof(libname)-5) len = sizeof(libname)-5;
2013 std::sprintf(libname, "%.*s", static_cast<int>(len), w);
2014 for (w2=libname; *w2!=0; w2++)
2015 if (w1==nullptr && *w2 == '.') w1 = w2;
2016 else if (*w2 == '/' || *w2 == '\\') w1 = nullptr;
2017 // Now of w1 is not nullptr it identifies a suffix ".xxx" where there is no
2018 // "/" or "\\" in the string xxx. A suffix such as ".so.1.3.2" is reported as
2019 // a whole despite the embedded dots.
2020 // On Windows if no suffix is provided a ".dll" will be appended, while
2021 // on other systems ".so" is used.
2022 #ifdef WIN32
2023 if (w1 == nullptr) std::strcat(libname, ".dll");
2024 for (w1=libname; *w1!=0; w1++)
2025 if (*w1 == '/') *w1 = '\\';
2026 // For now I will leave the trace print of the library name here, since
2027 // it should only appear once per run so ought not to cause over-much grief.
2028 // eventually I will remove it!
2029 #ifdef DEBUG
2030 std::printf("open-library Windows %s\n", libname);
2031 #endif
2032 a = LoadLibrary(libname);
2033 if (a == 0)
2034 {
2035 #ifdef DEBUG
2036 DWORD err = GetLastError();
2037 char errbuf[80];
2038 // The printf calls here to report errors will not be useful in some
2039 // windowed contexts, so I will need to rework them in due course.
2040 std::printf("Error code %ld = %lx\n", static_cast<long>(err),
2041 static_cast<long>(err));
2042 err = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2043 FORMAT_MESSAGE_IGNORE_INSERTS,
2044 nullptr, err, 0, errbuf, 80, nullptr);
2045 if (err != 0) std::printf("%s", errbuf);
2046 #endif
2047 return onevalue(nil);
2048 }
2049 #else
2050 if (w1 == nullptr) std::strcat(libname, ".so");
2051 #ifdef DEBUG
2052 // For now I will leave the trace print of the library name here, since
2053 // it should only appear once per run so ought not to cause over-much grief.
2054 // eventually I will remove it!
2055 std::printf("open-library Linux/Mac/BSD/Unix etc %s\n", libname);
2056 #endif
2057 #ifdef EMBEDDED
2058 a = nullptr;
2059 #else
2060 a = dlopen(libname, RTLD_NOW | RTLD_GLOBAL);
2061 #endif
2062 if (a == nullptr)
2063 {
2064 #ifdef DEBUG
2065 std::printf("Err = <%s>\n", dlerror()); std::fflush(stdout);
2066 #endif
2067 return onevalue(nil);
2068 }
2069 #endif
2070 r = encapsulate_pointer(reinterpret_cast<void *>(a));
2071 return onevalue(r);
2072 }
2073
2074 // (setq entrypoint (find!-foreign!-function "fname" libobject))
2075 // Using a library opened by open!-foreign!-library look up an entrypoint
2076 // for a function called "fname". If one can not be found return nil.
2077
Lfind_foreign_function(LispObject env,LispObject name,LispObject lib)2078 LispObject Lfind_foreign_function(LispObject env, LispObject name,
2079 LispObject lib)
2080 { LispObject r;
2081 void *b;
2082 const char *w;
2083 char sname[100];
2084 size_t len = 0;
2085 #ifdef WIN32
2086 HMODULE a;
2087 #else
2088 void *a;
2089 #endif
2090 if (Lencapsulatedp(nil, lib) == nil)
2091 return aerror("find-foreign-function");
2092 #ifdef WIN32
2093 a = (HMODULE)extract_pointer(lib);
2094 #else
2095 a = extract_pointer(lib);
2096 #endif
2097 w = get_string_data(name, "find-foreign-function", len);
2098 if (len > sizeof(sname)-2) len = sizeof(sname)-2;
2099 std::sprintf(sname, "%.*s", static_cast<int>(len), w);
2100 //=== #ifdef __CYGWIN__
2101 //=== printf("name to look up = %s\r\n", sname);
2102 //=== #else
2103 //=== printf("name to look up = %s\n", sname);
2104 //=== #endif
2105 #ifdef EMBEDDED
2106 b = nullptr;
2107 #else
2108 #ifdef WIN32
2109 b = reinterpret_cast<void *>(GetProcAddress(a, sname));
2110 #else
2111 b = dlsym(a, sname);
2112 #endif
2113 #endif
2114 if (b == nullptr) return onevalue(nil);
2115 r = encapsulate_pointer(b);
2116 // Observe that the result is an encapsulated pointer to the entrypoint of the
2117 // function that you are interested in.
2118 return onevalue(r);
2119 }
2120
2121 // (call!-foreign!-function fnptr)
2122 // call the function as found by find!-foreign!-function not passing it
2123 // any arguments and not expecting any result.
2124
2125 typedef void void_function();
2126
Lcallf_1(LispObject env,LispObject entry)2127 LispObject Lcallf_1(LispObject env, LispObject entry)
2128 { void *f;
2129 if (Lencapsulatedp(nil, entry) == nil)
2130 return aerror("call-foreign-function");
2131 f = extract_pointer(entry);
2132 ffi_cif cif;
2133 if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 0, &ffi_type_void,
2134 nullptr) != FFI_OK)
2135 return aerror("callf for a function with no arguments");
2136 // The strange looking double cast here is because some versions of C++ took
2137 // the view that conversion between function pointers and object pointers
2138 // should be labelled as illegal. On a Harvard architecture machine you can
2139 // see that as making a lot of sense. So I convert from the object pointer
2140 // "void *" to the function pointer "void_function *" using intptr_t as
2141 // an intermediary. This is obviously undefined behaviour! But "The Spirit
2142 // of C" would give a clear indication of expectations!
2143 ffi_call(&cif, reinterpret_cast<void_function *>(
2144 reinterpret_cast<uintptr_t>(f)), nullptr, nullptr);
2145 return onevalue(nil);
2146 }
2147
2148 // For calling foreign functions I need to know something of their type
2149 // signature. The view I will take here is NOT guaranteed portable but
2150 // is liable to work on many practical systems. I classify arguments that
2151 // are actually passed as Int32, Int64 or Double. These are expected to
2152 // be sufficient for:
2153 // Int32 int when sizeof(int)==4
2154 // char *, void * when sizeof(void *)==4, and hence "abcdef"
2155 // 'x'
2156 // Int64 int, long or long long when sizeof(.)==8
2157 // size_t if it has size 8
2158 // char *, void *, strings etc when size 8
2159 // Double double
2160
2161 #define MAX_ARGCOUNT 20
2162 #define MAX_STRINGLEN 256
2163
2164 // I will collect arguments for foreign functions in these arrays.
2165
2166 // targs and vargs are the arrays passed to libffi. i32args etc are
2167 // where the data is actually put.
2168
2169 ffi_type *targs[MAX_ARGCOUNT];
2170 void *vargs[MAX_ARGCOUNT];
2171
2172 void *fresult;
2173
2174 int32_t i32args[MAX_ARGCOUNT];
2175 int64_t i64args[MAX_ARGCOUNT];
2176 int64_t dblargs[MAX_ARGCOUNT];
2177 char strargs[MAX_ARGCOUNT][MAX_STRINGLEN];
2178
2179 long longres;
2180 int32_t i32res;
2181 int64_t i64res;
2182 double dblres;
2183 void *strres;
2184
2185 // Given a symbol (or in fact a string) this checks if its name is the
2186 // same as the value given as arg2.
2187
name_matches(LispObject a,const char * s)2188 int name_matches(LispObject a, const char *s)
2189 { size_t len = 0;
2190 const char *w = get_string_data(a, "call-foreign", len);
2191 if (len == std::strlen(s) &&
2192 std::strncmp(w, s, len) == 0) return 1;
2193 else return 0;
2194 }
2195
2196 // The general scheme for call-foreign-function is as follows, where the
2197 // key issue is that of the types of data passed and returned...
2198 // (call-foreign-function f) call f with no args, ignoring any result
2199 // (call-foreign-function f a1)
2200 // (call-foreign-function f a1 a2)
2201 // (call-foreign-function f a1 a2 ...)
2202 // etc
2203 // Each argument can be one of the following:
2204 // A symbol, where int32, int64, int, long, longlong, intptr and size
2205 // double and string are the useful values. This specifies the way in
2206 // which the next argument will be passed. If there is no
2207 // further argument then the name can also possibly be void,
2208 // and it indicates a return type.
2209 //
2210 // An integer. This is passed as the next argument to the function
2211 // as a 32-bit integer unless a type was specified by the previous symbol.
2212 //
2213 // A double-precision float. Passed to the function as the next argument.
2214 //
2215 // A string. A C string is passed to the function. There will be a
2216 // limit on the length of string that can be passed this way.
2217 // You might very reasonablly have expected that the string could be
2218 // passed to the foreign function without being copied. That is not
2219 // (always) possible because the Lisp representation of strings holds them
2220 // as a length and then bytes of data rather than as a null-terminated
2221 // sequence of bytes.
2222 //
2223 // A pair (sym . val) where sym can be one of
2224 // int int32 long int64 longlong intptr size string double
2225 // and val is something that can be mapped onto the matching type. The
2226 // purpose of this is so that whether an integer passed this way will be
2227 // 32 or 64-bit can depend on the nature of the host system.
2228
dumparg(int i,LispObject type,LispObject value)2229 static bool dumparg(int i, LispObject type, LispObject value)
2230 { size_t len = 0;
2231 const char *w = get_string_data(type, "call-foreign-function", len);
2232 if ((len==5 && std::strncmp(w, "int64", 5)==0) ||
2233 (sizeof(long)==8 && len==4 && std::strncmp(w, "long", 4)==0) ||
2234 (sizeof(size_t)==8 && len==4 && std::strncmp(w, "size", 4)==0) ||
2235 (sizeof(intptr_t)==8 && len==6 && std::strncmp(w, "intptr", 6)==0) ||
2236 (len==8 && std::strncmp(w, "longlong", 8)==0))
2237 { vargs[i] = &i64args[i];
2238 targs[i] = &ffi_type_sint64;
2239 i64args[i] = sixty_four_bits(value);
2240 return false;
2241 }
2242 else if ((type == nil && (is_fixnum(value) || is_bignum(value))) ||
2243 (len==5 && std::strncmp(w, "int32", 5)==0) ||
2244 (sizeof(long)==4 && len==4 && std::strncmp(w, "long", 4)==0) ||
2245 (sizeof(size_t)==4 && len==4 && std::strncmp(w, "size", 4)==0) ||
2246 (sizeof(intptr_t)==4 && len==6 && std::strncmp(w, "intptr", 6)==0) ||
2247 (len==3 && std::strncmp(w, "int", 3)==0))
2248 { vargs[i] = &i32args[i];
2249 targs[i] = &ffi_type_sint32;
2250 i32args[i] = thirty_two_bits(value);
2251 return false;
2252 }
2253 else if ((type == nil && is_float(value)) ||
2254 (len==6 && std::strncmp(w, "double", 6)==0))
2255 { vargs[i] = &dblargs[i];
2256 targs[i] = &ffi_type_double;
2257 dblargs[i] = float_of_number(value);
2258 return false;
2259 }
2260 else if ((type == nil && is_string(value)) ||
2261 (len==6 && std::strncmp(w, "string", 6)==0))
2262 { const char *w = get_string_data(value, "call-foreign-function",
2263 len);
2264 std::memcpy(&strargs[i][0], w, len);
2265 strargs[i][len] = 0;
2266 vargs[i] = &strargs[i][0];
2267 targs[i] = &ffi_type_pointer;
2268 return false;
2269 }
2270 else
2271 { aerror2("call-foreign-function", type, value);
2272 return true;
2273 }
2274 }
2275
callf_n(LispObject fun,LispObject args)2276 LispObject callf_n(LispObject fun, LispObject args)
2277 { if (Lencapsulatedp(nil, fun) == nil)
2278 return aerror1("call-foreign-function", fun);
2279 void_function *f = reinterpret_cast<void_function *>(
2280 reinterpret_cast<uintptr_t>(extract_pointer(fun)));
2281 LispObject currenttype = nil;
2282 unsigned int nargs = 0;
2283 while (args != nil)
2284 { LispObject a = car(args);
2285 args = cdr(args);
2286 // Perhaps the next argument is (type . value)...
2287 if (is_cons(a))
2288 { if (nargs >= MAX_ARGCOUNT) return aerror("call-foreign-function");
2289 if (dumparg(nargs++, car(a), cdr(a))) return nil;
2290 currenttype = nil;
2291 }
2292 // Perhaps the next argument is just a type name. I should never have two
2293 // type names in a row.
2294 else if (is_symbol(a))
2295 { if (currenttype != nil) return aerror1("call-foreign-function", a);
2296 currenttype = a;
2297 }
2298 // The next argument is a value, which will either use the type specified
2299 // by the previous argument, or a default type based on what its own type is.
2300 else if (is_fixnum(a) || is_numbers(a) ||
2301 is_bfloat(a) || stringp(a))
2302 { if (nargs >= MAX_ARGCOUNT) return aerror("call-foreign-function");
2303 if (dumparg(nargs++, currenttype, a)) return nil;
2304 currenttype = nil;
2305 }
2306 // Other cases are invalid.
2307 else return aerror1("call-foreign-function", a);
2308 }
2309 // The last item in the argument list may have been a type-name, in which
2310 // case it indicates a return type. If that was not provided then the
2311 // return type is taken as "void". You will see here that there are various
2312 // synonyms, sometimes conditional on the machine being used. So for instance
2313 // intptr_t is identified with either int32_t or int64_t.
2314 ffi_cif cif;
2315 if (currenttype == nil || name_matches(currenttype, "void"))
2316 { if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &ffi_type_void,
2317 targs) != FFI_OK)
2318 return aerror("call-foreign-function");
2319 ffi_call(&cif, f, nullptr, vargs);
2320 return onevalue(nil);
2321 }
2322 if (name_matches(currenttype, "int32") ||
2323 name_matches(currenttype, "int") ||
2324 (sizeof(long)==4 && name_matches(currenttype, "long")) ||
2325 (sizeof(size_t)==4 && name_matches(currenttype, "size")) ||
2326 (sizeof(intptr_t)==4 && name_matches(currenttype, "intptr")))
2327 { if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &ffi_type_sint32,
2328 targs) != FFI_OK)
2329 return aerror("call-foreign-function");
2330 ffi_call(&cif, f, &i32res, vargs);
2331 return onevalue(make_lisp_integer32(i32res));
2332 }
2333 if (name_matches(currenttype, "int64") ||
2334 name_matches(currenttype, "longlong") ||
2335 (sizeof(long)==8 && name_matches(currenttype, "long")) ||
2336 (sizeof(size_t)==8 && name_matches(currenttype, "size")) ||
2337 (sizeof(intptr_t)==8 && name_matches(currenttype, "intptr")))
2338 { if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &ffi_type_sint64,
2339 targs) != FFI_OK)
2340 return aerror("call-foreign-function");
2341 ffi_call(&cif, f, &i64res, vargs);
2342 return onevalue(make_lisp_integer64(i64res));
2343 }
2344 if (name_matches(currenttype, "double"))
2345 { if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &ffi_type_double,
2346 targs) != FFI_OK)
2347 return aerror("call-foreign-function");
2348 ffi_call(&cif, f, &dblres, vargs);
2349 return onevalue(make_boxfloat(dblres, TYPE_DOUBLE_FLOAT));
2350 }
2351 if (name_matches(currenttype, "string"))
2352 { if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, nargs, &ffi_type_pointer,
2353 targs) != FFI_OK)
2354 return aerror("call-foreign-function");
2355 ffi_call(&cif, f, &strres, vargs);
2356 return onevalue(make_string(reinterpret_cast<const char *>(strres)));
2357 }
2358 else return aerror1("call-foreign-function", currenttype);
2359 }
2360
Lcallf_4up(LispObject env,LispObject a1,LispObject a2,LispObject a3,LispObject a4up)2361 LispObject Lcallf_4up(LispObject env, LispObject a1, LispObject a2,
2362 LispObject a3, LispObject a4up)
2363 { return callf_n(a1, list2star(a2, a3, a4up));
2364 }
2365
Lcallf_3(LispObject env,LispObject entry,LispObject a1,LispObject a2)2366 LispObject Lcallf_3(LispObject env, LispObject entry, LispObject a1,
2367 LispObject a2)
2368 { return callf_n(entry, list2(a1, a2));
2369 }
2370
Lcallf_2(LispObject env,LispObject entry,LispObject a1)2371 LispObject Lcallf_2(LispObject env, LispObject entry, LispObject a1)
2372 { return callf_n(entry, ncons(a1));
2373 }
2374
2375 // It may be useful to pass callbacks into CSL to a foreign function so that
2376 // they can be stored and used...
2377
Lget_callback(LispObject env,LispObject a)2378 static LispObject Lget_callback(LispObject env, LispObject a)
2379 { void *r = nullptr;
2380 if (!is_fixnum(a)) return aerror("get_callback needs an integer arg");
2381 switch (int_of_fixnum(a))
2382 { case 0: r = reinterpret_cast<void *>(execute_lisp_function);
2383 break;
2384 case 1: r = reinterpret_cast<void *>(PROC_set_callbacks);
2385 break;
2386 case 2: r = reinterpret_cast<void *>(PROC_load_package);
2387 break;
2388 case 3: r = reinterpret_cast<void *>(PROC_set_switch);
2389 break;
2390 case 4: r = reinterpret_cast<void *>(PROC_gc_messages);
2391 break;
2392 case 5: r = reinterpret_cast<void *>(PROC_clear_stack);
2393 break;
2394 case 6: r = reinterpret_cast<void *>(PROC_push_symbol);
2395 break;
2396 case 7: r = reinterpret_cast<void *>(PROC_push_string);
2397 break;
2398 case 8: r = reinterpret_cast<void *>(PROC_push_small_integer);
2399 break;
2400 case 9: r = reinterpret_cast<void *>(PROC_push_big_integer);
2401 break;
2402 case 10: r = reinterpret_cast<void *>(PROC_push_floating);
2403 break;
2404 case 11: r = reinterpret_cast<void *>(PROC_make_function_call);
2405 break;
2406 case 12: r = reinterpret_cast<void *>(PROC_save);
2407 break;
2408 case 13: r = reinterpret_cast<void *>(PROC_load);
2409 break;
2410 case 14: r = reinterpret_cast<void *>(PROC_dup);
2411 break;
2412 case 15: r = reinterpret_cast<void *>(PROC_pop);
2413 break;
2414 case 16: r = reinterpret_cast<void *>(PROC_simplify);
2415 break;
2416 case 17: r = reinterpret_cast<void *>(PROC_make_printable);
2417 break;
2418 case 18: r = reinterpret_cast<void *>(PROC_get_value);
2419 break;
2420 case 19: r = reinterpret_cast<void *>(PROC_atom);
2421 break;
2422 case 20: r = reinterpret_cast<void *>(PROC_null);
2423 break;
2424 case 21: r = reinterpret_cast<void *>(PROC_fixnum);
2425 break;
2426 case 22: r = reinterpret_cast<void *>(PROC_floatnum);
2427 break;
2428 case 23: r = reinterpret_cast<void *>(PROC_string);
2429 break;
2430 case 24: r = reinterpret_cast<void *>(PROC_symbol);
2431 break;
2432 case 25: r = reinterpret_cast<void *>(PROC_first);
2433 break;
2434 case 26: r = reinterpret_cast<void *>(PROC_rest);
2435 break;
2436 case 27: r = reinterpret_cast<void *>(PROC_integer_value);
2437 break;
2438 case 28: r = reinterpret_cast<void *>(PROC_floating_value);
2439 break;
2440 case 29: r = reinterpret_cast<void *>(PROC_symbol_name);
2441 break;
2442 case 30: r = reinterpret_cast<void *>(PROC_string_data);
2443 break;
2444 case 31: r = reinterpret_cast<void *>(PROC_lisp_eval);
2445 break;
2446 case 32: r = reinterpret_cast<void *>(PROC_get_raw_value);
2447 break;
2448 }
2449 return onevalue(make_lisp_integer64(reinterpret_cast<LispObject>(r)));
2450 }
2451
2452 #endif // WITHOUT_FFI
2453
2454 // This is a rather silly function put in here to help me debug exception
2455 // handling. It raises a SIGSEGV.
2456
Lsigsegv(LispObject env,LispObject arg)2457 static LispObject Lsigsegv(LispObject env, LispObject arg)
2458 { trace_printf("\nsigsegv about to be raised\n");
2459 ensure_screen();
2460 if (arg == nil) std::raise(SIGSEGV);
2461 else *reinterpret_cast<char *>(-1) = 0x55;
2462 return onevalue(nil);
2463 }
2464
2465 setup_type const funcs1_setup[] =
2466 { DEF_3("acons", Lacons),
2467 DEF_1("atom", Latom),
2468 DEF_1("boundp", Lboundp),
2469
2470 DEF_1("car", Lcar),
2471 DEF_1("car*", Lcar_star),
2472 DEF_1("cdr", Lcdr),
2473 DEF_1("caar", Lcaar),
2474 DEF_1("cadr", Lcadr),
2475 DEF_1("cdar", Lcdar),
2476 DEF_1("cddr", Lcddr),
2477 DEF_1("caaar", Lcaaar),
2478 DEF_1("caadr", Lcaadr),
2479 DEF_1("cadar", Lcadar),
2480 DEF_1("caddr", Lcaddr),
2481 DEF_1("cdaar", Lcdaar),
2482 DEF_1("cdadr", Lcdadr),
2483 DEF_1("cddar", Lcddar),
2484 DEF_1("cdddr", Lcdddr),
2485 DEF_1("caaaar", Lcaaaar),
2486 DEF_1("caaadr", Lcaaadr),
2487 DEF_1("caadar", Lcaadar),
2488 DEF_1("caaddr", Lcaaddr),
2489 DEF_1("cadaar", Lcadaar),
2490 DEF_1("cadadr", Lcadadr),
2491 DEF_1("caddar", Lcaddar),
2492 DEF_1("cadddr", Lcadddr),
2493 DEF_1("cdaaar", Lcdaaar),
2494 DEF_1("cdaadr", Lcdaadr),
2495 DEF_1("cdadar", Lcdadar),
2496 DEF_1("cdaddr", Lcdaddr),
2497 DEF_1("cddaar", Lcddaar),
2498 DEF_1("cddadr", Lcddadr),
2499 DEF_1("cdddar", Lcdddar),
2500 DEF_1("cddddr", Lcddddr),
2501
2502 DEF_1("qcaar", Lcaar),
2503 DEF_1("qcadr", Lcadr),
2504 DEF_1("qcdar", Lcdar),
2505 DEF_1("qcddr", Lcddr),
2506
2507 DEF_1("bpsp", Lbpsp),
2508 DEF_1("codep", Lcodep),
2509 DEF_2("cons", Lcons),
2510 DEF_1("constantp", Lconstantp),
2511 DEF_0("count-up", Lcount_up),
2512 {"date", Ldate, Ldate1, G2Wother, G3Wother, G4Wother},
2513 {"date-and-time", Ldate_and_time, Ldate_and_time1, G2Wother, G3Wother, G4Wother},
2514 DEF_0("datestamp", Ldatestamp),
2515 DEF_0("timeofday", Ltimeofday),
2516 DEF_2("enable-errorset", Lenable_errorset),
2517 DEF_1("enable-backtrace", Lenable_backtrace),
2518 {"error", Lerror_0, Lerror_1, Lerror_2, Lerror_3, Lerror_4up},
2519 DEF_0("error1", Lerror_0),
2520 DEF_0("unwind", Lunwind),
2521 DEF_1("eq-safe", Leq_safe),
2522 DEF_1("fixp", Lfixp),
2523 DEF_1("floatp", Lfloatp),
2524 DEF_1("fluidp", Lsymbol_specialp),
2525 DEF_0("gctime", Lgctime),
2526 DEF_1("globalp", Lsymbol_globalp),
2527 DEF_1("hash-table-p", Lhash_table_p),
2528 DEF_1("indirect", Lindirect),
2529 DEF_1("integerp", Lintegerp),
2530 DEF_2("intersection", Lintersect),
2531 DEF_2("intersection_symlist", Lintersect_symlist),
2532 DEF_1("keywordp", Lsymbol_keywordp),
2533 DEF_2("list2", Llist_2),
2534 DEF_3("list2*", Llist_2star),
2535 DEF_3("list2*rev", Llist_2starrev),
2536 DEF_3("list3", Llist_3),
2537 DEF_3("list3rev", Llist_3rev),
2538 DEF_4up("list3*", Llist_3star),
2539 DEF_4up("list4", Llist_4),
2540 DEF_1("make-global", Lmake_global),
2541 DEF_1("make-keyword", Lmake_keyword),
2542 DEF_1("make-special", Lmake_special),
2543 DEF_1("mkquote", Lmkquote),
2544 DEF_1("ncons", Lncons),
2545 DEF_1("numberp", Lnumberp),
2546 DEF_2("pair", Lpair),
2547 DEF_1("protect-symbols", Lprotect_symbols),
2548 DEF_1("protected-symbol-warn", Lwarn_about_protected_symbols),
2549 DEF_3("put", Lputprop),
2550 DEF_2("remprop", Lremprop),
2551 {"representation", G0Wother, Lrepresentation1, Lrepresentation2, G3Wother, G4Wother},
2552 DEF_2("rplaca", Lrplaca),
2553 DEF_2("rplacd", Lrplacd),
2554 DEF_2("set", Lset),
2555 DEF_1("makeunbound", Lmakeunbound),
2556 DEF_1("special-form-p", Lspecial_form_p),
2557 {"stop", Lstop0, Lstop1, G2Wother, G3Wother, G4Wother},
2558 DEF_1("symbol-function", Lsymbol_function),
2559 DEF_1("symbol-value", Lsymbol_value),
2560 DEF_0("time", Ltime),
2561 DEF_0("walltime", Lwalltime),
2562 DEF_2("datelessp", Ldatelessp),
2563 DEF_2("union", Lunion),
2564 DEF_2("union-symlist", Lunion_symlist),
2565 DEF_1("unmake-global", Lunmake_global),
2566 DEF_1("unmake-keyword", Lunmake_keyword),
2567 DEF_1("unmake-special", Lunmake_special),
2568 DEF_2("xcons", Lxcons),
2569 // I provide both IDP and SYMBOLP in both modes...
2570 DEF_1("symbolp", Lsymbolp),
2571 DEF_1("idp", Lsymbolp),
2572 // I support the Common Lisp names here in both modes
2573 DEF_1("simple-string-p", Lstringp),
2574 DEF_1("simple-vector-p", Lsimple_vectorp),
2575 DEF_0("get-decoded-time", Ldecoded_time),
2576 DEF_1("short-floatp", Lshort_floatp),
2577 DEF_1("single-floatp", Lsingle_floatp),
2578 DEF_1("double-floatp", Ldouble_floatp),
2579 DEF_1("long-floatp", Llong_floatp),
2580 DEF_1("mantissa-bits", Lmantissa_bits),
2581 DEF_1("rationalp", Lrationalp),
2582 DEF_1("complexp", Lcomplexp),
2583 DEF_1("bit-vector-p", Lsimple_bit_vector_p),
2584 DEF_1("simple-bit-vector-p",Lsimple_bit_vector_p),
2585 {"get", G0Wother, G1Wother, Lget, Lget_3, G4Wother},
2586 DEF_1("arrayp", Larrayp),
2587 DEF_1("complex-arrayp", Lcomplex_arrayp),
2588 DEF_1("consp", Lconsp),
2589 DEF_1("convert-to-array", Lconvert_to_array),
2590 DEF_1("convert-to-struct", Lconvert_to_struct),
2591 DEF_1("identity", Lidentity),
2592 {"list", Lnilfn, Lncons, Llist_2, Llist_3, Llist_4up},
2593 {"list*", G0Wother, Lidentity, Lcons, Llist_2star, Lliststar_4up},
2594 DEF_1("listp", Llistp),
2595 DEF_1("structp", Lstructp),
2596 DEF_2("flag", Lflag),
2597 DEF_2("flagp", Lflagp),
2598 DEF_2("flagpcar", Lflagpcar),
2599 DEF_2("remflag", Lremflag),
2600 DEF_0("time*", Ltime),
2601 DEF_1("convert-to-evector", Lconvert_to_struct),
2602 DEF_1("evectorp", Lstructp),
2603 DEF_2("get*", Lget),
2604 DEF_1("pairp", Lconsp),
2605 DEF_1("consp", Lconsp),
2606 DEF_2("flagp**", Lflagp),
2607 DEF_1("cl-stringp", Lc_stringp),
2608 DEF_1("stringp", Lstringp),
2609 DEF_1("threevectorp", Lthreevectorp),
2610 DEF_1("vectorp", Lsimple_vectorp),
2611 #ifndef WITHOUT_FFI
2612 DEF_1("open-foreign-library", Lopen_foreign_library),
2613 DEF_2("find-foreign-function", Lfind_foreign_function),
2614 {"call-foreign-function", G0Wother, Lcallf_1, Lcallf_2, Lcallf_3, Lcallf_4up},
2615 DEF_1("get-callback", Lget_callback),
2616 #endif // WITHOUT_FFI
2617 {"gc-forcer", G0Wother, Lgc_forcer1, Lgc_forcer, G3Wother, G4Wother},
2618 DEF_1("sigsegv", Lsigsegv),
2619 {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}
2620 };
2621
2622 // end of fns1.cpp
2623