if( l10n_debug ) printf( "numbered argument type unknown\n" );
static int dosprintf(SprintfState *ss, const char *fmt, va_list ap){    char c;    int flags, width, prec, radix, type;    union {	char ch;	int i;	long l;	PRInt64 ll;	double d;	const char *s;	int *ip;    } u;    const char *fmt0;    static char *hex = "0123456789abcdef";    static char *HEX = "0123456789ABCDEF";    char *hexp;    int rv, i;    struct NumArgState* nas = NULL;    struct NumArgState  nasArray[ NAS_DEFAULT_NUM ];    char  pattern[20];    const char* dolPt = NULL;  /* in "%4$.2f", dolPt will poiont to . */    /*    ** build an argument array, IF the fmt is numbered argument    ** list style, to contain the Numbered Argument list pointers    */    nas = BuildArgArray( fmt, ap, &rv, nasArray );    if( rv < 0 ){	/* the fmt contains error Numbered Argument format, jliu@netscape.com */	PR_ASSERT(0);	return rv;    }    while ((c = *fmt++) != 0) {	if (c != '%') {	    rv = (*ss->stuff)(ss, fmt - 1, 1);	    if (rv < 0) {		return rv;	    }	    continue;	}	fmt0 = fmt - 1;	/*	** Gobble up the % format string. Hopefully we have handled all	** of the strange cases!	*/	flags = 0;	c = *fmt++;	if (c == '%') {	    /* quoting a % with %% */	    rv = (*ss->stuff)(ss, fmt - 1, 1);	    if (rv < 0) {		return rv;	    }	    continue;	}	if( nas != NULL ){	    /* the fmt contains the Numbered Arguments feature */	    i = 0;	    while( c && c != '$' ){	    /* should imporve error check later */		i = ( i * 10 ) + ( c - '0' );		c = *fmt++;	    }	    if( nas[i-1].type == TYPE_UNKNOWN ){		if( l10n_debug )		    printf( "numbered argument type unknown\n" );		if( nas && ( nas != nasArray ) )		    PR_DELETE( nas );		return -1;	    }	    ap = nas[i-1].ap;	    dolPt = fmt;	    c = *fmt++;	}	/*	 * Examine optional flags.  Note that we do not implement the	 * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is	 * somewhat ambiguous and not ideal, which is perhaps why	 * the various sprintf() implementations are inconsistent	 * on this feature.	 */	while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {	    if (c == '-') flags |= _LEFT;	    if (c == '+') flags |= _SIGNED;	    if (c == ' ') flags |= _SPACED;	    if (c == '0') flags |= _ZEROS;	    c = *fmt++;	}	if (flags & _SIGNED) flags &= ~_SPACED;	if (flags & _LEFT) flags &= ~_ZEROS;	/* width */	if (c == '*') {	    c = *fmt++;	    width = va_arg(ap, int);	} else {	    width = 0;	    while ((c >= '0') && (c <= '9')) {		width = (width * 10) + (c - '0');		c = *fmt++;	    }	}	/* precision */	prec = -1;	if (c == '.') {	    c = *fmt++;	    if (c == '*') {		c = *fmt++;		prec = va_arg(ap, int);	    } else {		prec = 0;		while ((c >= '0') && (c <= '9')) {		    prec = (prec * 10) + (c - '0');		    c = *fmt++;		}	    }	}	/* size */	type = TYPE_INTN;	if (c == 'h') {	    type = TYPE_INT16;	    c = *fmt++;	} else if (c == 'L') {	    /* XXX not quite sure here */	    type = TYPE_INT64;	    c = *fmt++;	} else if (c == 'l') {	    type = TYPE_INT32;	    c = *fmt++;	    if (c == 'l') {		type = TYPE_INT64;		c = *fmt++;	    }	}	/* format */	hexp = hex;	switch (c) {	  case 'd': case 'i':			/* decimal/integer */	    radix = 10;	    goto fetch_and_convert;	  case 'o':				/* octal */	    radix = 8;	    type |= 1;	    goto fetch_and_convert;	  case 'u':				/* unsigned decimal */	    radix = 10;	    type |= 1;	    goto fetch_and_convert;	  case 'x':				/* unsigned hex */	    radix = 16;	    type |= 1;	    goto fetch_and_convert;	  case 'X':				/* unsigned HEX */	    radix = 16;	    hexp = HEX;	    type |= 1;	    goto fetch_and_convert;	  fetch_and_convert:	    switch (type) {	      case TYPE_INT16:		u.l = va_arg(ap, int);		if (u.l < 0) {		    u.l = -u.l;		    flags |= _NEG;		}		goto do_long;	      case TYPE_UINT16:		u.l = va_arg(ap, int) & 0xffff;		goto do_long;	      case TYPE_INTN:		u.l = va_arg(ap, int);		if (u.l < 0) {		    u.l = -u.l;		    flags |= _NEG;		}		goto do_long;	      case TYPE_UINTN:		u.l = (long)va_arg(ap, unsigned int);		goto do_long;	      case TYPE_INT32:		u.l = va_arg(ap, PRInt32);		if (u.l < 0) {		    u.l = -u.l;		    flags |= _NEG;		}		goto do_long;	      case TYPE_UINT32:		u.l = (long)va_arg(ap, PRUint32);	      do_long:		rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);		if (rv < 0) {		    return rv;		}		break;	      case TYPE_INT64:		u.ll = va_arg(ap, PRInt64);		if (!LL_GE_ZERO(u.ll)) {		    LL_NEG(u.ll, u.ll);		    flags |= _NEG;		}		goto do_longlong;	      case TYPE_UINT64:		u.ll = va_arg(ap, PRUint64);	      do_longlong:		rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);		if (rv < 0) {		    return rv;		}		break;	    }	    break;	  case 'e':	  case 'E':	  case 'f':	  case 'g':	    u.d = va_arg(ap, double);	    if( nas != NULL ){		i = fmt - dolPt;		if( i < sizeof( pattern ) ){		    pattern[0] = '%';		    memcpy( &pattern[1], dolPt, i );		    rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );		}	    } else		rv = cvt_f(ss, u.d, fmt0, fmt);	    if (rv < 0) {		return rv;	    }	    break;	  case 'c':	    u.ch = va_arg(ap, int);            if ((flags & _LEFT) == 0) {                while (width-- > 1) {                    rv = (*ss->stuff)(ss, " ", 1);                    if (rv < 0) {                        return rv;                    }                }            }	    rv = (*ss->stuff)(ss, &u.ch, 1);	    if (rv < 0) {		return rv;	    }            if (flags & _LEFT) {                while (width-- > 1) {                    rv = (*ss->stuff)(ss, " ", 1);                    if (rv < 0) {                        return rv;                    }                }            }	    break;	  case 'p':	    if (sizeof(void *) == sizeof(PRInt32)) {	    	type = TYPE_UINT32;	    } else if (sizeof(void *) == sizeof(PRInt64)) {	    	type = TYPE_UINT64;	    } else if (sizeof(void *) == sizeof(int)) {		type = TYPE_UINTN;	    } else {		PR_ASSERT(0);		break;	    }	    radix = 16;	    goto fetch_and_convert;#if 0	  case 'C':	  case 'S':	  case 'E':	  case 'G':	    /* XXX not supported I suppose */	    PR_ASSERT(0);	    break;#endif	  case 's':	    u.s = va_arg(ap, const char*);	    rv = cvt_s(ss, u.s, width, prec, flags);	    if (rv < 0) {		return rv;	    }	    break;	  case 'n':	    u.ip = va_arg(ap, int*);	    if (u.ip) {		*u.ip = ss->cur - ss->base;	    }	    break;	  default:	    /* Not a % token after all... skip it */#if 0	    PR_ASSERT(0);#endif	    rv = (*ss->stuff)(ss, "%", 1);	    if (rv < 0) {		return rv;	    }	    rv = (*ss->stuff)(ss, fmt - 1, 1);	    if (rv < 0) {		return rv;	    }	}    }    /* Stuff trailing NUL */    rv = (*ss->stuff)(ss, "\0", 1);    if( nas && ( nas != nasArray ) ){	PR_DELETE( nas );    }    return rv;}