Coverage Report

Created: 2024-05-20 06:23

/src/nspr/pr/src/io/prprf.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
/*
7
** Portable safe sprintf code.
8
**
9
** Author: Kipp E.B. Hickman
10
*/
11
#include <stdarg.h>
12
#include <stddef.h>
13
#include <stdio.h>
14
#include <string.h>
15
#include "primpl.h"
16
#include "prprf.h"
17
#include "prlong.h"
18
#include "prlog.h"
19
#include "prmem.h"
20
21
#if defined(_MSC_VER) && _MSC_VER < 1900
22
#define snprintf _snprintf
23
#endif
24
25
/*
26
** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
27
*/
28
29
/*
30
** XXX This needs to be internationalized!
31
*/
32
33
typedef struct SprintfStateStr SprintfState;
34
35
struct SprintfStateStr {
36
    int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);
37
38
    char *base;
39
    char *cur;
40
    PRUint32 maxlen;  /* Must not exceed PR_INT32_MAX. */
41
42
    int (*func)(void *arg, const char *sp, PRUint32 len);
43
    void *arg;
44
};
45
46
/*
47
** Numbered Argument
48
*/
49
struct NumArg {
50
    int type;           /* type of the numbered argument    */
51
    union {             /* the numbered argument            */
52
        int i;
53
        unsigned int ui;
54
        PRInt32 i32;
55
        PRUint32 ui32;
56
        PRInt64 ll;
57
        PRUint64 ull;
58
        double d;
59
        const char *s;
60
        int *ip;
61
#ifdef WIN32
62
        const WCHAR *ws;
63
#endif
64
    } u;
65
};
66
67
0
#define NAS_DEFAULT_NUM 20  /* default number of NumberedArgument array */
68
69
/*
70
** For numeric types, the signed versions must have even values,
71
** and their corresponding unsigned versions must have the subsequent
72
** odd value.
73
*/
74
0
#define TYPE_INT16  0
75
0
#define TYPE_UINT16 1
76
133k
#define TYPE_INTN   2
77
0
#define TYPE_UINTN  3
78
15.0k
#define TYPE_INT32  4
79
14.7k
#define TYPE_UINT32 5
80
290
#define TYPE_INT64  6
81
290
#define TYPE_UINT64 7
82
0
#define TYPE_STRING 8
83
0
#define TYPE_DOUBLE 9
84
0
#define TYPE_INTSTR 10
85
#ifdef WIN32
86
#define TYPE_WSTRING    11
87
#endif
88
0
#define TYPE_UNKNOWN    20
89
90
148k
#define FLAG_LEFT   0x1
91
133k
#define FLAG_SIGNED 0x2
92
0
#define FLAG_SPACED 0x4
93
15.0k
#define FLAG_ZEROS  0x8
94
0
#define FLAG_NEG    0x10
95
96
/*
97
** Fill into the buffer using the data in src
98
*/
99
static int fill2(SprintfState *ss, const char *src, int srclen, int width,
100
                 int flags)
101
117k
{
102
117k
    char space = ' ';
103
117k
    int rv;
104
105
117k
    width -= srclen;
106
117k
    if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {    /* Right adjusting */
107
0
        if (flags & FLAG_ZEROS) {
108
0
            space = '0';
109
0
        }
110
0
        while (--width >= 0) {
111
0
            rv = (*ss->stuff)(ss, &space, 1);
112
0
            if (rv < 0) {
113
0
                return rv;
114
0
            }
115
0
        }
116
0
    }
117
118
    /* Copy out the source data */
119
117k
    rv = (*ss->stuff)(ss, src, srclen);
120
117k
    if (rv < 0) {
121
0
        return rv;
122
0
    }
123
124
117k
    if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {    /* Left adjusting */
125
0
        while (--width >= 0) {
126
0
            rv = (*ss->stuff)(ss, &space, 1);
127
0
            if (rv < 0) {
128
0
                return rv;
129
0
            }
130
0
        }
131
0
    }
132
117k
    return 0;
133
117k
}
134
135
/*
136
** Fill a number. The order is: optional-sign zero-filling conversion-digits
137
*/
138
static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
139
                  int prec, int type, int flags)
