PageRenderTime 602ms CodeModel.GetById 101ms app.highlight 366ms RepoModel.GetById 87ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsprf.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 1262 lines | 913 code | 150 blank | 199 comment | 253 complexity | 4dc8f471b63af55f52046a225dbc22ef MD5 | raw file
   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 "jsstddef.h"
  45#include <stdarg.h>
  46#include <stdio.h>
  47#include <string.h>
  48#include <stdlib.h>
  49#include "jsprf.h"
  50#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
  75typedef struct SprintfStateStr SprintfState;
  76
  77struct 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*/
  91struct 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*/
 122static 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*/
 161static 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*/
 252static 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*/
 292static 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*/
 340static 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*/
 381static 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
 401static 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        free(s);
 416    } 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
 429static 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            free( nas );
 634        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                free( nas );
 671            *rv = -1;
 672            return NULL;
 673        }
 674
 675        cn++;
 676    }
 677
 678
 679    return nas;
 680}
 681
 682/*
 683** The workhorse sprintf code.
 684*/
 685static 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                    free( nas );
 760                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        free( nas );
1041    }
1042
1043    return rv;
1044}
1045
1046/************************************************************************/
1047
1048static 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
1060JS_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
1072JS_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*/
1090static 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            newbase = (char*) realloc(ss->base, newlen);
1102        } else {
1103            newbase = (char*) malloc(newlen);
1104        }
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*/
1126JS_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*/
1140JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
1141{
1142        free(mem);
1143}
1144
1145JS_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            free(ss.base);
1158        }
1159        return 0;
1160    }
1161    return ss.base;
1162}
1163
1164/*
1165** Stuff routine that discards overflow data
1166*/
1167static 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*/
1185JS_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
1201JS_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
1226JS_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
1237JS_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            free(ss.base);
1257        }
1258        return 0;
1259    }
1260    return ss.base;
1261}
1262