dslinux/user/perl/uts sprintf_wrap.c strtol_wrap.c
cayenne
dslinux_cayenne at user.in-berlin.de
Mon Dec 4 18:02:14 CET 2006
Update of /cvsroot/dslinux/dslinux/user/perl/uts
In directory antilope:/tmp/cvs-serv17422/uts
Added Files:
sprintf_wrap.c strtol_wrap.c
Log Message:
Adding fresh perl source to HEAD to branch from
--- NEW FILE: sprintf_wrap.c ---
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
char *UTS_sprintf_wrap();
char *do_efmt();
char *do_gfmt();
char *Fill();
/* main(argc, argv)
* char **argv;
* {
* double d;
* char *Fmt, *Ret;
* char obuf[200];
*
* assert(argc > 2);
* Fmt = argv[1];
* d = strtod(argv[2], (char **)0);
*
* putchar('{');
* printf(Fmt, d);
* printf("}\n");
*
* Ret = UTS_sprintf_wrap(obuf, Fmt, d);
* assert(Ret == obuf);
*
* printf("{%s}\n", obuf);
* }
*/
char *
UTS_sprintf_wrap(obuf, fmt, d,
a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
char *obuf, *fmt;
double d;
{
int fmtlen, Width=0, Precision=6, Alt=0, Plus=0, Minus=0,
Zero = 0;
int FmtChar, BaseFmt = 0;
char *f = fmt, *AfterWidth = 0, *AfterPrecision = 0;
char *Dot;
if(*f++ != '%') {
return
sprintf(obuf, fmt, d, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
}
fmtlen = strlen(fmt);
FmtChar = fmt[fmtlen - 1];
switch(FmtChar) {
case 'f':
case 'F':
return
sprintf(obuf, fmt, d, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
case 'e':
case 'E':
BaseFmt = 'e';
goto BaseFmt_IsSet;
case 'g':
case 'G':
BaseFmt = 'g';
BaseFmt_IsSet:
if(*f == '#') { Alt = 1; ++f; } /* Always has '.' */
if(*f == '+') { Plus = 1; ++f; } /* Force explicit sign */
if(*f == '-') { Minus = 1; ++f; } /* Left justify */
if(*f == '0') { Zero = 1; ++f;} /* Fill using 0s*/
if(Dot = strchr(f, '.')) {
Precision = strtol(Dot+1, &AfterPrecision, 0);
}
if(!Dot || (Dot && Dot > f)) { /* Next char=='.' => no width*/
Width = strtol(f, &AfterWidth, 0);
}
if(Dot) { f = AfterPrecision; }
else if(AfterWidth) { f = AfterWidth; }
if(*f != FmtChar) goto regular_sprintf;
/* It doesn't look like a f.p. sprintf call */
/* from Perl_sv_vcatpvfn */
if(BaseFmt == 'e') {
return do_efmt(d, obuf, Width, Precision, Alt,
Plus, Minus, Zero, FmtChar == 'E');
} else {
return do_gfmt(d, obuf, Width, Precision, Alt,
Plus, Minus, Zero, FmtChar == 'G');
}
default:
regular_sprintf:
return
sprintf(obuf, fmt, d, a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
}
}
char *
do_efmt(d, obuf, Width, Precision, Alt, Plus, Minus, Zero, UpperCase)
char *obuf;
double d;
{
char *Ecvt;
char *ob;
int decpt, sign, E;
int len;
int AllZeroes = 0;
Ecvt = ecvt( d , Precision+1, &decpt, &sign);
/* fprintf(stderr, "decpt=%d, sign=%d\n", decpt, sign); */
len = strlen(Ecvt);
if(strspn(Ecvt, "0") == len) AllZeroes = 1;
ob = obuf;
if(sign) *ob++ = '-';
else if(Plus) *ob++ = '+';
*ob++ = Ecvt[0];
if(Precision > 0 || Alt) *ob++ = '.';
strcpy(ob, &Ecvt[1]);
ob += strlen(ob); /* ADVANCE TO END OF WHAT WE JUST ADDED */
*ob++ = UpperCase ? 'E' : 'e';
if(AllZeroes) E = 0;
else E = decpt - 1;
if(E < 0) { *ob++ = '-'; E = -E; }
else { *ob++ = '+'; }
sprintf(ob, "%.2d", E); /* Too much horsepower used here */
if(Width > strlen(obuf)) return Fill(obuf, Width, Minus, Zero);
else return obuf;
}
char *
do_gfmt(d, obuf, Width, Precision, Alt, Plus, Minus, Zero, UpperCase)
char *obuf;
double d;
{
char *Ecvt = gcvt(d, Precision ? Precision : 1, obuf);
int len = strlen(obuf);
/* gcvt fails (maybe give a warning? For now return empty string): */
if(!Ecvt) { *obuf = '\0'; return obuf; }
/* printf("Ecvt='%s'\n", Ecvt); */
if(Plus && (Ecvt[0] != '-')) {
memmove(obuf+1, obuf, len+1); /* "+1" to get '\0' at end */
obuf[0] = '+';
++len;
}
if(Alt && !strchr(Ecvt, '.')) {
int LenUpTo_E = strcspn(obuf, "eE");
int E_etc_len = strlen(&obuf[LenUpTo_E]);
/* ABOVE: Will be 0 if there's no E/e because */
/* strcspn will return length of whole string */
if(E_etc_len)
memmove(obuf+LenUpTo_E+1, obuf+LenUpTo_E, E_etc_len);
obuf[LenUpTo_E] = '.';
obuf[LenUpTo_E + 1 + E_etc_len ] = '\0';
}
{ char *E_loc;
if(UpperCase && (E_loc = strchr(obuf, 'e'))) { *E_loc = 'E'; }
}
if(Width > len)
return Fill(obuf, Width, Minus, Zero);
else
return obuf;
}
char *
Fill(obuf, Width, LeftJustify, Zero)
char *obuf;
{
int W = strlen(obuf);
int diff = Width - W;
/* LeftJustify means there was a '-' flag, and in that case, */
/* printf man page (UTS4.4) says ignore '0' */
char FillChar = (Zero && !LeftJustify) ? '0' : ' ';
int i;
int LeftFill = ! LeftJustify;
if(Width <= W) return obuf;
if(LeftFill) {
memmove(obuf+diff, obuf, W+1); /* "+1" to get '\0' at end */
for(i=0 ; i < diff ; ++i) { obuf[i] = FillChar; }
} else {
for(i=W ; i < Width ; ++i)
obuf[i] = FillChar;
obuf[Width] = '\0';
}
return obuf;
}
--- NEW FILE: strtol_wrap.c ---
/* A wrapper around strtol() and strtoul() to correct some
* "out of bounds" cases that don't work well on at least UTS.
* If a value is Larger than the max, strto[u]l should return
* the max value, and set errno to ERANGE
* The same if a value is smaller than the min value (only
* relevant for strtol(); not strtoul()), except the minimum
* value is returned (and errno == ERANGE).
*/
#include <ctype.h>
#include <string.h>
#include <sys/errno.h>
#include <stdlib.h>
extern int errno;
#undef I32
#undef U32
#define I32 int
#define U32 unsigned int
struct base_info {
char *ValidChars;
char *Ulong_max_str;
char *Long_max_str;
char *Long_min_str; /* Absolute value */
int Ulong_max_str_len;
int Long_max_str_len;
int Long_min_str_len; /* Absolute value */
U32 Ulong_max;
I32 Long_max;
I32 Long_min; /* NOT Absolute value */
};
static struct base_info Base_info[37];
static struct base_info Base_info_16 = {
"0123456789abcdefABCDEF",
"4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
10, 10, 10,
4294967295, 2147483647, - 2147483648,
};
static struct base_info Base_info_10 = {
"0123456789",
"4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
10, 10, 10,
4294967295, 2147483647, - 2147483648,
};
/* Used eventually (if this is fully developed) to hold info
* for processing bases 2-36. So that we can just plug the
* base in as a selector for its info, we sacrifice
* Base_info[0] and Base_info[1] (unless they are used
* at some point for special information).
*/
/* This may be replaced later by something more universal */
static void
init_Base_info()
{
if(Base_info[10].ValidChars) return;
Base_info[10] = Base_info_10;
Base_info[16] = Base_info_16;
}
unsigned int
strtoul_wrap32(char *s, char **pEnd, int base)
{
int Len;
int isNegated = 0;
char *sOrig = s;
init_Base_info();
while(*s && isspace(*s)) ++s;
if(*s == '-') {
++isNegated;
++s;
while(*s && isspace(*s)) ++s;
}
if(base == 0) {
if(*s == '0') {
if(s[1] == 'x' || s[1] == 'X') {
s += 2;
base = 16;
} else {
++s;
base = 8;
}
} else if(isdigit(*s)) {
base = 10;
}
}
if(base != 10) {
return strtoul(sOrig, pEnd, base);
}
Len = strspn(s, Base_info[base].ValidChars);
if(Len > Base_info[base].Ulong_max_str_len
||
(Len == Base_info[base].Ulong_max_str_len
&&
strncmp(Base_info[base].Ulong_max_str, s, Len) < 0)
) {
/* In case isNegated is set - what to do?? */
/* Mightn't we say a negative number is ERANGE for strtoul? */
errno = ERANGE;
return Base_info[base].Ulong_max;
}
return strtoul(sOrig, pEnd, base);
}
int
strtol_wrap32(char *s, char **pEnd, int base)
{
int Len;
int isNegated = 0;
char *sOrig = s;
init_Base_info();
while(*s && isspace(*s)) ++s;
if(*s == '-') {
++isNegated;
++s;
while(*s && isspace(*s)) ++s;
}
if(base == 0) {
if(*s == '0') {
if(s[1] == 'x' || s[1] == 'X') {
s += 2;
base = 16;
} else {
++s;
base = 8;
}
} else if(isdigit(*s)) {
base = 10;
}
}
if(base != 10) {
return strtol(sOrig, pEnd, base);
}
Len = strspn(s, Base_info[base].ValidChars);
if(Len > Base_info[base].Long_max_str_len
||
(!isNegated && Len == Base_info[base].Long_max_str_len
&&
strncmp(Base_info[base].Long_max_str, s, Len) < 0)
||
(isNegated && Len == Base_info[base].Long_min_str_len
&&
strncmp(Base_info[base].Long_min_str, s, Len) < 0)
) {
/* In case isNegated is set - what to do?? */
/* Mightn't we say a negative number is ERANGE for strtol? */
errno = ERANGE;
return(isNegated ? Base_info[base].Long_min
:
Base_info[base].Long_min);
}
return strtol(sOrig, pEnd, base);
}
More information about the dslinux-commit
mailing list