140
15.0k
{
141
15.0k
    int zerowidth = 0;
142
15.0k
    int precwidth = 0;
143
15.0k
    int signwidth = 0;
144
15.0k
    int leftspaces = 0;
145
15.0k
    int rightspaces = 0;
146
15.0k
    int cvtwidth;
147
15.0k
    int rv;
148
15.0k
    char sign;
149
150
15.0k
    if ((type & 1) == 0) {
151
0
        if (flags & FLAG_NEG) {
152
0
            sign = '-';
153
0
            signwidth = 1;
154
0
        } else if (flags & FLAG_SIGNED) {
155
0
            sign = '+';
156
0
            signwidth = 1;
157
0
        } else if (flags & FLAG_SPACED) {
158
0
            sign = ' ';
159
0
            signwidth = 1;
160
0
        }
161
0
    }
162
15.0k
    cvtwidth = signwidth + srclen;
163
164
15.0k
    if (prec > 0) {
165
0
        if (prec > srclen) {
166
0
            precwidth = prec - srclen;      /* Need zero filling */
167
0
            cvtwidth += precwidth;
168
0
        }
169
0
    }
170
171
15.0k
    if ((flags & FLAG_ZEROS) && (prec < 0)) {
172
0
        if (width > cvtwidth) {
173
0
            zerowidth = width - cvtwidth;   /* Zero filling */
174
0
            cvtwidth += zerowidth;
175
0
        }
176
0
    }
177
178
15.0k
    if (flags & FLAG_LEFT) {
179
0
        if (width > cvtwidth) {
180
            /* Space filling on the right (i.e. left adjusting) */
181
0
            rightspaces = width - cvtwidth;
182
0
        }
183
15.0k
    } else {
184
15.0k
        if (width > cvtwidth) {
185
            /* Space filling on the left (i.e. right adjusting) */
186
0
            leftspaces = width - cvtwidth;
187
0
        }
188
15.0k
    }
189
15.0k
    while (--leftspaces >= 0) {
190
0
        rv = (*ss->stuff)(ss, " ", 1);
191
0
        if (rv < 0) {
192
0
            return rv;
193
0
        }
194
0
    }
195
15.0k
    if (signwidth) {
196
0
        rv = (*ss->stuff)(ss, &sign, 1);
197
0
        if (rv < 0) {
198
0
            return rv;
199
0
        }
200
0
    }
201
15.0k
    while (--precwidth >= 0) {
202
0
        rv = (*ss->stuff)(ss, "0", 1);
203
0
        if (rv < 0) {
204
0
            return rv;
205
0
        }
206
0
    }
207
15.0k
    while (--zerowidth >= 0) {
208
0
        rv = (*ss->stuff)(ss, "0", 1);
209
0
        if (rv < 0) {
210
0
            return rv;
211
0
        }
212
0
    }
213
15.0k
    rv = (*ss->stuff)(ss, src, srclen);
214
15.0k
    if (rv < 0) {
215
0
        return rv;
216
0
    }
217
15.0k
    while (--rightspaces >= 0) {
218
0
        rv = (*ss->stuff)(ss, " ", 1);
219
0
        if (rv < 0) {
220
0
            return rv;
221
0
        }
222
0
    }
223
15.0k
    return 0;
224
15.0k
}
225
226
/*
227
** Convert a long into its printable form
228
*/
229
static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
230
                 int type, int flags, const char *hexp)
231
14.7k
{
232
14.7k
    char cvtbuf[100];
233
14.7k
    char *cvt;
234
14.7k
    int digits;
235
236
    /* according to the man page this needs to happen */
237
14.7k
    if ((prec == 0) && (num == 0)) {
238
0
        return 0;
239
0
    }
240
241
    /*
242
    ** Converting decimal is a little tricky. In the unsigned case we
243
    ** need to stop when we hit 10 digits. In the signed case, we can
244
    ** stop when the number is zero.
245
    */
246
14.7k
    cvt = cvtbuf + sizeof(cvtbuf);
247
14.7k
    digits = 0;
248
35.2k
    while (num) {
249
20.5k
        int digit = (((unsigned long)num) % radix) & 0xF;
250
20.5k
        *--cvt = hexp[digit];
251
20.5k
        digits++;
252
20.5k
        num = (long)(((unsigned long)num) / radix);
253
20.5k
    }
254
14.7k
    if (digits == 0) {
255
1.21k
        *--cvt = '0';
256
1.21k
        digits++;
257
1.21k
    }
258
259
    /*
260
    ** Now that we have the number converted without its sign, deal with
261
    ** the sign and zero padding.
262
    */
263
14.7k
    return fill_n(ss, cvt, digits, width, prec, type, flags);
264
14.7k
}
265
266
/*
267
** Convert a 64-bit integer into its printable form
268
*/
269
static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix,
270
                  int type, int flags, const char *hexp)
271
290
{
272
290
    char cvtbuf[100];
273
290
    char *cvt;
274
290
    int digits;
275
290
    PRInt64 rad;
276
277
    /* according to the man page this needs to happen */
278
290
    if ((prec == 0) && (LL_IS_ZERO(num))) {
279
0
        return 0;
280
0
    }
281
282
    /*
283
    ** Converting decimal is a little tricky. In the unsigned case we
284
    ** need to stop when we hit 10 digits. In the signed case, we can
285
    ** stop when the number is zero.
286
    */
287
290
    LL_I2L(rad, radix);
288
290
    cvt = cvtbuf + sizeof(cvtbuf);
289
290
    digits = 0;
290
3.15k
    while (!LL_IS_ZERO(num)) {
291
2.86k
        PRInt32 digit;
292
2.86k
        PRInt64 quot, rem;
293
2.86k
        LL_UDIVMOD(&quot, &rem, num, rad);
294
2.86k
        LL_L2I(digit, rem);
295
2.86k
        *--cvt = hexp[digit & 0xf];
296
2.86k
        digits++;
297
2.86k
        num = quot;
298
2.86k
    }
299
290
    if (digits == 0) {
300
0
        *--cvt = '0';
301
0
        digits++;
302
0
    }
303
304
    /*
305
    ** Now that we have the number converted without its sign, deal with
306
    ** the sign and zero padding.
307
    */
308
290
    return fill_n(ss, cvt, digits, width, prec, type, flags);
309
290
}
310
311
/*
312
** Convert a double precision floating point number into its printable
313
** form.
314
**
315
** XXX stop using snprintf to convert floating point
316
*/
317
static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
318
0
{
319
0
    char fin[20];
320
0
    char fout[300];
321
0
    int amount = fmt1 - fmt0;
322
323
0
    if (amount <= 0 || amount >= sizeof(fin)) {
324
        /* Totally bogus % command to snprintf. Just ignore it */
325
0
        return 0;
326
0
    }
327
0
    memcpy(fin, fmt0, amount);
328
0
    fin[amount] = 0;
329
330
    /* Convert floating point using the native snprintf code */
331
0
#ifdef DEBUG
332
0
    {
333
0
        const char *p = fin;
334
0
        while (*p) {
335
0
            PR_ASSERT(*p != 'L');
336
0
            p++;
337
0
        }
338
0
    }
339
0
#endif
340
0
    memset(fout, 0, sizeof(fout));
341
0
    snprintf(fout, sizeof(fout), fin, d);
342
    /* Explicitly null-terminate fout because on Windows snprintf doesn't
343
     * append a null-terminator if the buffer is too small. */
344
0
    fout[sizeof(fout) - 1] = '\0';
345
346
0
    return (*ss->stuff)(ss, fout, strlen(fout));
347
0
}
348
349
/*
350
** Convert a string into its printable form.  "width" is the output
351
** width. "prec" is the maximum number of characters of "s" to output,
352
** where -1 means until NUL.
353
*/
354
static int cvt_s(SprintfState *ss, const char *str, int width, int prec,
355
                 int flags)
