]> git.saurik.com Git - apple/libplatform.git/blob - src/simple/string_io.c
2e581e85416da3a0051f508bbb1ae289458e0544
[apple/libplatform.git] / src / simple / string_io.c
1 /*
2 * Copyright (c) 2005, 2006, 2009 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <mach/mach_init.h>
27 #include <mach/vm_map.h>
28 #include <errno.h>
29
30 #include "os/internal.h"
31 #include "_simple.h"
32 #include "platform/string.h"
33 #include "platform/compat.h"
34
35 #ifndef VM_PAGE_SIZE
36 #define VM_PAGE_SIZE 4096
37 #endif
38
39 #define BUF_SIZE(s) (((BUF *)(s))->end - ((BUF *)(s))->buf + 1)
40 /* we use a small buffer to minimize stack usage constraints */
41 #define MYBUFSIZE 32
42
43 typedef struct _BUF {
44 char *buf;
45 char *ptr;
46 char *end;
47 int fd;
48 void (*full)(struct _BUF *);
49 } BUF;
50
51 /* flush the buffer */
52 static void
53 _flush(BUF *b)
54 {
55 char *buf = b->buf;
56 ssize_t n = b->ptr - buf;
57 ssize_t w;
58
59 while (n > 0) {
60 w = write(b->fd, buf, n);
61 if (w < 0) {
62 if (errno == EINTR || errno == EAGAIN)
63 continue;
64 break;
65 }
66 n -= w;
67 buf += n;
68 }
69 }
70
71 /* flush the buffer and reset the pointer */
72 static void
73 _flush_reset(BUF *b)
74 {
75 _flush(b);
76 b->ptr = b->buf;
77 }
78
79 /* enlarge the buffer */
80 static void
81 _enlarge(BUF *b)
82 {
83 vm_address_t new;
84 vm_size_t sold, snew;
85 intptr_t diff;
86 kern_return_t kr;
87
88 new = (vm_address_t)(b->end + 1);
89 if(vm_allocate(mach_task_self(), &new, VM_PAGE_SIZE, 0) == 0) {
90 /* page is adjacent */
91 b->end += VM_PAGE_SIZE;
92 return;
93 }
94 sold = BUF_SIZE(b);
95 snew = (sold + VM_PAGE_SIZE) & ~(VM_PAGE_SIZE - 1);
96 if ((kr = vm_allocate(mach_task_self(), &new, snew, 1)) != 0) {
97 __LIBPLATFORM_CLIENT_CRASH__(kr, "Failed to allocate memory for buffer");
98 }
99 diff = new - (vm_address_t)b->buf;
100 memmove((void *)new, b->buf, sold);
101 if((intptr_t)(b->buf) & (VM_PAGE_SIZE - 1)) {
102 sold &= ~(VM_PAGE_SIZE - 1);
103 b->buf = (char *)((intptr_t)(b->buf + VM_PAGE_SIZE) & ~(VM_PAGE_SIZE - 1));
104 b->end = (char *)(new + snew - 1);
105 } else
106 b->end += diff + VM_PAGE_SIZE;
107 if(sold > 0) {
108 vm_deallocate(mach_task_self(), (vm_address_t)b->buf, sold);
109 }
110 b->buf = (char *)new;
111 b->ptr += diff;
112 }
113
114 static inline void put_s(BUF *, _esc_func, const char *);
115 /* output a single character */
116 static inline void
117 put_c(BUF *b, _esc_func esc, unsigned char c)
118 {
119 const char *cp;
120
121 if(esc && (cp = esc(c)) != NULL)
122 put_s(b, NULL, cp);
123 else {
124 if(b->ptr >= b->end)
125 b->full(b);
126 *b->ptr++ = c;
127 }
128 }
129
130 /* output a null-terminated string */
131 static inline void
132 put_s(BUF *b, _esc_func esc, const char *str)
133 {
134 while(*str)
135 put_c(b, esc, *str++);
136 }
137
138 /* output a string of the specified size */
139 static inline void
140 put_n(BUF *b, _esc_func esc, const char *str, ssize_t n)
141 {
142 while(n-- > 0)
143 put_c(b, esc, *str++);
144 }
145
146 /*
147 * Output the signed decimal string representing the number in "in". "width" is
148 * the minimum field width, and "zero" is a boolean value, true for zero padding
149 * (otherwise blank padding).
150 */
151 static void
152 dec(BUF *b, _esc_func esc, long long in, int width, int zero)
153 {
154 char buf[32];
155 char *cp = buf + sizeof(buf);
156 ssize_t pad;
157 int neg = 0;
158 unsigned long long n = (unsigned long long)in;
159
160 if(in < 0) {
161 neg++;
162 width--;
163 n = ~n + 1;
164 }
165 *--cp = 0;
166 if(n) {
167 while(n) {
168 *--cp = (n % 10) + '0';
169 n /= 10;
170 }
171 } else
172 *--cp = '0';
173 if(neg && zero) {
174 put_c(b, esc, '-');
175 neg = 0;
176 }
177 pad = width - strlen(cp);
178 zero = zero ? '0' : ' ';
179 while(pad-- > 0)
180 put_c(b, esc, zero);
181 if(neg)
182 put_c(b, esc, '-');
183 put_s(b, esc, cp);
184 }
185
186 /*
187 * Output the hex string representing the number in "n". "width" is the
188 * minimum field width, and "zero" is a boolean value, true for zero padding
189 * (otherwise blank padding). "upper" is a boolean value, true for upper
190 * case hex characters, lower case otherwise. "p" is a boolean value, true
191 * if 0x should be prepended (for %p), otherwise nothing.
192 */
193 static const char _h[] = "0123456789abcdef";
194 static const char _H[] = "0123456789ABCDEF";
195 static const char _0x[] = "0x";
196
197 static void
198 hex(BUF *b, _esc_func esc, unsigned long long n, int width, int zero, int upper, int p)
199 {
200 char buf[32];
201 char *cp = buf + sizeof(buf);
202 const char *h = upper ? _H : _h;
203
204 *--cp = 0;
205 if(n) {
206 while(n) {
207 *--cp = h[n & 0xf];
208 n >>= 4;
209 }
210 } else
211 *--cp = '0';
212 if(p) {
213 width -= 2;
214 if(zero) {
215 put_s(b, esc, _0x);
216 p = 0;
217 }
218 }
219 width -= strlen(cp);
220 zero = zero ? '0' : ' ';
221 while(width-- > 0)
222 put_c(b, esc, zero);
223 if(p)
224 put_s(b, esc, _0x);
225 put_s(b, esc, cp);
226 }
227
228 /*
229 * Output the unsigned decimal string representing the number in "n". "width"
230 * is the minimum field width, and "zero" is a boolean value, true for zero
231 * padding (otherwise blank padding).
232 */
233 static void
234 udec(BUF *b, _esc_func esc, unsigned long long n, int width, int zero)
235 {
236 char buf[32];
237 char *cp = buf + sizeof(buf);
238 ssize_t pad;
239
240 *--cp = 0;
241 if(n) {
242 while(n) {
243 *--cp = (n % 10) + '0';
244 n /= 10;
245 }
246 } else
247 *--cp = '0';
248 pad = width - strlen(cp);
249 zero = zero ? '0' : ' ';
250 while(pad-- > 0)
251 put_c(b, esc, zero);
252 put_s(b, esc, cp);
253 }
254
255 /*
256 * Output the unsigned decimal string representing the number in "n", rounded
257 * to the nearest MB, KB or b. "width" is the minimum field width, and "zero"
258 * is a boolean value, true for zero padding (otherwise blank padding).
259 */
260 static void
261 ydec(BUF *b, _esc_func esc, unsigned long long n, int width, int zero)
262 {
263 if(n >= 10 * (1 << 20)) {
264 n += (1 << 19);
265 udec(b, esc, n >> 20, width, zero);
266 put_s(b, esc, "MB");
267 } else if (n >= 10 * (1 << 10)) {
268 n += (1 << 9);
269 udec(b, esc, n >> 10, width, zero);
270 put_s(b, esc, "KB");
271 } else {
272 udec(b, esc, n, width, zero);
273 put_s(b, esc, "b");
274 }
275 }
276
277 /*
278 * The actual engine for all the _simple_*printf routines.
279 */
280 static void
281 __simple_bprintf(BUF *b, _esc_func esc, const char *fmt, va_list ap)
282 {
283 while(*fmt) {
284 int lflag, zero, width;
285 char *cp;
286 if(!(cp = strchr(fmt, '%'))) {
287 put_s(b, esc, fmt);
288 break;
289 }
290 put_n(b, esc, fmt, cp - fmt);
291 fmt = cp + 1;
292 if(*fmt == '%') {
293 put_c(b, esc, '%');
294 fmt++;
295 continue;
296 }
297 lflag = zero = width = 0;
298 for(;;) {
299 switch(*fmt) {
300 case '0':
301 zero++;
302 fmt++;
303 /* drop through */
304 case '1': case '2': case '3': case '4': case '5':
305 case '6': case '7': case '8': case '9':
306 while(*fmt >= '0' && *fmt <= '9')
307 width = 10 * width + (*fmt++ - '0');
308 continue;
309 case 'c':
310 zero = zero ? '0' : ' ';
311 width--;
312 while(width-- > 0)
313 put_c(b, esc, zero);
314 put_c(b, esc, va_arg(ap, int));
315 break;
316 case 'd': case 'i':
317 switch(lflag) {
318 case 0:
319 dec(b, esc, va_arg(ap, int), width, zero);
320 break;
321 case 1:
322 dec(b, esc, va_arg(ap, long), width, zero);
323 break;
324 default:
325 dec(b, esc, va_arg(ap, long long), width, zero);
326 break;
327 }
328 break;
329 case 'l':
330 lflag++;
331 fmt++;
332 continue;
333 case 'p':
334 hex(b, esc, (unsigned long)va_arg(ap, void *), width, zero, 0, 1);
335 break;
336 case 's':
337 cp = va_arg(ap, char *);
338 cp = cp ? cp : "(null)";
339 width -= strlen(cp);
340 zero = zero ? '0' : ' ';
341 while(width-- > 0)
342 put_c(b, esc, zero);
343 put_s(b, esc, cp);
344 break;
345 case 'u':
346 switch(lflag) {
347 case 0:
348 udec(b, esc, va_arg(ap, unsigned int), width, zero);
349 break;
350 case 1:
351 udec(b, esc, va_arg(ap, unsigned long), width, zero);
352 break;
353 default:
354 udec(b, esc, va_arg(ap, unsigned long long), width, zero);
355 break;
356 }
357 break;
358 case 'X': case 'x':
359 switch(lflag) {
360 case 0:
361 hex(b, esc, va_arg(ap, unsigned int), width, zero,
362 *fmt == 'X', 0);
363 break;
364 case 1:
365 hex(b, esc, va_arg(ap, unsigned long), width, zero,
366 *fmt == 'X', 0);
367 break;
368 default:
369 hex(b, esc, va_arg(ap, unsigned long long), width, zero,
370 *fmt == 'X', 0);
371 break;
372 }
373 break;
374 case 'y':
375 switch(lflag) {
376 case 0:
377 ydec(b, esc, va_arg(ap, unsigned int), width, zero);
378 break;
379 case 1:
380 ydec(b, esc, va_arg(ap, unsigned long), width, zero);
381 break;
382 default:
383 ydec(b, esc, va_arg(ap, unsigned long long), width, zero);
384 break;
385 }
386 break;
387 default:
388 put_c(b, esc, *fmt);
389 break;
390 }
391 break;
392 }
393 fmt++;
394 }
395 }
396
397 /*
398 * A simplified vfprintf variant. The format string is interpreted with
399 * arguments from the va_list, and the results are written to the given
400 * file descriptor.
401 */
402 void
403 _simple_vdprintf(int fd, const char *fmt, va_list ap)
404 {
405 BUF b;
406 char buf[MYBUFSIZE];
407
408 b.buf = buf;
409 b.fd = fd;
410 b.ptr = b.buf;
411 b.end = b.buf + MYBUFSIZE;
412 b.full = _flush_reset;
413 __simple_bprintf(&b, NULL, fmt, ap);
414 _flush(&b);
415 }
416
417 /*
418 * A simplified fprintf variant. The format string is interpreted with
419 * arguments from the variable argument list, and the results are written
420 * to the given file descriptor.
421 */
422 void
423 _simple_dprintf(int fd, const char *fmt, ...)
424 {
425 va_list ap;
426
427 va_start(ap, fmt);
428 _simple_vdprintf(fd, fmt, ap);
429 va_end(ap);
430 }
431
432 /*
433 * A simplified string allocate routine. Pass the opaque pointer to structure
434 * to _simple_*sprintf() routines. Use _simple_string() to retrieve the
435 * current string (the string is guaranteed to be null terminated only on
436 * the call to _simple_string()). Use _simple_sfree() to free the structure
437 * and string memory.
438 */
439 _SIMPLE_STRING
440 _simple_salloc(void)
441 {
442 kern_return_t kr;
443 BUF *b;
444
445 kr = vm_allocate(mach_task_self(), (vm_address_t *)&b, VM_PAGE_SIZE, 1);
446 if (kr) {
447 __LIBPLATFORM_CLIENT_CRASH__(kr, "Failed to allocate memory for string");
448 }
449 b->ptr = b->buf = (char *)b + sizeof(BUF);
450 b->end = (char *)b + VM_PAGE_SIZE - 1;
451 b->full = _enlarge;
452 return (_SIMPLE_STRING)b;
453 }
454
455 /*
456 * The format string is interpreted with arguments from the va_list, and the
457 * results are appended to the string maintained by the opaque structure, as
458 * returned by a previous call to _simple_salloc(). Always returns 0.
459 */
460 int
461 _simple_vsprintf(_SIMPLE_STRING b, const char *fmt, va_list ap)
462 {
463 return _simple_vesprintf(b, NULL, fmt, ap);
464 }
465
466 /*
467 * The format string is interpreted with arguments from the variable argument
468 * list, and the results are appended to the string maintained by the opaque
469 * structure, as returned by a previous call to _simple_salloc().
470 * Always returns 0.
471 */
472 int
473 _simple_sprintf(_SIMPLE_STRING b, const char *fmt, ...)
474 {
475 va_list ap;
476 int ret;
477
478 va_start(ap, fmt);
479 ret = _simple_vesprintf(b, NULL, fmt, ap);
480 va_end(ap);
481 return ret;
482 }
483
484 /*
485 * Like _simple_vsprintf(), except __esc is a function to call on each
486 * character; the function returns NULL if the character should be passed
487 * as is, otherwise, the returned character string is used instead.
488 */
489 int
490 _simple_vesprintf(_SIMPLE_STRING b, _esc_func esc, const char *fmt, va_list ap)
491 {
492 __simple_bprintf((BUF *)b, esc, fmt, ap);
493 return 0;
494 }
495
496 /*
497 * Like _simple_sprintf(), except __esc is a function to call on each
498 * character; the function returns NULL if the character should be passed
499 * as is, otherwise, the returned character string is used instead.
500 */
501 int _simple_esprintf(_SIMPLE_STRING b, _esc_func esc, const char *fmt, ...)
502 {
503 va_list ap;
504 int ret;
505
506 va_start(ap, fmt);
507 ret = _simple_vesprintf(b, esc, fmt, ap);
508 va_end(ap);
509 return ret;
510 }
511
512 /*
513 * Return the null terminated string from the opaque structure, as returned
514 * by a previous call to _simple_salloc().
515 */
516 char *
517 _simple_string(_SIMPLE_STRING b)
518 {
519 *((BUF *)b)->ptr = 0;
520 return ((BUF *)b)->buf;
521 }
522
523 /*
524 * Reposition the pointer to the first null in the buffer. After a call to
525 * _simple_string, the buffer can be modified, and shrunk.
526 */
527 void
528 _simple_sresize(_SIMPLE_STRING b)
529 {
530 ((BUF *)b)->ptr = ((BUF *)b)->buf + strlen(((BUF *)b)->buf);
531 }
532
533 /*
534 * Append the null-terminated string to the string associated with the opaque
535 * structure. Always returns 0.
536 */
537 int
538 _simple_sappend(_SIMPLE_STRING b, const char *str)
539 {
540 return _simple_esappend(b, NULL, str);
541 }
542
543 /*
544 * Like _simple_sappend(), except __esc is a function to call on each
545 * character; the function returns NULL if the character should be passed
546 * as is, otherwise, the returned character string is used instead.
547 */
548 int _simple_esappend(_SIMPLE_STRING b, _esc_func esc, const char *str)
549 {
550 put_s((BUF *)b, esc, str);
551 return 0;
552 }
553
554 /*
555 * Write the string associated with the opaque structure to the file descriptor.
556 */
557 void
558 _simple_put(_SIMPLE_STRING b, int fd)
559 {
560 ((BUF *)b)->fd = fd;
561 _flush((BUF *)b);
562 }
563
564 /*
565 * Write the string associated with the opaque structure and a trailing newline,
566 * to the file descriptor.
567 */
568 void
569 _simple_putline(_SIMPLE_STRING b, int fd)
570 {
571 ((BUF *)b)->fd = fd;
572 *((BUF *)b)->ptr++ = '\n';
573 _flush((BUF *)b);
574 ((BUF *)b)->ptr--;
575 }
576
577 /*
578 * Free the opaque structure, and the associated string.
579 */
580 void
581 _simple_sfree(_SIMPLE_STRING b)
582 {
583 vm_size_t s;
584
585 if(b == NULL) return;
586 if(((intptr_t)(((BUF *)b)->buf) & (VM_PAGE_SIZE - 1)) == 0) {
587 vm_deallocate(mach_task_self(), (vm_address_t)((BUF *)b)->buf, BUF_SIZE(b));
588 s = VM_PAGE_SIZE;
589 } else {
590 s = ((BUF *)b)->end - (char *)b + 1;
591 }
592 vm_deallocate(mach_task_self(), (vm_address_t)b, s);
593 }