1/* 2 * Copyright (c) 2012 Apple 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 <printf.h> 25#include <pthread.h> 26#include <stdlib.h> 27#include <errno.h> 28#include "xprintf_domain.h" 29#include "xprintf_private.h" 30 31/* These are flag characters and can never be used as conversion specifiers */ 32static const char _printf_tbl_flags[] = "#$'*+,-.0123456789:;L_hjlqtvz"; 33 34struct _printf_tbl_defaults_fbsd { 35 const char *spec; 36 printf_arginfo_function *arginfo; 37 printf_render *render; 38}; 39static struct _printf_tbl_defaults_fbsd _printf_tbl_defaults_fbsd[] = { 40 {"%", __printf_arginfo_pct, __printf_render_pct}, 41 {"AEFGaefg", __printf_arginfo_float, __printf_render_float}, 42 {"Cc", __printf_arginfo_chr, __printf_render_chr}, 43 {"DOUXdioux", __printf_arginfo_int, __printf_render_int}, 44 {"Ss", __printf_arginfo_str, __printf_render_str}, 45 {"p", __printf_arginfo_ptr, __printf_render_ptr}, 46}; 47struct _printf_tbl_defaults_glibc { 48 const char *spec; 49 printf_arginfo_function *arginfo; 50 printf_function *render; 51}; 52static struct _printf_tbl_defaults_glibc _printf_tbl_defaults_glibc[] = { 53 {"n", __printf_arginfo_n, __printf_render_n}, 54}; 55 56static printf_domain_t xprintf_domain_default; 57#ifdef XPRINTF_DEBUG 58__private_extern__ printf_domain_t xprintf_domain_global = NULL; 59#endif 60 61__private_extern__ pthread_once_t __xprintf_domain_once = PTHREAD_ONCE_INIT; 62 63__private_extern__ void 64__xprintf_domain_init(void) 65{ 66 xprintf_domain_default = (printf_domain_t)calloc( 67#ifdef XPRINTF_DEBUG 68 2, 69#else 70 1, 71#endif 72 sizeof(*xprintf_domain_default)); 73 if(xprintf_domain_default == NULL) 74 LIBC_ABORT("No memory"); 75 76 xprintf_domain_default->rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; 77 { 78 const char *cp; 79 for(cp = _printf_tbl_flags; *cp; cp++) 80 xprintf_domain_default->type[printf_tbl_index(*cp)] = PRINTF_DOMAIN_FLAG; 81 } 82 { 83 struct _printf_tbl_defaults_fbsd *d = _printf_tbl_defaults_fbsd; 84 int n = sizeof(_printf_tbl_defaults_fbsd) / sizeof(*_printf_tbl_defaults_fbsd); 85 for(; n > 0; d++, n--) { 86 for(const char *cp = d->spec; *cp; cp++) { 87 xprintf_domain_default->type[printf_tbl_index(*cp)] = PRINTF_DOMAIN_FBSD_API; 88 xprintf_domain_default->tbl[printf_tbl_index(*cp)] = (struct _printf_tbl){d->arginfo, d->render, NULL}; 89 } 90 } 91 } 92 { 93 struct _printf_tbl_defaults_glibc *d = _printf_tbl_defaults_glibc; 94 int n = sizeof(_printf_tbl_defaults_glibc) / sizeof(*_printf_tbl_defaults_glibc); 95 for(; n > 0; d++, n--) { 96 for(const char *cp = d->spec; *cp; cp++) { 97 xprintf_domain_default->type[printf_tbl_index(*cp)] = PRINTF_DOMAIN_GLIBC_API; 98 xprintf_domain_default->tbl[printf_tbl_index(*cp)] = (struct _printf_tbl){d->arginfo, d->render, NULL}; 99 } 100 } 101 } 102#ifdef XPRINTF_DEBUG 103 xprintf_domain_global = xprintf_domain_default + 1; 104 *xprintf_domain_global = *xprintf_domain_default; 105#endif 106} 107 108printf_domain_t 109copy_printf_domain(printf_domain_t src) 110{ 111 printf_domain_t restrict copy; 112 113 if(!src) { 114 errno = EINVAL; 115 return NULL; 116 } 117 copy = (printf_domain_t)MALLOC(sizeof(*copy)); 118 if(!copy) return NULL; 119 xprintf_domain_init(); 120 pthread_rwlock_rdlock(&src->rwlock); 121 *copy = *src; 122 pthread_rwlock_unlock(&src->rwlock); 123 copy->rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; 124 return copy; 125} 126 127void 128free_printf_domain(printf_domain_t d) 129{ 130 if(!d) return; 131 pthread_rwlock_destroy(&d->rwlock); 132 free(d); 133} 134 135printf_domain_t 136new_printf_domain(void) 137{ 138 printf_domain_t restrict d; 139 140 xprintf_domain_init(); 141 142 d = (printf_domain_t)MALLOC(sizeof(*d)); 143 if(!d) return NULL; 144 *d = *xprintf_domain_default; 145 return d; 146} 147 148int 149register_printf_domain_function(printf_domain_t d, int spec, printf_function *render, printf_arginfo_function *arginfo, void *context) 150{ 151 xprintf_domain_init(); 152 153 if(!d || !printf_tbl_in_range(spec)) { 154 errno = EINVAL; 155 return -1; 156 } 157 xprintf_domain_init(); 158 159 switch(d->type[printf_tbl_index(spec)]) { 160 case PRINTF_DOMAIN_FLAG: 161 errno = EINVAL; 162 return -1; 163 default: 164 pthread_rwlock_wrlock(&d->rwlock); 165 if(!render || !arginfo) { 166 d->type[printf_tbl_index(spec)] = PRINTF_DOMAIN_UNUSED; 167 } else { 168 d->type[printf_tbl_index(spec)] = PRINTF_DOMAIN_GLIBC_API; 169 d->tbl[printf_tbl_index(spec)] = (struct _printf_tbl){arginfo, render, context}; 170 } 171 pthread_rwlock_unlock(&d->rwlock); 172 } 173 174 return 0; 175} 176 177__private_extern__ int 178register_printf_domain_render(printf_domain_t d, int spec, printf_render *render, printf_arginfo_function *arginfo) 179{ 180 xprintf_domain_init(); 181 182 if(!d || !printf_tbl_in_range(spec)) { 183 errno = EINVAL; 184 return -1; 185 } 186 xprintf_domain_init(); 187 188 switch(d->type[printf_tbl_index(spec)]) { 189 case PRINTF_DOMAIN_FLAG: 190 errno = EINVAL; 191 return -1; 192 default: 193 pthread_rwlock_wrlock(&d->rwlock); 194 if(!render || !arginfo) { 195 d->type[printf_tbl_index(spec)] = PRINTF_DOMAIN_UNUSED; 196 } else { 197 d->type[printf_tbl_index(spec)] = PRINTF_DOMAIN_FBSD_API; 198 d->tbl[printf_tbl_index(spec)] = (struct _printf_tbl){arginfo, render, NULL}; 199 } 200 pthread_rwlock_unlock(&d->rwlock); 201 } 202 203 return 0; 204} 205 206int 207register_printf_domain_render_std(printf_domain_t d, const char *specs) 208{ 209 int ret = 0; 210 211 for (; *specs != '\0'; specs++) { 212 switch (*specs) { 213 case 'H': 214 ret = register_printf_domain_render(d, *specs, 215 __printf_render_hexdump, 216 __printf_arginfo_hexdump); 217 break; 218 case 'M': 219 ret = register_printf_domain_render(d, *specs, 220 __printf_render_errno, 221 __printf_arginfo_errno); 222 break; 223 case 'Q': 224 ret = register_printf_domain_render(d, *specs, 225 __printf_render_quote, 226 __printf_arginfo_quote); 227 break; 228 case 'T': 229 ret = register_printf_domain_render(d, *specs, 230 __printf_render_time, 231 __printf_arginfo_time); 232 break; 233 case 'V': 234 ret = register_printf_domain_render(d, *specs, 235 __printf_render_vis, 236 __printf_arginfo_vis); 237 break; 238 default: 239 errno = EINVAL; 240 return (-1); 241 } 242 if(ret < 0) return ret; 243 } 244 return (0); 245} 246