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