BSD 4 release
[unix-history] / usr / src / cmd / lisp / lam5.c
CommitLineData
31cef89c
BJ
1static char *sccsid = "@(#)lam5.c 34.1 10/3/80";
2
654e6e2d
JF
3#include "global.h"
4#include "chkrtab.h"
5
6/*===========================================
7-
31cef89c
BJ
8- explode functions: aexplode , aexplodec, aexploden
9- The following function partially implement the explode functions for atoms.
10- The full explode functions are written in lisp and call these for atom args.
654e6e2d
JF
11-
12-===========================================*/
13
14#include "chars.h"
15lispval
16Lexpldx(kind,slashify)
31cef89c
BJ
17int kind, slashify; /* kind = 0 => explode to characters
18 = 1 => explode to fixnums (aexploden)
19 slashify = 0 => do not quote bizarre characters
20 = 1 => quote bizarre characters
21 */
654e6e2d
JF
22{
23 int typ, i;
24 char ch, *strb, strbb[BUFSIZ]; /* temporary string buffer */
25 register lispval last, handy;
31cef89c 26 register char *cp;
654e6e2d
JF
27 char Idqc = Xdqc;
28 snpand(4); /* kludge register save mask */
29
31cef89c 30 chkarg(1,"expldx");
654e6e2d 31
31cef89c 32 handy = Vreadtable->a.clb;
654e6e2d
JF
33 chkrtab(handy);
34 handy = lbot->val;
35 *strbuf = 0;
36 typ=TYPE(handy); /* we only work for a few types */
37
38
39 /* put the characters to return in the string buffer strb */
40
41 switch(typ) {
42 case STRNG:
31cef89c
BJ
43 if(slashify && !Xsdc)
44 errorh(Vermisc,"Can't explode without string delimiter",nil
45 ,FALSE,0,handy);
46
47 strb = strbb;
48 if(slashify) *strb++ = Xsdc;
49 /* copy string into buffer, escape only occurances of the
50 double quoting character if in slashify mode
51 */
52 for(cp = (char *) handy; *cp; cp++)
53 {
54 if(slashify &&
55 (*cp == Xsdc || ctable[*cp]==VESC))
56 *strb++ = Xesc;
57 *strb++ = *cp;
58 }
59 if(slashify) *strb++ = Xsdc;
60 *strb = NULL_CHAR ;
61 strb = strbb;
62 break;
63
654e6e2d 64 case ATOM:
31cef89c 65 strb = handy->a.pname;
654e6e2d
JF
66 if(strb[0]==0) {
67 strb = strbb;
68 strbb[0] = Xdqc;
69 strbb[1] = Xdqc;
70 strbb[2] = 0;
71 } else
72 common:
73 if(slashify != 0)
74 {
31cef89c 75 register char *out = strbb;
654e6e2d
JF
76 cp = strb;
77 strb = strbb;
78 if(ctable[(*cp)&0177]==VNUM)
79 *out++ = Xesc;
80 for(; *cp; cp++)
81 {
82 if(ctable[*cp]& QUTMASK)
83 *out++ = Xesc;
84 *out++ = *cp;
85 }
86 *out = 0;
87 }
88
89 break;
90 case INT:
91 strb = strbb;
92 sprintf(strb, "%d", lbot->val->i);
93 break;
94 case DOUB:
95 strb = strbb;
31cef89c 96 lfltpr(strb, lbot->val->r);
654e6e2d
JF
97 break;
98 case SDOT:
99 {
100 struct _iobuf _strbuf;
101 register count;
102 for((handy = lbot->val), count = 12;
31cef89c
BJ
103 handy->s.CDR!=(lispval) 0;
104 (handy = handy->s.CDR), count += 12);
654e6e2d
JF
105 strb = (char *) alloca(count);
106
107 _strbuf._flag = _IOWRT+_IOSTRG;
108 _strbuf._ptr = strb;
109 _strbuf._cnt = count;
110 pbignum(lbot->val,&_strbuf);
654e6e2d
JF
111 putc(0,&_strbuf);
112 break;
113 }
114 default:
115 errorh(Vermisc,"EXPLODE ARG MUST BE STRING, SYMBOL, FIXNUM, OR FLONUM",nil,FALSE,0,handy);
116 return(nil);
117 }
118
119
120 if( strb[0] != NULL_CHAR ) /* if there is something to do */
121 {
122 register lispval prev;
123
124 protect(handy = last = newdot());
125 strbuf[1] = NULL_CHAR ; /* set up for getatom */
126 atmlen = 2;
127
128 for(i=0; ch = strb[i++]; ) {
129 switch(kind) {
130
131 case 0: strbuf[0] = hash = ch; /* character explode */
31cef89c 132 last->d.car = (lispval) getatom(); /* look in oblist */
654e6e2d
JF
133 break;
134
135 case 1:
31cef89c 136 last->d.car = inewint(ch);
654e6e2d
JF
137 break;
138 }
139
140 /* advance pointers */
141 prev = last;
31cef89c
BJ
142 last->d.cdr = newdot();
143 last = last->d.cdr;
654e6e2d
JF
144 }
145
146 /* end list with a nil pointer */
31cef89c 147 prev->d.cdr = nil;
654e6e2d
JF
148 return(handy);
149 }
150 else return(nil); /* return nil if no characters */
151}
152
153/*===========================
154-
31cef89c
BJ
155- (aexplodec 'atm) returns (a t m)
156- (aexplodec 234) returns (\2 \3 \4)
654e6e2d
JF
157-===========================*/
158
159lispval
160Lexpldc()
161{ return(Lexpldx(0,0)); }
162
163
164/*===========================
165-
31cef89c
BJ
166- (aexploden 'abc) returns (65 66 67)
167- (aexploden 123) returns (49 50 51)
654e6e2d
JF
168-=============================*/
169
170
171lispval
172Lexpldn()
173{ return(Lexpldx(1,0)); }
174
175/*===========================
176-
31cef89c
BJ
177- (aexplode "123") returns (\\ \1 \2 \3);
178- (aexplode 123) returns (\1 \2 \3);
654e6e2d
JF
179-=============================*/
180
181lispval
182Lexplda()
183{ return(Lexpldx(0,1)); }
184
185/*
186 * (argv) returns how many arguments where on the command line which invoked
187 * lisp; (argv i) returns the i'th argument made into an atom;
188 */
189
190lispval
191Largv()
192{
193 register lispval handy;
194 register index;
31cef89c
BJ
195 register char *base;
196 char c;
654e6e2d
JF
197 extern int Xargc;
198 extern char **Xargv;
31cef89c 199 snpand(3);
654e6e2d 200
31cef89c 201 if(lbot-np==0)protect(nil);
654e6e2d
JF
202 handy = lbot->val;
203
204 if(TYPE(handy)==INT && handy->i>=0 && handy->i<Xargc) {
205 strcpy(strbuf,Xargv[handy->i]);
206 return(getatom());
207 } else {
208 return(inewint(Xargc));
209 }
210}
211/*
212 * (chdir <atom>) executes a chdir command
213 * if successful, return t otherwise returns nil
214 */
215lispval Lchdir(){
31cef89c 216 register char *filenm;
654e6e2d 217
31cef89c
BJ
218 chkarg(1,"chdir");
219 filenm = (char *) verify(lbot->val,"chdir - non symbol or string arg");
220 if(chdir(filenm)>=0)
654e6e2d
JF
221 return(tatom);
222 else
223 return(nil);
224}
225
226/* ==========================================================
227-
228- ascii - convert from number to ascii character
229-
230- form:(ascii number)
231-
232- the number is checked so that it is in the range 0-255
233- then it is made a character and returned
234- =========================================================*/
235
236lispval
237Lascii()
238{
239 register lispval handy;
240
241 handy = lbot->val; /* get argument */
242
243 if(TYPE(handy) != INT) /* insure that it is an integer */
244 { error("argument not an integer",FALSE);
245 return(nil);
246 }
247
248 if(handy->i < 0 || handy->i > 0377) /* insure that it is in range*/
249 { error("argument is out of ascii range",FALSE);
250 return(nil);
251 }
252
253 strbuf[0] = handy->i ; /* ok value, make into a char */
254 strbuf[1] = NULL_CHAR;
255
256 /* lookup and possibly intern the atom given in strbuf */
257
258 return( (lispval) getatom() );
259}
260
261/*
262 * boole - maclisp bitwise boolean function
263 * (boole k x y) where k determines which of 16 possible bitwise
264 * truth tables may be applied. Common values are 1 (and) 6 (xor) 7 (or)
265 * the result is mapped over each pair of bits on input
266 */
267lispval
268Lboole(){
269 register x, y;
270 register lispval result;
271 register struct argent *mynp;
272 int k;
273
274 if(np - lbot < 3)
275 error("Boole demands at least 3 args",FALSE);
276 mynp = lbot+AD;
277 k = mynp->val->i & 15;
278 x = (mynp+1)->val->i;
279 for(mynp += 2; mynp < np; mynp++) {
280 y = mynp->val->i;
281 switch(k) {
282
283 case 0: x = 0;
284 break;
285 case 1: x = x & y;
286 break;
287 case 2: x = y & ~x;
288 break;
289 case 3: x = y;
290 break;
291 case 4: x = x & ~y;
292 break;
293 /* case 5: x = x; break; */
294 case 6: x = x ^ y;
295 break;
296 case 7: x = x | y;
297 break;
298 case 8: x = ~(x | y);
299 break;
300 case 9: x = ~(x ^ y);
301 break;
302 case 10: x = ~x;
303 break;
304 case 11: x = ~x | y;
305 break;
306 case 12: x = ~y;
307 break;
308 case 13: x = x | ~y;
309 break;
310 case 14: x = ~x | ~y;
311 break;
312 case 15: x = -1;
313 }
314 }
315 return(inewint(x));
316}
317lispval
318Lfact()
319{
320 register lispval result, handy;
321 register itemp;
322 snpand(3); /* fixup entry mask */
323
324 result = lbot->val;
325 if(TYPE(result)!=INT) error("Factorial of Non-fixnum. If you want me\
326to calculate fact of > 2^30 We will be here till doomsday!.",FALSE);
327 itemp = result->i;
328 protect(result = newsdot());
31cef89c 329 result->s.CDR=(lispval)0;
654e6e2d
JF
330 result->i = 1;
331 for(; itemp > 1; itemp--)
332 dmlad(result,itemp,0);
31cef89c 333 if(result->s.CDR) return(result);
654e6e2d
JF
334 (handy = newint())->i = result->i;
335 return(handy);
336}
337/*
338 * fix -- maclisp floating to fixnum conversion
339 * for the moment, mereley convert floats to ints.
340 * eventual convert to bignum if too big to fit.
341 */
342 lispval Lfix()
343 {
344 register lispval result, handy;
345
31cef89c 346 chkarg(1,"fix");
654e6e2d
JF
347 handy = lbot->val;
348 switch(TYPE(handy)) {
349 default:
350 error("innaproriate arg to fix.",FALSE);
351 case INT:
352 case SDOT:
353 return(handy);
354 case DOUB:
355 if(handy->r >= 0)
356 return(inewint((int)handy->r));
357 else
358 return(inewint(((int)handy->r)-1));
359 }
360}
31cef89c
BJ
361#define SIGFPE 8
362#define B 1073741824.0
363static double table[] = { 1.0, B, B*B, B*B*B, B*B*B*B, 0.0};
654e6e2d
JF
364
365lispval
366Lfloat()
367{
368 register lispval handy,result;
31cef89c
BJ
369 register double sum = 0;
370 register int count;
371 chkarg(1,"float");
654e6e2d
JF
372 handy = lbot->val;
373 switch(TYPE(handy))
374 {
375 case DOUB: return(handy);
376
377
378 case INT: result = newdoub();
379 result->r = (double) handy->i;
380 return(result);
31cef89c
BJ
381 case SDOT:
382 {
383 for(handy = lbot->val, count = 0;
384 count < 5;
385 count++, handy = handy->s.CDR) {
386 sum += handy->s.I * table[count];
387 if(handy->s.CDR==(lispval)0) goto done;
388 }
389 kill(getpid(),SIGFPE);
390 done:
391 result = newdoub();
392 result->r = sum;
393 return(result);
394 }
395 default: errorh(Vermisc,"Bad argument to float",nil,FALSE,0,handy);
654e6e2d
JF
396 }
397}
398
31cef89c 399
654e6e2d
JF
400/* Lbreak ***************************************************************/
401/* If first argument is not nil, this is evaluated and printed. Then */
402/* error is called with the "breaking" message. */
403lispval Lbreak() {
404 register lispval hold;
405
406 if (np > lbot) {
407 printr(lbot->val,poport);
408 dmpport(poport);
409 }
410 return(error("",TRUE));
411}
412
413
414lispval LDivide() {
415 register lispval result, work, temp;
416 register struct argent *mynp;
417 register struct argent *lbot, *np;
418 int typ;
419 lispval quo, rem; struct sdot dummy;
420
31cef89c 421 chkarg(2,"Divide");
654e6e2d
JF
422 mynp = lbot;
423 result = mynp->val;
424 work = (mynp+1)->val;
425
426 if((typ=TYPE(result))==INT) {
427 protect(temp=newsdot());
428 temp->i = result->i;
429 result = temp;
430 } else if (typ!=SDOT)
431 error("First arg to divide neither a bignum nor int.",FALSE);
432 typ = TYPE(work);
433 if(typ != INT && typ != SDOT)
434 error("second arg to Divide neither an sdot nor an int.",FALSE);
435 if(typ == INT) {
436 dummy.CDR = (lispval) 0;
437 dummy.I = work->i;
438 work = (lispval) &dummy;
439 }
440 divbig(result,work, &quo, &rem);
441 protect(quo);
442 if(rem==((lispval) &dummy))
443 protect(rem = inewint(dummy.I));
444 protect(result = work = newdot());
31cef89c
BJ
445 work->d.car = quo;
446 (work->d.cdr = newdot())->d.car = rem;
654e6e2d
JF
447 return(result);
448}
31cef89c 449
654e6e2d
JF
450lispval LEmuldiv(){
451 register struct argent * mynp = lbot+AD;
452 register lispval work, result;
453 int quo, rem;
454 snpand(3); /* fix register mask */
455
456 /* (Emuldiv mul1 mult2 add quo) =>
457 temp = mul1 + mul2 + sext(add);
458 result = (list temp/quo temp%quo);
459 to mix C and lisp a bit */
460
461 Imuldiv(mynp[0].val->i, mynp[1].val->i, mynp[2].val->i,
462 mynp[3].val->i, &quo, &rem);
463 protect(result=newdot());
31cef89c
BJ
464 (result->d.car=inewint(quo));
465 work = result->d.cdr = newdot();
466 (work->d.car=inewint(rem));
654e6e2d
JF
467 return(result);
468}
469static Imuldiv() {
470asm(" emul 4(ap),8(ap),12(ap),r0");
471asm(" ediv 16(ap),r0,*20(ap),*24(ap)");
472}
473
474