1 /*
2 ******************************************************************************
3 *
4 * Copyright (C) 2001-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 ******************************************************************************
8 *
9 * File sprintf.c
10 *
11 * Modification History:
12 *
13 * Date Name Description
14 * 02/08/2001 george Creation. Copied from uprintf.c
15 * 03/27/2002 Mark Schneckloth Many fixes regarding alignment, null termination
16 * (mschneckloth@atomz.com) and other various problems.
17 * 08/07/2003 george Reunify printf implementations
18 *******************************************************************************
19 */
20
21 #include "unicode/utypes.h"
22
23 #if !UCONFIG_NO_FORMATTING
24
25 #include "unicode/ustdio.h"
26 #include "unicode/ustring.h"
27 #include "unicode/putil.h"
28
29 #include "uprintf.h"
30 #include "locbund.h"
31
32 #include "cmemory.h"
33 #include <ctype.h>
34
35 /* u_minstrncpy copies the minimum number of code units of (count or output->available) */
36 static int32_t
u_sprintf_write(void * context,const UChar * str,int32_t count)37 u_sprintf_write(void *context,
38 const UChar *str,
39 int32_t count)
40 {
41 u_localized_print_string *output = (u_localized_print_string *)context;
42 int32_t size = ufmt_min(count, output->available);
43
44 u_strncpy(output->str + (output->len - output->available), str, size);
45 output->available -= size;
46 return size;
47 }
48
49 static int32_t
u_sprintf_pad_and_justify(void * context,const u_printf_spec_info * info,const UChar * result,int32_t resultLen)50 u_sprintf_pad_and_justify(void *context,
51 const u_printf_spec_info *info,
52 const UChar *result,
53 int32_t resultLen)
54 {
55 u_localized_print_string *output = (u_localized_print_string *)context;
56 int32_t written = 0;
57
58 resultLen = ufmt_min(resultLen, output->available);
59
60 /* pad and justify, if needed */
61 if(info->fWidth != -1 && resultLen < info->fWidth) {
62 int32_t paddingLeft = info->fWidth - resultLen;
63 int32_t outputPos = output->len - output->available;
64
65 if (paddingLeft + resultLen > output->available) {
66 paddingLeft = output->available - resultLen;
67 if (paddingLeft < 0) {
68 paddingLeft = 0;
69 }
70 /* paddingLeft = output->available - resultLen;*/
71 }
72 written += paddingLeft;
73
74 /* left justify */
75 if(info->fLeft) {
76 written += u_sprintf_write(output, result, resultLen);
77 u_memset(&output->str[outputPos + resultLen], info->fPadChar, paddingLeft);
78 output->available -= paddingLeft;
79 }
80 /* right justify */
81 else {
82 u_memset(&output->str[outputPos], info->fPadChar, paddingLeft);
83 output->available -= paddingLeft;
84 written += u_sprintf_write(output, result, resultLen);
85 }
86 }
87 /* just write the formatted output */
88 else {
89 written = u_sprintf_write(output, result, resultLen);
90 }
91
92 return written;
93 }
94
95 U_CAPI int32_t U_EXPORT2
u_sprintf(UChar * buffer,const char * patternSpecification,...)96 u_sprintf(UChar *buffer,
97 const char *patternSpecification,
98 ... )
99 {
100 va_list ap;
101 int32_t written;
102
103 va_start(ap, patternSpecification);
104 written = u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap);
105 va_end(ap);
106
107 return written;
108 }
109
110 U_CAPI int32_t U_EXPORT2
u_sprintf_u(UChar * buffer,const UChar * patternSpecification,...)111 u_sprintf_u(UChar *buffer,
112 const UChar *patternSpecification,
113 ... )
114 {
115 va_list ap;
116 int32_t written;
117
118 va_start(ap, patternSpecification);
119 written = u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap);
120 va_end(ap);
121
122 return written;
123 }
124
125 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_vsprintf(UChar * buffer,const char * patternSpecification,va_list ap)126 u_vsprintf(UChar *buffer,
127 const char *patternSpecification,
128 va_list ap)
129 {
130 return u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap);
131 }
132
133 U_CAPI int32_t U_EXPORT2
u_snprintf(UChar * buffer,int32_t count,const char * patternSpecification,...)134 u_snprintf(UChar *buffer,
135 int32_t count,
136 const char *patternSpecification,
137 ... )
138 {
139 va_list ap;
140 int32_t written;
141
142 va_start(ap, patternSpecification);
143 written = u_vsnprintf(buffer, count, patternSpecification, ap);
144 va_end(ap);
145
146 return written;
147 }
148
149 U_CAPI int32_t U_EXPORT2
u_snprintf_u(UChar * buffer,int32_t count,const UChar * patternSpecification,...)150 u_snprintf_u(UChar *buffer,
151 int32_t count,
152 const UChar *patternSpecification,
153 ... )
154 {
155 va_list ap;
156 int32_t written;
157
158 va_start(ap, patternSpecification);
159 written = u_vsnprintf_u(buffer, count, patternSpecification, ap);
160 va_end(ap);
161
162 return written;
163 }
164
165 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_vsnprintf(UChar * buffer,int32_t count,const char * patternSpecification,va_list ap)166 u_vsnprintf(UChar *buffer,
167 int32_t count,
168 const char *patternSpecification,
169 va_list ap)
170 {
171 int32_t written;
172 UChar *pattern;
173 UChar patBuffer[UFMT_DEFAULT_BUFFER_SIZE];
174 int32_t size = (int32_t)strlen(patternSpecification) + 1;
175
176 /* convert from the default codepage to Unicode */
177 if (size >= MAX_UCHAR_BUFFER_SIZE(patBuffer)) {
178 pattern = (UChar *)uprv_malloc(size * sizeof(UChar));
179 if(pattern == 0) {
180 return 0;
181 }
182 }
183 else {
184 pattern = patBuffer;
185 }
186 u_charsToUChars(patternSpecification, pattern, size);
187
188 /* do the work */
189 written = u_vsnprintf_u(buffer, count, pattern, ap);
190
191 /* clean up */
192 if (pattern != patBuffer) {
193 uprv_free(pattern);
194 }
195
196 return written;
197 }
198
199 U_CAPI int32_t U_EXPORT2
u_vsprintf_u(UChar * buffer,const UChar * patternSpecification,va_list ap)200 u_vsprintf_u(UChar *buffer,
201 const UChar *patternSpecification,
202 va_list ap)
203 {
204 return u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap);
205 }
206
207 static const u_printf_stream_handler g_sprintf_stream_handler = {
208 u_sprintf_write,
209 u_sprintf_pad_and_justify
210 };
211
212 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_vsnprintf_u(UChar * buffer,int32_t count,const UChar * patternSpecification,va_list ap)213 u_vsnprintf_u(UChar *buffer,
214 int32_t count,
215 const UChar *patternSpecification,
216 va_list ap)
217 {
218 int32_t written = 0; /* haven't written anything yet */
219
220 u_localized_print_string outStr;
221
222 if (count < 0) {
223 count = INT32_MAX;
224 }
225
226 outStr.str = buffer;
227 outStr.len = count;
228 outStr.available = count;
229
230 if(u_locbund_init(&outStr.fBundle, "en_US_POSIX") == 0) {
231 return 0;
232 }
233
234 /* parse and print the whole format string */
235 u_printf_parse(&g_sprintf_stream_handler, patternSpecification, &outStr, &outStr, &outStr.fBundle, &written, ap);
236
237 /* Terminate the buffer, if there's room. */
238 if (outStr.available > 0) {
239 buffer[outStr.len - outStr.available] = 0x0000;
240 }
241
242 /* Release the cloned bundle, if we cloned it. */
243 u_locbund_close(&outStr.fBundle);
244
245 /* return # of UChars written */
246 return written;
247 }
248
249 #endif /* #if !UCONFIG_NO_FORMATTING */
250
251