1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include "string.h" 30 31static const char hex[] = "0123456789abcdef"; 32 33static int 34_mach_strlen(const char *str) 35{ 36 const char *p; 37 for (p = str; p; p++) { 38 if (*p == '\0') { 39 return (int)(p - str); 40 } 41 } 42 /* NOTREACHED */ 43 return 0; 44} 45 46static void 47_mach_hex(char **buffer, int *length, unsigned long long n) 48{ 49 char buf[32]; 50 char *cp = buf + sizeof(buf); 51 52 if (n) { 53 *--cp = '\0'; 54 while (n) { 55 *--cp = hex[n & 0xf]; 56 n >>= 4; 57 } 58 59 int width = _mach_strlen(cp); 60 while (width > 0 && length > 0) { 61 *(*buffer)++ = *cp++; 62 (*length)--; 63 width--; 64 } 65 } 66} 67 68int 69_mach_vsnprintf(char *buffer, int length, const char *fmt, va_list ap) 70{ 71 int width, max = length; 72 char *out_ptr = buffer; 73 74 // we only ever write n-1 bytes so we can put a \0 at the end 75 length--; 76 while (length > 0 && *fmt) { 77 if (*fmt == '\0') { 78 break; 79 } 80 if (*fmt != '%') { 81 *(out_ptr++) = *(fmt++); 82 length--; 83 continue; 84 } 85 fmt++; 86 // only going to support a specific subset of sprintf flags 87 // namely %s, %x, with no padding modifiers 88 switch (*fmt++) { 89 case 's': 90 { 91 char *cp = va_arg(ap, char*); 92 width = _mach_strlen(cp); 93 while (width > 0 && length > 0) { 94 *(out_ptr++) = *(cp++); 95 width--; 96 length--; 97 } 98 break; 99 } 100 case 'x': 101 { 102 _mach_hex(&out_ptr, &length, va_arg(ap, unsigned int)); 103 break; 104 } 105 } 106 } 107 *out_ptr = '\0'; 108 return max - length; 109} 110 111int 112_mach_snprintf(char *buffer, int length, const char *fmt, ...) 113{ 114 int ret; 115 va_list ap; 116 va_start(ap, fmt); 117 ret = _mach_vsnprintf(buffer, length, fmt, ap); 118 va_end(ap); 119 return ret; 120} 121