356
117k
{
357
117k
    int slen;
358
359
117k
    if (prec == 0) {
360
0
        return 0;
361
0
    }
362
363
    /* Limit string length by precision value */
364
117k
    if (!str) {
365
0
        str = "(null)";
366
0
    }
367
117k
    if (prec > 0) {
368
        /* this is:  slen = strnlen(str, prec); */
369
0
        register const char *s;
370
371
0
        for(s = str; prec && *s; s++, prec-- )
372
0
            ;
373
0
        slen = s - str;
374
117k
    } else {
375
117k
        slen = strlen(str);
376
117k
    }
377
378
    /* and away we go */
379
117k
    return fill2(ss, str, slen, width, flags);
380
117k
}
381
382
/*
383
** BuildArgArray stands for Numbered Argument list Sprintf
384
** for example,
385
**  fmt = "%4$i, %2$d, %3s, %1d";
386
** the number must start from 1, and no gap among them
387
*/
388
389
static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray )
390
21.3k
{
391
21.3k
    int number = 0, cn = 0, i;
392
21.3k
    const char* p;
393
21.3k
    char  c;
394
21.3k
    struct NumArg* nas;
395
396
397
    /*
398
    **  first pass:
399
    **  determine how many legal % I have got, then allocate space
400
    */
401
402
21.3k
    p = fmt;
403
21.3k
    *rv = 0;
404
21.3k
    i = 0;
405
2.09M
    while( ( c = *p++ ) != 0 ) {
406
2.07M
        if( c != '%' ) {
407
1.93M
            continue;
408
1.93M
        }
409
133k
        if( ( c = *p++ ) == '%' ) { /* skip %% case */
410
0
            continue;
411
0
        }
412
413
133k
        while( c != 0 ) {
414
133k
            if( c > '9' || c < '0' ) {
415
133k
                if( c == '$' ) {    /* numbered argument case */
416
0
                    if( i > 0 ) {
417
0
                        *rv = -1;
418
0
                        return NULL;
419
0
                    }
420
0
                    number++;
421
133k
                } else {        /* non-numbered argument case */
422
133k
                    if( number > 0 ) {
423
0
                        *rv = -1;
424
0
                        return NULL;
425
0
                    }
426
133k
                    i = 1;
427
133k
                }
428
133k
                break;
429
133k
            }
430
431
0
            c = *p++;
432
0
        }
433
133k
    }
434
435
21.3k
    if( number == 0 ) {
436
21.3k
        return NULL;
437
21.3k
    }
438
439
440
0
    if( number > NAS_DEFAULT_NUM ) {
441
0
        nas = (struct NumArg*)PR_MALLOC( number * sizeof( struct NumArg ) );
442
0
        if( !nas ) {
443
0
            *rv = -1;
444
0
            return NULL;
445
0
        }
446
0
    } else {
447
0
        nas = nasArray;
448
0
    }
449
450
0
    for( i = 0; i < number; i++ ) {
451
0
        nas[i].type = TYPE_UNKNOWN;
452
0
    }
453
454
455
    /*
456
    ** second pass:
457
    ** set nas[].type
458
    */
459
460
0
    p = fmt;
461
0
    while( ( c = *p++ ) != 0 ) {
462
0
        if( c != '%' ) {
463
0
            continue;
464
0
        }
465
0
        c = *p++;
466
0
        if( c == '%' ) {
467
0
            continue;
468
0
        }
469
470
0
        cn = 0;
471
0
        while( c && c != '$' ) {    /* should improve error check later */
472
0
            cn = cn*10 + c - '0';
473
0
            c = *p++;
474
0
        }
475
476
0
        if( !c || cn < 1 || cn > number ) {
477
0
            *rv = -1;
478
0
            break;
479
0
        }
480
481
        /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
482
0
        cn--;
483
0
        if( nas[cn].type != TYPE_UNKNOWN ) {
484
0
            continue;
485
0
        }
486
487
0
        c = *p++;
488
489
        /* width */
490
0
        if (c == '*') {
491
            /* not supported feature, for the argument is not numbered */
492
0
            *rv = -1;
493
0
            break;
494
0
        }
495
496
0
        while ((c >= '0') && (c <= '9')) {
497
0
            c = *p++;
498
0
        }
499
500
        /* precision */
501
0
        if (c == '.') {
502
0
            c = *p++;
503
0
            if (c == '*') {
504
                /* not supported feature, for the argument is not numbered */
505
0
                *rv = -1;
506
0
                break;
507
0
            }
508
509
0
            while ((c >= '0') && (c <= '9')) {
510
0
                c = *p++;
511
0
            }
512
0
        }
513
514
        /* size */
515
0
        nas[cn].type = TYPE_INTN;
516
0
        if (c == 'h') {
517
0
            nas[cn].type = TYPE_INT16;
518
0
            c = *p++;
519
0
        } else if (c == 'L') {
520
            /* XXX not quite sure here */
521
0
            nas[cn].type = TYPE_INT64;
522
0
            c = *p++;
523
0
        } else if (c == 'l') {
524
0
            nas[cn].type = TYPE_INT32;
525
0
            c = *p++;
526
0
            if (c == 'l') {
527
0
                nas[cn].type = TYPE_INT64;
528
0
                c = *p++;
529
0
            }
530
0
        } else if (c == 'z') {
531
0
            if (sizeof(size_t) == sizeof(PRInt32)) {
532
0
                nas[ cn ].type = TYPE_INT32;
533
0
            } else if (sizeof(size_t) == sizeof(PRInt64)) {
534
0
                nas[ cn ].type = TYPE_INT64;
535
0
            } else {
536
0
                nas[ cn ].type = TYPE_UNKNOWN;
537
0
            }
538
0
            c = *p++;
539
0
        }
540
541
        /* format */
542
0
        switch (c) {
543
0
            case 'd':
544
0
            case 'c':
545
0
            case 'i':
546
0
            case 'o':
547
0
            case 'u':
548
0
            case 'x':
549
0
            case 'X':
550
0
                break;
551
552
0
            case 'e':
553
0
            case 'f':
554
0
            case 'g':
555
0
                nas[ cn ].type = TYPE_DOUBLE;
556
0
                break;
557
558
0
            case 'p':
559
                /* XXX should use cpp */
560
0
                if (sizeof(void *) == sizeof(PRInt32)) {
561
0
                    nas[ cn ].type = TYPE_UINT32;
562
0
                } else if (sizeof(void *) == sizeof(PRInt64)) {
563
0
                    nas[ cn ].type = TYPE_UINT64;
564
0
                } else if (sizeof(void *) == sizeof(PRIntn)) {
565
0
                    nas[ cn ].type = TYPE_UINTN;
566
0
                } else {
567
0
                    nas[ cn ].type = TYPE_UNKNOWN;
568
0
                }
569
0
                break;
570
571
0
            case 'S':
572
#ifdef WIN32
573
                nas[ cn ].type = TYPE_WSTRING;
574
                break;
575
#endif
576
0
            case 'C':
577
0
            case 'E':
578
0
            case 'G':
579
                /* XXX not supported I suppose */
580
0
                PR_ASSERT(0);
581
0
                nas[ cn ].type = TYPE_UNKNOWN;
582
0
                break;
583
584
0
            case 's':
585
0
                nas[ cn ].type = TYPE_STRING;
586
0
                break;
587
588
0
            case 'n':
589
0
                nas[ cn ].type = TYPE_INTSTR;
590
0
                break;
591
592
0
            default:
593
0
                PR_ASSERT(0);
594
0
                nas[ cn ].type = TYPE_UNKNOWN;
595
0
                break;
596
0
        }
597
598
        /* get a legal para. */
599
0
        if( nas[ cn ].type == TYPE_UNKNOWN ) {
600
0
            *rv = -1;
601
0
            break;
602
0
        }
603
0
    }
604
605
606
    /*
607
    ** third pass
608
    ** fill the nas[cn].ap
609
    */
610
611
0
    if( *rv < 0 ) {
612
0
        if( nas != nasArray ) {
613
0
            PR_DELETE( nas );
614
0
        }
615
0
        return NULL;
616
0
    }
617
618
0
    cn = 0;
619
0
    while( cn < number ) {
620
0
        if( nas[cn].type == TYPE_UNKNOWN ) {
621
0
            cn++;
622
0
            continue;
623
0
        }
624
625
0
        switch( nas[cn].type ) {
626
0
            case TYPE_INT16:
627
0
            case TYPE_UINT16:
628
0
            case TYPE_INTN:
629
0
                nas[cn].u.i = va_arg( ap, int );
630
0
                break;
631
632
0
            case TYPE_UINTN:
633
0
                nas[cn].u.ui = va_arg( ap, unsigned int );
634
0
                break;
635
636
0
            case TYPE_INT32:
637
0
                nas[cn].u.i32 = va_arg( ap, PRInt32 );
638
0
                break;
639
640
0
            case TYPE_UINT32:
641
0
                nas[cn].u.ui32 = va_arg( ap, PRUint32 );
642
0
                break;
643
644
0
            case TYPE_INT64:
645
0
                nas[cn].u.ll = va_arg( ap, PRInt64 );
646
0
                break;
647
648
0
            case TYPE_UINT64:
649
0
                nas[cn].u.ull = va_arg( ap, PRUint64 );
650
0
                break;
651
652
0
            case TYPE_STRING:
653
0
                nas[cn].u.s = va_arg( ap, char* );
654
0
                break;
655
656
#ifdef WIN32
657
            case TYPE_WSTRING:
658
                nas[cn].u.ws = va_arg( ap, WCHAR* );
659
                break;
660
#endif
661
662
0
            case TYPE_INTSTR:
663
0
                nas[cn].u.ip = va_arg( ap, int* );
664
0
                break;
665
666
0
            case TYPE_DOUBLE:
667
0
                nas[cn].u.d = va_arg( ap, double );
668
0
                break;
669
670
0
            default:
671
0
                if( nas != nasArray ) {
672
0
                    PR_DELETE( nas );
673
0
                }
674
0
                *rv = -1;
675
0
                return NULL;
676
0
        }
677
678
0
        cn++;
679
0
    }
680
681
682
0
    return nas;
683
0
}
684
685
/*
686
** The workhorse sprintf code.
687
*/
688
static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
689
21.3k
{
690
21.3k
    char c;
691
21.3k
    int flags, width, prec, radix, type;
692
21.3k
    union {
693
21.3k
        char ch;
694
21.3k
        int i;
695
21.3k
        long l;
696
21.3k
        PRInt64 ll;
697
21.3k
        double d;
698
21.3k
        const char *s;
699
21.3k
        int *ip;
700
#ifdef WIN32
701
        const WCHAR *ws;
702
#endif
703
21.3k
    } u;
704
21.3k
    const char *fmt0;
705
21.3k
    static char *hex = "0123456789abcdef";
706
21.3k
    static char *HEX = "0123456789ABCDEF";
707
21.3k
    char *hexp;
708
21.3k
    int rv, i;
709
21.3k
    struct NumArg* nas = NULL;
710
21.3k
    struct NumArg* nap = NULL;
711
21.3k
    struct NumArg  nasArray[ NAS_DEFAULT_NUM ];
712
21.3k
    char  pattern[20];
713
21.3k
    const char* dolPt = NULL;  /* in "%4$.2f", dolPt will point to . */
714
#ifdef WIN32
715
    char *pBuf = NULL;
716
#endif
717
718
    /*
719
    ** build an argument array, IF the fmt is numbered argument
720
    ** list style, to contain the Numbered Argument list pointers
721
    */
722
723
21.3k
    nas = BuildArgArray( fmt, ap, &rv, nasArray );
724
21.3k
    if( rv < 0 ) {
725
        /* the fmt contains error Numbered Argument format, jliu@netscape.com */
726
0
        PR_ASSERT(0);
727
0
        return rv;
728
0
    }
729
730
2.07M
    while ((c = *fmt++) != 0) {
731
2.05M
        if (c != '%') {
732
1.92M
            rv = (*ss->stuff)(ss, fmt - 1, 1);
733
1.92M
            if (rv < 0) {
734
0
                return rv;
735
0
            }
736
1.92M
            continue;
737
1.92M
        }
738
133k
        fmt0 = fmt - 1;
739
740
        /*
741
        ** Gobble up the % format string. Hopefully we have handled all
742
        ** of the strange cases!
743
        */
744
133k
        flags = 0;
745
133k
        c = *fmt++;
746
133k
        if (c == '%') {
747
            /* quoting a % with %% */
748
0
            rv = (*ss->stuff)(ss, fmt - 1, 1);
749
0
            if (rv < 0) {
750
0
                return rv;
751
0
            }
752
0
            continue;
753
0
        }
754
755
133k
        if( nas != NULL ) {
756
            /* the fmt contains the Numbered Arguments feature */
757
0
            i = 0;
758
0
            while( c && c != '$' ) {    /* should improve error check later */
759
0
                i = ( i * 10 ) + ( c - '0' );
760
0
                c = *fmt++;
761
0
            }
762
763
0
            if( nas[i-1].type == TYPE_UNKNOWN ) {
764
0
                if( nas && ( nas != nasArray ) ) {
765
0
                    PR_DELETE( nas );
766
0
                }
767
0
                return -1;
768
0
            }
769
770
0
            nap = &nas[i-1];
771
0
            dolPt = fmt;
772
0
            c = *fmt++;
773
0
        }
774
775
        /*
776
         * Examine optional flags.  Note that we do not implement the
777
         * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
778
         * somewhat ambiguous and not ideal, which is perhaps why
779
         * the various sprintf() implementations are inconsistent
780
         * on this feature.
781
         */
782
133k
        while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
783
0
            if (c == '-') {
784
0
                flags |= FLAG_LEFT;
785
0
            }
786
0
            if (c == '+') {
787
0
                flags |= FLAG_SIGNED;
788
0
            }
789
0
            if (c == ' ') {
790
0
                flags |= FLAG_SPACED;
791
0
            }
792
0
            if (c == '0') {
793
0
                flags |= FLAG_ZEROS;
794
0
            }
795
0
            c = *fmt++;
796
0
        }
797
133k
        if (flags & FLAG_SIGNED) {
798
0
            flags &= ~FLAG_SPACED;
799
0
        }
800
133k
        if (flags & FLAG_LEFT) {
801
0
            flags &= ~FLAG_ZEROS;
802
0
        }
803
804
        /* width */
805
133k
        if (c == '*') {
806
0
            c = *fmt++;
807
0
            width = va_arg(ap, int);
808
133k
        } else {
809
133k
            width = 0;
810
133k
            while ((c >= '0') && (c <= '9')) {
811
0
                width = (width * 10) + (c - '0');
812
0
                c = *fmt++;
813
0
            }
814
133k
        }
815
816
        /* precision */
817
133k
        prec = -1;
818
133k
        if (c == '.') {
819
0
            c = *fmt++;
820
0
            if (c == '*') {
821
0
                c = *fmt++;
822
0
                prec = va_arg(ap, int);
823
0
            } else {
824
0
                prec = 0;
825
0
                while ((c >= '0') && (c <= '9')) {
826
0
                    prec = (prec * 10) + (c - '0');
827
0
                    c = *fmt++;
828
0
                }
829
0
            }
830
0
        }
831
832
        /* size */
833
133k
        type = TYPE_INTN;
834
133k
        if (c == 'h') {
835
0
            type = TYPE_INT16;
836
0
            c = *fmt++;
837
133k
        } else if (c == 'L') {
838
            /* XXX not quite sure here */
839
0
            type = TYPE_INT64;
840
0
            c = *fmt++;
841
133k
        } else if (c == 'l') {
842
15.0k
            type = TYPE_INT32;
843
15.0k
            c = *fmt++;
844
15.0k
            if (c == 'l') {
845
290
                type = TYPE_INT64;
846
290
                c = *fmt++;
847
290
            }
848
117k
        } else if (c == 'z') {
849
0
            if (sizeof(size_t) == sizeof(PRInt32)) {
850
0
                type = TYPE_INT32;
851
0
            } else if (sizeof(size_t) == sizeof(PRInt64)) {
852
0
                type = TYPE_INT64;
853
0
            }
854
0
            c = *fmt++;
855
0
        }
856
857
        /* format */
858
133k
        hexp = hex;
859
133k
        switch (c) {
860
0
            case 'd': case 'i':           /* decimal/integer */
861
0
                radix = 10;
862
0
                goto fetch_and_convert;
863
864
0
            case 'o':             /* octal */
865
0
                radix = 8;
866
0
                type |= 1;
867
0
                goto fetch_and_convert;
868
869
15.0k
            case 'u':             /* unsigned decimal */
870
15.0k
                radix = 10;
871
15.0k
                type |= 1;
872
15.0k
                goto fetch_and_convert;
873
874
0
            case 'x':             /* unsigned hex */
875
0
                radix = 16;
876
0
                type |= 1;
877
0
                goto fetch_and_convert;
878
879
0
            case 'X':             /* unsigned HEX */
880
0
                radix = 16;
881
0
                hexp = HEX;
882
0
                type |= 1;
883
0
                goto fetch_and_convert;
884
885
15.0k
fetch_and_convert:
886
15.0k
                switch (type) {
887
0
                    case TYPE_INT16:
888
0
                        u.l = nas ? nap->u.i : va_arg(ap, int);
889
0
                        if (u.l < 0) {
890
0
                            u.l = -u.l;
891
0
                            flags |= FLAG_NEG;
892
0
                        }
893
0
                        goto do_long;
894
0
                    case TYPE_UINT16:
895
0
                        u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff;
896
0
                        goto do_long;
897
0
                    case TYPE_INTN:
898
0
                        u.l = nas ? nap->u.i : va_arg(ap, int);
899
0
                        if (u.l < 0) {
900
0
                            u.l = -u.l;
901
0
                            flags |= FLAG_NEG;
902
0
                        }
903
0
                        goto do_long;
904
0
                    case TYPE_UINTN:
905
0
                        u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int));
906
0
                        goto do_long;
907
908
0
                    case TYPE_INT32:
909
0
                        u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32);
