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