/[jscoverage]/trunk/js/jsprf.cpp
ViewVC logotype

Annotation of /trunk/js/jsprf.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (hide annotations)
Sun Jan 10 07:23:34 2010 UTC (9 years, 10 months ago) by siliconforks
File size: 32150 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

1 siliconforks 332 /* -*- 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 siliconforks 507 #include "jsstdint.h"
50 siliconforks 332 #include "jslong.h"
51     #include "jsutil.h" /* Added by JSIFY */
52     #include "jspubtd.h"
53     #include "jsstr.h"
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, JSUint32 len);
79    
80     char *base;
81     char *cur;
82     JSUint32 maxlen;
83    
84     int (*func)(void *arg, const char *sp, JSUint32 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     static int fill2(SprintfState *ss, const char *src, int srclen, int width,
123     int flags)
124     {
125     char space = ' ';
126     int rv;
127    
128     width -= srclen;
129     if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */
130     if (flags & FLAG_ZEROS) {
131     space = '0';
132     }
133     while (--width >= 0) {
134     rv = (*ss->stuff)(ss, &space, 1);
135     if (rv < 0) {
136     return rv;
137     }
138     }
139     }
140    
141     /* Copy out the source data */
142     rv = (*ss->stuff)(ss, src, (JSUint32)srclen);
143     if (rv < 0) {
144     return rv;
145     }
146    
147     if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */
148     while (--width >= 0) {
149     rv = (*ss->stuff)(ss, &space, 1);
150     if (rv < 0) {
151     return rv;
152     }
153     }
154     }
155     return 0;
156     }
157    
158     /*
159     ** Fill a number. The order is: optional-sign zero-filling conversion-digits
160     */
161     static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
162     int prec, int type, int flags)
163     {
164     int zerowidth = 0;
165     int precwidth = 0;
166     int signwidth = 0;
167     int leftspaces = 0;
168     int rightspaces = 0;
169     int cvtwidth;
170     int rv;
171     char sign;
172    
173     if ((type & 1) == 0) {
174     if (flags & FLAG_NEG) {
175     sign = '-';
176     signwidth = 1;
177     } else if (flags & FLAG_SIGNED) {
178     sign = '+';
179     signwidth = 1;
180     } else if (flags & FLAG_SPACED) {
181     sign = ' ';
182     signwidth = 1;
183     }
184     }
185     cvtwidth = signwidth + srclen;
186    
187     if (prec > 0) {
188     if (prec > srclen) {
189     precwidth = prec - srclen; /* Need zero filling */
190     cvtwidth += precwidth;
191     }
192     }
193    
194     if ((flags & FLAG_ZEROS) && (prec < 0)) {
195     if (width > cvtwidth) {
196     zerowidth = width - cvtwidth; /* Zero filling */
197     cvtwidth += zerowidth;
198     }
199     }
200    
201     if (flags & FLAG_LEFT) {
202     if (width > cvtwidth) {
203     /* Space filling on the right (i.e. left adjusting) */
204     rightspaces = width - cvtwidth;
205     }
206     } else {
207     if (width > cvtwidth) {
208     /* Space filling on the left (i.e. right adjusting) */
209     leftspaces = width - cvtwidth;
210     }
211     }
212     while (--leftspaces >= 0) {
213     rv = (*ss->stuff)(ss, " ", 1);
214     if (rv < 0) {
215     return rv;
216     }
217     }
218     if (signwidth) {
219     rv = (*ss->stuff)(ss, &sign, 1);
220     if (rv < 0) {
221     return rv;
222     }
223     }
224     while (--precwidth >= 0) {
225     rv = (*ss->stuff)(ss, "0", 1);
226     if (rv < 0) {
227     return rv;
228     }
229     }
230     while (--zerowidth >= 0) {
231     rv = (*ss->stuff)(ss, "0", 1);
232     if (rv < 0) {
233     return rv;
234     }
235     }
236     rv = (*ss->stuff)(ss, src, (JSUint32)srclen);
237     if (rv < 0) {
238     return rv;
239     }
240     while (--rightspaces >= 0) {
241     rv = (*ss->stuff)(ss, " ", 1);
242     if (rv < 0) {
243     return rv;
244     }
245     }
246     return 0;
247     }
248    
249     /*
250     ** Convert a long into its printable form
251     */
252     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     if ((prec == 0) && (num == 0)) {
261     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     cvt = cvtbuf + sizeof(cvtbuf);
270     digits = 0;
271     while (num) {
272     int digit = (((unsigned long)num) % radix) & 0xF;
273     *--cvt = hexp[digit];
274     digits++;
275     num = (long)(((unsigned long)num) / radix);
276     }
277     if (digits == 0) {
278     *--cvt = '0';
279     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     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     static int cvt_ll(SprintfState *ss, JSInt64 num, int width, int prec, int radix,
293     int type, int flags, const char *hexp)
294     {
295     char cvtbuf[100];
296     char *cvt;
297     int digits;
298     JSInt64 rad;
299    
300     /* according to the man page this needs to happen */
301     if ((prec == 0) && (JSLL_IS_ZERO(num))) {
302     return 0;
303     }
304    
305     /*
306     ** Converting decimal is a little tricky. In the unsigned case we
307     ** need to stop when we hit 10 digits. In the signed case, we can
308     ** stop when the number is zero.
309     */
310     JSLL_I2L(rad, radix);
311     cvt = cvtbuf + sizeof(cvtbuf);
312     digits = 0;
313     while (!JSLL_IS_ZERO(num)) {
314     JSInt32 digit;
315     JSInt64 quot, rem;
316     JSLL_UDIVMOD(&quot, &rem, num, rad);
317     JSLL_L2I(digit, rem);
318     *--cvt = hexp[digit & 0xf];
319     digits++;
320     num = quot;
321     }
322     if (digits == 0) {
323     *--cvt = '0';
324     digits++;
325     }
326    
327     /*
328     ** Now that we have the number converted without its sign, deal with
329     ** the sign and zero padding.
330     */
331     return fill_n(ss, cvt, digits, width, prec, type, flags);
332     }
333    
334     /*
335     ** Convert a double precision floating point number into its printable
336     ** form.
337     **
338     ** XXX stop using sprintf to convert floating point
339     */
340     static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
341     {
342     char fin[20];
343     char fout[300];
344     int amount = fmt1 - fmt0;
345    
346     JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
347     if (amount >= (int)sizeof(fin)) {
348     /* Totally bogus % command to sprintf. Just ignore it */
349     return 0;
350     }
351     memcpy(fin, fmt0, (size_t)amount);
352     fin[amount] = 0;
353    
354     /* Convert floating point using the native sprintf code */
355     #ifdef DEBUG
356     {
357     const char *p = fin;
358     while (*p) {
359     JS_ASSERT(*p != 'L');
360     p++;
361     }
362     }
363     #endif
364     sprintf(fout, fin, d);
365    
366     /*
367     ** This assert will catch overflow's of fout, when building with
368     ** debugging on. At least this way we can track down the evil piece
369     ** of calling code and fix it!
370     */
371     JS_ASSERT(strlen(fout) < sizeof(fout));
372    
373     return (*ss->stuff)(ss, fout, strlen(fout));
374     }
375    
376     /*
377     ** Convert a string into its printable form. "width" is the output
378     ** width. "prec" is the maximum number of characters of "s" to output,
379     ** where -1 means until NUL.
380     */
381     static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
382     int flags)
383     {
384     int slen;
385    
386     if (prec == 0)
387     return 0;
388    
389     /* Limit string length by precision value */
390     slen = s ? strlen(s) : 6;
391     if (prec > 0) {
392     if (prec < slen) {
393     slen = prec;
394     }
395     }
396    
397     /* and away we go */
398     return fill2(ss, s ? s : "(null)", slen, width, flags);
399     }
400    
401     static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec,
402     int flags)
403     {
404     int result;
405     /*
406     * Supply NULL as the JSContext; errors are not reported,
407     * and malloc() is used to allocate the buffer buffer.
408     */
409     if (ws) {
410     int slen = js_strlen(ws);
411     char *s = js_DeflateString(NULL, ws, slen);
412     if (!s)
413     return -1; /* JSStuffFunc error indicator. */
414     result = cvt_s(ss, s, width, prec, flags);
415 siliconforks 507 js_free(s);
416 siliconforks 332 } else {
417     result = cvt_s(ss, NULL, width, prec, flags);
418     }
419     return result;
420     }
421    
422     /*
423     ** BuildArgArray stands for Numbered Argument list Sprintf
424     ** for example,
425     ** fmp = "%4$i, %2$d, %3s, %1d";
426     ** the number must start from 1, and no gap among them
427     */
428    
429     static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
430     {
431     int number = 0, cn = 0, i;
432     const char *p;
433     char c;
434     struct NumArgState *nas;
435    
436    
437     /*
438     ** first pass:
439     ** detemine how many legal % I have got, then allocate space
440     */
441    
442     p = fmt;
443     *rv = 0;
444     i = 0;
445     while( ( c = *p++ ) != 0 ){
446     if( c != '%' )
447     continue;
448     if( ( c = *p++ ) == '%' ) /* skip %% case */
449     continue;
450    
451     while( c != 0 ){
452     if( c > '9' || c < '0' ){
453     if( c == '$' ){ /* numbered argument csae */
454     if( i > 0 ){
455     *rv = -1;
456     return NULL;
457     }
458     number++;
459     } else { /* non-numbered argument case */
460     if( number > 0 ){
461     *rv = -1;
462     return NULL;
463     }
464     i = 1;
465     }
466     break;
467     }
468    
469     c = *p++;
470     }
471     }
472    
473     if( number == 0 ){
474     return NULL;
475     }
476    
477    
478     if( number > NAS_DEFAULT_NUM ){
479     nas = (struct NumArgState*)malloc( number * sizeof( struct NumArgState ) );
480     if( !nas ){
481     *rv = -1;
482     return NULL;
483     }
484     } else {
485     nas = nasArray;
486     }
487    
488     for( i = 0; i < number; i++ ){
489     nas[i].type = TYPE_UNKNOWN;
490     }
491    
492    
493     /*
494     ** second pass:
495     ** set nas[].type
496     */
497    
498     p = fmt;
499     while( ( c = *p++ ) != 0 ){
500     if( c != '%' ) continue;
501     c = *p++;
502     if( c == '%' ) continue;
503    
504     cn = 0;
505     while( c && c != '$' ){ /* should improve error check later */
506     cn = cn*10 + c - '0';
507     c = *p++;
508     }
509    
510     if( !c || cn < 1 || cn > number ){
511     *rv = -1;
512     break;
513     }
514    
515     /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
516     cn--;
517     if( nas[cn].type != TYPE_UNKNOWN )
518     continue;
519    
520     c = *p++;
521    
522     /* width */
523     if (c == '*') {
524     /* not supported feature, for the argument is not numbered */
525     *rv = -1;
526     break;
527     }
528    
529     while ((c >= '0') && (c <= '9')) {
530     c = *p++;
531     }
532    
533     /* precision */
534     if (c == '.') {
535     c = *p++;
536     if (c == '*') {
537     /* not supported feature, for the argument is not numbered */
538     *rv = -1;
539     break;
540     }
541    
542     while ((c >= '0') && (c <= '9')) {
543     c = *p++;
544     }
545     }
546    
547     /* size */
548     nas[cn].type = TYPE_INTN;
549     if (c == 'h') {
550     nas[cn].type = TYPE_INT16;
551     c = *p++;
552     } else if (c == 'L') {
553     /* XXX not quite sure here */
554     nas[cn].type = TYPE_INT64;
555     c = *p++;
556     } else if (c == 'l') {
557     nas[cn].type = TYPE_INT32;
558     c = *p++;
559     if (c == 'l') {
560     nas[cn].type = TYPE_INT64;
561     c = *p++;
562     }
563     }
564    
565     /* format */
566     switch (c) {
567     case 'd':
568     case 'c':
569     case 'i':
570     case 'o':
571     case 'u':
572     case 'x':
573     case 'X':
574     break;
575    
576     case 'e':
577     case 'f':
578     case 'g':
579     nas[ cn ].type = TYPE_DOUBLE;
580     break;
581    
582     case 'p':
583     /* XXX should use cpp */
584     if (sizeof(void *) == sizeof(JSInt32)) {
585     nas[ cn ].type = TYPE_UINT32;
586     } else if (sizeof(void *) == sizeof(JSInt64)) {
587     nas[ cn ].type = TYPE_UINT64;
588     } else if (sizeof(void *) == sizeof(JSIntn)) {
589     nas[ cn ].type = TYPE_UINTN;
590     } else {
591     nas[ cn ].type = TYPE_UNKNOWN;
592     }
593     break;
594    
595     case 'C':
596     case 'S':
597     case 'E':
598     case 'G':
599     /* XXX not supported I suppose */
600     JS_ASSERT(0);
601     nas[ cn ].type = TYPE_UNKNOWN;
602     break;
603    
604     case 's':
605     nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
606     break;
607    
608     case 'n':
609     nas[ cn ].type = TYPE_INTSTR;
610     break;
611    
612     default:
613     JS_ASSERT(0);
614     nas[ cn ].type = TYPE_UNKNOWN;
615     break;
616     }
617    
618     /* get a legal para. */
619     if( nas[ cn ].type == TYPE_UNKNOWN ){
620     *rv = -1;
621     break;
622     }
623     }
624    
625    
626     /*
627     ** third pass
628     ** fill the nas[cn].ap
629     */
630    
631     if( *rv < 0 ){
632     if( nas != nasArray )
633 siliconforks 507 js_free( nas );
634 siliconforks 332 return NULL;
635     }
636    
637     cn = 0;
638     while( cn < number ){
639     if( nas[cn].type == TYPE_UNKNOWN ){
640     cn++;
641     continue;
642     }
643    
644     VARARGS_ASSIGN(nas[cn].ap, ap);
645    
646     switch( nas[cn].type ){
647     case TYPE_INT16:
648     case TYPE_UINT16:
649     case TYPE_INTN:
650     case TYPE_UINTN: (void)va_arg( ap, JSIntn ); break;
651    
652     case TYPE_INT32: (void)va_arg( ap, JSInt32 ); break;
653    
654     case TYPE_UINT32: (void)va_arg( ap, JSUint32 ); break;
655    
656     case TYPE_INT64: (void)va_arg( ap, JSInt64 ); break;
657    
658     case TYPE_UINT64: (void)va_arg( ap, JSUint64 ); break;
659    
660     case TYPE_STRING: (void)va_arg( ap, char* ); break;
661    
662     case TYPE_WSTRING: (void)va_arg( ap, jschar* ); break;
663    
664     case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break;
665    
666     case TYPE_DOUBLE: (void)va_arg( ap, double ); break;
667    
668     default:
669     if( nas != nasArray )
670 siliconforks 507 js_free( nas );
671 siliconforks 332 *rv = -1;
672     return NULL;
673     }
674    
675     cn++;
676     }
677    
678    
679     return nas;
680     }
681    
682     /*
683     ** The workhorse sprintf code.
684     */
685     static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
686     {
687     char c;
688     int flags, width, prec, radix, type;
689     union {
690     char ch;
691     jschar wch;
692     int i;
693     long l;
694     JSInt64 ll;
695     double d;
696     const char *s;
697     const jschar* ws;
698     int *ip;
699     } u;
700     const char *fmt0;
701     static const char hex[] = "0123456789abcdef";
702     static const char HEX[] = "0123456789ABCDEF";
703     const char *hexp;
704     int rv, i;
705     struct NumArgState *nas = NULL;
706     struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
707     char pattern[20];
708     const char *dolPt = NULL; /* in "%4$.2f", dolPt will poiont to . */
709     uint8 utf8buf[6];
710     int utf8len;
711    
712     /*
713     ** build an argument array, IF the fmt is numbered argument
714     ** list style, to contain the Numbered Argument list pointers
715     */
716    
717     nas = BuildArgArray( fmt, ap, &rv, nasArray );
718     if( rv < 0 ){
719     /* the fmt contains error Numbered Argument format, jliu@netscape.com */
720     JS_ASSERT(0);
721     return rv;
722     }
723    
724     while ((c = *fmt++) != 0) {
725     if (c != '%') {
726     rv = (*ss->stuff)(ss, fmt - 1, 1);
727     if (rv < 0) {
728     return rv;
729     }
730     continue;
731     }
732     fmt0 = fmt - 1;
733    
734     /*
735     ** Gobble up the % format string. Hopefully we have handled all
736     ** of the strange cases!
737     */
738     flags = 0;
739     c = *fmt++;
740     if (c == '%') {
741     /* quoting a % with %% */
742     rv = (*ss->stuff)(ss, fmt - 1, 1);
743     if (rv < 0) {
744     return rv;
745     }
746     continue;
747     }
748    
749     if( nas != NULL ){
750     /* the fmt contains the Numbered Arguments feature */
751     i = 0;
752     while( c && c != '$' ){ /* should imporve error check later */
753     i = ( i * 10 ) + ( c - '0' );
754     c = *fmt++;
755     }
756    
757     if( nas[i-1].type == TYPE_UNKNOWN ){
758     if( nas && ( nas != nasArray ) )
759 siliconforks 507 js_free( nas );
760 siliconforks 332 return -1;
761     }
762    
763     ap = nas[i-1].ap;
764     dolPt = fmt;
765     c = *fmt++;
766     }
767    
768     /*
769     * Examine optional flags. Note that we do not implement the
770     * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is
771     * somewhat ambiguous and not ideal, which is perhaps why
772     * the various sprintf() implementations are inconsistent
773     * on this feature.
774     */
775     while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
776     if (c == '-') flags |= FLAG_LEFT;
777     if (c == '+') flags |= FLAG_SIGNED;
778     if (c == ' ') flags |= FLAG_SPACED;
779     if (c == '0') flags |= FLAG_ZEROS;
780     c = *fmt++;
781     }
782     if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
783     if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
784    
785     /* width */
786     if (c == '*') {
787     c = *fmt++;
788     width = va_arg(ap, int);
789     } else {
790     width = 0;
791     while ((c >= '0') && (c <= '9')) {
792     width = (width * 10) + (c - '0');
793     c = *fmt++;
794     }
795     }
796    
797     /* precision */
798     prec = -1;
799     if (c == '.') {
800     c = *fmt++;
801     if (c == '*') {
802     c = *fmt++;
803     prec = va_arg(ap, int);
804     } else {
805     prec = 0;
806     while ((c >= '0') && (c <= '9')) {
807     prec = (prec * 10) + (c - '0');
808     c = *fmt++;
809     }
810     }
811     }
812    
813     /* size */
814     type = TYPE_INTN;
815     if (c == 'h') {
816     type = TYPE_INT16;
817     c = *fmt++;
818     } else if (c == 'L') {
819     /* XXX not quite sure here */
820     type = TYPE_INT64;
821     c = *fmt++;
822     } else if (c == 'l') {
823     type = TYPE_INT32;
824     c = *fmt++;
825     if (c == 'l') {
826     type = TYPE_INT64;
827     c = *fmt++;
828     }
829     }
830    
831     /* format */
832     hexp = hex;
833     switch (c) {
834     case 'd': case 'i': /* decimal/integer */
835     radix = 10;
836     goto fetch_and_convert;
837    
838     case 'o': /* octal */
839     radix = 8;
840     type |= 1;
841     goto fetch_and_convert;
842    
843     case 'u': /* unsigned decimal */
844     radix = 10;
845     type |= 1;
846     goto fetch_and_convert;
847    
848     case 'x': /* unsigned hex */
849     radix = 16;
850     type |= 1;
851     goto fetch_and_convert;
852    
853     case 'X': /* unsigned HEX */
854     radix = 16;
855     hexp = HEX;
856     type |= 1;
857     goto fetch_and_convert;
858    
859     fetch_and_convert:
860     switch (type) {
861     case TYPE_INT16:
862     u.l = va_arg(ap, int);
863     if (u.l < 0) {
864     u.l = -u.l;
865     flags |= FLAG_NEG;
866     }
867     goto do_long;
868     case TYPE_UINT16:
869     u.l = va_arg(ap, int) & 0xffff;
870     goto do_long;
871     case TYPE_INTN:
872     u.l = va_arg(ap, int);
873     if (u.l < 0) {
874     u.l = -u.l;
875     flags |= FLAG_NEG;
876     }
877     goto do_long;
878     case TYPE_UINTN:
879     u.l = (long)va_arg(ap, unsigned int);
880     goto do_long;
881    
882     case TYPE_INT32:
883     u.l = va_arg(ap, JSInt32);
884     if (u.l < 0) {
885     u.l = -u.l;
886     flags |= FLAG_NEG;
887     }
888     goto do_long;
889     case TYPE_UINT32:
890     u.l = (long)va_arg(ap, JSUint32);
891     do_long:
892     rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
893     if (rv < 0) {
894     return rv;
895     }
896     break;
897    
898     case TYPE_INT64:
899     u.ll = va_arg(ap, JSInt64);
900     if (!JSLL_GE_ZERO(u.ll)) {
901     JSLL_NEG(u.ll, u.ll);
902     flags |= FLAG_NEG;
903     }
904     goto do_longlong;
905     case TYPE_UINT64:
906     u.ll = va_arg(ap, JSUint64);
907     do_longlong:
908     rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
909     if (rv < 0) {
910     return rv;
911     }
912     break;
913     }
914     break;
915    
916     case 'e':
917     case 'E':
918     case 'f':
919     case 'g':
920     u.d = va_arg(ap, double);
921     if( nas != NULL ){
922     i = fmt - dolPt;
923     if( i < (int)sizeof( pattern ) ){
924     pattern[0] = '%';
925     memcpy( &pattern[1], dolPt, (size_t)i );
926     rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
927     }
928     } else
929     rv = cvt_f(ss, u.d, fmt0, fmt);
930    
931     if (rv < 0) {
932     return rv;
933     }
934     break;
935    
936     case 'c':
937     if ((flags & FLAG_LEFT) == 0) {
938     while (width-- > 1) {
939     rv = (*ss->stuff)(ss, " ", 1);
940     if (rv < 0) {
941     return rv;
942     }
943     }
944     }
945     switch (type) {
946     case TYPE_INT16:
947     /* Treat %hc as %c unless js_CStringsAreUTF8. */
948     if (js_CStringsAreUTF8) {
949     u.wch = va_arg(ap, int);
950     utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch);
951     rv = (*ss->stuff)(ss, (char *)utf8buf, utf8len);
952     break;
953     }
954     case TYPE_INTN:
955     u.ch = va_arg(ap, int);
956     rv = (*ss->stuff)(ss, &u.ch, 1);
957     break;
958     }
959     if (rv < 0) {
960     return rv;
961     }
962     if (flags & FLAG_LEFT) {
963     while (width-- > 1) {
964     rv = (*ss->stuff)(ss, " ", 1);
965     if (rv < 0) {
966     return rv;
967     }
968     }
969     }
970     break;
971    
972     case 'p':
973     if (sizeof(void *) == sizeof(JSInt32)) {
974     type = TYPE_UINT32;
975     } else if (sizeof(void *) == sizeof(JSInt64)) {
976     type = TYPE_UINT64;
977     } else if (sizeof(void *) == sizeof(int)) {
978     type = TYPE_UINTN;
979     } else {
980     JS_ASSERT(0);
981     break;
982     }
983     radix = 16;
984     goto fetch_and_convert;
985    
986     #if 0
987     case 'C':
988     case 'S':
989     case 'E':
990     case 'G':
991     /* XXX not supported I suppose */
992     JS_ASSERT(0);
993     break;
994     #endif
995    
996     case 's':
997     if(type == TYPE_INT16) {
998     /*
999     * This would do a simple string/byte conversion
1000     * unless js_CStringsAreUTF8.
1001     */
1002     u.ws = va_arg(ap, const jschar*);
1003     rv = cvt_ws(ss, u.ws, width, prec, flags);
1004     } else {
1005     u.s = va_arg(ap, const char*);
1006     rv = cvt_s(ss, u.s, width, prec, flags);
1007     }
1008     if (rv < 0) {
1009     return rv;
1010     }
1011     break;
1012    
1013     case 'n':
1014     u.ip = va_arg(ap, int*);
1015     if (u.ip) {
1016     *u.ip = ss->cur - ss->base;
1017     }
1018     break;
1019    
1020     default:
1021     /* Not a % token after all... skip it */
1022     #if 0
1023     JS_ASSERT(0);
1024     #endif
1025     rv = (*ss->stuff)(ss, "%", 1);
1026     if (rv < 0) {
1027     return rv;
1028     }
1029     rv = (*ss->stuff)(ss, fmt - 1, 1);
1030     if (rv < 0) {
1031     return rv;
1032     }
1033     }
1034     }
1035    
1036     /* Stuff trailing NUL */
1037     rv = (*ss->stuff)(ss, "\0", 1);
1038    
1039     if( nas && ( nas != nasArray ) ){
1040 siliconforks 507 js_free( nas );
1041 siliconforks 332 }
1042    
1043     return rv;
1044     }
1045    
1046     /************************************************************************/
1047    
1048     static int FuncStuff(SprintfState *ss, const char *sp, JSUint32 len)
1049     {
1050     int rv;
1051    
1052     rv = (*ss->func)(ss->arg, sp, len);
1053     if (rv < 0) {
1054     return rv;
1055     }
1056     ss->maxlen += len;
1057     return 0;
1058     }
1059    
1060     JS_PUBLIC_API(JSUint32) JS_sxprintf(JSStuffFunc func, void *arg,
1061     const char *fmt, ...)
1062     {
1063     va_list ap;
1064     int rv;
1065    
1066     va_start(ap, fmt);
1067     rv = JS_vsxprintf(func, arg, fmt, ap);
1068     va_end(ap);
1069     return rv;
1070     }
1071    
1072     JS_PUBLIC_API(JSUint32) JS_vsxprintf(JSStuffFunc func, void *arg,
1073     const char *fmt, va_list ap)
1074     {
1075     SprintfState ss;
1076     int rv;
1077    
1078     ss.stuff = FuncStuff;
1079     ss.func = func;
1080     ss.arg = arg;
1081     ss.maxlen = 0;
1082     rv = dosprintf(&ss, fmt, ap);
1083     return (rv < 0) ? (JSUint32)-1 : ss.maxlen;
1084     }
1085    
1086     /*
1087     ** Stuff routine that automatically grows the malloc'd output buffer
1088     ** before it overflows.
1089     */
1090     static int GrowStuff(SprintfState *ss, const char *sp, JSUint32 len)
1091     {
1092     ptrdiff_t off;
1093     char *newbase;
1094     JSUint32 newlen;
1095    
1096     off = ss->cur - ss->base;
1097     if (off + len >= ss->maxlen) {
1098     /* Grow the buffer */
1099     newlen = ss->maxlen + ((len > 32) ? len : 32);
1100     if (ss->base) {
1101 siliconforks 507 newbase = (char*) js_realloc(ss->base, newlen);
1102 siliconforks 332 } else {
1103 siliconforks 507 newbase = (char*) js_malloc(newlen);
1104 siliconforks 332 }
1105     if (!newbase) {
1106     /* Ran out of memory */
1107     return -1;
1108     }
1109     ss->base = newbase;
1110     ss->maxlen = newlen;
1111     ss->cur = ss->base + off;
1112     }
1113    
1114     /* Copy data */
1115     while (len) {
1116     --len;
1117     *ss->cur++ = *sp++;
1118     }
1119     JS_ASSERT((JSUint32)(ss->cur - ss->base) <= ss->maxlen);
1120     return 0;
1121     }
1122    
1123     /*
1124     ** sprintf into a malloc'd buffer
1125     */
1126     JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
1127     {
1128     va_list ap;
1129     char *rv;
1130    
1131     va_start(ap, fmt);
1132     rv = JS_vsmprintf(fmt, ap);
1133     va_end(ap);
1134     return rv;
1135     }
1136    
1137     /*
1138     ** Free memory allocated, for the caller, by JS_smprintf
1139     */
1140     JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
1141     {
1142 siliconforks 507 js_free(mem);
1143 siliconforks 332 }
1144    
1145     JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
1146     {
1147     SprintfState ss;
1148     int rv;
1149    
1150     ss.stuff = GrowStuff;
1151     ss.base = 0;
1152     ss.cur = 0;
1153     ss.maxlen = 0;
1154     rv = dosprintf(&ss, fmt, ap);
1155     if (rv < 0) {
1156     if (ss.base) {
1157 siliconforks 507 js_free(ss.base);
1158 siliconforks 332 }
1159     return 0;
1160     }
1161     return ss.base;
1162     }
1163    
1164     /*
1165     ** Stuff routine that discards overflow data
1166     */
1167     static int LimitStuff(SprintfState *ss, const char *sp, JSUint32 len)
1168     {
1169     JSUint32 limit = ss->maxlen - (ss->cur - ss->base);
1170    
1171     if (len > limit) {
1172     len = limit;
1173     }
1174     while (len) {
1175     --len;
1176     *ss->cur++ = *sp++;
1177     }
1178     return 0;
1179     }
1180    
1181     /*
1182     ** sprintf into a fixed size buffer. Make sure there is a NUL at the end
1183     ** when finished.
1184     */
1185     JS_PUBLIC_API(JSUint32) JS_snprintf(char *out, JSUint32 outlen, const char *fmt, ...)
1186     {
1187     va_list ap;
1188     int rv;
1189    
1190     JS_ASSERT((JSInt32)outlen > 0);
1191     if ((JSInt32)outlen <= 0) {
1192     return 0;
1193     }
1194    
1195     va_start(ap, fmt);
1196     rv = JS_vsnprintf(out, outlen, fmt, ap);
1197     va_end(ap);
1198     return rv;
1199     }
1200    
1201     JS_PUBLIC_API(JSUint32) JS_vsnprintf(char *out, JSUint32 outlen,const char *fmt,
1202     va_list ap)
1203     {
1204     SprintfState ss;
1205     JSUint32 n;
1206    
1207     JS_ASSERT((JSInt32)outlen > 0);
1208     if ((JSInt32)outlen <= 0) {
1209     return 0;
1210     }
1211    
1212     ss.stuff = LimitStuff;
1213     ss.base = out;
1214     ss.cur = out;
1215     ss.maxlen = outlen;
1216     (void) dosprintf(&ss, fmt, ap);
1217    
1218     /* If we added chars, and we didn't append a null, do it now. */
1219     if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') )
1220     ss.cur[-1] = '\0';
1221    
1222     n = ss.cur - ss.base;
1223     return n ? n - 1 : n;
1224     }
1225    
1226     JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
1227     {
1228     va_list ap;
1229     char *rv;
1230    
1231     va_start(ap, fmt);
1232     rv = JS_vsprintf_append(last, fmt, ap);
1233     va_end(ap);
1234     return rv;
1235     }
1236    
1237     JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
1238     {
1239     SprintfState ss;
1240     int rv;
1241    
1242     ss.stuff = GrowStuff;
1243     if (last) {
1244     int lastlen = strlen(last);
1245     ss.base = last;
1246     ss.cur = last + lastlen;
1247     ss.maxlen = lastlen;
1248     } else {
1249     ss.base = 0;
1250     ss.cur = 0;
1251     ss.maxlen = 0;
1252     }
1253     rv = dosprintf(&ss, fmt, ap);
1254     if (rv < 0) {
1255     if (ss.base) {
1256 siliconforks 507 js_free(ss.base);
1257 siliconforks 332 }
1258     return 0;
1259     }
1260     return ss.base;
1261     }
1262    

  ViewVC Help
Powered by ViewVC 1.1.24