1 #include "simstring.h"
2
3 #include <assert.h>
4 #include <string.h>
5 #include <stdio.h>
6
7
8 static char thousand_sep = ',';
9 static char fraction_sep = '.';
10 static const char *large_number_string = "M";
11 static double large_number_factor = 1e99; // off
12 static int thousand_sep_exponent = 3;
13
14
15 /**
16 * Set thousand separator, used in money_to_string and
17 * number_to_string
18 * @author Hj. Malthaner
19 */
set_thousand_sep(char c)20 void set_thousand_sep(char c)
21 {
22 thousand_sep = c;
23 }
24
25
26 /**
27 * Set thousand exponent (3=1000, 4=10000), used in money_to_string and
28 * number_to_string
29 * @author prissi
30 */
set_thousand_sep_exponent(int new_thousand_sep_exponent)31 void set_thousand_sep_exponent(int new_thousand_sep_exponent)
32 {
33 thousand_sep_exponent = new_thousand_sep_exponent>0 ? new_thousand_sep_exponent : 3;
34 }
35
36
37 /**
38 * Set fraction separator, used in money_to_string and
39 * number_to_string
40 * @author Hj. Malthaner
41 */
set_fraction_sep(char c)42 void set_fraction_sep(char c)
43 {
44 fraction_sep = c;
45 }
46
47
get_fraction_sep()48 char get_fraction_sep()
49 {
50 return fraction_sep;
51 }
52
get_large_money_string()53 const char *get_large_money_string()
54 {
55 return large_number_string;
56 }
57
58
59 /**
60 * Set large money abbreviation, used in money_to_string and
61 * number_to_string
62 * @author prissi
63 */
set_large_amout(const char * s,const double v)64 void set_large_amout(const char *s, const double v)
65 {
66 large_number_string = s;
67 large_number_factor = v;
68 }
69
70
71 /**
72 * Formats a money value. Uses thousand separator. Two digits precision.
73 * Concludes format with $ sign. Buffer must be large enough, no checks
74 * are made!
75 * @author Hj. Malthaner
76 */
money_to_string(char * p,double f,const bool show_decimal)77 void money_to_string(char * p, double f, const bool show_decimal)
78 {
79 char tmp[128];
80 char *tp = tmp;
81 int i,l;
82
83 if( f>1000.0*large_number_factor ) {
84 sprintf( tp, "%.1f", f/large_number_factor );
85 }
86 else {
87 sprintf( tp, "%.2f", f );
88 }
89
90 // Hajo: skip sign
91 if(*tp == '-') {
92 *p ++ = *tp++;
93 }
94
95 // Hajo: format string
96 l = (long)(size_t)(strchr(tp,'.') - tp);
97
98 i = l % thousand_sep_exponent;
99
100 if(i != 0) {
101 memcpy(p, tp, i);
102 p += i;
103 *p++ = thousand_sep;
104 }
105
106 while(i < l) {
107 for( int j=0; j<thousand_sep_exponent; j++ ) {
108 *p++ = tp[i++];
109 }
110 *p++ = thousand_sep;
111 }
112 --p;
113
114 if( f>1000.0*large_number_factor ) {
115 // only decimals for smaller numbers; add large number string instead
116 for( i=0; large_number_string[i]!=0; i++ ) {
117 *p++ = large_number_string[i];
118 }
119 }
120 else if( show_decimal ) {
121 i = l+1;
122 // only decimals for smaller numbers
123 *p++ = fraction_sep;
124 // since it might be longer due to unicode characters
125 while( tp[i]!=0 ) {
126 *p++ = tp[i++];
127 }
128 }
129 *p++ = '$';
130 *p = 0;
131 }
132
133
number_to_string(char * p,double f,int decimals)134 int number_to_string(char * p, double f, int decimals )
135 {
136 char tmp[128];
137 char *tp = tmp;
138 long i,l;
139 bool has_decimals;
140
141 if( decimals>0 ) {
142 sprintf(tp,"%.*f",decimals,f);
143 has_decimals = true;
144 }
145 else {
146 sprintf(tp,"%.0f", f);
147 // some compilers produce trailing dots then ...
148 has_decimals = strchr(tp,'.')!=NULL;
149 }
150
151 // Hajo: skip sign
152 if(*tp == '-') {
153 *p ++ = *tp++;
154 }
155
156 // Hajo: format string
157 l = has_decimals ? (long)(size_t)(strchr(tp,'.') - tp) : strlen(tp);
158
159 i = l % thousand_sep_exponent;
160
161 if(i != 0) {
162 memcpy(p, tp, i);
163 p += i;
164 *p++ = thousand_sep;
165 }
166
167 while(i < l) {
168 for( int j=0; j<thousand_sep_exponent; j++ ) {
169 *p++ = tp[i++];
170 }
171 *p++ = thousand_sep;
172 }
173 p--;
174
175 if( has_decimals ) {
176 i++;
177 *p++ = fraction_sep;
178 while( tp[i]!=0 ) {
179 *p++ = tp[i++];
180 }
181 }
182 *p = 0;
183
184 return (int)(p-tmp);
185 }
186
187
188
189 /**
190 * tries to squeese a nubmer into a string with max_length
191 * Will still produce a too long string with too large nubmers!
192 */
number_to_string_fit(char * ret,double f,int decimals,int max_length)193 void number_to_string_fit(char *ret, double f, int decimals, int max_length )
194 {
195 char result[128];
196 int len;
197
198 number_to_string( result, f, decimals );
199 len = strlen(result);
200
201 if( len <= max_length ) {
202 // ok fits ...
203 strcpy( ret, result );
204 return;
205 }
206
207 // not fitting: first strip decimals
208 if( decimals > 0 && len <= max_length+decimals+1 ) {
209 tstrncpy( ret, result, len-(decimals) );
210 return;
211 }
212
213 // still not fitting: Then we have to really shorten the string
214 number_to_string( result, f/large_number_factor, 2 );
215 len = strlen( result );
216 const int llen = strlen(large_number_string);
217
218 // not fitting: then strip those remaining decimals
219 if( len+llen > max_length ) {
220 result[len-3] = 0;
221 }
222 strcat( result, large_number_string );
223 strcpy( ret, result );
224 }
225
226
227
228 // copies a n into a single line and maximum 128 characters
229 // @author prissi
make_single_line_string(const char * in,int number_of_lines)230 char *make_single_line_string(const char *in,int number_of_lines)
231 {
232 static char buf[64];
233 int pos;
234
235 // skip leading whitespaces
236 while(*in=='\n' || *in==' ') {
237 in++;
238 }
239 // start copying
240 for(pos=0; pos<62 && *in!=0 && number_of_lines>0; ) {
241 if((unsigned)(*in)>' ') {
242 buf[pos++] = *in++;
243 }
244 else {
245 // replace new lines by space
246 while(*in=='\n' || *in==' ') {
247 if(*in=='\n') {
248 number_of_lines--;
249 }
250 in++;
251 }
252 buf[pos++] = ' ';
253 }
254 }
255 // trim trailing spaces
256 while(pos>0 && buf[pos-1]==' ') {
257 pos--;
258 }
259 // end mark!
260 buf[pos] = 0;
261 return buf;
262 }
263
264
265
266
267 /**
268 * Terminated, length limited string copy. Copies at most
269 * n characters. Terminates dest string always by 0.
270 * @return dest
271 * @author Hj. Malthaner
272 */
tstrncpy(char * dest,const char * src,size_t n)273 char *tstrncpy(char *dest, const char *src, size_t n)
274 {
275 strncpy(dest, src, n);
276 dest[n-1] = '\0';
277
278 return dest;
279 }
280
281
282 /**
283 * Removes whitespace from the end of the string.
284 * Modifies the argument!
285 * @author Hj. Malthaner
286 */
rtrim(char * buf)287 void rtrim(char * buf)
288 {
289 for (size_t l = strlen(buf); l-- != 0 && 0 < buf[l] && buf[l] <= 32;) {
290 buf[l] = '\0';
291 }
292 }
293
294
295 /**
296 * Hands back a pointer to the first non-whitespace character
297 * of the argument. The argument must be 0 terminated
298 * @author Hj. Malthaner
299 */
ltrim(const char * p)300 const char * ltrim(const char *p)
301 {
302 while(*p != '\0' && *p > 0 && *p <= 32) {
303 p ++;
304 }
305 return p;
306 }
307
308
309 /**
310 * Trims a std::string by removing any beginning and ending space/tab characters.
311 * (Move to simstring?)
312 * @author Max Kielland
313 *
314 * @retval std::string The trimmed string.
315 */
trim(const std::string & str_)316 std::string trim(const std::string &str_)
317 {
318 std::string str(str_);
319
320 // left trim
321 std::string::size_type pos = str.find_first_not_of(" \t");
322 if( pos && pos != std::string::npos ) {
323 str = str.substr(pos);
324 }
325
326 // right trim
327 pos = str.find_last_not_of(" \t");
328 if( pos != str.length()-1 && pos != std::string::npos ) {
329 str = str.erase(pos+1);
330 }
331
332 return str;
333 }
334
335
strstart(char const * str,char const * start)336 char const* strstart(char const* str, char const* start)
337 {
338 while (*start != '\0') {
339 if (*str++ != *start++) return 0;
340 }
341 return str;
342 }
343