File:  [gforth] / gforth / engine / support.c
Revision 1.26: download - view: text, annotated - select for diffs
Wed May 9 07:12:59 2007 UTC (16 years, 11 months ago) by anton
Branches: MAIN
CVS tags: HEAD
use nanosleep() for MS where available (thanks to Shawn K. Quinn).

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>