aboutsummaryrefslogtreecommitdiffstats
path: root/skeletons/REAL.c
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2004-09-27 20:52:18 +0000
committerLev Walkin <vlm@lionet.info>2004-09-27 20:52:18 +0000
commit92b35d2b2bf8832311afca29d6050e5ac6e9a7eb (patch)
tree3e2b794ba1b808fc7fd5d5500014d285a4319ba7 /skeletons/REAL.c
parent1e609cfbdacab2b6732c248865ccdd20f5af9fdd (diff)
pretty-printing
Diffstat (limited to 'skeletons/REAL.c')
-rw-r--r--skeletons/REAL.c99
1 files changed, 79 insertions, 20 deletions
diff --git a/skeletons/REAL.c b/skeletons/REAL.c
index 010097b9..927a94b3 100644
--- a/skeletons/REAL.c
+++ b/skeletons/REAL.c
@@ -47,17 +47,34 @@ asn1_TYPE_descriptor_t asn1_DEF_REAL = {
ssize_t
REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) {
- char local_buf[32];
+ char local_buf[64];
char *buf = local_buf;
ssize_t buflen = sizeof(local_buf);
- const char *fmt = canonical?"%15E":"f";
+ const char *fmt = canonical?"%.15E":"%.15f";
ssize_t ret;
+ int expval;
/*
* Check whether it is a special value.
*/
- if(finite(d) == 0) {
- if(isinf(d)) {
+ /*
+ * ilogb(+-0) returns -INT_MAX or INT_MIN (platform-dependent)
+ * ilogb(+-inf) returns INT_MAX
+ */
+ expval = ilogb(d);
+ if(expval <= -INT_MAX /* Also catches (d == 0) */
+ || expval == INT_MAX /* catches finite() which catches isnan() */
+ ) {
+ /* fpclassify(3) is not portable yet */
+ if(expval <= -INT_MAX) {
+ if(copysign(1.0, d) < 0.0) {
+ buf = "-0";
+ buflen = 2;
+ } else {
+ buf = "0";
+ buflen = 1;
+ }
+ } else if(isinf(d)) {
if(copysign(1.0, d) < 0.0) {
buf = "<MINUS-INFINITY/>";
buflen = 17;
@@ -90,43 +107,85 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key)
if(!buf) return -1;
} while(1);
- /*
- * Transform the "[-]d.dddE+-dd" output into "[-]d.dddE[-]d"
- */
if(canonical) {
+ /*
+ * Transform the "[-]d.dddE+-dd" output into "[-]d.dddE[-]d"
+ */
char *dot, *E;
char *end = buf + buflen;
+ char *last_zero;
dot = (buf[0] == '-') ? (buf + 2) : (buf + 1);
if(*dot >= 0x30) {
errno = EINVAL;
return -1; /* Not a dot, really */
}
- *dot = '.'; /* Replace possible comma */
-
- for(E = dot; dot < end; E++) {
- if(*E == 'E') {
- char *s = ++E;
- if(*E == '+') {
- /* Skip the "+" too */
- buflen -= 2;
- } else {
+ *dot = 0x2e; /* Replace possible comma */
+
+ for(last_zero = dot + 2, E = dot; dot < end; E++) {
+ if(*E == 0x45) {
+ char *expptr = ++E;
+ char *s = expptr;
+ int sign;
+ if(*expptr == '+') {
+ /* Skip the "+" */
buflen -= 1;
+ sign = 0;
+ } else {
+ sign = 1;
s++;
}
- E += 2;
- if(E[-1] != '0' || E > end) {
+ expptr++;
+ if(expptr > end) {
errno = EINVAL;
return -1;
}
- for(; E <= end; s++, E++)
- *s = *E;
+ if(*expptr == 0x30) {
+ buflen--;
+ expptr++;
+ }
+ if(*last_zero == 0x30) {
+ *last_zero = 0x45; /* E */
+ s = last_zero + 1;
+ if(sign) *s++ = '-';
+ }
+ for(; expptr <= end; s++, expptr++)
+ *s = *expptr;
+ break;
+ } else if(*E == 0x30) {
+ if(*last_zero != 0x30)
+ last_zero = E;
}
}
if(E == end) {
errno = EINVAL;
return -1; /* No promised E */
}
+ } else {
+ /*
+ * Remove trailing zeros.
+ */
+ char *end = buf + buflen;
+ char *last_zero = end;
+ char *z;
+ for(z = end - 1; z > buf; z--) {
+ switch(*z) {
+ case 0x030:
+ last_zero = z;
+ case 0x31: case 0x32: case 0x33: case 0x34:
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+ continue;
+ default: /* Catch dot and other separators */
+ *z = 0x2e; /* Replace possible comma */
+ if(last_zero == z + 1) { /* leave x.0 */
+ last_zero++;
+ }
+ buflen = last_zero - buf;
+ *last_zero = '\0';
+ break;
+ }
+ break;
+ }
}
ret = cb(buf, buflen, app_key);