]> git.saurik.com Git - apple/libplatform.git/blob - src/simple/string_io.c
libplatform-254.40.4.tar.gz
[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 #if DEBUG
41 #define MYBUFSIZE 256
42 #else
43 /* we use a small buffer to minimize stack usage constraints */
44 #define MYBUFSIZE 32
45 #endif
46
47 typedef struct _BUF {
48 char *buf;
49 char *ptr;
50 char *end;
51 int fd;
52 void (*full)(struct _BUF *);
53 } BUF;
54
55 /* flush the buffer */
56 static void
57 _flush(BUF *b)
58 {
59 char *buf = b->buf;
60 ssize_t n = b->ptr - buf;
61 ssize_t w;
62
63 while (n > 0) {
64 w = write(b->fd, buf, n);
65 if (w < 0) {
66 if (errno == EINTR || errno == EAGAIN)
67 continue;
68 break;
69 }
70 n -= w;
71 buf += n;
72 }
73 }
74
75 /* flush the buffer and reset the pointer */
76 static void
77 _flush_reset(BUF *b)
78 {
79 _flush(b);
80 b->ptr = b->buf;
81 }
82
83 /* enlarge the buffer */
84 static void
85 _enlarge(BUF *b)
86 {
87 vm_address_t new;
88 vm_size_t sold, snew;
89 intptr_t diff;
90 kern_return_t kr;
91
92 new = (vm_address_t)(b->end + 1);
93 if(vm_allocate(mach_task_self(), &new, VM_PAGE_SIZE, 0) == 0) {
94 /* page is adjacent */
95 b->end += VM_PAGE_SIZE;
96 return;
97 }
98 sold = BUF_SIZE(b);
99 snew = (sold + VM_PAGE_SIZE) & ~(VM_PAGE_SIZE - 1);
100 if ((kr = vm_allocate(mach_task_self(), &new, snew, 1)) != 0) {
101 __LIBPLATFORM_CLIENT_CRASH__(kr, "Failed to allocate memory for buffer");
102 }
103 diff = new - (vm_address_t)b->buf;
104 memmove((void *)new, b->buf, sold);
105 if((intptr_t)(b->buf) & (VM_PAGE_SIZE - 1)) {
106 sold &= ~(VM_PAGE_SIZE - 1);
107 b->buf = (char *)((intptr_t)(b->buf + VM_PAGE_SIZE) & ~(VM_PAGE_SIZE - 1));
108 b->end = (char *)(new + snew - 1);
109 } else
110 b->end += diff + VM_PAGE_SIZE;
111 if(sold > 0) {
112 vm_deallocate(mach_task_self(), (vm_address_t)b->buf, sold);
113 }
114 b->buf = (char *)new;
115 b->ptr += diff;
116 }
117
118 static inline void put_s(BUF *, _esc_func, const char *);
119 /* output a single character */
120 static inline void
121 put_c(BUF *b, _esc_func esc, unsigned char c)
122 {
123 const char *cp;
124
125 if(esc && (cp = esc(c)) != NULL)
126 put_s(b, NULL, cp);
127 else {
128 if(b->ptr >= b->end)
129 b->full(b);
130 *b->ptr++ = c;
131 }
132 }
133
134 /* output a null-terminated string */
135 static inline void
136 put_s(BUF *b, _esc_func esc, const char *str)
137 {
138 while(*str)
139 put_c(b, esc, *str++);
140 }
141
142 /* output a string of the specified size */
143 static inline void
144 put_n(BUF *b, _esc_func esc, const char *str, ssize_t n)
145 {
146 while(n-- > 0)
147 put_c(b, esc, *str++);
148 }
149
150 #if __LP64__ || defined(__arm64__)
151 static unsigned long long
152 udiv10(unsigned long long a, unsigned long long *rem)
153 {
154 *rem = a % 10;
155 return a / 10;
156 }
157 #else
158 unsigned long long
159 udiv10(unsigned long long a, unsigned long long *rem_out)
160 {
161 if (a <= UINT_MAX) {
162 *rem_out = (unsigned long long)((unsigned int)a % 10);
163 return (unsigned long long)((unsigned int)a / 10);
164 }
165
166 // The biggest multiple of 10 that dividend might contain
167 unsigned long long divisor = 0xa000000000000000;
168 unsigned long long dividend = a;
169 unsigned long long quotient = 0;
170
171 while (divisor >= 0xa) {
172 quotient = quotient << 1;
173 if (dividend >= divisor) {
174 dividend -= divisor;
175 quotient += 1;
176 }
177 divisor = divisor >> 1;
178 }
179
180 *rem_out = dividend;
181 return quotient;
182 }
183 #endif
184
185 /*
186 * Output the signed decimal string representing the number in "in". "width" is
187 * the minimum field width, and "zero" is a boolean value, true for zero padding
188 * (otherwise blank padding).
189 */
190 static void
191 dec(BUF *b, _esc_func esc, long long in, int width, int zero)
192 {
193 char buf[32];
194 char *cp = buf + sizeof(buf);
195 ssize_t pad;
196 int neg = 0;
197 unsigned long long n = (unsigned long long)in;
198 unsigned long long rem;
199
200 if(in < 0) {
201 neg++;
202 width--;
203 n = ~n + 1;
204 }
205 *--cp = 0;
206 if(n) {
207 while(n) {
208 n = udiv10(n, &rem);
209 *--cp = rem + '0';
210 }
211 } else
212 *--cp = '0';
213 if(neg && zero) {
214 put_c(b, esc, '-');
215 neg = 0;
216 }
217 pad = width - strlen(cp);
218 zero = zero ? '0' : ' ';
219 while(pad-- > 0)
220 put_c(b, esc, zero);
221 if(neg)
222 put_c(b, esc, '-');
223 put_s(b, esc, cp);
224 }
225
226 /*
227 * Output the octal string representing the number in "n". "width" is
228 * the minimum field width, and "zero" is a boolean value, true for zero padding
229 * (otherwise blank padding).
230 */
231 static void
232 oct(BUF *b, _esc_func esc, unsigned long long n, int width, int zero)
233 {
234 char buf[32];
235 char *cp = buf + sizeof(buf);
236 ssize_t pad;
237
238 *--cp = 0;
239 if (n) {
240 while (n) {
241 *--cp = (n % 8) + '0';
242 n /= 8;
243 }
244 } else {
245 *--cp = '0';
246 }
247 pad = width - strlen(cp);
248 zero = zero ? '0' : ' ';
249 while (pad-- > 0) {
250 put_c(b, esc, zero);
251 }
252 put_s(b, esc, cp);
253 }
254
255 /*
256 * Output the hex string representing the number in "n". "width" is the
257 * minimum field width, and "zero" is a boolean value, true for zero padding
258 * (otherwise blank padding). "upper" is a boolean value, true for upper
259 * case hex characters, lower case otherwise. "p" is a boolean value, true
260 * if 0x should be prepended (for %p), otherwise nothing.
261 */
262 static const char _h[] = "0123456789abcdef";
263 static const char _H[] = "0123456789ABCDEF";
264 static const char _0x[] = "0x";
265
266 static void
267 hex(BUF *b, _esc_func esc, unsigned long long n, int width, int zero, int upper, int p)
268 {
269 char buf[32];
270 char *cp = buf + sizeof(buf);
271 const char *h = upper ? _H : _h;
272
273 *--cp = 0;
274 if(n) {
275 while(n) {
276 *--cp = h[n & 0xf];
277 n >>= 4;
278 }
279 } else
280 *--cp = '0';
281 if(p) {
282 width -= 2;
283 if(zero) {
284 put_s(b, esc, _0x);
285 p = 0;
286 }
287 }
288 width -= strlen(cp);
289 zero = zero ? '0' : ' ';
290 while(width-- > 0)
291 put_c(b, esc, zero);
292 if(p)
293 put_s(b, esc, _0x);
294 put_s(b, esc, cp);
295 }
296
297 /*
298 * Output the unsigned decimal string representing the number in "n". "width"
299 * is the minimum field width, and "zero" is a boolean value, true for zero
300 * padding (otherwise blank padding).
301 */
302 static void
303 udec(BUF *b, _esc_func esc, unsigned long long n, int width, int zero)
304 {
305 char buf[32];
306 char *cp = buf + sizeof(buf);
307 unsigned long long rem;
308 ssize_t pad;
309
310 *--cp = 0;
311 if(n) {
312 while(n) {
313 n = udiv10(n, &rem);
314 *--cp = rem + '0';
315 }
316 } else
317 *--cp = '0';
318 pad = width - strlen(cp);
319 zero = zero ? '0' : ' ';
320 while(pad-- > 0)
321 put_c(b, esc, zero);
322 put_s(b, esc, cp);
323 }
324
325 /*
326 * Output the unsigned decimal string representing the number in "n", rounded
327 * to the nearest MB, KB or b. "width" is the minimum field width, and "zero"
328 * is a boolean value, true for zero padding (otherwise blank padding).
329 */
330 static void
331 ydec(BUF *b, _esc_func esc, unsigned long long n, int width, int zero)
332 {
333 if(n >= 10 * (1 << 20)) {
334 n += (1 << 19);
335 udec(b, esc, n >> 20, width, zero);
336 put_s(b, esc, "MB");
337 } else if (n >= 10 * (1 << 10)) {
338 n += (1 << 9);
339 udec(b, esc, n >> 10, width, zero);
340 put_s(b, esc, "KB");
341 } else {
342 udec(b, esc, n, width, zero);
343 put_s(b, esc, "b");
344 }
345 }
346
347 /*
348 * The actual engine for all the _simple_*printf routines.
349 */
350 static void
351 __simple_bprintf(BUF *b, _esc_func esc, const char *fmt, va_list ap)
352 {
353 while(*fmt) {
354 int lflag, zero, width;
355 char *cp;
356 if(!(cp = strchr(fmt, '%'))) {
357 put_s(b, esc, fmt);
358 break;
359 }
360 put_n(b, esc, fmt, cp - fmt);
361 fmt = cp + 1;
362 if(*fmt == '%') {
363 put_c(b, esc, '%');
364 fmt++;
365 continue;
366 }
367 lflag = zero = width = 0;
368 for(;;) {
369 switch(*fmt) {
370 case '0':
371 zero++;
372 fmt++;
373 /* drop through */
374 case '1': case '2': case '3': case '4': case '5':
375 case '6': case '7': case '8': case '9':
376 while(*fmt >= '0' && *fmt <= '9')
377 width = 10 * width + (*fmt++ - '0');
378 continue;
379 case 'c':
380 zero = zero ? '0' : ' ';
381 width--;
382 while(width-- > 0)
383 put_c(b, esc, zero);
384 put_c(b, esc, va_arg(ap, int));
385 break;
386 case 'd': case 'i':
387 switch(lflag) {
388 case 0:
389 dec(b, esc, va_arg(ap, int), width, zero);
390 break;
391 case 1:
392 dec(b, esc, va_arg(ap, long), width, zero);
393 break;
394 default:
395 dec(b, esc, va_arg(ap, long long), width, zero);
396 break;
397 }
398 break;
399 case 'l':
400 lflag++;
401 fmt++;
402 continue;
403 case 'o':
404 switch (lflag) {
405 case 0:
406 oct(b, esc, va_arg(ap, int), width, zero);
407 break;
408 case 1:
409 oct(b, esc, va_arg(ap, long), width, zero);
410 break;
411 default:
412 oct(b, esc, va_arg(ap, long long), width, zero);
413 break;
414 }
415 break;
416 case 'p':
417 hex(b, esc, (unsigned long)va_arg(ap, void *), width, zero, 0, 1);
418 break;
419 case 's':
420 cp = va_arg(ap, char *);
421 cp = cp ? cp : "(null)";
422 width -= strlen(cp);
423 zero = zero ? '0' : ' ';
424 while(width-- > 0)
425 put_c(b, esc, zero);
426 put_s(b, esc, cp);
427 break;
428 case 'u':
429 switch(lflag) {
430 case 0:
431 udec(b, esc, va_arg(ap, unsigned int), width, zero);
432 break;
433 case 1:
434 udec(b, esc, va_arg(ap, unsigned long), width, zero);
435 break;
436 default:
437 udec(b, esc, va_arg(ap, unsigned long long), width, zero);
438 break;
439 }
440 break;
441 case 'X': case 'x':
442 switch(lflag) {
443 case 0:
444 hex(b, esc, va_arg(ap, unsigned int), width, zero,
445 *fmt == 'X', 0);
446 break;
447 case 1:
448 hex(b, esc, va_arg(ap, unsigned long), width, zero,
449 *fmt == 'X', 0);
450 break;
451 default:
452 hex(b, esc, va_arg(ap, unsigned long long), width, zero,
453 *fmt == 'X', 0);
454 break;
455 }
456 break;
457 case 'y':
458 switch(lflag) {
459 case 0:
460 ydec(b, esc, va_arg(ap, unsigned int), width, zero);
461 break;
462 case 1:
463 ydec(b, esc, va_arg(ap, unsigned long), width, zero);
464 break;
465 default:
466 ydec(b, esc, va_arg(ap, unsigned long long), width, zero);
467 break;
468 }
469 break;
470 default:
471 put_c(b, esc, *fmt);
472 break;
473 }
474 break;
475 }
476 fmt++;
477 }
478 }
479
480 /*
481 * A simplified vfprintf variant. The format string is interpreted with
482 * arguments from the va_list, and the results are written to the given
483 * file descriptor.
484 */
485 void
486 _simple_vdprintf(int fd, const char *fmt, va_list ap)
487 {
488 BUF b;
489 char buf[MYBUFSIZE];
490
491 b.buf = buf;
492 b.fd = fd;
493 b.ptr = b.buf;
494 b.end = b.buf + MYBUFSIZE;
495 b.full = _flush_reset;
496 __simple_bprintf(&b, NULL, fmt, ap);
497 _flush(&b);
498 }
499
500 /*
501 * A simplified fprintf variant. The format string is interpreted with
502 * arguments from the variable argument list, and the results are written
503 * to the given file descriptor.
504 */
505 void
506 _simple_dprintf(int fd, const char *fmt, ...)
507 {
508 va_list ap;
509
510 va_start(ap, fmt);
511 _simple_vdprintf(fd, fmt, ap);
512 va_end(ap);
513 }
514
515 /*
516 * A simplified string allocate routine. Pass the opaque pointer to structure
517 * to _simple_*sprintf() routines. Use _simple_string() to retrieve the
518 * current string (the string is guaranteed to be null terminated only on
519 * the call to _simple_string()). Use _simple_sfree() to free the structure
520 * and string memory.
521 */
522 _SIMPLE_STRING
523 _simple_salloc(void)
524 {
525 BUF *b;
526
527 if(vm_allocate(mach_task_self(), (vm_address_t *)&b, VM_PAGE_SIZE, 1))
528 return NULL;
529 b->ptr = b->buf = (char *)b + sizeof(BUF);
530 b->end = (char *)b + VM_PAGE_SIZE - 1;
531 b->full = _enlarge;
532 return (_SIMPLE_STRING)b;
533 }
534
535 /*
536 * The format string is interpreted with arguments from the va_list, and the
537 * results are appended to the string maintained by the opaque structure, as
538 * returned by a previous call to _simple_salloc(). Non-zero is returned on
539 * out-of-memory error.
540 */
541 int
542 _simple_vsprintf(_SIMPLE_STRING b, const char *fmt, va_list ap)
543 {
544 return _simple_vesprintf(b, NULL, fmt, ap);
545 }
546
547 /*
548 * The format string is interpreted with arguments from the variable argument
549 * list, and the results are appended to the string maintained by the opaque
550 * structure, as returned by a previous call to _simple_salloc(). Non-zero is
551 * returned on out-of-memory error.
552 */
553 int
554 _simple_sprintf(_SIMPLE_STRING b, const char *fmt, ...)
555 {
556 va_list ap;
557 int ret;
558
559 va_start(ap, fmt);
560 ret = _simple_vesprintf(b, NULL, fmt, ap);
561 va_end(ap);
562 return ret;
563 }
564
565 /*
566 * Like _simple_vsprintf(), except __esc is a function to call on each
567 * character; the function returns NULL if the character should be passed
568 * as is, otherwise, the returned character string is used instead.
569 */
570 int
571 _simple_vesprintf(_SIMPLE_STRING b, _esc_func esc, const char *fmt, va_list ap)
572 {
573 __simple_bprintf((BUF *)b, esc, fmt, ap);
574 return 0;
575 }
576
577 /*
578 * Like _simple_sprintf(), except __esc is a function to call on each
579 * character; the function returns NULL if the character should be passed
580 * as is, otherwise, the returned character string is used instead.
581 */
582 int _simple_esprintf(_SIMPLE_STRING b, _esc_func esc, const char *fmt, ...)
583 {
584 va_list ap;
585 int ret;
586
587 va_start(ap, fmt);
588 ret = _simple_vesprintf(b, esc, fmt, ap);
589 va_end(ap);
590 return ret;
591 }
592
593 /*
594 * Return the null terminated string from the opaque structure, as returned
595 * by a previous call to _simple_salloc().
596 */
597 char *
598 _simple_string(_SIMPLE_STRING b)
599 {
600 *((BUF *)b)->ptr = 0;
601 return ((BUF *)b)->buf;
602 }
603
604 /*
605 * Reposition the pointer to the first null in the buffer. After a call to
606 * _simple_string, the buffer can be modified, and shrunk.
607 */
608 void
609 _simple_sresize(_SIMPLE_STRING b)
610 {
611 ((BUF *)b)->ptr = ((BUF *)b)->buf + strlen(((BUF *)b)->buf);
612 }
613
614 /*
615 * Append the null-terminated string to the string associated with the opaque
616 * structure. Non-zero is returned on out-of-memory error.
617 */
618 int
619 _simple_sappend(_SIMPLE_STRING b, const char *str)
620 {
621 return _simple_esappend(b, NULL, str);
622 }
623
624 /*
625 * Like _simple_sappend(), except __esc is a function to call on each
626 * character; the function returns NULL if the character should be passed
627 * as is, otherwise, the returned character string is used instead.
628 */
629 int _simple_esappend(_SIMPLE_STRING b, _esc_func esc, const char *str)
630 {
631 put_s((BUF *)b, esc, str);
632 return 0;
633 }
634
635 /*
636 * Write the string associated with the opaque structure to the file descriptor.
637 */
638 void
639 _simple_put(_SIMPLE_STRING b, int fd)
640 {
641 ((BUF *)b)->fd = fd;
642 _flush((BUF *)b);
643 }
644
645 /*
646 * Write the string associated with the opaque structure and a trailing newline,
647 * to the file descriptor.
648 */
649 void
650 _simple_putline(_SIMPLE_STRING b, int fd)
651 {
652 ((BUF *)b)->fd = fd;
653 *((BUF *)b)->ptr++ = '\n';
654 _flush((BUF *)b);
655 ((BUF *)b)->ptr--;
656 }
657
658 /*
659 * Free the opaque structure, and the associated string.
660 */
661 void
662 _simple_sfree(_SIMPLE_STRING b)
663 {
664 vm_size_t s;
665
666 if(b == NULL) return;
667 if(((intptr_t)(((BUF *)b)->buf) & (VM_PAGE_SIZE - 1)) == 0) {
668 vm_deallocate(mach_task_self(), (vm_address_t)((BUF *)b)->buf, BUF_SIZE(b));
669 s = VM_PAGE_SIZE;
670 } else {
671 s = ((BUF *)b)->end - (char *)b + 1;
672 }
673 vm_deallocate(mach_task_self(), (vm_address_t)b, s);
674 }