910
0
                        if (u.l < 0) {
911
0
                            u.l = -u.l;
912
0
                            flags |= FLAG_NEG;
913
0
                        }
914
0
                        goto do_long;
915
14.7k
                    case TYPE_UINT32:
916
14.7k
                        u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32));
917
14.7k
do_long:
918
14.7k
                        rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
919
14.7k
                        if (rv < 0) {
920
0
                            return rv;
921
0
                        }
922
14.7k
                        break;
923
924
14.7k
                    case TYPE_INT64:
925
0
                        u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64);
926
0
                        if (!LL_GE_ZERO(u.ll)) {
927
0
                            LL_NEG(u.ll, u.ll);
928
0
                            flags |= FLAG_NEG;
929
0
                        }
930
0
                        goto do_longlong;
931
290
                    case TYPE_UINT64:
932
290
                        u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64);
933
290
do_longlong:
934
290
                        rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
935
290
                        if (rv < 0) {
936
0
                            return rv;
937
0
                        }
938
290
                        break;
939
15.0k
                }
940
15.0k
                break;
941
942
15.0k
            case 'e':
943
0
            case 'E':
944
0
            case 'f':
945
0
            case 'g':
946
0
                u.d = nas ? nap->u.d : va_arg(ap, double);
947
0
                if( nas != NULL ) {
948
0
                    i = fmt - dolPt;
949
0
                    if( i < sizeof( pattern ) ) {
950
0
                        pattern[0] = '%';
951
0
                        memcpy( &pattern[1], dolPt, i );
952
0
                        rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
953
0
                    }
954
0
                } else {
955
0
                    rv = cvt_f(ss, u.d, fmt0, fmt);
956
0
                }
