Annotation of gforth/engine/support.c, revision 1.18
1.1 anton 1: /* Gforth support functions
2:
1.18 ! anton 3: Copyright (C) 1995,1996,1997,1998,2000,2003,2004,2006 Free Software Foundation, Inc.
1.1 anton 4:
5: This file is part of Gforth.
6:
7: Gforth is free software; you can redistribute it and/or
8: modify it under the terms of the GNU General Public License
9: as published by the Free Software Foundation; either version 2
10: of the License, or (at your option) any later version.
11:
12: This program is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with this program; if not, write to the Free Software
19: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
20: */
21:
22: #include "config.h"
23: #include "forth.h"
1.10 anton 24: #include "io.h"
1.1 anton 25: #include <stdlib.h>
26: #include <string.h>
27: #include <sys/time.h>
28: #include <unistd.h>
29: #include <pwd.h>
30: #include <dirent.h>
1.2 anton 31: #include <math.h>
1.5 anton 32: #include <ctype.h>
33: #include <errno.h>
1.1 anton 34:
35: #ifdef HAS_FILE
36: char *cstr(Char *from, UCell size, int clear)
37: /* return a C-string corresponding to the Forth string ( FROM SIZE ).
38: the C-string lives until the next call of cstr with CLEAR being true */
39: {
40: static struct cstr_buffer {
41: char *buffer;
42: size_t size;
43: } *buffers=NULL;
44: static int nbuffers=0;
45: static int used=0;
46: struct cstr_buffer *b;
47:
48: if (buffers==NULL)
49: buffers=malloc(0);
50: if (clear)
51: used=0;
52: if (used>=nbuffers) {
53: buffers=realloc(buffers,sizeof(struct cstr_buffer)*(used+1));
54: buffers[used]=(struct cstr_buffer){malloc(0),0};
55: nbuffers=used+1;
56: }
57: b=&buffers[used];
58: if (size+1 > b->size) {
59: b->buffer = realloc(b->buffer,size+1);
60: b->size = size+1;
61: }
62: memcpy(b->buffer,from,size);
63: b->buffer[size]='\0';
64: used++;
65: return b->buffer;
66: }
67:
68: char *tilde_cstr(Char *from, UCell size, int clear)
69: /* like cstr(), but perform tilde expansion on the string */
70: {
71: char *s1,*s2;
72: int s1_len, s2_len;
73: struct passwd *getpwnam (), *user_entry;
74:
75: if (size<1 || from[0]!='~')
76: return cstr(from, size, clear);
77: if (size<2 || from[1]=='/') {
78: s1 = (char *)getenv ("HOME");
79: if(s1 == NULL)
1.8 pazsan 80: #if defined(_WIN32) || defined (MSDOS)
81: s1 = (char *)getenv ("TEMP");
82: if(s1 == NULL)
83: s1 = (char *)getenv ("TMP");
84: if(s1 == NULL)
85: #endif
1.1 anton 86: s1 = "";
1.15 pazsan 87: s2 = (char *)from+1;
1.1 anton 88: s2_len = size-1;
89: } else {
90: UCell i;
91: for (i=1; i<size && from[i]!='/'; i++)
92: ;
93: if (i==2 && from[1]=='+') /* deal with "~+", i.e., the wd */
94: return cstr(from+3, size<3?0:size-3,clear);
95: {
96: char user[i];
97: memcpy(user,from+1,i-1);
98: user[i-1]='\0';
99: user_entry=getpwnam(user);
100: }
101: if (user_entry==NULL)
102: return cstr(from, size, clear);
103: s1 = user_entry->pw_dir;
1.15 pazsan 104: s2 = (char *)from+i;
1.1 anton 105: s2_len = size-i;
106: }
107: s1_len = strlen(s1);
108: if (s1_len>1 && s1[s1_len-1]=='/')
109: s1_len--;
110: {
111: char path[s1_len+s2_len];
112: memcpy(path,s1,s1_len);
113: memcpy(path+s1_len,s2,s2_len);
1.15 pazsan 114: return cstr((Char *)path,s1_len+s2_len,clear);
1.1 anton 115: }
116: }
117: #endif
118:
119: DCell timeval2us(struct timeval *tvp)
120: {
121: #ifndef BUGGY_LONG_LONG
122: return (tvp->tv_sec*(DCell)1000000)+tvp->tv_usec;
123: #else
124: DCell d2;
125: DCell d1=mmul(tvp->tv_sec,1000000);
126: d2.lo = d1.lo+tvp->tv_usec;
127: d2.hi = d1.hi + (d2.lo<d1.lo);
128: return d2;
129: #endif
130: }
131:
1.2 anton 132: DCell double2ll(Float r)
133: {
134: #ifndef BUGGY_LONG_LONG
135: return (DCell)(r);
136: #else
137: double ldexp(double x, int exp);
138: DCell d;
139: if (r<0) {
140: d.hi = ldexp(-r,-(int)(CELL_BITS));
141: d.lo = (-r)-ldexp((Float)d.hi,CELL_BITS);
142: return dnegate(d);
143: }
144: d.hi = ldexp(r,-(int)(CELL_BITS));
145: d.lo = r-ldexp((Float)d.hi,CELL_BITS);
146: return d;
147: #endif
1.5 anton 148: }
149:
150: void cmove(Char *c_from, Char *c_to, UCell u)
151: {
152: while (u-- > 0)
153: *c_to++ = *c_from++;
154: }
155:
156: void cmove_up(Char *c_from, Char *c_to, UCell u)
157: {
158: while (u-- > 0)
159: c_to[u] = c_from[u];
160: }
161:
162: Cell compare(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
163: {
164: Cell n;
165:
166: n = memcmp(c_addr1, c_addr2, u1<u2 ? u1 : u2);
167: if (n==0)
168: n = u1-u2;
169: if (n<0)
170: n = -1;
171: else if (n>0)
172: n = 1;
173: return n;
174: }
175:
176: Cell memcasecmp(const Char *s1, const Char *s2, Cell n)
177: {
178: Cell i;
179:
180: for (i=0; i<n; i++) {
181: Char c1=toupper(s1[i]);
182: Char c2=toupper(s2[i]);
183: if (c1 != c2) {
184: if (c1 < c2)
185: return -1;
186: else
187: return 1;
188: }
189: }
190: return 0;
191: }
192:
1.14 pazsan 193: Cell capscompare(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
194: {
195: Cell n;
196:
197: n = memcasecmp(c_addr1, c_addr2, u1<u2 ? u1 : u2);
198: if (n==0)
199: n = u1-u2;
200: if (n<0)
201: n = -1;
202: else if (n>0)
203: n = 1;
204: return n;
205: }
206:
1.5 anton 207: struct Longname *listlfind(Char *c_addr, UCell u, struct Longname *longname1)
208: {
209: for (; longname1 != NULL; longname1 = (struct Longname *)(longname1->next))
210: if ((UCell)LONGNAME_COUNT(longname1)==u &&
1.15 pazsan 211: memcasecmp(c_addr, (Char *)(longname1->name), u)== 0 /* or inline? */)
1.5 anton 212: break;
213: return longname1;
214: }
215:
216: struct Longname *hashlfind(Char *c_addr, UCell u, Cell *a_addr)
217: {
218: struct Longname *longname1;
219:
220: while(a_addr != NULL) {
221: longname1=(struct Longname *)(a_addr[1]);
222: a_addr=(Cell *)(a_addr[0]);
223: if ((UCell)LONGNAME_COUNT(longname1)==u &&
1.15 pazsan 224: memcasecmp(c_addr, (Char *)(longname1->name), u)== 0 /* or inline? */) {
1.5 anton 225: return longname1;
226: }
227: }
228: return NULL;
229: }
230:
231: struct Longname *tablelfind(Char *c_addr, UCell u, Cell *a_addr)
232: {
233: struct Longname *longname1;
234: while(a_addr != NULL) {
235: longname1=(struct Longname *)(a_addr[1]);
236: a_addr=(Cell *)(a_addr[0]);
237: if ((UCell)LONGNAME_COUNT(longname1)==u &&
238: memcmp(c_addr, longname1->name, u)== 0 /* or inline? */) {
239: return longname1;
240: }
241: }
242: return NULL;
243: }
244:
245: UCell hashkey1(Char *c_addr, UCell u, UCell ubits)
246: /* this hash function rotates the key at every step by rot bits within
247: ubits bits and xors it with the character. This function does ok in
248: the chi-sqare-test. Rot should be <=7 (preferably <=5) for
249: ASCII strings (larger if ubits is large), and should share no
250: divisors with ubits.
251: */
252: {
253: static char rot_values[] = {5,0,1,2,3,4,5,5,5,5,3,5,5,5,5,7,5,5,5,5,7,5,5,5,5,6,5,5,5,5,7,5,5};
254: unsigned rot = rot_values[ubits];
255: Char *cp = c_addr;
256: UCell ukey;
257:
258: for (ukey=0; cp<c_addr+u; cp++)
259: ukey = ((((ukey<<rot) | (ukey>>(ubits-rot)))
260: ^ toupper(*cp))
261: & ((1<<ubits)-1));
262: return ukey;
263: }
264:
265: struct Cellpair parse_white(Char *c_addr1, UCell u1)
266: {
267: /* use !isgraph instead of isspace? */
268: struct Cellpair result;
269: Char *c_addr2;
270: Char *endp = c_addr1+u1;
271: while (c_addr1<endp && isspace(*c_addr1))
272: c_addr1++;
273: if (c_addr1<endp) {
274: for (c_addr2 = c_addr1; c_addr1<endp && !isspace(*c_addr1); c_addr1++)
275: ;
1.6 anton 276: result.n1 = (Cell)c_addr2;
1.5 anton 277: result.n2 = c_addr1-c_addr2;
278: } else {
1.6 anton 279: result.n1 = (Cell)c_addr1;
1.5 anton 280: result.n2 = 0;
281: }
282: return result;
283: }
284:
285: Cell rename_file(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
286: {
287: char *s1=tilde_cstr(c_addr2, u2, 1);
288: return IOR(rename(tilde_cstr(c_addr1, u1, 0), s1)==-1);
289: }
290:
291: struct Cellquad read_line(Char *c_addr, UCell u1, Cell wfileid)
292: {
293: UCell u2, u3;
294: Cell flag, wior;
295: Cell c;
296: struct Cellquad r;
297:
298: flag=-1;
299: u3=0;
300: for(u2=0; u2<u1; u2++) {
301: c = getc((FILE *)wfileid);
302: u3++;
303: if (c=='\n') break;
304: if (c=='\r') {
305: if ((c = getc((FILE *)wfileid))!='\n')
306: ungetc(c,(FILE *)wfileid);
307: else
308: u3++;
309: break;
310: }
311: if (c==EOF) {
312: flag=FLAG(u2!=0);
313: break;
314: }
315: c_addr[u2] = (Char)c;
316: }
317: wior=FILEIO(ferror((FILE *)wfileid));
318: r.n1 = u2;
319: r.n2 = flag;
320: r.n3 = u3;
321: r.n4 = wior;
322: return r;
323: }
324:
325: struct Cellpair file_status(Char *c_addr, UCell u)
326: {
327: struct Cellpair r;
328: Cell wfam;
329: Cell wior;
330: char *filename=tilde_cstr(c_addr, u, 1);
331:
332: if (access (filename, F_OK) != 0) {
333: wfam=0;
334: wior=IOR(1);
335: }
336: else if (access (filename, R_OK | W_OK) == 0) {
337: wfam=2; /* r/w */
338: wior=0;
339: }
340: else if (access (filename, R_OK) == 0) {
341: wfam=0; /* r/o */
342: wior=0;
343: }
344: else if (access (filename, W_OK) == 0) {
345: wfam=4; /* w/o */
346: wior=0;
347: }
348: else {
349: wfam=1; /* well, we cannot access the file, but better deliver a
350: legal access mode (r/o bin), so we get a decent error
351: later upon open. */
352: wior=0;
353: }
354: r.n1 = wfam;
355: r.n2 = wior;
1.6 anton 356: return r;
1.5 anton 357: }
358:
359: Cell to_float(Char *c_addr, UCell u, Float *rp)
360: {
361: Float r;
362: Cell flag;
363: char *number=cstr(c_addr, u, 1);
364: char *endconv;
365: int sign = 0;
1.12 anton 366: if(number[0]==' ') {
367: UCell i;
368: for (i=1; i<u; i++)
369: if (number[i] != ' ')
370: return 0;
1.13 anton 371: *rp = 0.0;
1.12 anton 372: return -1;
373: }
1.5 anton 374: if(number[0]=='-') {
375: sign = 1;
376: number++;
377: u--;
1.12 anton 378: if (u==0)
379: return 0;
1.5 anton 380: }
1.12 anton 381: switch(number[u-1]) {
1.5 anton 382: case 'd':
383: case 'D':
384: case 'e':
1.12 anton 385: case 'E':
386: u--;
387: break;
1.5 anton 388: }
389: number[u]='\0';
390: r=strtod(number,&endconv);
1.12 anton 391: flag=FLAG((*endconv)=='\0');
392: if(flag) {
1.5 anton 393: if (sign)
394: r = -r;
395: } else if(*endconv=='d' || *endconv=='D') {
396: *endconv='E';
397: r=strtod(number,&endconv);
1.12 anton 398: flag=FLAG((*endconv)=='\0');
399: if (flag) {
1.5 anton 400: if (sign)
401: r = -r;
402: }
403: }
404: *rp = r;
405: return flag;
406: }
407:
408: Float v_star(Float *f_addr1, Cell nstride1, Float *f_addr2, Cell nstride2, UCell ucount)
409: {
410: Float r;
411:
412: for (r=0.; ucount>0; ucount--) {
413: r += *f_addr1 * *f_addr2;
414: f_addr1 = (Float *)(((Address)f_addr1)+nstride1);
415: f_addr2 = (Float *)(((Address)f_addr2)+nstride2);
416: }
417: return r;
418: }
419:
420: void faxpy(Float ra, Float *f_x, Cell nstridex, Float *f_y, Cell nstridey, UCell ucount)
421: {
422: for (; ucount>0; ucount--) {
423: *f_y += ra * *f_x;
424: f_x = (Float *)(((Address)f_x)+nstridex);
425: f_y = (Float *)(((Address)f_y)+nstridey);
426: }
1.1 anton 427: }
1.9 pazsan 428:
429: UCell lshift(UCell u1, UCell n)
430: {
431: return u1 << n;
432: }
433:
434: UCell rshift(UCell u1, UCell n)
435: {
436: return u1 >> n;
1.10 anton 437: }
438:
439: int gforth_system(Char *c_addr, UCell u)
440: {
441: int retval;
442: char *prefix = getenv("GFORTHSYSTEMPREFIX") ? : DEFAULTSYSTEMPREFIX;
443: size_t prefixlen = strlen(prefix);
444: char buffer[prefixlen+u+1];
445: #ifndef MSDOS
446: int old_tp=terminal_prepped;
447: deprep_terminal();
448: #endif
449: memcpy(buffer,prefix,prefixlen);
450: memcpy(buffer+prefixlen,c_addr,u);
451: buffer[prefixlen+u]='\0';
452: retval=system(buffer); /* ~ expansion on first part of string? */
453: #ifndef MSDOS
454: if (old_tp)
455: prep_terminal();
456: #endif
457: return retval;
1.9 pazsan 458: }
1.16 anton 459:
1.17 anton 460: /* mixed division support; should usually be faster than gcc's
1.16 anton 461: double-by-double division (and gcc typically does not generate
462: double-by-single division because of exception handling issues. If
463: the architecture has double-by-single division, you should define
1.17 anton 464: ASM_SM_SLASH_REM and ASM_UM_SLASH_MOD appropriately. */
1.16 anton 465:
1.17 anton 466: /* Type definitions for longlong.h (according to the comments at the start):
467: declarations taken from libgcc2.h */
468:
469: typedef unsigned int UQItype __attribute__ ((mode (QI)));
470: typedef int SItype __attribute__ ((mode (SI)));
471: typedef unsigned int USItype __attribute__ ((mode (SI)));
472: typedef int DItype __attribute__ ((mode (DI)));
473: typedef unsigned int UDItype __attribute__ ((mode (DI)));
474: typedef UCell UWtype;
475: #if (SIZEOF_CHAR_P == 4)
476: typedef unsigned int UHWtype __attribute__ ((mode (HI)));
477: #endif
478: #if (SIZEOF_CHAR_P == 8)
479: typedef USItype UHWtype;
480: #endif
481: #ifndef BUGGY_LONG_LONG
482: typedef UDCell UDWtype;
483: #endif
484: #define W_TYPE_SIZE (SIZEOF_CHAR_P * 8)
485:
486: #include "longlong.h"
487:
488: static Cell MAYBE_UNUSED nlz(UCell x)
1.16 anton 489: /* number of leading zeros, adapted from "Hacker's Delight" */
490: {
491: Cell n;
492:
1.17 anton 493: #if !defined(COUNT_LEADING_ZEROS_0)
1.16 anton 494: if (x == 0) return(CELL_BITS);
1.17 anton 495: #endif
496: #if defined(count_leading_zeros)
497: count_leading_zeros(n,x);
498: #else
499: #warning "count_leading_zeros undefined (should not happen)"
1.16 anton 500: n = 0;
501: #if (SIZEOF_CHAR_P > 4)
502: if (x <= 0xffffffff) {n+=32; x <<= 32;}
503: #endif
504: if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
505: if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
506: if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
507: if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
508: if (x <= 0x7FFFFFFF) {n = n + 1;}
1.17 anton 509: #endif
1.16 anton 510: return n;
511: }
512:
1.17 anton 513: #if !defined(ASM_UM_SLASH_MOD)
1.16 anton 514: UDCell umdiv (UDCell u, UCell v)
515: /* Divide unsigned double by single precision using shifts and subtracts.
516: Return quotient in lo, remainder in hi. */
517: {
1.17 anton 518: UDCell res;
519: #if defined(udiv_qrnnd)
520: UCell q,r,u0,u1;
521: UCell MAYBE_UNUSED lz;
522:
523: vm_ud2twoCell(u,u0,u1);
524: if (v==0)
525: throw(BALL_DIVZERO);
526: if (u1>=v)
527: throw(BALL_RESULTRANGE);
528: #if UDIV_NEEDS_NORMALIZATION
529: lz = nlz(v);
530: v <<= lz;
531: u <<= lz;
532: vm_ud2twoCell(u,u0,u1);
533: #endif
534: udiv_qrnnd(q,r,u1,u0,v);
535: #if UDIV_NEEDS_NORMALIZATION
536: r >>= lz;
537: #endif
538: vm_twoCell2ud(q,r,res);
539: #else /* !(defined(udiv_qrnnd) */
540: #warning "udiv_qrnnd undefined (should not happen)"
1.16 anton 541: /* simple restoring subtract-and-shift algorithm, might be faster on Alpha */
542: int i = CELL_BITS, c = 0;
543: UCell q = 0;
544: Ucell h, l;
545:
546: vm_ud2twoCell(u,l,h);
547: if (v==0)
548: throw(BALL_DIVZERO);
549: if (h>=v)
550: throw(BALL_RESULTRANGE);
551: for (;;)
552: {
553: if (c || h >= v)
554: {
555: q++;
556: h -= v;
557: }
558: if (--i < 0)
559: break;
560: c = HIGHBIT (h);
561: h <<= 1;
562: h += HIGHBIT (l);
563: l <<= 1;
564: q <<= 1;
565: }
566: vm_twoCell2ud(q,h,res);
1.17 anton 567: #endif /* !(defined(udiv_qrnnd) && */
1.16 anton 568: return res;
569: }
570: #endif
571:
572: #if !defined(ASM_SM_SLASH_REM)
573: #if defined(ASM_UM_SLASH_MOD)
574: /* define it if it is not defined above */
1.17 anton 575: static UDCell MAYBE_UNUSED umdiv (UDCell u, UCell v)
1.16 anton 576: {
577: UDCell res;
578: UCell u0,u1;
579: vm_ud2twoCell(u,u0,u1);
580: ASM_UM_SLASH_MOD(u0,u1,v,r,q);
581: vm_twoCell2ud(q,r,res);
582: return res;
583: }
584: #endif /* defined(ASM_UM_SLASH_MOD) */
585:
586: #ifndef BUGGY_LONG_LONG
587: #define dnegate(x) (-(x))
588: #endif
589:
1.17 anton 590: DCell smdiv (DCell num, Cell denom)
591: /* symmetric divide procedure, mixed prec */
1.16 anton 592: {
593: DCell res;
1.17 anton 594: #if defined(sdiv_qrnnd)
595: #warning "using sdiv_qrnnd"
596: Cell u1,q,r
597: UCell u0;
598: UCell MAYBE_UNUSED lz;
599:
600: vm_d2twoCell(u,u0,u1);
601: if (v==0)
602: throw(BALL_DIVZERO);
603: if (u1>=v)
604: throw(BALL_RESULTRANGE);
605: sdiv_qrnnd(q,r,u1,u0,v);
606: vm_twoCell2d(q,r,res);
607: #else
1.16 anton 608: UDCell ures;
609: UCell l, q, r;
610: Cell h;
611: Cell denomsign=denom;
612:
613: vm_d2twoCell(num,l,h);
614: if (h < 0)
615: num = dnegate (num);
616: if (denomsign < 0)
617: denom = -denom;
618: ures = umdiv(D2UD(num), denom);
619: vm_ud2twoCell(ures,q,r);
620: if ((h^denomsign)<0) {
621: q = -q;
622: if (((Cell)q) > 0) /* note: == 0 is possible */
623: throw(BALL_RESULTRANGE);
624: } else {
625: if (((Cell)q) < 0)
626: throw(BALL_RESULTRANGE);
627: }
628: if (h<0)
629: r = -r;
630: vm_twoCell2d(q,r,res);
1.17 anton 631: #endif
1.16 anton 632: return res;
633: }
634:
1.17 anton 635: DCell fmdiv (DCell num, Cell denom)
636: /* floored divide procedure, mixed prec */
1.16 anton 637: {
638: /* I have this technique from Andrew Haley */
639: DCell res;
640: UDCell ures;
641: Cell denomsign=denom;
642: Cell numsign;
643: UCell q,r;
644:
645: if (denom < 0) {
646: denom = -denom;
647: num = dnegate(num);
648: }
649: numsign = DHI(num);
650: if (numsign < 0)
651: DHI_IS(num,DHI(num)+denom);
652: ures = umdiv(D2UD(num),denom);
653: vm_ud2twoCell(ures,q,r);
654: if ((numsign^((Cell)q)) < 0)
655: throw(BALL_RESULTRANGE);
656: if (denomsign<0)
657: r = -r;
658: vm_twoCell2d(q,r,res);
659: return res;
660: }
661: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>