|
|
researchv10 Norman
/* Copyright 1990, AT&T Bell Labs */
/* Canonicalize the number string pointed to by dp, of length
len. Put the result in kp.
A field of length zero, or all blank, is regarded as 0.
Over/underflow is rendered as huge or zero and properly signed.
It happens 1e+-1022.
Canonicalized strings may be compared as strings of unsigned
chars. For good measure, a canonical string has no zero bytes.
Syntax: optionally signed floating point, with optional
leading spaces. A syntax deviation ends the number.
Form of output: packed in 4-bit nibbles. First
3 nibbles count the number N of significant digits
before the decimal point. The quantity actually stored
is 2048+sign(x)*(N+1024). Further nibbles contain
1 decimal digit d each, stored as d+2 if x is positive
and as 10-d if x is negative. Leading and trailing
zeros are stripped, and a trailing "digit" d = -1
is appended. (The trailing digit handled like all others,
so encodes as 1 or 0xb according to the sign of x.)
An odd number of nibbles is padded with zero.
Buglet: overflow is reported if output is exactly filled.
*/
#include "fsort.h"
#define encode(x) (neg? 10-(x): (x)+2)
#define putdig(x) (nib? (*dig=encode(x)<<4, nib=0): \
(*dig++|=encode(x), nib=1))
static int gflag;
int
gcode(uchar *dp, uchar*kp, int len, struct field *f)
{
int ret;
gflag++;
ret = ncode(dp, kp, len, f);
gflag--;
return ret;
}
int
ncode(uchar *dp, uchar*kp, int len, struct field *f)
{
uchar *dig = kp + 1; /* byte for next digit */
int nib = 0; /* high nibble 1, low nibble 0 */
uchar *cp = dp;
uchar *ep = cp + len; /* end pointer */
int zeros = 0; /* count zeros seen but not installed */
int sigdig = 1024;
int neg = f->rflag; /* 0 for +, 1 for - */
int decimal = 0;
int n, inv;
kp[1] = 0;
for( ; cp<ep ; cp++) /* eat blanks */
if(*cp!=' ' && *cp!='\t')
break;
if(cp < ep) /* eat sign */
switch(*cp) {
case '-':
neg ^= 1;
case '+':
cp++;
}
for( ; cp<ep; cp++) /* eat leading zeros */
if(*cp != '0')
break;
if(*cp=='.' && cp<ep) { /* decimal point among lead zeros */
decimal++;
for(cp++; cp<ep; cp++) {
if(*cp != '0')
break;
sigdig--;
}
}
if(*cp>'9' || *cp<'0' || cp>=ep) { /* no sig digit*/
sigdig = 0;
neg = 0;
goto retzero;
}
for( ; cp<ep; cp++) {
switch(*cp) {
default:
goto out;
case '.':
if(decimal)
goto out;
decimal++;
continue;
case '0':
zeros++;
if(!decimal)
sigdig++;
continue;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
for( ; zeros>0; zeros--)
putdig(0);
n = *cp - '0';
putdig(n);
if(!decimal)
sigdig++;
continue;
case 'e':
case 'E':
if(!gflag)
goto out;
inv = 1;
if(cp < ep) switch(*++cp) {
case '-':
inv = -1;
case '+':
cp++;
}
if(*cp>'9' || *cp<'0' || cp>=ep)
goto out;
for(n=0; cp<ep; cp++) {
int c = *cp;
if(c<'0' || c>'9')
break;
if((n = 10*n+c-'0') >= 0)
continue;
sigdig = 2047*inv;
goto out;
}
sigdig += n*inv;
goto out;
}
}
out:
if(sigdig<0 || sigdig>=2047) {
sigdig = sigdig<0? 0: 2047;
warn("numeric field overflow", (char*)dp, len);
dig = kp + 1;
*dig = 0;
nib = 0;
}
retzero:
if(neg)
sigdig = 2048 - sigdig;
else
sigdig = 2048 + sigdig;
kp[0] = sigdig >> 4;
kp[1] |= sigdig << 4;
putdig(-1);
return dig - kp + 1 - nib;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.