957
958
0
                if (rv < 0) {
959
0
                    return rv;
960
0
                }
961
0
                break;
962
963
0
            case 'c':
964
0
                u.ch = nas ? nap->u.i : va_arg(ap, int);
965
0
                if ((flags & FLAG_LEFT) == 0) {
966
0
                    while (width-- > 1) {
967
0
                        rv = (*ss->stuff)(ss, " ", 1);
968
0
                        if (rv < 0) {
969
0
                            return rv;
970
0
                        }
971
0
                    }
972
0
                }
973
0
                rv = (*ss->stuff)(ss, &u.ch, 1);
974
0
                if (rv < 0) {
975
0
                    return rv;
976
0
                }
977
0
                if (flags & FLAG_LEFT) {
978
0
                    while (width-- > 1) {
979
0
                        rv = (*ss->stuff)(ss, " ", 1);
980
0
                        if (rv < 0) {
981
0
                            return rv;
982
0
                        }
983
0
                    }
984
0
                }
985
0
                break;
986
987
0
            case 'p':
988
0
                if (sizeof(void *) == sizeof(PRInt32)) {
989
0
                    type = TYPE_UINT32;
990
0
                } else if (sizeof(void *) == sizeof(PRInt64)) {
991
0
                    type = TYPE_UINT64;
992
0
                } else if (sizeof(void *) == sizeof(int)) {
993
0
                    type = TYPE_UINTN;
994
0
                } else {
995
0
                    PR_ASSERT(0);
996
0
                    break;
997
0
                }
