xref: /dragonfly/lib/libc/stdio/xprintf_str.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1 /*-
2  * Copyright (c) 2005 Poul-Henning Kamp
3  * Copyright (c) 1990, 1993
4  *        The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Chris Torek.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/lib/libc/stdio/xprintf_str.c,v 1.1 2005/12/16 18:56:38 phk Exp $
34  */
35 
36 #include "namespace.h"
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <limits.h>
41 #include <stdint.h>
42 #include <assert.h>
43 #include <wchar.h>
44 #include "un-namespace.h"
45 #include "printf.h"
46 
47 /*
48  * Convert a wide character string argument for the %ls format to a multibyte
49  * string representation. If not -1, prec specifies the maximum number of
50  * bytes to output, and also means that we can't assume that the wide char.
51  * string ends is null-terminated.
52  */
53 static char *
__wcsconv(wchar_t * wcsarg,int prec)54 __wcsconv(wchar_t *wcsarg, int prec)
55 {
56           static const mbstate_t initial;
57           mbstate_t mbs;
58           char buf[MB_LEN_MAX];
59           wchar_t *p;
60           char *convbuf;
61           size_t clen, nbytes;
62 
63           /* Allocate space for the maximum number of bytes we could output. */
64           if (prec < 0) {
65                     p = wcsarg;
66                     mbs = initial;
67                     nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
68                     if (nbytes == (size_t)-1)
69                               return (NULL);
70           } else {
71                     /*
72                      * Optimisation: if the output precision is small enough,
73                      * just allocate enough memory for the maximum instead of
74                      * scanning the string.
75                      */
76                     if (prec < 128)
77                               nbytes = prec;
78                     else {
79                               nbytes = 0;
80                               p = wcsarg;
81                               mbs = initial;
82                               for (;;) {
83                                         clen = wcrtomb(buf, *p++, &mbs);
84                                         if (clen == 0 || clen == (size_t)-1 ||
85                                             (int)(nbytes + clen) > prec)
86                                                   break;
87                                         nbytes += clen;
88                               }
89                     }
90           }
91           if ((convbuf = malloc(nbytes + 1)) == NULL)
92                     return (NULL);
93 
94           /* Fill the output buffer. */
95           p = wcsarg;
96           mbs = initial;
97           if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
98               nbytes, &mbs)) == (size_t)-1) {
99                     free(convbuf);
100                     return (NULL);
101           }
102           convbuf[nbytes] = '\0';
103           return (convbuf);
104 }
105 
106 
107 /* 's' ---------------------------------------------------------------*/
108 
109 int
__printf_arginfo_str(const struct printf_info * pi,size_t n,int * argt)110 __printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt)
111 {
112 
113           assert (n > 0);
114           if (pi->is_long || pi->spec == 'C')
115                     argt[0] = PA_WSTRING;
116           else
117                     argt[0] = PA_STRING;
118           return (1);
119 }
120 
121 int
__printf_render_str(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)122 __printf_render_str(struct __printf_io *io, const struct printf_info *pi,
123                         const void *const *arg)
124 {
125           const char *p;
126           wchar_t *wcp;
127           char *convbuf;
128           int l;
129 
130           if (pi->is_long || pi->spec == 'S') {
131                     wcp = *((wint_t **)arg[0]);
132                     if (wcp == NULL)
133                               return (__printf_out(io, pi, "(null)", 6));
134                     convbuf = __wcsconv(wcp, pi->prec);
135                     if (convbuf == NULL)
136                               return (-1);
137                     l = __printf_out(io, pi, convbuf, strlen(convbuf));
138                     free(convbuf);
139                     return (l);
140           }
141           p = *((char **)arg[0]);
142           if (p == NULL)
143                     return (__printf_out(io, pi, "(null)", 6));
144           l = strlen(p);
145           if (pi->prec >= 0 && pi->prec < l)
146                     l = pi->prec;
147           return (__printf_out(io, pi, p, l));
148 }
149 
150 /* 'c' ---------------------------------------------------------------*/
151 
152 int
__printf_arginfo_chr(const struct printf_info * pi,size_t n,int * argt)153 __printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt)
154 {
155 
156           assert (n > 0);
157           if (pi->is_long || pi->spec == 'C')
158                     argt[0] = PA_WCHAR;
159           else
160                     argt[0] = PA_INT;
161           return (1);
162 }
163 
164 int
__printf_render_chr(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)165 __printf_render_chr(struct __printf_io *io, const struct printf_info *pi,
166                         const void *const *arg)
167 {
168           int i;
169           wint_t ii;
170           unsigned char c;
171           static const mbstate_t initial;                   /* XXX: this is bogus! */
172           mbstate_t mbs;
173           size_t mbseqlen;
174           char buf[MB_CUR_MAX];
175 
176           if (pi->is_long || pi->spec == 'C') {
177                     ii = *((wint_t *)arg[0]);
178 
179                     mbs = initial;
180                     mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs);
181                     if (mbseqlen == (size_t) -1)
182                               return (-1);
183                     return (__printf_out(io, pi, buf, mbseqlen));
184           }
185           i = *((int *)arg[0]);
186           c = i;
187           i = __printf_out(io, pi, &c, 1);
188           __printf_flush(io);
189           return (i);
190 }
191