imported 9.0.300
[ckermit.git] / ckclib.c
index ac6f62d..51b9f06 100644 (file)
--- a/ckclib.c
+++ b/ckclib.c
@@ -1,4 +1,4 @@
-char * cklibv = "C-Kermit library, 9.0.049, 30 Dec 2010";
+char * cklibv = "C-Kermit library, 9.0.052, 29 Jun 2011";
 
 #define CKCLIB_C
 
@@ -8,7 +8,7 @@ char * cklibv = "C-Kermit library, 9.0.049, 30 Dec 2010";
   Author: Frank da Cruz <fdc@columbia.edu>,
   Columbia University Academic Information Systems, New York City.
 
-  Copyright (C) 1999, 2010,
+  Copyright (C) 1999, 2011,
     Trustees of Columbia University in the City of New York.
     All rights reserved.  See the C-Kermit COPYING.TXT file or the
     copyright text in the ckcmai.c module for disclaimer and permissions.
@@ -54,6 +54,7 @@ char * cklibv = "C-Kermit library, 9.0.049, 30 Dec 2010";
     chknum()     - Checks if string is a (possibly signed) integer.
     rdigits()    - Checks if string is composed only of decimal digits.
     isfloat()    - Checks if string is a valid floating-point number.
+    ckround()    - Rounds a floating-point number to desired precision.
     parnam()     - Returns parity name string.
     hhmmss()     - Converts seconds to hh:mm:ss string.
     lset()       - Write fixed-length field left-adjusted into a record.
@@ -2051,6 +2052,122 @@ isfloat(s,flag) char *s; int flag; {
     floatval = f;                      /* Set result */
     return(d ? 2 : 1);                 /* Succeed */
 }
+
+/*
+  c k r o u n d  --  Rounds a floating point number or an integer.
+
+  fpnum:
+    Floating-point number to round.
+  places:
+    Positive...To how many decimal places.
+    Zero.......Round to integer.
+    Negative...-1 = nearest ten, -2 = nearest 100, -3 = nearest thousand, etc.
+  obuf
+    Output buffer for string result if desired.
+  obuflen    
+    Length of output buffer.
+  Returns:
+    Result as CKFLOAT (which is not going to be as exact as the string result)
+    And the exact result in the string output buffer, if one was specified.
+*/
+CKFLOAT
+#ifdef CK_ANSIC
+ckround(CKFLOAT fpnum, int places, char *obuf, int obuflen)
+#else
+ckround(fpnum,places,obuf,obuflen)
+ CKFLOAT fpnum; int places, obuflen; char *obuf;
+#endif /* CK_ANSIC */
+/* ckround  */ {
+    char *s, *s2, *d;
+    int i, p, len, x, n, digits;
+    int carry = 0;
+    int minus = 0;
+    char buf[200];
+    char * number;
+    CKFLOAT value;
+    extern int fp_digits;
+
+    sprintf(buf,"%200.100f",fpnum);    /* Make string version to work with */
+    number = (char *) buf;             /* Make pointer to it */
+
+    p = places;                                /* Precision */
+    d = (char *)0;                     /* Pointer to decimal or string end */
+
+    s = number;                                /* Fix number... */
+    while (*s == ' ' || *s == '\011') s++; /* Strip leading whitespace */
+    if (*s == '+') s++;                           /* Skip leading plus sign*/
+    number = s;                                   /* Start of number */
+    if (*s == '-') { minus++; number++; s++; } /* Remember if negative */
+
+    s = number;                                /* Don't allow false precision */
+    n = 0;
+    while (*s && *s != '.') s++, n++;   /* Find decimal */
+
+    if (p + n > fp_digits)             /* Too many digits */
+      p = fp_digits - n;               /* Don't ask for bogus precision */
+    if (p < 0) p = 0;                  /* But don't ask for less than zero */
+    if (n > fp_digits)                 /* Integer part has too many digits */
+      *s = 0;                          /* but we can't truncate it */
+    else                               /* Magnitude is OK */
+      number[fp_digits+1] = 0;         /* Truncate fractional part. */
+
+    len = (int)strlen(number);         /* Length of non-bogus number */
+    d = s;                             /* Pointer to decimal point */
+    if (p > 0) {                       /* Rounding the fractional part */
+       if (n + p < len) {              /* If it's not already shorter */
+           if (*s == '.') s++;         /* Skip past decimal */
+           s += p;                     /* Go to desired spot */
+           if (*s > '4' && *s <= '9')  /* Check value of digit */
+             carry = 1;
+           *s = 0;                     /* And end the string */ 
+           s--;                        /* Point to last digit */
+       }
+    } else if (p == 0) {               /* Rounding to integer */
+       if (*s == '.') {
+           *s = 0;                     /* erase the decimal point */
+           if (*(s+1)) {               /* and there is a factional part */
+               if (*(s+1) > '4' && *(s+1) <= '9') /* Check for carry */
+                 carry = 1;
+           }
+           s--;                        /* Point to last digit */
+       }
+    } else {                           /* Rounding the integer part */
+       if (s + p > number) {           /* as in "the nearest hundred" */
+           s += p;                     /* Go left to desired digit */
+           *d = 0;                     /* Discard fraction */
+           carry = 0;
+           if (*s > '4')               /* Check first digit of fraction */
+             carry = 1;                /* and set carry flag */
+           s2 = s;
+           while (s2 < d)              /* Fill in the rest with zeros */
+             *s2++ = '0';
+           s--;                        /* Point to last digit */
+       }
+    }
+    if (carry) {                       /* Handle carry, if any */
+        while (s >= number) {
+            if (*s == '.') {           /* Skip backwards over decimal */
+                s--;
+                continue;
+            }
+            *s += 1;                   /* Add 1 to current digit */
+            carry = 0;
+            if (*s <= '9')             /* If result is 9 or less */
+             break;                    /* we're done */
+            *s = '0';                  /* Otherwise put 0 */
+            carry = 1;                 /* carry the 1 */
+            s--;                       /* and back up to next digit */
+       }
+    }
+#ifdef __alpha
+    sscanf(number,"%f",&value);                /* Convert back to floating point */
+#else
+    sscanf(number,"%lf",&value);        /* Convert back to floating point */
+#endif
+    if (obuf) strncpy(obuf,number,obuflen); /* Set string result */
+    return(value);                         /* Return floating-point result */
+}
+
 #endif /* CKFLOAT */
 
 /* Sorting routines... */