998
0
                radix = 16;
999
0
                goto fetch_and_convert;
1000
1001
0
#ifndef WIN32
1002
0
            case 'S':
1003
                /* XXX not supported I suppose */
1004
0
                PR_ASSERT(0);
1005
0
                break;
1006
0
#endif
1007
1008
#if 0
1009
            case 'C':
1010
            case 'E':
1011
            case 'G':
1012
                /* XXX not supported I suppose */
1013
                PR_ASSERT(0);
1014
                break;
1015
#endif
1016
1017
#ifdef WIN32
1018
            case 'S':
1019
                u.ws = nas ? nap->u.ws : va_arg(ap, const WCHAR*);
1020
1021
                /* Get the required size in rv */
1022
                rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
1023
                if (rv == 0) {
1024
                    rv = 1;
1025
                }
1026
                pBuf = PR_MALLOC(rv);
1027
                WideCharToMultiByte(CP_ACP, 0, u.ws, -1, pBuf, (int)rv, NULL, NULL);
1028
                pBuf[rv-1] = '\0';
1029
1030
                rv = cvt_s(ss, pBuf, width, prec, flags);
1031
1032
                /* We don't need the allocated buffer anymore */
1033
                PR_Free(pBuf);
1034
                if (rv < 0) {
1035
                    return rv;
1036
                }
