Subversion Repositories filter_foundry

Compare Revisions

Regard whitespace Rev 192 → Rev 193

/trunk/telegraphics_common/tt/sprintf_tiny.c
0,0 → 1,140
/*
This file is part of a common library
Copyright (C) 2002-6 Toby Thain, toby@telegraphics.com.au
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
#include <stdarg.h>
#include <string.h> // memcpy
 
#include "sprintf_tiny.h"
#include "str.h"
 
// integer exponentiation;
// may not be more efficient than repeated multiplication, for small n
// (a small lookup table would be much quicker!)
// refer: http://www-mitpress.mit.edu/sicp/chapter1/node15.html
// and http://www.uvsc.edu/profpages/merrinst/exponentiation_and_java.html
long int_exp(long b,int n){
long temp;
if(n&1)
return b*int_exp(b,n^1);
else
return n ? ( temp = int_exp(b,n>>1),temp*temp ) : 1;
}
 
// format a signed integer as a decimal string
// returns pointer after last character copied
// (easily generalised to other bases)
// *** this is reimplemented here mainly to avoid
// *** global data, a dealbreaker on MPW 68K
 
#define INT_BASE 10
 
// format a positive integer; return pointer after last digit
// DON'T add trailing NUL
char *udigits(char *p,unsigned long x,int base){
long m = x/base;
if(m)
p = udigits(p,m,base);
*p++ = (x%base)+'0';
return p;
}
// format a possibly negative integer;
// return pointer to trailing NUL (after last digit)
char *int_str(char *dst,long x,int base){
char *p = dst;
if(x<0){ // handle negative case
*p++ = '-';
x = -x;
}
p = udigits(p,x,base);
*p = 0; // add terminating null
return p;
}
 
// format unsigned integer into n decimal places, zero padded
// return pointer to trailing NUL (after last digit)
char *int_strpad(char *dst,unsigned long x,int places,int base){
char *p;
// generate digits, storing last to first
for(p=dst+places;p!=dst;x/=base)
*(--p) = (x%base)+'0';
dst[places] = 0; // add terminating null
return dst+places;
}
 
// quick and dirty way to format a double value as a string
// with a certain number of decimal places
// note INT_BASE^decplaces must be representable as signed long
// therefore WILL FAIL FOR (base 10) decplaces > 9 !!
// will also fail for fp values > 2^31-1
char *float_str(char *dst,double x,int places){
char *q = dst;
 
// format integer part
q = int_str(q,(long)x /*truncated towards zero*/,INT_BASE);
*q++ = '.';
// format fractional part
return int_strpad(q,(x-(long)x)*int_exp(INT_BASE,places)+.5,places,INT_BASE);
}
 
// *** this is here because the stdio sprintf()
// *** has global data, which breaks a 68K code resource build.
// *** (also, sprintf() brings a lot of unnecessary baggage)
 
int vsprintf_tiny(char *s,char *fmt,va_list v){
char *p,*q;
for(p=fmt,q=s;*p;)
if(*p == '%'){
int lflag = 0;
++p; // eat '%'
if(*p == 'l'){
lflag = 1;
++p; // eat 'l'
}
switch(*p){
case 'c': *q++ = va_arg(v,int); break;
// case 'o': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),8); break;
case 'i':
case 'd': q = int_str(q,lflag ? va_arg(v,long) : va_arg(v,int),10); break;
case 'u': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),10); break;
// case 'x': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),16); break;
case 'F': q = float_str(q,va_arg(v,double),1); break;
case 'g':
case 'f': q = float_str(q,va_arg(v,double),4); break;
case 's': q = cat(q,va_arg(v,char*)); break;
default: *q++ = *p;
}
++p; // eat format character
}else
*q++ = *p++;
 
*q = 0;
return q - s;
}
 
int sprintf_tiny(char *s,char *fmt,...){
va_list v;
int n;
va_start(v,fmt);
n = vsprintf_tiny(s,fmt,v);
va_end(v);
return n;
}