Subversion Repositories filter_foundry

Rev

Rev 193 | Rev 268 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
259 daniel-mar 1
/*
2
        This file is part of a common library
3
    Copyright (C) 2002-6 Toby Thain, toby@telegraphics.com.au
4
 
5
    This program is free software; you can redistribute it and/or modify
6
    it under the terms of the GNU General Public License as published by  
7
    the Free Software Foundation; either version 2 of the License, or
8
    (at your option) any later version.
9
 
10
    This program is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    GNU General Public License for more details.
14
 
15
    You should have received a copy of the GNU General Public License  
16
    along with this program; if not, write to the Free Software
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
*/
19
 
20
#include <stdarg.h>
21
#include <string.h> // memcpy
22
 
23
#include "sprintf_tiny.h"
24
#include "str.h"
25
 
26
// integer exponentiation;
27
// may not be more efficient than repeated multiplication, for small n
28
// (a small lookup table would be much quicker!)
29
// refer: http://www-mitpress.mit.edu/sicp/chapter1/node15.html
30
// and http://www.uvsc.edu/profpages/merrinst/exponentiation_and_java.html
31
long int_exp(long b,int n){
32
        long temp;
33
        if(n&1)
34
                return b*int_exp(b,n^1);
35
        else
36
                return n ? ( temp = int_exp(b,n>>1),temp*temp ) : 1;
37
}
38
 
39
// format a signed integer as a decimal string
40
// returns pointer after last character copied
41
// (easily generalised to other bases)
42
// *** this is reimplemented here mainly to avoid
43
// *** global data, a dealbreaker on MPW 68K
44
 
45
#define INT_BASE 10
46
 
47
// format a positive integer; return pointer after last digit
48
// DON'T add trailing NUL
49
char *udigits(char *p,unsigned long x,int base){
50
        long m = x/base;
51
        if(m)
52
                p = udigits(p,m,base);
53
        *p++ = (x%base)+'0';
54
        return p;
55
}
56
// format a possibly negative integer;
57
// return pointer to trailing NUL (after last digit)
58
char *int_str(char *dst,long x,int base){
59
        char *p = dst;
60
        if(x<0){ // handle negative case
61
                *p++ = '-';
62
                x = -x;
63
        }
64
        p = udigits(p,x,base);
65
        *p = 0; // add terminating null
66
        return p;
67
}      
68
 
69
// format unsigned integer into n decimal places, zero padded
70
// return pointer to trailing NUL (after last digit)
71
char *int_strpad(char *dst,unsigned long x,int places,int base){
72
        char *p;
73
        // generate digits, storing last to first
74
        for(p=dst+places;p!=dst;x/=base)
75
                *(--p) = (x%base)+'0';
76
        dst[places] = 0; // add terminating null
77
        return dst+places;
78
}
79
 
80
// quick and dirty way to format a double value as a string
81
// with a certain number of decimal places
82
// note INT_BASE^decplaces must be representable as signed long
83
// therefore WILL FAIL FOR (base 10) decplaces > 9 !!
84
// will also fail for fp values > 2^31-1
85
char *float_str(char *dst,double x,int places){
86
        char *q = dst;
87
 
88
        // format integer part
89
        q = int_str(q,(long)x /*truncated towards zero*/,INT_BASE);
90
        *q++ = '.';
91
 
92
        // format fractional part
93
        return int_strpad(q,(x-(long)x)*int_exp(INT_BASE,places)+.5,places,INT_BASE);
94
}
95
 
96
// *** this is here because the stdio sprintf()
97
// *** has global data, which breaks a 68K code resource build.
98
// *** (also, sprintf() brings a lot of unnecessary baggage)
99
 
100
int vsprintf_tiny(char *s,char *fmt,va_list v){
101
        char *p,*q;
102
 
103
        for(p=fmt,q=s;*p;)
104
                if(*p == '%'){
105
                        int lflag = 0;
106
                        ++p; // eat '%'
107
                        if(*p == 'l'){
108
                                lflag = 1;
109
                                ++p; // eat 'l'
110
                        }
111
                        switch(*p){
112
                        case 'c': *q++ = va_arg(v,int); break;
113
//                      case 'o': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),8); break;
114
                        case 'i':
115
                        case 'd': q = int_str(q,lflag ? va_arg(v,long) : va_arg(v,int),10); break;
116
                        case 'u': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),10); break;
117
//                      case 'x': q = udigits(q,lflag ? va_arg(v,unsigned long) : va_arg(v,unsigned int),16); break;
118
                        case 'F': q = float_str(q,va_arg(v,double),1); break;
119
                        case 'g':
120
                        case 'f': q = float_str(q,va_arg(v,double),4); break;
121
                        case 's': q = cat(q,va_arg(v,char*)); break;
122
                        default: *q++ = *p;
123
                        }
124
                        ++p; // eat format character
125
                }else
126
                        *q++ = *p++;
127
 
128
        *q = 0;
129
        return q - s;
130
}
131
 
132
int sprintf_tiny(char *s,char *fmt,...){
133
        va_list v;
134
        int n;
135
 
136
        va_start(v,fmt);
137
        n = vsprintf_tiny(s,fmt,v);
138
        va_end(v);
139
        return n;
140
}