File:  [gforth] / gforth / engine / support.c
Revision 1.29: download - view: text, annotated - select for diffs
Tue Aug 21 10:33:52 2007 UTC (16 years, 8 months ago) by anton
Branches: MAIN
CVS tags: HEAD
OPEN-FILE with W/O no longer creates or truncates files (probably bugfix)
  compatibility file for old code missing
Bugfix in Makefile.in

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

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