]> git.saurik.com Git - apple/libc.git/blame - stdio/xprintf_domain.c
Libc-1044.1.2.tar.gz
[apple/libc.git] / stdio / xprintf_domain.c
CommitLineData
6465356a
A
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}