if( l10n_debug ) printf( "invalid argument number (valid range [1, %d]), \"%s\"\n", number, fmt );
static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray ){    int number = 0, cn = 0, i;    const char* p;    char  c;    struct NumArgState* nas;        /*    ** set the l10n_debug flag    ** this routine should be executed only once    ** 'cause getenv does take time    */    if( !l10n_debug_init ){	l10n_debug_init = PR_TRUE;	p = getenv( "NETSCAPE_LOCALIZATION_DEBUG" );	if( ( p != NULL ) && ( *p == '1' ) ){	    l10n_debug = PR_TRUE;	}    }    /*    **	first pass:    **	detemine how many legal % I have got, then allocate space    */    p = fmt;    *rv = 0;    i = 0;    while( ( c = *p++ ) != 0 ){	if( c != '%' )	    continue;	if( ( c = *p++ ) == '%' )	/* skip %% case */	    continue;	while( c != 0 ){	    if( c > '9' || c < '0' ){		if( c == '$' ){		/* numbered argument csae */		    if( i > 0 ){			*rv = -1;			if( l10n_debug )			    printf( "either no *OR* all arguments are numbered \"%s\"\n", fmt );			return NULL;		    }		    number++;		    break;		} else{			/* non-numbered argument case */		    if( number > 0 ){			if( l10n_debug )			    printf( "either no *OR* all arguments are numbered \"%s\"\n", fmt );			*rv = -1;			return NULL;		    }		    i = 1;		    break;		}	    }	    c = *p++;	}    }    if( number == 0 ){	return NULL;    }        if( number > NAS_DEFAULT_NUM ){	nas = (struct NumArgState*)PR_MALLOC( number * sizeof( struct NumArgState ) );	if( !nas ){	    *rv = -1;	    if( l10n_debug )		printf( "PR_MALLOC() error for \"%s\"\n", fmt );	    return NULL;	}    } else {	nas = nasArray;    }    for( i = 0; i < number; i++ ){	nas[i].type = TYPE_UNKNOWN;    }    /*    ** second pass:    ** set nas[].type    */    p = fmt;    while( ( c = *p++ ) != 0 ){    	if( c != '%' )	continue;	    c = *p++;	if( c == '%' )	continue;	cn = 0;	while( c && c != '$' ){	    /* should imporve error check later */	    cn = cn*10 + c - '0';	    c = *p++;	}	if( !c || cn < 1 || cn > number ){	    *rv = -1;	    if( l10n_debug )		printf( "invalid argument number (valid range [1, %d]), \"%s\"\n", number, fmt );	    break;        }	/* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */        cn--;	if( nas[cn].type != TYPE_UNKNOWN )	    continue;        c = *p++;        /* width */        if (c == '*') {	    /* not supported feature, for the argument is not numbered */	    *rv = -1;	    if( l10n_debug )		printf( "* width specifier not support for numbered arguments \"%s\"\n", fmt );	    break;	} else {	    while ((c >= '0') && (c <= '9')) {	        c = *p++;	    }	}	/* precision */	if (c == '.') {	    c = *p++;	    if (c == '*') {	        /* not supported feature, for the argument is not numbered */		if( l10n_debug )		    printf( "* precision specifier not support for numbered arguments \"%s\"\n", fmt );	        *rv = -1;	        break;	    } else {	        while ((c >= '0') && (c <= '9')) {		    c = *p++;		}	    }	}	/* size */	nas[cn].type = TYPE_INTN;	if (c == 'h') {	    nas[cn].type = TYPE_INT16;	    c = *p++;	} else if (c == 'L') {	    /* XXX not quite sure here */	    nas[cn].type = TYPE_INT64;	    c = *p++;	} else if (c == 'l') {	    nas[cn].type = TYPE_INT32;	    c = *p++;	    if (c == 'l') {	        nas[cn].type = TYPE_INT64;	        c = *p++;	    }	}	/* format */	switch (c) {	case 'd':	case 'c':	case 'i':	case 'o':	case 'u':	case 'x':	case 'X':	    break;	case 'e':	case 'f':	case 'g':	    nas[ cn ].type = TYPE_DOUBLE;	    break;	case 'p':	    /* XXX should use cpp */	    if (sizeof(void *) == sizeof(PRInt32)) {		nas[ cn ].type = TYPE_UINT32;	    } else if (sizeof(void *) == sizeof(PRInt64)) {	        nas[ cn ].type = TYPE_UINT64;	    } else if (sizeof(void *) == sizeof(PRIntn)) {	        nas[ cn ].type = TYPE_UINTN;	    } else {	        nas[ cn ].type = TYPE_UNKNOWN;	    }	    break;	case 'C':	case 'S':	case 'E':	case 'G':	    /* XXX not supported I suppose */	    PR_ASSERT(0);	    nas[ cn ].type = TYPE_UNKNOWN;	    break;	case 's':	    nas[ cn ].type = TYPE_STRING;	    break;	case 'n':	    nas[ cn ].type = TYPE_INTSTR;	    break;	default:	    PR_ASSERT(0);	    nas[ cn ].type = TYPE_UNKNOWN;	    break;	}	/* get a legal para. */	if( nas[ cn ].type == TYPE_UNKNOWN ){	    if( l10n_debug )		printf( "unknown type \"%s\"\n", fmt );	    *rv = -1;	    break;	}    }    /*    ** third pass    ** fill the nas[cn].ap    */    if( *rv < 0 ){	if( nas != nasArray )	    PR_DELETE( nas );	return NULL;    }    cn = 0;    while( cn < number ){	if( nas[cn].type == TYPE_UNKNOWN ){	    cn++;	    continue;	}	VARARGS_ASSIGN(nas[cn].ap, ap);	switch( nas[cn].type ){	case TYPE_INT16:	case TYPE_UINT16:	case TYPE_INTN:	case TYPE_UINTN:		(void)va_arg( ap, PRIntn );		break;	case TYPE_INT32:		(void)va_arg( ap, PRInt32 );		break;	case TYPE_UINT32:	(void)va_arg( ap, PRUint32 );	break;	case TYPE_INT64:	(void)va_arg( ap, PRInt64 );		break;	case TYPE_UINT64:	(void)va_arg( ap, PRUint64 );		break;	case TYPE_STRING:	(void)va_arg( ap, char* );		break;	case TYPE_INTSTR:	(void)va_arg( ap, PRIntn* );		break;	case TYPE_DOUBLE:	(void)va_arg( ap, double );		break;	default:	    if( nas != nasArray )		PR_DELETE( nas );	    *rv = -1;	    return NULL;	}	cn++;    }    return nas;}