Annotation of gforth/engine/support.c, revision 1.22
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:
1.22 ! pazsan 285: #ifdef HAS_FILE
1.5 anton 286: Cell rename_file(Char *c_addr1, UCell u1, Char *c_addr2, UCell u2)
287: {
288: char *s1=tilde_cstr(c_addr2, u2, 1);
289: return IOR(rename(tilde_cstr(c_addr1, u1, 0), s1)==-1);
290: }
291:
292: struct Cellquad read_line(Char *c_addr, UCell u1, Cell wfileid)
293: {
294: UCell u2, u3;
295: Cell flag, wior;
296: Cell c;
297: struct Cellquad r;
298:
299: flag=-1;
300: u3=0;
301: for(u2=0; u2<u1; u2++) {
302: c = getc((FILE *)wfileid);
303: u3++;
304: if (c=='\n') break;
305: if (c=='\r') {
306: if ((c = getc((FILE *)wfileid))!='\n')
307: ungetc(c,(FILE *)wfileid);
308: else
309: u3++;
310: break;
311: }
312: if (c==EOF) {
313: flag=FLAG(u2!=0);
314: break;
315: }
316: c_addr[u2] = (Char)c;
317: }
318: wior=FILEIO(ferror((FILE *)wfileid));
319: r.n1 = u2;
320: r.n2 = flag;
321: r.n3 = u3;
322: r.n4 = wior;
323: return r;
324: }
325:
326: struct Cellpair file_status(Char *c_addr, UCell u)
327: {
328: struct Cellpair r;
329: Cell wfam;
330: Cell wior;
331: char *filename=tilde_cstr(c_addr, u, 1);
332:
333: if (access (filename, F_OK) != 0) {
334: wfam=0;
335: wior=IOR(1);
336: }
337: else if (access (filename, R_OK | W_OK) == 0) {
338: wfam=2; /* r/w */
339: wior=0;
340: }
341: else if (access (filename, R_OK) == 0) {
342: wfam=0; /* r/o */
343: wior=0;
344: }
345: else if (access (filename, W_OK) == 0) {
346: wfam=4; /* w/o */
347: wior=0;
348: }
349: else {
350: wfam=1; /* well, we cannot access the file, but better deliver a
351: legal access mode (r/o bin), so we get a decent error
352: later upon open. */
353: wior=0;
354: }
355: r.n1 = wfam;
356: r.n2 = wior;
1.6 anton 357: return r;
1.5 anton 358: }
359:
360: Cell to_float(Char *c_addr, UCell u, Float *rp)
361: {
362: Float r;
363: Cell flag;
364: char *number=cstr(c_addr, u, 1);
365: char *endconv;
366: int sign = 0;
1.12 anton 367: if(number[0]==' ') {
368: UCell i;
369: for (i=1; i<u; i++)
370: if (number[i] != ' ')
371: return 0;
1.13 anton 372: *rp = 0.0;
1.12 anton 373: return -1;
374: }
1.5 anton 375: if(number[0]=='-') {
376: sign = 1;
377: number++;
378: u--;
1.12 anton 379: if (u==0)
380: return 0;
1.5 anton 381: }
1.12 anton 382: switch(number[u-1]) {
1.5 anton 383: case 'd':
384: case 'D':
385: case 'e':
1.12 anton 386: case 'E':
387: u--;
388: break;
1.5 anton 389: }
390: number[u]='\0';
391: r=strtod(number,&endconv);
1.12 anton 392: flag=FLAG((*endconv)=='\0');
393: if(flag) {
1.5 anton 394: if (sign)
395: r = -r;
396: } else if(*endconv=='d' || *endconv=='D') {
397: *endconv='E';
398: r=strtod(number,&endconv);
1.12 anton 399: flag=FLAG((*endconv)=='\0');
400: if (flag) {
1.5 anton 401: if (sign)
402: r = -r;
403: }
404: }
405: *rp = r;
406: return flag;
407: }
1.22 ! pazsan 408: #endif
1.5 anton 409:
410: Float v_star(Float *f_addr1, Cell nstride1, Float *f_addr2, Cell nstride2, UCell ucount)
411: {
412: Float r;
413:
414: for (r=0.; ucount>0; ucount--) {
415: r += *f_addr1 * *f_addr2;
416: f_addr1 = (Float *)(((Address)f_addr1)+nstride1);
417: f_addr2 = (Float *)(((Address)f_addr2)+nstride2);
418: }
419: return r;
420: }
421:
422: void faxpy(Float ra, Float *f_x, Cell nstridex, Float *f_y, Cell nstridey, UCell ucount)
423: {
424: for (; ucount>0; ucount--) {
425: *f_y += ra * *f_x;
426: f_x = (Float *)(((Address)f_x)+nstridex);
427: f_y = (Float *)(((Address)f_y)+nstridey);
428: }
1.1 anton 429: }
1.9 pazsan 430:
431: UCell lshift(UCell u1, UCell n)
432: {
433: return u1 << n;
434: }
435:
436: UCell rshift(UCell u1, UCell n)
437: {
438: return u1 >> n;
1.10 anton 439: }
440:
441: int gforth_system(Char *c_addr, UCell u)
442: {
443: int retval;
444: char *prefix = getenv("GFORTHSYSTEMPREFIX") ? : DEFAULTSYSTEMPREFIX;
445: size_t prefixlen = strlen(prefix);
446: char buffer[prefixlen+u+1];
447: #ifndef MSDOS
448: int old_tp=terminal_prepped;
449: deprep_terminal();
450: #endif
451: memcpy(buffer,prefix,prefixlen);
452: memcpy(buffer+prefixlen,c_addr,u);
453: buffer[prefixlen+u]='\0';
454: retval=system(buffer); /* ~ expansion on first part of string? */
455: #ifndef MSDOS
456: if (old_tp)
457: prep_terminal();
458: #endif
459: return retval;
1.9 pazsan 460: }
1.16 anton 461:
1.17 anton 462: /* mixed division support; should usually be faster than gcc's
1.16 anton 463: double-by-double division (and gcc typically does not generate
464: double-by-single division because of exception handling issues. If
465: the architecture has double-by-single division, you should define
1.17 anton 466: ASM_SM_SLASH_REM and ASM_UM_SLASH_MOD appropriately. */
1.16 anton 467:
1.17 anton 468: /* Type definitions for longlong.h (according to the comments at the start):
469: declarations taken from libgcc2.h */
470:
471: typedef unsigned int UQItype __attribute__ ((mode (QI)));
472: typedef int SItype __attribute__ ((mode (SI)));
473: typedef unsigned int USItype __attribute__ ((mode (SI)));
474: typedef int DItype __attribute__ ((mode (DI)));
475: typedef unsigned int UDItype __attribute__ ((mode (DI)));
476: typedef UCell UWtype;
477: #if (SIZEOF_CHAR_P == 4)
478: typedef unsigned int UHWtype __attribute__ ((mode (HI)));
479: #endif
480: #if (SIZEOF_CHAR_P == 8)
481: typedef USItype UHWtype;
482: #endif
483: #ifndef BUGGY_LONG_LONG
484: typedef UDCell UDWtype;
485: #endif
486: #define W_TYPE_SIZE (SIZEOF_CHAR_P * 8)
487:
488: #include "longlong.h"
489:
490: static Cell MAYBE_UNUSED nlz(UCell x)
1.16 anton 491: /* number of leading zeros, adapted from "Hacker's Delight" */
492: {
493: Cell n;
494:
1.17 anton 495: #if !defined(COUNT_LEADING_ZEROS_0)
1.16 anton 496: if (x == 0) return(CELL_BITS);
1.17 anton 497: #endif
498: #if defined(count_leading_zeros)
499: count_leading_zeros(n,x);
500: #else
501: #warning "count_leading_zeros undefined (should not happen)"
1.16 anton 502: n = 0;
503: #if (SIZEOF_CHAR_P > 4)
504: if (x <= 0xffffffff) {n+=32; x <<= 32;}
1.21 anton 505: #error "this can't be correct"
1.16 anton 506: #endif
507: if (x <= 0x0000FFFF) {n = n +16; x = x <<16;}
508: if (x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
509: if (x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
510: if (x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
511: if (x <= 0x7FFFFFFF) {n = n + 1;}
1.17 anton 512: #endif
1.16 anton 513: return n;
514: }
515:
1.17 anton 516: #if !defined(ASM_UM_SLASH_MOD)
1.16 anton 517: UDCell umdiv (UDCell u, UCell v)
518: /* Divide unsigned double by single precision using shifts and subtracts.
519: Return quotient in lo, remainder in hi. */
520: {
1.17 anton 521: UDCell res;
522: #if defined(udiv_qrnnd)
523: UCell q,r,u0,u1;
524: UCell MAYBE_UNUSED lz;
525:
526: vm_ud2twoCell(u,u0,u1);
527: if (v==0)
528: throw(BALL_DIVZERO);
529: if (u1>=v)
530: throw(BALL_RESULTRANGE);
531: #if UDIV_NEEDS_NORMALIZATION
532: lz = nlz(v);
533: v <<= lz;
1.19 anton 534: u = UDLSHIFT(u,lz);
1.17 anton 535: vm_ud2twoCell(u,u0,u1);
536: #endif
537: udiv_qrnnd(q,r,u1,u0,v);
538: #if UDIV_NEEDS_NORMALIZATION
539: r >>= lz;
540: #endif
541: vm_twoCell2ud(q,r,res);
542: #else /* !(defined(udiv_qrnnd) */
543: #warning "udiv_qrnnd undefined (should not happen)"
1.16 anton 544: /* simple restoring subtract-and-shift algorithm, might be faster on Alpha */
545: int i = CELL_BITS, c = 0;
546: UCell q = 0;
547: Ucell h, l;
548:
549: vm_ud2twoCell(u,l,h);
550: if (v==0)
551: throw(BALL_DIVZERO);
552: if (h>=v)
553: throw(BALL_RESULTRANGE);
554: for (;;)
555: {
556: if (c || h >= v)
557: {
558: q++;
559: h -= v;
560: }
561: if (--i < 0)
562: break;
563: c = HIGHBIT (h);
564: h <<= 1;
565: h += HIGHBIT (l);
566: l <<= 1;
567: q <<= 1;
568: }
569: vm_twoCell2ud(q,h,res);
1.17 anton 570: #endif /* !(defined(udiv_qrnnd) && */
1.16 anton 571: return res;
572: }
573: #endif
574:
575: #if !defined(ASM_SM_SLASH_REM)
576: #if defined(ASM_UM_SLASH_MOD)
577: /* define it if it is not defined above */
1.17 anton 578: static UDCell MAYBE_UNUSED umdiv (UDCell u, UCell v)
1.16 anton 579: {
580: UDCell res;
581: UCell u0,u1;
582: vm_ud2twoCell(u,u0,u1);
583: ASM_UM_SLASH_MOD(u0,u1,v,r,q);
584: vm_twoCell2ud(q,r,res);
585: return res;
586: }
587: #endif /* defined(ASM_UM_SLASH_MOD) */
588:
589: #ifndef BUGGY_LONG_LONG
590: #define dnegate(x) (-(x))
591: #endif
592:
1.17 anton 593: DCell smdiv (DCell num, Cell denom)
594: /* symmetric divide procedure, mixed prec */
1.16 anton 595: {
596: DCell res;
1.17 anton 597: #if defined(sdiv_qrnnd)
598: #warning "using sdiv_qrnnd"
599: Cell u1,q,r
600: UCell u0;
601: UCell MAYBE_UNUSED lz;
602:
603: vm_d2twoCell(u,u0,u1);
604: if (v==0)
605: throw(BALL_DIVZERO);
606: if (u1>=v)
607: throw(BALL_RESULTRANGE);
608: sdiv_qrnnd(q,r,u1,u0,v);
609: vm_twoCell2d(q,r,res);
610: #else
1.16 anton 611: UDCell ures;
612: UCell l, q, r;
613: Cell h;
614: Cell denomsign=denom;
615:
616: vm_d2twoCell(num,l,h);
617: if (h < 0)
618: num = dnegate (num);
619: if (denomsign < 0)
620: denom = -denom;
621: ures = umdiv(D2UD(num), denom);
622: vm_ud2twoCell(ures,q,r);
623: if ((h^denomsign)<0) {
624: q = -q;
625: if (((Cell)q) > 0) /* note: == 0 is possible */
626: throw(BALL_RESULTRANGE);
627: } else {
628: if (((Cell)q) < 0)
629: throw(BALL_RESULTRANGE);
630: }
631: if (h<0)
632: r = -r;
633: vm_twoCell2d(q,r,res);
1.17 anton 634: #endif
1.16 anton 635: return res;
636: }
637:
1.17 anton 638: DCell fmdiv (DCell num, Cell denom)
639: /* floored divide procedure, mixed prec */
1.16 anton 640: {
641: /* I have this technique from Andrew Haley */
642: DCell res;
643: UDCell ures;
644: Cell denomsign=denom;
645: Cell numsign;
646: UCell q,r;
647:
648: if (denom < 0) {
649: denom = -denom;
650: num = dnegate(num);
651: }
652: numsign = DHI(num);
653: if (numsign < 0)
654: DHI_IS(num,DHI(num)+denom);
655: ures = umdiv(D2UD(num),denom);
656: vm_ud2twoCell(ures,q,r);
657: if ((numsign^((Cell)q)) < 0)
658: throw(BALL_RESULTRANGE);
659: if (denomsign<0)
660: r = -r;
661: vm_twoCell2d(q,r,res);
662: return res;
663: }
664: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>