"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

misc.c

Go to the documentation of this file.
00001 /*
00002  * misc.c - miscellaneous routines
00003  *
00004  * This file is a part of the SimpleScalar tool suite written by
00005  * Todd M. Austin as a part of the Multiscalar Research Project.
00006  *  
00007  * The tool suite is currently maintained by Doug Burger and Todd M. Austin.
00008  * 
00009  * Copyright (C) 1994, 1995, 1996, 1997, 1998 by Todd M. Austin
00010  *
00011  * This source file is distributed "as is" in the hope that it will be
00012  * useful.  The tool set comes with no warranty, and no author or
00013  * distributor accepts any responsibility for the consequences of its
00014  * use. 
00015  * 
00016  * Everyone is granted permission to copy, modify and redistribute
00017  * this tool set under the following conditions:
00018  * 
00019  *    This source code is distributed for non-commercial use only. 
00020  *    Please contact the maintainer for restrictions applying to 
00021  *    commercial use.
00022  *
00023  *    Permission is granted to anyone to make or distribute copies
00024  *    of this source code, either as received or modified, in any
00025  *    medium, provided that all copyright notices, permission and
00026  *    nonwarranty notices are preserved, and that the distributor
00027  *    grants the recipient permission for further redistribution as
00028  *    permitted by this document.
00029  *
00030  *    Permission is granted to distribute this file in compiled
00031  *    or executable form under the same conditions that apply for
00032  *    source code, provided that either:
00033  *
00034  *    A. it is accompanied by the corresponding machine-readable
00035  *       source code,
00036  *    B. it is accompanied by a written offer, with no time limit,
00037  *       to give anyone a machine-readable copy of the corresponding
00038  *       source code in return for reimbursement of the cost of
00039  *       distribution.  This written offer must permit verbatim
00040  *       duplication by anyone, or
00041  *    C. it is distributed by someone who received only the
00042  *       executable form, and is accompanied by a copy of the
00043  *       written offer of source code that they received concurrently.
00044  *
00045  * In other words, you are welcome to use, share and improve this
00046  * source file.  You are forbidden to forbid anyone else to use, share
00047  * and improve what you give them.
00048  *
00049  * INTERNET: dburger@cs.wisc.edu
00050  * US Mail:  1210 W. Dayton Street, Madison, WI 53706
00051  *
00052  * $Id: misc.c,v 1.1.1.1 2000/05/26 15:18:58 taustin Exp $
00053  *
00054  * $Log: misc.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:18:58  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.8  1999/12/31 18:45:17  taustin
00060  * quad_t naming conflicts removed
00061  * myprintf() buffer overflows less likely
00062  *
00063  * Revision 1.7  1999/12/13 18:44:31  taustin
00064  * crc generation support added (useful for debugging)
00065  *
00066  * Revision 1.6  1998/08/27 15:41:27  taustin
00067  * implemented host interface description in host.h
00068  * added target interface support
00069  * implemented a more portable random() interface
00070  * disabled calls to sbrk() under malloc(), this breaks some
00071  *       malloc() implementation (e.g., newer Linux releases)
00072  * added myprintf() and myatoq() routines for printing and reading
00073  *       qword's, respectively
00074  * added gzopen() and gzclose() routines for reading and writing
00075  *       compressed files, updated sysprobe to search for GZIP, if found
00076  *       support is enabled
00077  *
00078  * Revision 1.5  1997/03/11  01:17:36  taustin
00079  * updated copyright
00080  * supported added for non-GNU C compilers
00081  *
00082  * Revision 1.4  1997/01/06  16:01:45  taustin
00083  * comments updated
00084  *
00085  * Revision 1.1  1996/12/05  18:52:32  taustin
00086  * Initial revision
00087  *
00088  *
00089  */
00090 
00091 #include <stdio.h>
00092 #include <stdlib.h>
00093 #include <stdarg.h>
00094 #include <string.h>
00095 #include <ctype.h>
00096 #include <errno.h>
00097 
00098 #if defined(__alpha) || defined(linux)
00099 #include <unistd.h>
00100 #endif /* __alpha || linux */
00101 
00102 #include "host.h"
00103 #include "misc.h"
00104 #include "machine.h"
00105 
00106 /* verbose output flag */
00107 int verbose = FALSE;
00108 
00109 #ifdef DEBUG
00110 /* active debug flag */
00111 int debugging = FALSE;
00112 #endif /* DEBUG */
00113 
00114 /* fatal function hook, this function is called just before an exit
00115    caused by a fatal error, used to spew stats, etc. */
00116 static void (*hook_fn)(FILE *stream) = NULL;
00117 
00118 /* register a function to be called when an error is detected */
00119 void
00120 fatal_hook(void (*fn)(FILE *stream))    /* fatal hook function */
00121 {
00122   hook_fn = fn;
00123 }
00124 
00125 /* declare a fatal run-time error, calls fatal hook function */
00126 #ifdef __GNUC__
00127 void
00128 _fatal(char *file, char *func, int line, char *fmt, ...)
00129 #else /* !__GNUC__ */
00130 void
00131 fatal(char *fmt, ...)
00132 #endif /* __GNUC__ */
00133 {
00134   va_list v;
00135   va_start(v, fmt);
00136 
00137   fprintf(stderr, "fatal: ");
00138   myvfprintf(stderr, fmt, v);
00139 #ifdef __GNUC__
00140   if (verbose)
00141     fprintf(stderr, " [%s:%s, line %d]", func, file, line);
00142 #endif /* __GNUC__ */
00143   fprintf(stderr, "\n");
00144   if (hook_fn)
00145     (*hook_fn)(stderr);
00146   exit(1);
00147 }
00148 
00149 /* declare a panic situation, dumps core */
00150 #ifdef __GNUC__
00151 void
00152 _panic(char *file, char *func, int line, char *fmt, ...)
00153 #else /* !__GNUC__ */
00154 void
00155 panic(char *fmt, ...)
00156 #endif /* __GNUC__ */
00157 {
00158   va_list v;
00159   va_start(v, fmt);
00160 
00161   fprintf(stderr, "panic: ");
00162   myvfprintf(stderr, fmt, v);
00163 #ifdef __GNUC__
00164   fprintf(stderr, " [%s:%s, line %d]", func, file, line);
00165 #endif /* __GNUC__ */
00166   fprintf(stderr, "\n");
00167   if (hook_fn)
00168     (*hook_fn)(stderr);
00169   abort();
00170 }
00171 
00172 /* declare a warning */
00173 #ifdef __GNUC__
00174 void
00175 _warn(char *file, char *func, int line, char *fmt, ...)
00176 #else /* !__GNUC__ */
00177 void
00178 warn(char *fmt, ...)
00179 #endif /* __GNUC__ */
00180 {
00181   va_list v;
00182   va_start(v, fmt);
00183 
00184   fprintf(stderr, "warning: ");
00185   myvfprintf(stderr, fmt, v);
00186 #ifdef __GNUC__
00187   if (verbose)
00188     fprintf(stderr, " [%s:%s, line %d]", func, file, line);
00189 #endif /* __GNUC__ */
00190   fprintf(stderr, "\n");
00191 }
00192 
00193 /* print general information */
00194 #ifdef __GNUC__
00195 void
00196 _info(char *file, char *func, int line, char *fmt, ...)
00197 #else /* !__GNUC__ */
00198 void
00199 info(char *fmt, ...)
00200 #endif /* __GNUC__ */
00201 {
00202   va_list v;
00203   va_start(v, fmt);
00204 
00205   myvfprintf(stderr, fmt, v);
00206 #ifdef __GNUC__
00207   if (verbose)
00208     fprintf(stderr, " [%s:%s, line %d]", func, file, line);
00209 #endif /* __GNUC__ */
00210   fprintf(stderr, "\n");
00211 }
00212 
00213 #ifdef DEBUG
00214 /* print a debugging message */
00215 #ifdef __GNUC__
00216 void
00217 _debug(char *file, char *func, int line, char *fmt, ...)
00218 #else /* !__GNUC__ */
00219 void
00220 debug(char *fmt, ...)
00221 #endif /* __GNUC__ */
00222 {
00223     va_list v;
00224     va_start(v, fmt);
00225 
00226     if (debugging)
00227       {
00228         fprintf(stderr, "debug: ");
00229         myvfprintf(stderr, fmt, v);
00230 #ifdef __GNUC__
00231         fprintf(stderr, " [%s:%s, line %d]", func, file, line);
00232 #endif
00233         fprintf(stderr, "\n");
00234       }
00235 }
00236 #endif /* DEBUG */
00237 
00238 
00239 /* seed the random number generator */
00240 void
00241 mysrand(unsigned int seed)      /* random number generator seed */
00242 {
00243 #if defined(__CYGWIN32__) || defined(hpux) || defined(__hpux) || defined(__svr4__) || defined(_MSC_VER)
00244       srand(seed);
00245 #else
00246       srandom(seed);
00247 #endif
00248 }
00249 
00250 /* get a random number */
00251 int
00252 myrand(void)                    /* returns random number */
00253 {
00254 #if !defined(__alpha) && !defined(linux)
00255   extern long random(void);
00256 #endif
00257 
00258 #if defined(__CYGWIN32__) || defined(hpux) || defined(__hpux) || defined(__svr4__) || defined(_MSC_VER)
00259   return rand();
00260 #else
00261   return random();
00262 #endif
00263 }
00264 
00265 /* copy a string to a new storage allocation (NOTE: many machines are missing
00266    this trivial function, so I funcdup() it here...) */
00267 char *                          /* duplicated string */
00268 mystrdup(char *s)               /* string to duplicate to heap storage */
00269 {
00270   char *buf;
00271 
00272   if (!(buf = (char *)malloc(strlen(s)+1)))
00273     return NULL;
00274   strcpy(buf, s);
00275   return buf;
00276 }
00277 
00278 /* find the last occurrence of a character in a string */
00279 char *
00280 mystrrchr(char *s, char c)
00281 {
00282   char *rtnval = 0;
00283 
00284   do {
00285     if (*s == c)
00286       rtnval = s;
00287   } while (*s++);
00288 
00289   return rtnval;
00290 }
00291 
00292 /* case insensitive string compare (NOTE: many machines are missing this
00293    trivial function, so I funcdup() it here...) */
00294 int                             /* compare result, see strcmp() */
00295 mystricmp(char *s1, char *s2)   /* strings to compare, case insensitive */
00296 {
00297   unsigned char u1, u2;
00298 
00299   for (;;)
00300     {
00301       u1 = (unsigned char)*s1++; u1 = tolower(u1);
00302       u2 = (unsigned char)*s2++; u2 = tolower(u2);
00303 
00304       if (u1 != u2)
00305         return u1 - u2;
00306       if (u1 == '\0')
00307         return 0;
00308     }
00309 }
00310 
00311 /* allocate some core, this memory has overhead no larger than a page
00312    in size and it cannot be released. the storage is returned cleared */
00313 void *
00314 getcore(int nbytes)
00315 {
00316   return calloc(nbytes, 1);
00317 
00318 #if 0 /* FIXME: sbrk() calls break malloc() on Linux... */
00319 #if !defined(PURIFY) && !defined(_MSC_VER)
00320   void *p = (void *)sbrk(nbytes);
00321 
00322   if (p == (void *)-1)
00323     return NULL;
00324 
00325   /* this may be superfluous */
00326 #if defined(__svr4__) || defined(_MSC_VER)
00327   memset(p, '\0', nbytes);
00328 #else /* !defined(__svr4__) */
00329   bzero(p, nbytes);
00330 #endif
00331   return p;
00332 #else
00333   return calloc(nbytes, 1);
00334 #endif /* PURIFY */
00335 #endif
00336 }
00337 
00338 /* return log of a number to the base 2 */
00339 int
00340 log_base2(int n)
00341 {
00342   int power = 0;
00343 
00344   if (n <= 0 || (n & (n-1)) != 0)
00345     panic("log2() only works for positive power of two values");
00346 
00347   while (n >>= 1)
00348     power++;
00349 
00350   return power;
00351 }
00352 
00353 /* return string describing elapsed time, passed in SEC in seconds */
00354 char *
00355 elapsed_time(long sec)
00356 {
00357   static char tstr[256];
00358   char temp[256];
00359 
00360   if (sec <= 0)
00361     return "0s";
00362 
00363   tstr[0] = '\0';
00364 
00365   /* days */
00366   if (sec >= 86400)
00367     {
00368       sprintf(temp, "%ldD ", sec/86400);
00369       strcat(tstr, temp);
00370       sec = sec % 86400;
00371     }
00372   /* hours */
00373   if (sec >= 3600)
00374     {
00375       sprintf(temp, "%ldh ", sec/3600);
00376       strcat(tstr, temp);
00377       sec = sec % 3600;
00378     }
00379   /* mins */
00380   if (sec >= 60)
00381     {
00382       sprintf(temp, "%ldm ", sec/60);
00383       strcat(tstr, temp);
00384       sec = sec % 60;
00385     }
00386   /* secs */
00387   if (sec >= 1)
00388     {
00389       sprintf(temp, "%lds ", sec);
00390       strcat(tstr, temp);
00391     }
00392   tstr[strlen(tstr)-1] = '\0';
00393   return tstr;
00394 }
00395 
00396 /* assume bit positions numbered 31 to 0 (31 high order bit), extract num bits
00397    from word starting at position pos (with pos as the high order bit of those
00398    to be extracted), result is right justified and zero filled to high order
00399    bit, for example, extractl(word, 6, 3) w/ 8 bit word = 01101011 returns
00400    00000110 */
00401 unsigned int
00402 extractl(int word,              /* the word from which to extract */
00403          int pos,               /* bit positions 31 to 0 */
00404          int num)               /* number of bits to extract */
00405 {
00406     return(((unsigned int) word >> (pos + 1 - num)) & ~(~0 << num));
00407 }
00408 
00409 #define PUT(p, n)                                                       \
00410   {                                                                     \
00411     int nn, cc;                                                         \
00412                                                                         \
00413     for (nn = 0; nn < n; nn++)                                          \
00414       {                                                                 \
00415         cc = *(p+nn);                                                   \
00416         *obuf++ = cc;                                                   \
00417       }                                                                 \
00418   }
00419 
00420 #define PAD(s, n)                                                       \
00421   {                                                                     \
00422     int nn, cc;                                                         \
00423                                                                         \
00424     cc = *s;                                                            \
00425     for (nn = n; nn > 0; nn--)                                          \
00426       *obuf++ = cc;                                                     \
00427   }
00428 
00429 #ifdef HOST_HAS_QWORD
00430 #define HIBITL          LL(0x8000000000000000)
00431 typedef sqword_t slargeint_t;
00432 typedef qword_t largeint_t;
00433 #else /* !HOST_HAS_QWORD */
00434 #define HIBITL          0x80000000L
00435 typedef sword_t slargeint_t;
00436 typedef word_t largeint_t;
00437 #endif /* HOST_HAS_QWORD */
00438 
00439 static int
00440 _lowdigit(slargeint_t *valptr)
00441 {
00442   /* this function computes the decimal low-order digit of the number pointed
00443      to by valptr, and returns this digit after dividing *valptr by ten; this
00444      function is called ONLY to compute the low-order digit of a long whose
00445      high-order bit is set */
00446 
00447   int lowbit = (int)(*valptr & 1);
00448   slargeint_t value = (*valptr >> 1) & ~HIBITL;
00449 
00450   *valptr = value / 5;
00451   return (int)(value % 5 * 2 + lowbit + '0');
00452 }
00453 
00454 /* portable vsprintf with qword support, returns end pointer */
00455 char *
00456 myvsprintf(char *obuf, char *format, va_list v)
00457 {
00458   static char _blanks[] = "                    ";
00459   static char _zeroes[] = "00000000000000000000";
00460 
00461   /* counts output characters */
00462   int count = 0;
00463 
00464   /* format code */
00465   int fcode;
00466 
00467   /* field width and precision */
00468   int width, prec;
00469 
00470   /* number of padding zeroes required on the left and right */
00471   int lzero;
00472 
00473   /* length of prefix */
00474   int prefixlength;
00475 
00476   /* combined length of leading zeroes, trailing zeroes, and suffix */
00477   int otherlength;
00478 
00479   /* format flags */
00480 #define PADZERO         0x0001  /* padding zeroes requested via '0' */
00481 #define RZERO           0x0002  /* there will be trailing zeros in output */
00482 #define LZERO           0x0004  /* there will be leading zeroes in output */
00483 #define DOTSEEN         0x0008  /* dot appeared in format specification */
00484 #define LENGTH          0x0010  /* l */
00485   int flagword;
00486 
00487   /* maximum number of digits in printable number */
00488 #define MAXDIGS         22
00489 
00490   /* starting and ending points for value to be printed */
00491   char *bp, *p;
00492 
00493   /* work variables */
00494   int k, lradix, mradix;
00495 
00496   /* pointer to sign, "0x", "0X", or empty */
00497   char *prefix;
00498 
00499   /* values are developed in this buffer */
00500   static char buf[MAXDIGS*4], buf1[MAXDIGS*4];
00501 
00502   /* pointer to a translate table for digits of whatever radix */
00503   char *tab;
00504 
00505   /* value being converted, if integer */
00506   slargeint_t val;
00507 
00508   /* value being converted, if floating point */
00509   dfloat_t fval;
00510 
00511   for (;;)
00512     {
00513       int n;
00514 
00515       while ((fcode = *format) != '\0' && fcode != '%')
00516         {
00517           *obuf++ = fcode;
00518           format++;
00519           count++;
00520         }
00521 
00522       if (fcode == '\0')
00523         {
00524           /* end of format; terminate and return */
00525           *obuf = '\0';
00526           return obuf;
00527         }
00528 
00529 
00530       /* % has been found, the following switch is used to parse the format
00531          specification and to perform the operation specified by the format
00532          letter; the program repeatedly goes back to this switch until the
00533          format letter is encountered */
00534 
00535       width = prefixlength = otherlength = flagword = 0;
00536       format++;
00537 
00538     charswitch:
00539       switch (fcode = *format++)
00540         {
00541         case '0': /* means pad with leading zeros */
00542           flagword |= PADZERO;
00543         case '1':
00544         case '2':
00545         case '3':
00546         case '4':
00547         case '5':
00548         case '6':
00549         case '7':
00550         case '8':
00551         case '9':
00552           {
00553             int num = fcode - '0';
00554             while (isdigit(fcode = *format))
00555               {
00556                 num = num * 10 + fcode - '0';
00557                 format++;
00558               }
00559             if (flagword & DOTSEEN)
00560               prec = num;
00561             else
00562               width = num;
00563             goto charswitch;
00564           }
00565 
00566         case '.':
00567           flagword |= DOTSEEN;
00568           goto charswitch;
00569 
00570         case 'l':
00571           flagword |= LENGTH;
00572           goto charswitch;
00573 
00574         case 'n': /* host counter */
00575 #ifdef HOST_HAS_QWORD
00576           flagword |= LENGTH;
00577           /* fallthru */
00578 #else /* !HOST_HAS_QWORD */
00579           flagword |= DOTSEEN;
00580           if (!width)
00581             width = 12;
00582           prec = 0;
00583           goto process_float;
00584 #endif /* HOST_HAS_QWORD */
00585           
00586         case 'd':
00587           /* fetch the argument to be printed */
00588           if (flagword & LENGTH)
00589             val = va_arg(v, slargeint_t);
00590           else
00591             val = (slargeint_t)va_arg(v, sword_t);
00592 
00593           /* set buffer pointer to last digit */
00594           p = bp = buf + MAXDIGS;
00595 
00596           /* If signed conversion, make sign */
00597           if (val < 0)
00598             {
00599               prefix = "-";
00600               prefixlength = 1;
00601               /* negate, checking in advance for possible overflow */
00602               if (val != (slargeint_t)HIBITL)
00603                 val = -val;
00604               else
00605                 {
00606                   /* number is -HIBITL; convert last digit and get pos num */
00607                   *--bp = _lowdigit(&val);
00608                 }
00609             }
00610 
00611         decimal:
00612           {
00613             slargeint_t qval = val;
00614 
00615             if (qval <= 9)
00616               *--bp = (int)qval + '0';
00617             else
00618               {
00619                 do {
00620                   n = (int)qval;
00621                   qval /= 10;
00622                   *--bp = n - (int)qval * 10 + '0';
00623                 }
00624                 while (qval > 9);
00625                 *--bp = (int)qval + '0';
00626               }
00627           }
00628           break;
00629 
00630         case 'u':
00631           /* fetch the argument to be printed */
00632           if (flagword & LENGTH)
00633             val = va_arg(v, largeint_t);
00634           else
00635             val = (largeint_t)va_arg(v, word_t);
00636 
00637           /* set buffer pointer to last digit */
00638           p = bp = buf + MAXDIGS;
00639 
00640           if (val & HIBITL)
00641             *--bp = _lowdigit(&val);
00642           goto decimal;
00643 
00644         case 'o':
00645           mradix = 7;
00646           lradix = 2;
00647           goto fixed;
00648 
00649         case 'p': /* target address */
00650           if (sizeof(md_addr_t) > 4)
00651             flagword |= LENGTH;
00652           /* fallthru */
00653 
00654         case 'X':
00655         case 'x':
00656           mradix = 15;
00657           lradix = 3;
00658 
00659         fixed:
00660           /* fetch the argument to be printed */
00661           if (flagword & LENGTH)
00662             val = va_arg(v, largeint_t);
00663           else
00664             val = (largeint_t)va_arg(v, word_t);
00665 
00666           /* set translate table for digits */
00667           tab = (fcode == 'X') ? "0123456789ABCDEF" : "0123456789abcdef";
00668 
00669           /* develop the digits of the value */
00670           p = bp = buf + MAXDIGS;
00671 
00672           {
00673             slargeint_t qval = val;
00674 
00675             if (qval == 0)
00676               {
00677                 otherlength = lzero = 1;
00678                 flagword |= LZERO;
00679               }
00680             else
00681               do {
00682                 *--bp = tab[qval & mradix];
00683                 qval = ((qval >> 1) & ~HIBITL) >> lradix;
00684               } while (qval != 0);
00685           }
00686           break;
00687 
00688 #ifndef HOST_HAS_QWORD
00689         process_float:
00690 #endif /* !HOST_HAS_QWORD */
00691 
00692         case 'f':
00693           if (flagword & DOTSEEN)
00694             sprintf(buf1, "%%%d.%df", width, prec);
00695           else if (width)
00696             sprintf(buf1, "%%%df", width);
00697           else
00698             sprintf(buf1, "%%f");
00699 
00700           /* fetch the argument to be printed */
00701           fval = va_arg(v, dfloat_t);
00702 
00703           /* print floating point value */
00704           sprintf(buf, buf1, fval);
00705           bp = buf;
00706           p = bp + strlen(bp);
00707           break;
00708 
00709         case 's':
00710           bp = va_arg(v, char *);
00711           if (bp == NULL)
00712             bp = "(null)";
00713           p = bp + strlen(bp);
00714           break;
00715 
00716         case '%':
00717           buf[0] = fcode;
00718           goto c_merge;
00719 
00720         case 'c':
00721           buf[0] = va_arg(v, int);
00722         c_merge:
00723           p = (bp = &buf[0]) + 1;
00724           break;
00725 
00726         default:
00727           /* this is technically an error; what we do is to back up the format
00728              pointer to the offending char and continue with the format scan */
00729           format--;
00730           continue;
00731         }
00732 
00733       /* calculate number of padding blanks */
00734       k = (n = p - bp) + prefixlength + otherlength;
00735       if (width <= k)
00736         count += k;
00737       else
00738         {
00739           count += width;
00740 
00741           /* set up for padding zeroes if requested; otherwise emit padding
00742              blanks unless output is to be left-justified */
00743           if (flagword & PADZERO)
00744             {
00745               if (!(flagword & LZERO))
00746                 {
00747                   flagword |= LZERO;
00748                   lzero = width - k;
00749                 }
00750               else
00751                 lzero += width - k;
00752 
00753               /* cancel padding blanks */
00754               k = width;
00755             }
00756           else
00757             {
00758               /* blanks on left if required */
00759               PAD(_blanks, width - k);
00760             }
00761         }
00762 
00763       /* prefix, if any */
00764       if (prefixlength != 0)
00765         {
00766           PUT(prefix, prefixlength);
00767         }
00768 
00769       /* zeroes on the left */
00770       if (flagword & LZERO)
00771         {
00772           PAD(_zeroes, lzero);
00773         }
00774 
00775       /* the value itself */
00776       if (n > 0)
00777         {
00778           PUT(bp, n);
00779         }
00780     }
00781 }
00782 
00783 /* portable sprintf with qword support, returns end pointer */
00784 char *
00785 mysprintf(char *obuf, char *format, ...)
00786 {
00787   /* vararg parameters */
00788   va_list v;
00789   va_start(v, format);
00790 
00791   return myvsprintf(obuf, format, v);
00792 }
00793 
00794 /* portable vfprintf with qword support, returns end pointer */
00795 void
00796 myvfprintf(FILE *stream, char *format, va_list v)
00797 {
00798   /* temp buffer */
00799   char buf[2048];
00800 
00801   myvsprintf(buf, format, v);
00802   fputs(buf, stream);
00803 }
00804 
00805 /* portable fprintf with qword support, returns end pointer */
00806 void
00807 myfprintf(FILE *stream, char *format, ...)
00808 {
00809   /* temp buffer */
00810   char buf[2048];
00811 
00812   /* vararg parameters */
00813   va_list v;
00814   va_start(v, format);
00815 
00816   myvsprintf(buf, format, v);
00817   fputs(buf, stream);
00818 }
00819 
00820 #ifdef HOST_HAS_QWORD
00821 
00822 #define LL_MAX          LL(9223372036854775807)
00823 #define LL_MIN          (-LL_MAX - 1)
00824 #define ULL_MAX         (ULL(9223372036854775807) * ULL(2) + 1)
00825 
00826 /* convert a string to a signed result */
00827 sqword_t
00828 myatosq(char *nptr, char **endp, int base)
00829 {
00830   char *s, *save;
00831   int negative, overflow;
00832   sqword_t cutoff, cutlim, i;
00833   unsigned char c;
00834   extern int errno;
00835 
00836   if (!nptr || !*nptr)
00837     panic("strtoll() passed a NULL string");
00838 
00839   s = nptr;
00840 
00841   /* skip white space */
00842   while (isspace((int)(*s)))
00843     ++s;
00844   if (*s == '\0')
00845     goto noconv;
00846 
00847   if (base == 0)
00848     {
00849       if (s[0] == '0' && toupper(s[1]) == 'X')
00850         base = 16;
00851       else
00852         base = 10;
00853     }
00854 
00855   if (base <= 1 || base > 36)
00856     panic("bogus base: %d", base);
00857 
00858   /* check for a sign */
00859   if (*s == '-')
00860     {
00861       negative = 1;
00862       ++s;
00863     }
00864   else if (*s == '+')
00865     {
00866       negative = 0;
00867       ++s;
00868     }
00869   else
00870     negative = 0;
00871 
00872   if (base == 16 && s[0] == '0' && toupper(s[1]) == 'X')
00873     s += 2;
00874 
00875   /* save the pointer so we can check later if anything happened */
00876   save = s;
00877 
00878   cutoff = LL_MAX / (unsigned long int) base;
00879   cutlim = LL_MAX % (unsigned long int) base;
00880 
00881   overflow = 0;
00882   i = 0;
00883   for (c = *s; c != '\0'; c = *++s)
00884     {
00885       if (isdigit (c))
00886         c -= '0';
00887       else if (isalpha (c))
00888         c = toupper(c) - 'A' + 10;
00889       else
00890         break;
00891       if (c >= base)
00892         break;
00893 
00894       /* check for overflow */
00895       if (i > cutoff || (i == cutoff && c > cutlim))
00896         overflow = 1;
00897       else
00898         {
00899           i *= (unsigned long int) base;
00900           i += c;
00901         }
00902     }
00903 
00904   /* check if anything actually happened */
00905   if (s == save)
00906     goto noconv;
00907 
00908   /* store in ENDP the address of one character past the last character
00909      we converted */
00910   if (endp != NULL)
00911     *endp = (char *) s;
00912 
00913   if (overflow)
00914     {
00915       errno = ERANGE;
00916       return negative ? LL_MIN : LL_MAX;
00917     }
00918   else
00919     {
00920       errno = 0;
00921 
00922       /* return the result of the appropriate sign */
00923       return (negative ? -i : i);
00924     }
00925 
00926 noconv:
00927   /* there was no number to convert */
00928   if (endp != NULL)
00929     *endp = (char *) nptr;
00930   return 0;
00931 }
00932 
00933 /* convert a string to a unsigned result */
00934 qword_t
00935 myatoq(char *nptr, char **endp, int base)
00936 {
00937   char *s, *save;
00938   int overflow;
00939   qword_t cutoff, cutlim, i;
00940   unsigned char c;
00941   extern int errno;
00942 
00943   if (!nptr || !*nptr)
00944     panic("strtoll() passed a NULL string");
00945 
00946   s = nptr;
00947 
00948   /* skip white space */
00949   while (isspace((int)(*s)))
00950     ++s;
00951   if (*s == '\0')
00952     goto noconv;
00953 
00954   if (base == 0)
00955     {
00956       if (s[0] == '0' && toupper(s[1]) == 'X')
00957         base = 16;
00958       else
00959         base = 10;
00960     }
00961 
00962   if (base <= 1 || base > 36)
00963     panic("bogus base: %d", base);
00964 
00965   if (base == 16 && s[0] == '0' && toupper(s[1]) == 'X')
00966     s += 2;
00967 
00968   /* save the pointer so we can check later if anything happened */
00969   save = s;
00970 
00971   cutoff = ULL_MAX / (unsigned long int) base;
00972   cutlim = ULL_MAX % (unsigned long int) base;
00973 
00974   overflow = 0;
00975   i = 0;
00976   for (c = *s; c != '\0'; c = *++s)
00977     {
00978       if (isdigit (c))
00979         c -= '0';
00980       else if (isalpha (c))
00981         c = toupper(c) - 'A' + 10;
00982       else
00983         break;
00984       if (c >= base)
00985         break;
00986 
00987       /* check for overflow */
00988       if (i > cutoff || (i == cutoff && c > cutlim))
00989         overflow = 1;
00990       else
00991         {
00992           i *= (unsigned long int) base;
00993           i += c;
00994         }
00995     }
00996 
00997   /* check if anything actually happened */
00998   if (s == save)
00999     goto noconv;
01000 
01001   /* store in ENDP the address of one character past the last character
01002      we converted */
01003   if (endp != NULL)
01004     *endp = (char *) s;
01005 
01006   if (overflow)
01007     {
01008       errno = ERANGE;
01009       return ULL_MAX;
01010     }
01011   else
01012     {
01013       errno = 0;
01014 
01015       /* return the result of the appropriate sign */
01016       return i;
01017     }
01018 
01019 noconv:
01020   /* there was no number to convert */
01021   if (endp != NULL)
01022     *endp = (char *) nptr;
01023   return 0;
01024 }
01025 
01026 #ifdef TESTIT
01027 void
01028 testit(char *s)
01029 {
01030   char buf[128];
01031   qword_t qval;
01032 
01033   qval = myatoq(s, NULL, 10);
01034 
01035   myqtoa(qval, "%x", buf, NULL);
01036   fprintf(stderr, "x:    %s\n", buf);
01037   myqtoa(qval, "%16x", buf, NULL);
01038   fprintf(stderr, "16x:  %s\n", buf);
01039   myqtoa(qval, "%016x", buf, NULL);
01040   fprintf(stderr, "016x: %s\n", buf);
01041   myqtoa(qval, "0x%016x", buf, NULL);
01042   fprintf(stderr, "0x016x: %s\n", buf);
01043   myqtoa(qval, "0x%08x", buf, NULL);
01044   fprintf(stderr, "0x08x: %s\n", buf);
01045 
01046   myqtoa(qval, "%d", buf, NULL);
01047   fprintf(stderr, "d:    %s\n", buf);
01048   myqtoa(qval, "%22d", buf, NULL);
01049   fprintf(stderr, "22d:  %s\n", buf);
01050   myqtoa(qval, "%022d", buf, NULL);
01051   fprintf(stderr, "022d: %s\n", buf);
01052 
01053   myqtoa(qval, "%u", buf, NULL);
01054   fprintf(stderr, "u:    %s\n", buf);
01055 
01056   myqtoa(qval, "%o", buf, NULL);
01057   fprintf(stderr, "o:    %s\n", buf);
01058 }
01059 
01060 void
01061 stestit(char *s)
01062 {
01063   char buf[128];
01064   sqword_t sqval;
01065 
01066   sqval = myatosq(s, NULL, 10);
01067 
01068   myqtoa(sqval, "%x", buf, NULL);
01069   fprintf(stderr, "x: %s\n", buf);
01070 
01071   myqtoa(sqval, "%d", buf, NULL);
01072   fprintf(stderr, "d: %s\n", buf);
01073 
01074   myqtoa(sqval, "%u", buf, NULL);
01075   fprintf(stderr, "u: %s\n", buf);
01076 }
01077 
01078 void
01079 xtestit(char *s)
01080 {
01081   char buf[128];
01082   qword_t qval;
01083 
01084   qval = myatoq(s, NULL, 16);
01085 
01086   myqtoa(qval, "%x", buf, NULL);
01087   fprintf(stderr, "x: %s\n", buf);
01088 
01089   myqtoa(qval, "%d", buf, NULL);
01090   fprintf(stderr, "d: %s\n", buf);
01091 
01092   myqtoa(qval, "%u", buf, NULL);
01093   fprintf(stderr, "u: %s\n", buf);
01094 }
01095 #endif /* TESTIT */
01096 
01097 #endif /* HOST_HAS_QWORD */
01098 
01099 #ifdef GZIP_PATH
01100 
01101 static struct {
01102   char *type;
01103   char *ext;
01104   char *cmd;
01105 } gzcmds[] = {
01106   /* type */    /* extension */         /* command */
01107   { "r",        ".gz",                  "%s -dc %s" },
01108   { "rb",       ".gz",                  "%s -dc %s" },
01109   { "r",        ".Z",                   "%s -dc %s" },
01110   { "rb",       ".Z",                   "%s -dc %s" },
01111   { "w",        ".gz",                  "%s > %s" },
01112   { "wb",       ".gz",                  "%s > %s" }
01113 };
01114 
01115 /* same semantics as fopen() except that filenames ending with a ".gz" or ".Z"
01116    will be automagically get compressed */
01117 FILE *
01118 gzopen(char *fname, char *type)
01119 {
01120   int i;
01121   char *cmd = NULL, *ext;
01122   FILE *fd;
01123   char str[2048];
01124 
01125   /* get the extension */
01126   ext = mystrrchr(fname, '.');
01127 
01128   /* check if extension indicates compressed file */
01129   if (ext != NULL && *ext != '\0')
01130     {
01131       for (i=0; i < N_ELT(gzcmds); i++)
01132         {
01133           if (!strcmp(gzcmds[i].type, type) && !strcmp(gzcmds[i].ext, ext))
01134             {
01135               cmd = gzcmds[i].cmd;
01136               break;
01137             }
01138         }
01139     }
01140 
01141   if (!cmd)
01142     {
01143       /* open file */
01144       fd = fopen(fname, type);
01145     }
01146   else
01147     {
01148       /* open pipe to compressor/decompressor */
01149       sprintf(str, cmd, GZIP_PATH, fname);
01150       fd = popen(str, type);
01151     }
01152 
01153   return fd;
01154 }
01155 
01156 /* close compressed stream */
01157 void
01158 gzclose(FILE *fd)
01159 {
01160   /* attempt pipe close, otherwise file close */
01161   if (pclose(fd) == -1)
01162     fclose(fd);
01163 }
01164 
01165 #else /* !GZIP_PATH */
01166 
01167 FILE *
01168 gzopen(char *fname, char *type)
01169 {
01170   return fopen(fname, type);
01171 }
01172 
01173 void
01174 gzclose(FILE *fd)
01175 {
01176   fclose(fd);
01177 }
01178 
01179 #endif /* GZIP_PATH */
01180 
01181 /* compute 32-bit CRC one byte at a time using the high-bit first (big-endian)
01182    bit ordering convention */
01183 #define POLYNOMIAL 0x04c11db7L
01184 
01185 static int crc_init = FALSE;
01186 static unsigned long crc_table[256];
01187 
01188 /* generate the table of CRC remainders for all possible bytes */
01189 static void
01190 crc_gentab(void)
01191 {
01192   int i, j;
01193   word_t crc_accum;
01194 
01195   for (i=0; i < 256; i++)
01196     {
01197       crc_accum = ((unsigned long)i << 24);
01198       for (j=0; j < 8; j++)
01199         {
01200           if (crc_accum & 0x80000000L)
01201             crc_accum = (crc_accum << 1) ^ POLYNOMIAL;
01202           else
01203             crc_accum = (crc_accum << 1);
01204         }
01205       crc_table[i] = crc_accum;
01206     }
01207   return;
01208 }
01209 
01210 /* update the CRC on the data block one byte at a time */
01211 word_t
01212 crc(word_t crc_accum, word_t data)
01213 {
01214   int i, j;
01215 
01216   if (!crc_init)
01217     {
01218       crc_gentab();
01219       crc_init = TRUE;
01220     }
01221 
01222   for (j=0; j < sizeof(word_t); j++)
01223     {
01224       i = ((int)(crc_accum >> 24) ^ (data >> (j*8))) & 0xff;
01225       crc_accum = (crc_accum << 8) ^ crc_table[i];
01226     }
01227   return crc_accum;
01228 }


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214