1037
                break;
1038
1039
#endif
1040
1041
117k
            case 's':
1042
117k
                u.s = nas ? nap->u.s : va_arg(ap, const char*);
1043
117k
                rv = cvt_s(ss, u.s, width, prec, flags);
1044
117k
                if (rv < 0) {
1045
0
                    return rv;
1046
0
                }
1047
117k
                break;
1048
1049
117k
            case 'n':
1050
0
                u.ip = nas ? nap->u.ip : va_arg(ap, int*);
1051
0
                if (u.ip) {
1052
0
                    *u.ip = ss->cur - ss->base;
1053
0
                }
1054
0
                break;
1055
1056
0
            default:
1057
                /* Not a % token after all... skip it */
1058
#if 0
1059
                PR_ASSERT(0);
1060
#endif
1061
0
                rv = (*ss->stuff)(ss, "%", 1);
1062
0
                if (rv < 0) {
1063
0
                    return rv;
1064
0
                }
1065
0
                rv = (*ss->stuff)(ss, fmt - 1, 1);
1066
0
                if (rv < 0) {
1067
0
                    return rv;
1068
0
                }
1069
133k
        }
1070
133k
    }
1071
1072
    /* Stuff trailing NUL */
1073
21.3k
    rv = (*ss->stuff)(ss, "\0", 1);
1074
1075
21.3k
    if( nas && ( nas != nasArray ) ) {
1076
0
        PR_DELETE( nas );
1077
0
    }
1078
1079
21.3k
    return rv;
1080
21.3k
}
1081
1082
/************************************************************************/
1083
1084
static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
1085
0
{
1086
0
    int rv;
1087
1088
    /*
1089
    ** We will add len to ss->maxlen at the end of the function. First check
1090
    ** if ss->maxlen + len would overflow or be greater than PR_INT32_MAX.
1091
    */
1092
0
    if (PR_UINT32_MAX - ss->maxlen < len || ss->maxlen + len > PR_INT32_MAX) {
1093
0
        return -1;
1094
0
    }
1095
0
    rv = (*ss->func)(ss->arg, sp, len);
1096
0
    if (rv < 0) {
1097
0
        return rv;
1098
0
    }
1099
0
    ss->maxlen += len;
1100
0
    return 0;
1101
0
}
1102
1103
PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg,
1104
                                   const char *fmt, ...)
1105
0
{
1106
0
    va_list ap;
1107
0
    PRUint32 rv;
1108
1109
0
    va_start(ap, fmt);
1110
0
    rv = PR_vsxprintf(func, arg, fmt, ap);
1111
0
    va_end(ap);
1112
0
    return rv;
1113
0
}
1114
1115
PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRStuffFunc func, void *arg,
1116
                                    const char *fmt, va_list ap)
1117
0
{
1118
0
    SprintfState ss;
1119
0
    int rv;
1120
1121
0
    ss.stuff = FuncStuff;
1122
0
    ss.func = func;
1123
0
    ss.arg = arg;
1124
0
    ss.maxlen = 0;
1125
0
    rv = dosprintf(&ss, fmt, ap);
1126
0
    return (rv < 0) ? (PRUint32)-1 : ss.maxlen;
1127
0
}
1128
1129
/*
1130
** Stuff routine that automatically grows the malloc'd output buffer
1131
** before it overflows.
1132
*/
1133
static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
1134
2.07M
{
1135
2.07M
    ptrdiff_t off;
1136
2.07M
    char *newbase;
1137
2.07M
    PRUint32 newlen;
1138
1139
2.07M
    off = ss->cur - ss->base;
1140
2.07M
    if (PR_UINT32_MAX - len < off) {
1141
        /* off + len would be too big. */
1142
0
        return -1;
1143
0
    }
1144
2.07M
    if (off + len >= ss->maxlen) {
1145
        /* Grow the buffer */
1146
98.0k
        PRUint32 increment = (len > 32) ? len : 32;
1147
98.0k
        if (PR_UINT32_MAX - ss->maxlen < increment) {
1148
            /* ss->maxlen + increment would overflow. */
1149
0
            return -1;
1150
0
        }
1151
98.0k
        newlen = ss->maxlen + increment;
1152
98.0k
        if (newlen > PR_INT32_MAX) {
1153
0
            return -1;
1154
0
        }
1155
98.0k
        if (ss->base) {
1156
76.7k
            newbase = (char*) PR_REALLOC(ss->base, newlen);
1157
76.7k
        } else {
1158
21.3k
            newbase = (char*) PR_MALLOC(newlen);
1159
21.3k
        }
1160
98.0k
        if (!newbase) {
1161
            /* Ran out of memory */
1162
0
            return -1;
1163
0
        }
1164
98.0k
        ss->base = newbase;
1165
98.0k
        ss->maxlen = newlen;
1166
98.0k
        ss->cur = ss->base + off;
1167
98.0k
    }
1168
1169
    /* Copy data */
1170
4.95M
    while (len) {
1171
2.87M
        --len;
1172
2.87M
        *ss->cur++ = *sp++;
1173
2.87M
    }
1174
2.07M
    PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen);
