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