]>
git.saurik.com Git - apple/libplatform.git/blob - src/simple/string_io.c
2 * Copyright (c) 2005, 2006, 2009 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <mach/mach_init.h>
27 #include <mach/vm_map.h>
30 #include "os/internal.h"
32 #include "platform/string.h"
33 #include "platform/compat.h"
36 #define VM_PAGE_SIZE 4096
39 #define BUF_SIZE(s) (((BUF *)(s))->end - ((BUF *)(s))->buf + 1)
43 /* we use a small buffer to minimize stack usage constraints */
52 void (*full
)(struct _BUF
*);
55 /* flush the buffer */
60 ssize_t n
= b
->ptr
- buf
;
64 w
= write(b
->fd
, buf
, n
);
66 if (errno
== EINTR
|| errno
== EAGAIN
)
75 /* flush the buffer and reset the pointer */
83 /* enlarge the buffer */
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
;
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");
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);
110 b
->end
+= diff
+ VM_PAGE_SIZE
;
112 vm_deallocate(mach_task_self(), (vm_address_t
)b
->buf
, sold
);
114 b
->buf
= (char *)new;
118 static inline void put_s(BUF
*, _esc_func
, const char *);
119 /* output a single character */
121 put_c(BUF
*b
, _esc_func esc
, unsigned char c
)
125 if(esc
&& (cp
= esc(c
)) != NULL
)
134 /* output a null-terminated string */
136 put_s(BUF
*b
, _esc_func esc
, const char *str
)
139 put_c(b
, esc
, *str
++);
142 /* output a string of the specified size */
144 put_n(BUF
*b
, _esc_func esc
, const char *str
, ssize_t n
)
147 put_c(b
, esc
, *str
++);
150 #if __LP64__ || defined(__arm64__)
151 static unsigned long long
152 udiv10(unsigned long long a
, unsigned long long *rem
)
159 udiv10(unsigned long long a
, unsigned long long *rem_out
)
162 *rem_out
= (unsigned long long)((unsigned int)a
% 10);
163 return (unsigned long long)((unsigned int)a
/ 10);
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;
171 while (divisor
>= 0xa) {
172 quotient
= quotient
<< 1;
173 if (dividend
>= divisor
) {
177 divisor
= divisor
>> 1;
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).
191 dec(BUF
*b
, _esc_func esc
, long long in
, int width
, int zero
)
194 char *cp
= buf
+ sizeof(buf
);
197 unsigned long long n
= (unsigned long long)in
;
198 unsigned long long rem
;
217 pad
= width
- strlen(cp
);
218 zero
= zero
? '0' : ' ';
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).
232 oct(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
235 char *cp
= buf
+ sizeof(buf
);
241 *--cp
= (n
% 8) + '0';
247 pad
= width
- strlen(cp
);
248 zero
= zero
? '0' : ' ';
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.
262 static const char _h
[] = "0123456789abcdef";
263 static const char _H
[] = "0123456789ABCDEF";
264 static const char _0x
[] = "0x";
267 hex(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
, int upper
, int p
)
270 char *cp
= buf
+ sizeof(buf
);
271 const char *h
= upper
? _H
: _h
;
289 zero
= zero
? '0' : ' ';
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).
303 udec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
306 char *cp
= buf
+ sizeof(buf
);
307 unsigned long long rem
;
318 pad
= width
- strlen(cp
);
319 zero
= zero
? '0' : ' ';
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).
331 ydec(BUF
*b
, _esc_func esc
, unsigned long long n
, int width
, int zero
)
333 if(n
>= 10 * (1 << 20)) {
335 udec(b
, esc
, n
>> 20, width
, zero
);
337 } else if (n
>= 10 * (1 << 10)) {
339 udec(b
, esc
, n
>> 10, width
, zero
);
342 udec(b
, esc
, n
, width
, zero
);
348 * The actual engine for all the _simple_*printf routines.
351 __simple_bprintf(BUF
*b
, _esc_func esc
, const char *fmt
, va_list ap
)
354 int lflag
, zero
, width
;
356 if(!(cp
= strchr(fmt
, '%'))) {
360 put_n(b
, esc
, fmt
, cp
- fmt
);
367 lflag
= zero
= width
= 0;
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');
380 zero
= zero
? '0' : ' ';
384 put_c(b
, esc
, va_arg(ap
, int));
389 dec(b
, esc
, va_arg(ap
, int), width
, zero
);
392 dec(b
, esc
, va_arg(ap
, long), width
, zero
);
395 dec(b
, esc
, va_arg(ap
, long long), width
, zero
);
406 oct(b
, esc
, va_arg(ap
, int), width
, zero
);
409 oct(b
, esc
, va_arg(ap
, long), width
, zero
);
412 oct(b
, esc
, va_arg(ap
, long long), width
, zero
);
417 hex(b
, esc
, (unsigned long)va_arg(ap
, void *), width
, zero
, 0, 1);
420 cp
= va_arg(ap
, char *);
421 cp
= cp
? cp
: "(null)";
423 zero
= zero
? '0' : ' ';
431 udec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
434 udec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
437 udec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
444 hex(b
, esc
, va_arg(ap
, unsigned int), width
, zero
,
448 hex(b
, esc
, va_arg(ap
, unsigned long), width
, zero
,
452 hex(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
,
460 ydec(b
, esc
, va_arg(ap
, unsigned int), width
, zero
);
463 ydec(b
, esc
, va_arg(ap
, unsigned long), width
, zero
);
466 ydec(b
, esc
, va_arg(ap
, unsigned long long), width
, zero
);
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
486 _simple_vdprintf(int fd
, const char *fmt
, va_list ap
)
494 b
.end
= b
.buf
+ MYBUFSIZE
;
495 b
.full
= _flush_reset
;
496 __simple_bprintf(&b
, NULL
, fmt
, ap
);
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.
506 _simple_dprintf(int fd
, const char *fmt
, ...)
511 _simple_vdprintf(fd
, fmt
, ap
);
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
527 if(vm_allocate(mach_task_self(), (vm_address_t
*)&b
, VM_PAGE_SIZE
, 1))
529 b
->ptr
= b
->buf
= (char *)b
+ sizeof(BUF
);
530 b
->end
= (char *)b
+ VM_PAGE_SIZE
- 1;
532 return (_SIMPLE_STRING
)b
;
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.
542 _simple_vsprintf(_SIMPLE_STRING b
, const char *fmt
, va_list ap
)
544 return _simple_vesprintf(b
, NULL
, fmt
, ap
);
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.
554 _simple_sprintf(_SIMPLE_STRING b
, const char *fmt
, ...)
560 ret
= _simple_vesprintf(b
, NULL
, fmt
, ap
);
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.
571 _simple_vesprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, va_list ap
)
573 __simple_bprintf((BUF
*)b
, esc
, fmt
, ap
);
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.
582 int _simple_esprintf(_SIMPLE_STRING b
, _esc_func esc
, const char *fmt
, ...)
588 ret
= _simple_vesprintf(b
, esc
, fmt
, ap
);
594 * Return the null terminated string from the opaque structure, as returned
595 * by a previous call to _simple_salloc().
598 _simple_string(_SIMPLE_STRING b
)
600 *((BUF
*)b
)->ptr
= 0;
601 return ((BUF
*)b
)->buf
;
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.
609 _simple_sresize(_SIMPLE_STRING b
)
611 ((BUF
*)b
)->ptr
= ((BUF
*)b
)->buf
+ strlen(((BUF
*)b
)->buf
);
615 * Append the null-terminated string to the string associated with the opaque
616 * structure. Non-zero is returned on out-of-memory error.
619 _simple_sappend(_SIMPLE_STRING b
, const char *str
)
621 return _simple_esappend(b
, NULL
, str
);
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.
629 int _simple_esappend(_SIMPLE_STRING b
, _esc_func esc
, const char *str
)
631 put_s((BUF
*)b
, esc
, str
);
636 * Write the string associated with the opaque structure to the file descriptor.
639 _simple_put(_SIMPLE_STRING b
, int fd
)
646 * Write the string associated with the opaque structure and a trailing newline,
647 * to the file descriptor.
650 _simple_putline(_SIMPLE_STRING b
, int fd
)
653 *((BUF
*)b
)->ptr
++ = '\n';
659 * Free the opaque structure, and the associated string.
662 _simple_sfree(_SIMPLE_STRING b
)
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
));
671 s
= ((BUF
*)b
)->end
- (char *)b
+ 1;
673 vm_deallocate(mach_task_self(), (vm_address_t
)b
, s
);