/ stdio / xprintf_domain.c
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