aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/icu/io/sprintf.cpp
blob: 48d9bcc27c510a7b6d5f089051f012f3d246dc57 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
*
*   Copyright (C) 2001-2014, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
******************************************************************************
*
* File sprintf.c
*
* Modification History:
*
*   Date        Name            Description
*   02/08/2001  george          Creation. Copied from uprintf.c
*   03/27/2002  Mark Schneckloth Many fixes regarding alignment, null termination
*       (mschneckloth@atomz.com) and other various problems.
*   08/07/2003  george          Reunify printf implementations
*******************************************************************************
*/

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION

#include "unicode/ustdio.h"
#include "unicode/ustring.h"
#include "unicode/putil.h"

#include "uprintf.h"
#include "locbund.h"

#include "cmemory.h"
#include <ctype.h>

/* u_minstrncpy copies the minimum number of code units of (count or output->available) */
static int32_t
u_sprintf_write(void        *context,
                const char16_t *str,
                int32_t     count)
{
    u_localized_print_string *output = (u_localized_print_string *)context;

    /* just calculating buffer size */
    if (output->str == 0) {
        return count;
    }

    int32_t size = ufmt_min(count, output->available);

    u_strncpy(output->str + (output->len - output->available), str, size);
    output->available -= size;
    return size;
}

static int32_t
u_sprintf_pad_and_justify(void                        *context,
                          const u_printf_spec_info    *info,
                          const char16_t              *result,
                          int32_t                     resultLen)
{
    u_localized_print_string *output = (u_localized_print_string *)context;
    int32_t written = 0;
    int32_t lengthOfResult = resultLen;

    /* just calculating buffer size */
    if (output->str == 0 &&
        info->fWidth != -1 && resultLen < info->fWidth) {
        return info->fWidth;
    }

    resultLen = ufmt_min(resultLen, output->available);

    /* pad and justify, if needed */
    if(info->fWidth != -1 && resultLen < info->fWidth) {
        int32_t paddingLeft = info->fWidth - resultLen;
        int32_t outputPos = output->len - output->available;
  
        if (paddingLeft + resultLen > output->available) {
            paddingLeft = output->available - resultLen;
            if (paddingLeft < 0) {
                paddingLeft = 0;
            }
            /* paddingLeft = output->available - resultLen;*/
        }
        written += paddingLeft;

        /* left justify */
        if(info->fLeft) {
            written += u_sprintf_write(output, result, resultLen);
            u_memset(&output->str[outputPos + resultLen], info->fPadChar, paddingLeft);
            output->available -= paddingLeft;
        }
        /* right justify */
        else {
            u_memset(&output->str[outputPos], info->fPadChar, paddingLeft);
            output->available -= paddingLeft;
            written += u_sprintf_write(output, result, resultLen);
        }
    }
    /* just write the formatted output */
    else {
        written = u_sprintf_write(output, result, resultLen);
    }
    
    if (written >= 0 && lengthOfResult > written) {
    	return lengthOfResult;
    }

    return written;
}

U_CAPI int32_t U_EXPORT2
u_sprintf(char16_t    *buffer,
          const char    *patternSpecification,
          ... )
{
    va_list ap;
    int32_t written;

    va_start(ap, patternSpecification);
    written = u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap);
    va_end(ap);

    return written;
}

U_CAPI int32_t U_EXPORT2
u_sprintf_u(char16_t  *buffer,
            const char16_t *patternSpecification,
            ... )
{
    va_list ap;
    int32_t written;

    va_start(ap, patternSpecification);
    written = u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap);
    va_end(ap);

    return written;
}

U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_vsprintf(char16_t    *buffer,
           const char     *patternSpecification,
           va_list         ap)
{
    return u_vsnprintf(buffer, INT32_MAX, patternSpecification, ap);
}

U_CAPI int32_t U_EXPORT2
u_snprintf(char16_t    *buffer,
           int32_t         count,
           const char    *patternSpecification,
           ... )
{
    va_list ap;
    int32_t written;

    va_start(ap, patternSpecification);
    written = u_vsnprintf(buffer, count, patternSpecification, ap);
    va_end(ap);

    return written;
}

U_CAPI int32_t U_EXPORT2
u_snprintf_u(char16_t  *buffer,
             int32_t        count,
             const char16_t *patternSpecification,
             ... )
{
    va_list ap;
    int32_t written;

    va_start(ap, patternSpecification);
    written = u_vsnprintf_u(buffer, count, patternSpecification, ap);
    va_end(ap);

    return written;
}

U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_vsnprintf(char16_t    *buffer,
            int32_t         count,
            const char     *patternSpecification,
            va_list         ap)
{
    int32_t written;
    char16_t *pattern;
    char16_t patBuffer[UFMT_DEFAULT_BUFFER_SIZE];
    int32_t size = (int32_t)strlen(patternSpecification) + 1;

    /* convert from the default codepage to Unicode */
    if (size >= (int32_t)MAX_UCHAR_BUFFER_SIZE(patBuffer)) {
        pattern = (char16_t *)uprv_malloc(size * sizeof(char16_t));
        if(pattern == 0) {
            return 0;
        }
    }
    else {
        pattern = patBuffer;
    }
    u_charsToUChars(patternSpecification, pattern, size);

    /* do the work */
    written = u_vsnprintf_u(buffer, count, pattern, ap);

    /* clean up */
    if (pattern != patBuffer) {
        uprv_free(pattern);
    }

    return written;
}

U_CAPI int32_t U_EXPORT2 
u_vsprintf_u(char16_t    *buffer,
             const char16_t *patternSpecification,
             va_list     ap) 
{ 
    return u_vsnprintf_u(buffer, INT32_MAX, patternSpecification, ap); 
} 

static const u_printf_stream_handler g_sprintf_stream_handler = {
    u_sprintf_write,
    u_sprintf_pad_and_justify
};

U_CAPI int32_t  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
u_vsnprintf_u(char16_t *buffer,
              int32_t        count,
              const char16_t *patternSpecification,
              va_list        ap)
{
    int32_t          written = 0;   /* haven't written anything yet */
    int32_t			 result = 0; /* test the return value of u_printf_parse */

    u_localized_print_string outStr;

    if (count < 0) {
        count = INT32_MAX;
    }

    outStr.str = buffer;
    outStr.len = count;
    outStr.available = count;

    if(u_locbund_init(&outStr.fBundle, "en_US_POSIX") == 0) {
        return 0;
    }

    /* parse and print the whole format string */
    result = u_printf_parse(&g_sprintf_stream_handler, patternSpecification, &outStr, &outStr, &outStr.fBundle, &written, ap);
    
    /* Terminate the buffer, if there's room. */
    if (outStr.available > 0) {
        buffer[outStr.len - outStr.available] = 0x0000;
    }

    /* Release the cloned bundle, if we cloned it. */
    u_locbund_close(&outStr.fBundle);

    /* parsing error */ 
    if (result < 0) {
    	return result;
    }
    /* return # of UChars written */
    return written;
}

#endif /* #if !UCONFIG_NO_FORMATTING */