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