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