1175
2.07M
    return 0;
1176
2.07M
}
1177
1178
/*
1179
** sprintf into a malloc'd buffer
1180
*/
1181
PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...)
1182
21.3k
{
1183
21.3k
    va_list ap;
1184
21.3k
    char *rv;
1185
1186
21.3k
    va_start(ap, fmt);
1187
21.3k
    rv = PR_vsmprintf(fmt, ap);
1188
21.3k
    va_end(ap);
1189
21.3k
    return rv;
1190
21.3k
}
1191
1192
/*
1193
** Free memory allocated, for the caller, by PR_smprintf
1194
*/
1195
PR_IMPLEMENT(void) PR_smprintf_free(char *mem)
1196
21.3k
{
1197
21.3k
    PR_DELETE(mem);
1198
21.3k
}
1199
1200
PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap)
1201
21.3k
{
1202
21.3k
    SprintfState ss;
1203
21.3k
    int rv;
1204
1205
21.3k
    ss.stuff = GrowStuff;
1206
21.3k
    ss.base = 0;
1207
21.3k
    ss.cur = 0;
1208
21.3k
    ss.maxlen = 0;
1209
21.3k
    rv = dosprintf(&ss, fmt, ap);
1210
21.3k
    if (rv < 0) {
1211
0
        if (ss.base) {
1212
0
            PR_DELETE(ss.base);
1213
0
        }
1214
0
        return 0;
1215
0
    }
1216
21.3k
    return ss.base;
1217
21.3k
}
1218
1219
/*
1220
** Stuff routine that discards overflow data
1221
*/
1222
static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len)
1223
0
{
1224
0
    PRUint32 limit = ss->maxlen - (ss->cur - ss->base);
1225
1226
0
    if (len > limit) {
1227
0
        len = limit;
1228
0
    }
1229
0
    while (len) {
1230
0
        --len;
1231
0
        *ss->cur++ = *sp++;
1232
0
    }
1233
0
    return 0;
1234
0
}
1235
1236
/*
1237
** sprintf into a fixed size buffer. Make sure there is a NUL at the end
1238
** when finished.
1239
*/
1240
PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...)
1241
0
{
1242
0
    va_list ap;
1243
0
    PRUint32 rv;
1244
1245
0
    va_start(ap, fmt);
1246
0
    rv = PR_vsnprintf(out, outlen, fmt, ap);
1247
0
    va_end(ap);
1248
0
    return rv;
1249
0
}
1250
1251
PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt,
1252
                                    va_list ap)
1253
0
{
1254
0
    SprintfState ss;
1255
0
    PRUint32 n;
1256
1257
0
    PR_ASSERT(outlen != 0 && outlen <= PR_INT32_MAX);
1258
0
    if (outlen == 0 || outlen > PR_INT32_MAX) {
1259
0
        return 0;
1260
0
    }
1261
1262
0
    ss.stuff = LimitStuff;
1263
0
    ss.base = out;
1264
0
    ss.cur = out;
1265
0
    ss.maxlen = outlen;
1266
0
    (void) dosprintf(&ss, fmt, ap);
1267
1268
    /* If we added chars, and we didn't append a null, do it now. */
1269
0
    if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') ) {
1270
0
        *(ss.cur - 1) = '\0';
1271
0
    }
1272
1273
0
    n = ss.cur - ss.base;
1274
0
    return n ? n - 1 : n;
1275
0
}
1276
1277
PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...)
1278
0
{
1279
0
    va_list ap;
1280
0
    char *rv;
1281
1282
0
    va_start(ap, fmt);
1283
0
    rv = PR_vsprintf_append(last, fmt, ap);
1284
0
    va_end(ap);
1285
0
    return rv;
1286
0
}
1287
1288
PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
1289
0
{
1290
0
    SprintfState ss;
1291
0
    int rv;
1292
1293
0
    ss.stuff = GrowStuff;
1294
0
    if (last) {
1295
0
        size_t lastlen = strlen(last);
1296
0
        if (lastlen > PR_INT32_MAX) {
1297
0
            return 0;
1298
0
        }
1299
0
        ss.base = last;
1300
0
        ss.cur = last + lastlen;
1301
0
        ss.maxlen = lastlen;
1302
0
    } else {
1303
0
        ss.base = 0;
1304
0
        ss.cur = 0;
1305
0
        ss.maxlen = 0;
1306
0
    }
1307
0
    rv = dosprintf(&ss, fmt, ap);
1308
0
    if (rv < 0) {
1309
0
        if (ss.base) {
1310
0
            PR_DELETE(ss.base);
1311
0
        }
1312
0
        return 0;
1313
0
    }
1314
0
    return ss.base;
1315
0
}
1316