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