| author | Borja Ferrer <faluco@alliedmods.net> |
| Fri Dec 29 03:21:09 2006 +0000 (2006-12-29) | |
| changeset 227 | 72ab30bba3b9 |
| child 230 | f6abafc7c96c |
| permissions | -rw-r--r-- |
1 #include "sm_stringutil.h"
3 #define ALT 0x00000001 /* alternate form */
4 #define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */
5 #define LADJUST 0x00000004 /* left adjustment */
6 #define LONGDBL 0x00000008 /* long double */
7 #define LONGINT 0x00000010 /* long integer */
8 #define QUADINT 0x00000020 /* quad integer */
9 #define SHORTINT 0x00000040 /* short integer */
10 #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
11 #define FPT 0x00000100 /* floating point number */
12 #define to_digit(c) ((c) - '0')
13 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
14 #define to_char(n) ((n) + '0')
16 //:TODO: fix this macro when we have a debugger
18 #define CHECK_ARGS(n)/* \
19 if ((arg+n) > args) { \
20 LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
21 return 0; \
22 }
23 */
25 void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int prec)
26 {
27 int size = 0;
28 char *buf;
29 static char nlstr[] = {'(','n','u','l','l',')','\0'};
31 buf = *buf_p;
33 if (string == NULL)
34 {
35 string = nlstr;
36 prec = -1;
37 }
39 if (prec >= 0)
40 {
41 for (size = 0; size < prec; size++)
42 {
43 if (string[size] == '\0')
44 {
45 break;
46 }
47 }
48 } else {
49 while (string[size++]);
50 size--;
51 }
53 if (size > (int)maxlen)
54 {
55 size = maxlen;
56 }
58 maxlen -= size;
59 width -= size;
61 while (size--)
62 {
63 *buf++ = *string++;
64 }
66 while ((width-- > 0) && maxlen)
67 {
68 *buf++ = ' ';
69 maxlen--;
70 }
72 *buf_p = buf;
73 }
75 void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
76 {
77 char text[32];
78 int digits;
79 double signedVal;
80 char *buf;
81 int val;
83 // get the sign
84 signedVal = fval;
85 if (fval < 0)
86 {
87 fval = -fval;
88 }
90 // write the float number
91 digits = 0;
92 val = (int)fval;
93 do
94 {
95 text[digits++] = '0' + val % 10;
96 val /= 10;
97 } while (val);
99 if (signedVal < 0)
100 {
101 text[digits++] = '-';
102 }
104 buf = *buf_p;
106 while ((digits < width) && maxlen)
107 {
108 *buf++ = ' ';
109 width--;
110 maxlen--;
111 }
113 while ((digits--) && maxlen)
114 {
115 *buf++ = text[digits];
116 maxlen--;
117 }
119 *buf_p = buf;
121 if (prec < 0)
122 {
123 prec = 6;
124 }
125 // write the fraction
126 digits = 0;
127 while (digits < prec)
128 {
129 fval -= (int)fval;
130 fval *= 10.0;
131 val = (int)fval;
132 text[digits++] = '0' + val % 10;
133 }
135 if ((digits > 0) && maxlen)
136 {
137 buf = *buf_p;
138 *buf++ = '.';
139 maxlen--;
140 for (prec = 0; maxlen && (prec < digits); prec++)
141 {
142 *buf++ = text[prec];
143 maxlen--;
144 }
145 *buf_p = buf;
146 }
147 }
149 void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
150 {
151 char text[32];
152 int digits;
153 char *buf;
155 digits = 0;
156 do
157 {
158 text[digits++] = '0' + val % 10;
159 val /= 10;
160 } while (val);
162 buf = *buf_p;
164 if (!(flags & LADJUST))
165 {
166 while (digits < width && maxlen)
167 {
168 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
169 width--;
170 maxlen--;
171 }
172 }
174 while (digits-- && maxlen)
175 {
176 *buf++ = text[digits];
177 width--;
178 maxlen--;
179 }
181 if (flags & LADJUST)
182 {
183 while (width-- && maxlen)
184 {
185 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
186 maxlen--;
187 }
188 }
190 *buf_p = buf;
191 }
193 void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
194 {
195 char text[32];
196 int digits;
197 int signedVal;
198 char *buf;
199 unsigned int unsignedVal;
201 digits = 0;
202 signedVal = val;
203 if (val < 0)
204 {
205 /* we want the unsigned version */
206 unsignedVal = abs(val);
207 } else {
208 unsignedVal = val;
209 }
210 do
211 {
212 text[digits++] = '0' + unsignedVal % 10;
213 unsignedVal /= 10;
214 } while (unsignedVal);
216 if (signedVal < 0)
217 {
218 text[digits++] = '-';
219 }
221 buf = *buf_p;
223 if (!(flags & LADJUST))
224 {
225 while ((digits < width) && maxlen)
226 {
227 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
228 width--;
229 maxlen--;
230 }
231 }
233 while (digits-- && maxlen)
234 {
235 *buf++ = text[digits];
236 width--;
237 maxlen--;
238 }
240 if (flags & LADJUST)
241 {
242 while (width-- && maxlen)
243 {
244 *buf++ = (flags & ZEROPAD) ? '0' : ' ';
245 maxlen--;
246 }
247 }
249 *buf_p = buf;
250 }
252 size_t atcprintf(char *buffer, size_t maxlen, const char *format, IPluginContext *pCtx, const cell_t *params, int *param)
253 {
254 int arg;
255 //int args = params[0] / sizeof(cell); //:TODO: wrong, i think params[0] has now the param count not the byte count
256 // either way this is only used when the above macro is fixed, until then not needed
257 char *buf_p;
258 char ch;
259 int flags;
260 int width;
261 int prec;
262 int n;
263 char sign;
264 const char *fmt;
265 size_t llen = maxlen;
267 buf_p = buffer;
268 arg = *param;
269 fmt = format;
271 while (true)
272 {
273 // run through the format string until we hit a '%' or '\0'
274 for (ch = *fmt; llen && ((ch = *fmt) != '\0') && (ch != '%'); fmt++)
275 {
276 *buf_p++ = ch;
277 llen--;
278 }
279 if ((ch == '\0') || (llen <= 0))
280 {
281 goto done;
282 }
284 // skip over the '%'
285 fmt++;
287 // reset formatting state
288 flags = 0;
289 width = 0;
290 prec = -1;
291 sign = '\0';
293 rflag:
294 ch = *fmt++;
295 reswitch:
296 switch(ch)
297 {
298 case '-':
299 {
300 flags |= LADJUST;
301 goto rflag;
302 }
303 case '.':
304 {
305 n = 0;
306 while(is_digit((ch = *fmt++)))
307 {
308 n = 10 * n + (ch - '0');
309 }
310 prec = (n < 0) ? -1 : n;
311 goto reswitch;
312 }
313 case '0':
314 {
315 flags |= ZEROPAD;
316 goto rflag;
317 }
318 case '1':
319 case '2':
320 case '3':
321 case '4':
322 case '5':
323 case '6':
324 case '7':
325 case '8':
326 case '9':
327 {
328 n = 0;
329 do
330 {
331 n = 10 * n + (ch - '0');
332 ch = *fmt++;
333 } while(is_digit(ch));
334 width = n;
335 goto reswitch;
336 }
337 case 'c':
338 {
339 CHECK_ARGS(0);
340 if (llen <= 1)
341 {
342 goto done;
343 }
344 char *c;
345 pCtx->LocalToString(params[arg], &c);
346 *buf_p++ = *c;
347 llen--;
348 arg++;
349 break;
350 }
351 case 'd':
352 case 'i':
353 {
354 CHECK_ARGS(0);
355 cell_t *value;
356 pCtx->LocalToPhysAddr(params[arg], &value);
357 AddInt(&buf_p, llen, static_cast<int>(*value), width, flags);
358 arg++;
359 break;
360 }
361 case 'u':
362 {
363 CHECK_ARGS(0);
364 cell_t *value;
365 pCtx->LocalToPhysAddr(params[arg], &value);
366 AddUInt(&buf_p, llen, static_cast<unsigned int>(*value), width, flags);
367 arg++;
368 break;
369 }
370 case 'f':
371 {
372 CHECK_ARGS(0);
373 cell_t *value;
374 pCtx->LocalToPhysAddr(params[arg], &value);
375 AddFloat(&buf_p, llen, ctof(*value), width, prec);
376 arg++;
377 break;
378 }
379 case 's':
380 {
381 CHECK_ARGS(0);
382 char *str;
383 pCtx->LocalToString(params[arg], &str);
384 AddString(&buf_p, llen, str, width, prec);
385 arg++;
386 break;
387 }
388 case '%':
389 {
390 if (llen <= 1)
391 {
392 goto done;
393 }
394 *buf_p++ = ch;
395 llen--;
396 break;
397 }
398 case '\0':
399 {
400 if (llen <= 1)
401 {
402 goto done;
403 }
404 *buf_p++ = '%';
405 llen--;
406 goto done;
407 }
408 default:
409 {
410 if (llen <= 1)
411 {
412 goto done;
413 }
414 *buf_p++ = ch;
415 llen--;
416 break;
417 }
418 }
419 }
421 done:
422 *buf_p = '\0';
423 *param = arg;
424 return (maxlen - llen);
425 }