nsprpub/pr/src/io/prprf.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7 ** Portable safe sprintf code.
     8 **
     9 ** Author: Kipp E.B. Hickman
    10 */
    11 #include <stdarg.h>
    12 #include <stddef.h>
    13 #include <stdio.h>
    14 #include <string.h>
    15 #include "primpl.h"
    16 #include "prprf.h"
    17 #include "prlong.h"
    18 #include "prlog.h"
    19 #include "prmem.h"
    21 #ifdef _MSC_VER
    22 #define snprintf _snprintf
    23 #endif
    25 /*
    26 ** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)
    27 */
    29 /*
    30 ** XXX This needs to be internationalized!
    31 */
    33 typedef struct SprintfStateStr SprintfState;
    35 struct SprintfStateStr {
    36     int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);
    38     char *base;
    39     char *cur;
    40     PRUint32 maxlen;
    42     int (*func)(void *arg, const char *sp, PRUint32 len);
    43     void *arg;
    44 };
    46 /*
    47 ** Numbered Argument
    48 */
    49 struct NumArg {
    50     int type;           /* type of the numbered argument    */
    51     union {             /* the numbered argument            */
    52 	int i;
    53 	unsigned int ui;
    54 	PRInt32 i32;
    55 	PRUint32 ui32;
    56 	PRInt64 ll;
    57 	PRUint64 ull;
    58 	double d;
    59 	const char *s;
    60 	int *ip;
    61 #ifdef WIN32
    62 	const WCHAR *ws;
    63 #endif
    64     } u;
    65 };
    67 #define NAS_DEFAULT_NUM 20  /* default number of NumberedArgument array */
    70 #define TYPE_INT16	0
    71 #define TYPE_UINT16	1
    72 #define TYPE_INTN	2
    73 #define TYPE_UINTN	3
    74 #define TYPE_INT32	4
    75 #define TYPE_UINT32	5
    76 #define TYPE_INT64	6
    77 #define TYPE_UINT64	7
    78 #define TYPE_STRING	8
    79 #define TYPE_DOUBLE	9
    80 #define TYPE_INTSTR	10
    81 #ifdef WIN32
    82 #define TYPE_WSTRING	11
    83 #endif
    84 #define TYPE_UNKNOWN	20
    86 #define FLAG_LEFT	0x1
    87 #define FLAG_SIGNED	0x2
    88 #define FLAG_SPACED	0x4
    89 #define FLAG_ZEROS	0x8
    90 #define FLAG_NEG	0x10
    92 /*
    93 ** Fill into the buffer using the data in src
    94 */
    95 static int fill2(SprintfState *ss, const char *src, int srclen, int width,
    96 		int flags)
    97 {
    98     char space = ' ';
    99     int rv;
   101     width -= srclen;
   102     if ((width > 0) && ((flags & FLAG_LEFT) == 0)) {	/* Right adjusting */
   103 	if (flags & FLAG_ZEROS) {
   104 	    space = '0';
   105 	}
   106 	while (--width >= 0) {
   107 	    rv = (*ss->stuff)(ss, &space, 1);
   108 	    if (rv < 0) {
   109 		return rv;
   110 	    }
   111 	}
   112     }
   114     /* Copy out the source data */
   115     rv = (*ss->stuff)(ss, src, srclen);
   116     if (rv < 0) {
   117 	return rv;
   118     }
   120     if ((width > 0) && ((flags & FLAG_LEFT) != 0)) {	/* Left adjusting */
   121 	while (--width >= 0) {
   122 	    rv = (*ss->stuff)(ss, &space, 1);
   123 	    if (rv < 0) {
   124 		return rv;
   125 	    }
   126 	}
   127     }
   128     return 0;
   129 }
   131 /*
   132 ** Fill a number. The order is: optional-sign zero-filling conversion-digits
   133 */
   134 static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
   135 		  int prec, int type, int flags)
   136 {
   137     int zerowidth = 0;
   138     int precwidth = 0;
   139     int signwidth = 0;
   140     int leftspaces = 0;
   141     int rightspaces = 0;
   142     int cvtwidth;
   143     int rv;
   144     char sign;
   146     if ((type & 1) == 0) {
   147 	if (flags & FLAG_NEG) {
   148 	    sign = '-';
   149 	    signwidth = 1;
   150 	} else if (flags & FLAG_SIGNED) {
   151 	    sign = '+';
   152 	    signwidth = 1;
   153 	} else if (flags & FLAG_SPACED) {
   154 	    sign = ' ';
   155 	    signwidth = 1;
   156 	}
   157     }
   158     cvtwidth = signwidth + srclen;
   160     if (prec > 0) {
   161 	if (prec > srclen) {
   162 	    precwidth = prec - srclen;		/* Need zero filling */
   163 	    cvtwidth += precwidth;
   164 	}
   165     }
   167     if ((flags & FLAG_ZEROS) && (prec < 0)) {
   168 	if (width > cvtwidth) {
   169 	    zerowidth = width - cvtwidth;	/* Zero filling */
   170 	    cvtwidth += zerowidth;
   171 	}
   172     }
   174     if (flags & FLAG_LEFT) {
   175 	if (width > cvtwidth) {
   176 	    /* Space filling on the right (i.e. left adjusting) */
   177 	    rightspaces = width - cvtwidth;
   178 	}
   179     } else {
   180 	if (width > cvtwidth) {
   181 	    /* Space filling on the left (i.e. right adjusting) */
   182 	    leftspaces = width - cvtwidth;
   183 	}
   184     }
   185     while (--leftspaces >= 0) {
   186 	rv = (*ss->stuff)(ss, " ", 1);
   187 	if (rv < 0) {
   188 	    return rv;
   189 	}
   190     }
   191     if (signwidth) {
   192 	rv = (*ss->stuff)(ss, &sign, 1);
   193 	if (rv < 0) {
   194 	    return rv;
   195 	}
   196     }
   197     while (--precwidth >= 0) {
   198 	rv = (*ss->stuff)(ss, "0", 1);
   199 	if (rv < 0) {
   200 	    return rv;
   201 	}
   202     }
   203     while (--zerowidth >= 0) {
   204 	rv = (*ss->stuff)(ss, "0", 1);
   205 	if (rv < 0) {
   206 	    return rv;
   207 	}
   208     }
   209     rv = (*ss->stuff)(ss, src, srclen);
   210     if (rv < 0) {
   211 	return rv;
   212     }
   213     while (--rightspaces >= 0) {
   214 	rv = (*ss->stuff)(ss, " ", 1);
   215 	if (rv < 0) {
   216 	    return rv;
   217 	}
   218     }
   219     return 0;
   220 }
   222 /*
   223 ** Convert a long into its printable form
   224 */
   225 static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
   226 		 int type, int flags, const char *hexp)
   227 {
   228     char cvtbuf[100];
   229     char *cvt;
   230     int digits;
   232     /* according to the man page this needs to happen */
   233     if ((prec == 0) && (num == 0)) {
   234 	return 0;
   235     }
   237     /*
   238     ** Converting decimal is a little tricky. In the unsigned case we
   239     ** need to stop when we hit 10 digits. In the signed case, we can
   240     ** stop when the number is zero.
   241     */
   242     cvt = cvtbuf + sizeof(cvtbuf);
   243     digits = 0;
   244     while (num) {
   245 	int digit = (((unsigned long)num) % radix) & 0xF;
   246 	*--cvt = hexp[digit];
   247 	digits++;
   248 	num = (long)(((unsigned long)num) / radix);
   249     }
   250     if (digits == 0) {
   251 	*--cvt = '0';
   252 	digits++;
   253     }
   255     /*
   256     ** Now that we have the number converted without its sign, deal with
   257     ** the sign and zero padding.
   258     */
   259     return fill_n(ss, cvt, digits, width, prec, type, flags);
   260 }
   262 /*
   263 ** Convert a 64-bit integer into its printable form
   264 */
   265 static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix,
   266 		  int type, int flags, const char *hexp)
   267 {
   268     char cvtbuf[100];
   269     char *cvt;
   270     int digits;
   271     PRInt64 rad;
   273     /* according to the man page this needs to happen */
   274     if ((prec == 0) && (LL_IS_ZERO(num))) {
   275 	return 0;
   276     }
   278     /*
   279     ** Converting decimal is a little tricky. In the unsigned case we
   280     ** need to stop when we hit 10 digits. In the signed case, we can
   281     ** stop when the number is zero.
   282     */
   283     LL_I2L(rad, radix);
   284     cvt = cvtbuf + sizeof(cvtbuf);
   285     digits = 0;
   286     while (!LL_IS_ZERO(num)) {
   287 	PRInt32 digit;
   288 	PRInt64 quot, rem;
   289 	LL_UDIVMOD(&quot, &rem, num, rad);
   290 	LL_L2I(digit, rem);
   291 	*--cvt = hexp[digit & 0xf];
   292 	digits++;
   293 	num = quot;
   294     }
   295     if (digits == 0) {
   296 	*--cvt = '0';
   297 	digits++;
   298     }
   300     /*
   301     ** Now that we have the number converted without its sign, deal with
   302     ** the sign and zero padding.
   303     */
   304     return fill_n(ss, cvt, digits, width, prec, type, flags);
   305 }
   307 /*
   308 ** Convert a double precision floating point number into its printable
   309 ** form.
   310 **
   311 ** XXX stop using snprintf to convert floating point
   312 */
   313 static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
   314 {
   315     char fin[20];
   316     char fout[300];
   317     int amount = fmt1 - fmt0;
   319     if (amount <= 0 || amount >= sizeof(fin)) {
   320 	/* Totally bogus % command to snprintf. Just ignore it */
   321 	return 0;
   322     }
   323     memcpy(fin, fmt0, amount);
   324     fin[amount] = 0;
   326     /* Convert floating point using the native snprintf code */
   327 #ifdef DEBUG
   328     {
   329         const char *p = fin;
   330         while (*p) {
   331             PR_ASSERT(*p != 'L');
   332             p++;
   333         }
   334     }
   335 #endif
   336     memset(fout, 0, sizeof(fout));
   337     snprintf(fout, sizeof(fout), fin, d);
   338     /* Explicitly null-terminate fout because on Windows snprintf doesn't
   339      * append a null-terminator if the buffer is too small. */
   340     fout[sizeof(fout) - 1] = '\0';
   342     return (*ss->stuff)(ss, fout, strlen(fout));
   343 }
   345 /*
   346 ** Convert a string into its printable form.  "width" is the output
   347 ** width. "prec" is the maximum number of characters of "s" to output,
   348 ** where -1 means until NUL.
   349 */
   350 static int cvt_s(SprintfState *ss, const char *str, int width, int prec,
   351 		 int flags)
   352 {
   353     int slen;
   355     if (prec == 0)
   356 	return 0;
   358     /* Limit string length by precision value */
   359     if (!str) {
   360     	str = "(null)";
   361     } 
   362     if (prec > 0) {
   363 	/* this is:  slen = strnlen(str, prec); */
   364 	register const char *s;
   366 	for(s = str; prec && *s; s++, prec-- )
   367 	    ;
   368 	slen = s - str;
   369     } else {
   370 	slen = strlen(str);
   371     }
   373     /* and away we go */
   374     return fill2(ss, str, slen, width, flags);
   375 }
   377 /*
   378 ** BuildArgArray stands for Numbered Argument list Sprintf
   379 ** for example,  
   380 **	fmp = "%4$i, %2$d, %3s, %1d";
   381 ** the number must start from 1, and no gap among them
   382 */
   384 static struct NumArg* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArg* nasArray )
   385 {
   386     int number = 0, cn = 0, i;
   387     const char* p;
   388     char  c;
   389     struct NumArg* nas;
   392     /*
   393     **	first pass:
   394     **	determine how many legal % I have got, then allocate space
   395     */
   397     p = fmt;
   398     *rv = 0;
   399     i = 0;
   400     while( ( c = *p++ ) != 0 ){
   401 	if( c != '%' )
   402 	    continue;
   403 	if( ( c = *p++ ) == '%' )	/* skip %% case */
   404 	    continue;
   406 	while( c != 0 ){
   407 	    if( c > '9' || c < '0' ){
   408 		if( c == '$' ){		/* numbered argument case */
   409 		    if( i > 0 ){
   410 			*rv = -1;
   411 			return NULL;
   412 		    }
   413 		    number++;
   414 		} else{			/* non-numbered argument case */
   415 		    if( number > 0 ){
   416 			*rv = -1;
   417 			return NULL;
   418 		    }
   419 		    i = 1;
   420 		}
   421 		break;
   422 	    }
   424 	    c = *p++;
   425 	}
   426     }
   428     if( number == 0 ){
   429 	return NULL;
   430     }
   433     if( number > NAS_DEFAULT_NUM ){
   434 	nas = (struct NumArg*)PR_MALLOC( number * sizeof( struct NumArg ) );
   435 	if( !nas ){
   436 	    *rv = -1;
   437 	    return NULL;
   438 	}
   439     } else {
   440 	nas = nasArray;
   441     }
   443     for( i = 0; i < number; i++ ){
   444 	nas[i].type = TYPE_UNKNOWN;
   445     }
   448     /*
   449     ** second pass:
   450     ** set nas[].type
   451     */
   453     p = fmt;
   454     while( ( c = *p++ ) != 0 ){
   455     	if( c != '%' )	continue;
   456 	    c = *p++;
   457 	if( c == '%' )	continue;
   459 	cn = 0;
   460 	while( c && c != '$' ){	    /* should imporve error check later */
   461 	    cn = cn*10 + c - '0';
   462 	    c = *p++;
   463 	}
   465 	if( !c || cn < 1 || cn > number ){
   466 	    *rv = -1;
   467 	    break;
   468         }
   470 	/* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
   471         cn--;
   472 	if( nas[cn].type != TYPE_UNKNOWN )
   473 	    continue;
   475         c = *p++;
   477         /* width */
   478         if (c == '*') {
   479 	    /* not supported feature, for the argument is not numbered */
   480 	    *rv = -1;
   481 	    break;
   482 	}
   484 	while ((c >= '0') && (c <= '9')) {
   485 	    c = *p++;
   486 	}
   488 	/* precision */
   489 	if (c == '.') {
   490 	    c = *p++;
   491 	    if (c == '*') {
   492 	        /* not supported feature, for the argument is not numbered */
   493 	        *rv = -1;
   494 	        break;
   495 	    }
   497 	    while ((c >= '0') && (c <= '9')) {
   498 		c = *p++;
   499 	    }
   500 	}
   502 	/* size */
   503 	nas[cn].type = TYPE_INTN;
   504 	if (c == 'h') {
   505 	    nas[cn].type = TYPE_INT16;
   506 	    c = *p++;
   507 	} else if (c == 'L') {
   508 	    /* XXX not quite sure here */
   509 	    nas[cn].type = TYPE_INT64;
   510 	    c = *p++;
   511 	} else if (c == 'l') {
   512 	    nas[cn].type = TYPE_INT32;
   513 	    c = *p++;
   514 	    if (c == 'l') {
   515 	        nas[cn].type = TYPE_INT64;
   516 	        c = *p++;
   517 	    }
   518 	}
   520 	/* format */
   521 	switch (c) {
   522 	case 'd':
   523 	case 'c':
   524 	case 'i':
   525 	case 'o':
   526 	case 'u':
   527 	case 'x':
   528 	case 'X':
   529 	    break;
   531 	case 'e':
   532 	case 'f':
   533 	case 'g':
   534 	    nas[ cn ].type = TYPE_DOUBLE;
   535 	    break;
   537 	case 'p':
   538 	    /* XXX should use cpp */
   539 	    if (sizeof(void *) == sizeof(PRInt32)) {
   540 		nas[ cn ].type = TYPE_UINT32;
   541 	    } else if (sizeof(void *) == sizeof(PRInt64)) {
   542 	        nas[ cn ].type = TYPE_UINT64;
   543 	    } else if (sizeof(void *) == sizeof(PRIntn)) {
   544 	        nas[ cn ].type = TYPE_UINTN;
   545 	    } else {
   546 	        nas[ cn ].type = TYPE_UNKNOWN;
   547 	    }
   548 	    break;
   550 	case 'S':
   551 #ifdef WIN32
   552 	    nas[ cn ].type = TYPE_WSTRING;
   553 	    break;
   554 #endif
   555 	case 'C':
   556 	case 'E':
   557 	case 'G':
   558 	    /* XXX not supported I suppose */
   559 	    PR_ASSERT(0);
   560 	    nas[ cn ].type = TYPE_UNKNOWN;
   561 	    break;
   563 	case 's':
   564 	    nas[ cn ].type = TYPE_STRING;
   565 	    break;
   567 	case 'n':
   568 	    nas[ cn ].type = TYPE_INTSTR;
   569 	    break;
   571 	default:
   572 	    PR_ASSERT(0);
   573 	    nas[ cn ].type = TYPE_UNKNOWN;
   574 	    break;
   575 	}
   577 	/* get a legal para. */
   578 	if( nas[ cn ].type == TYPE_UNKNOWN ){
   579 	    *rv = -1;
   580 	    break;
   581 	}
   582     }
   585     /*
   586     ** third pass
   587     ** fill the nas[cn].ap
   588     */
   590     if( *rv < 0 ){
   591 	if( nas != nasArray )
   592 	    PR_DELETE( nas );
   593 	return NULL;
   594     }
   596     cn = 0;
   597     while( cn < number ){
   598 	if( nas[cn].type == TYPE_UNKNOWN ){
   599 	    cn++;
   600 	    continue;
   601 	}
   603 	switch( nas[cn].type ){
   604 	case TYPE_INT16:
   605 	case TYPE_UINT16:
   606 	case TYPE_INTN:
   607 	    nas[cn].u.i = va_arg( ap, int );
   608 	    break;
   610 	case TYPE_UINTN:
   611 	    nas[cn].u.ui = va_arg( ap, unsigned int );
   612 	    break;
   614 	case TYPE_INT32:
   615 	    nas[cn].u.i32 = va_arg( ap, PRInt32 );
   616 	    break;
   618 	case TYPE_UINT32:
   619 	    nas[cn].u.ui32 = va_arg( ap, PRUint32 );
   620 	    break;
   622 	case TYPE_INT64:
   623 	    nas[cn].u.ll = va_arg( ap, PRInt64 );
   624 	    break;
   626 	case TYPE_UINT64:
   627 	    nas[cn].u.ull = va_arg( ap, PRUint64 );
   628 	    break;
   630 	case TYPE_STRING:
   631 	    nas[cn].u.s = va_arg( ap, char* );
   632 	    break;
   634 #ifdef WIN32
   635 	case TYPE_WSTRING:
   636 	    nas[cn].u.ws = va_arg( ap, WCHAR* );
   637 	    break;
   638 #endif
   640 	case TYPE_INTSTR:
   641 	    nas[cn].u.ip = va_arg( ap, int* );
   642 	    break;
   644 	case TYPE_DOUBLE:
   645 	    nas[cn].u.d = va_arg( ap, double );
   646 	    break;
   648 	default:
   649 	    if( nas != nasArray )
   650 		PR_DELETE( nas );
   651 	    *rv = -1;
   652 	    return NULL;
   653 	}
   655 	cn++;
   656     }
   659     return nas;
   660 }
   662 /*
   663 ** The workhorse sprintf code.
   664 */
   665 static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
   666 {
   667     char c;
   668     int flags, width, prec, radix, type;
   669     union {
   670 	char ch;
   671 	int i;
   672 	long l;
   673 	PRInt64 ll;
   674 	double d;
   675 	const char *s;
   676 	int *ip;
   677 #ifdef WIN32
   678 	const WCHAR *ws;
   679 #endif
   680     } u;
   681     const char *fmt0;
   682     static char *hex = "0123456789abcdef";
   683     static char *HEX = "0123456789ABCDEF";
   684     char *hexp;
   685     int rv, i;
   686     struct NumArg* nas = NULL;
   687     struct NumArg* nap;
   688     struct NumArg  nasArray[ NAS_DEFAULT_NUM ];
   689     char  pattern[20];
   690     const char* dolPt = NULL;  /* in "%4$.2f", dolPt will point to . */
   691 #ifdef WIN32
   692     char *pBuf = NULL;
   693 #endif
   695     /*
   696     ** build an argument array, IF the fmt is numbered argument
   697     ** list style, to contain the Numbered Argument list pointers
   698     */
   700     nas = BuildArgArray( fmt, ap, &rv, nasArray );
   701     if( rv < 0 ){
   702 	/* the fmt contains error Numbered Argument format, jliu@netscape.com */
   703 	PR_ASSERT(0);
   704 	return rv;
   705     }
   707     while ((c = *fmt++) != 0) {
   708 	if (c != '%') {
   709 	    rv = (*ss->stuff)(ss, fmt - 1, 1);
   710 	    if (rv < 0) {
   711 		return rv;
   712 	    }
   713 	    continue;
   714 	}
   715 	fmt0 = fmt - 1;
   717 	/*
   718 	** Gobble up the % format string. Hopefully we have handled all
   719 	** of the strange cases!
   720 	*/
   721 	flags = 0;
   722 	c = *fmt++;
   723 	if (c == '%') {
   724 	    /* quoting a % with %% */
   725 	    rv = (*ss->stuff)(ss, fmt - 1, 1);
   726 	    if (rv < 0) {
   727 		return rv;
   728 	    }
   729 	    continue;
   730 	}
   732 	if( nas != NULL ){
   733 	    /* the fmt contains the Numbered Arguments feature */
   734 	    i = 0;
   735 	    while( c && c != '$' ){	    /* should imporve error check later */
   736 		i = ( i * 10 ) + ( c - '0' );
   737 		c = *fmt++;
   738 	    }
   740 	    if( nas[i-1].type == TYPE_UNKNOWN ){
   741 		if( nas && ( nas != nasArray ) )
   742 		    PR_DELETE( nas );
   743 		return -1;
   744 	    }
   746 	    nap = &nas[i-1];
   747 	    dolPt = fmt;
   748 	    c = *fmt++;
   749 	}
   751 	/*
   752 	 * Examine optional flags.  Note that we do not implement the
   753 	 * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
   754 	 * somewhat ambiguous and not ideal, which is perhaps why
   755 	 * the various sprintf() implementations are inconsistent
   756 	 * on this feature.
   757 	 */
   758 	while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
   759 	    if (c == '-') flags |= FLAG_LEFT;
   760 	    if (c == '+') flags |= FLAG_SIGNED;
   761 	    if (c == ' ') flags |= FLAG_SPACED;
   762 	    if (c == '0') flags |= FLAG_ZEROS;
   763 	    c = *fmt++;
   764 	}
   765 	if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
   766 	if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
   768 	/* width */
   769 	if (c == '*') {
   770 	    c = *fmt++;
   771 	    width = va_arg(ap, int);
   772 	} else {
   773 	    width = 0;
   774 	    while ((c >= '0') && (c <= '9')) {
   775 		width = (width * 10) + (c - '0');
   776 		c = *fmt++;
   777 	    }
   778 	}
   780 	/* precision */
   781 	prec = -1;
   782 	if (c == '.') {
   783 	    c = *fmt++;
   784 	    if (c == '*') {
   785 		c = *fmt++;
   786 		prec = va_arg(ap, int);
   787 	    } else {
   788 		prec = 0;
   789 		while ((c >= '0') && (c <= '9')) {
   790 		    prec = (prec * 10) + (c - '0');
   791 		    c = *fmt++;
   792 		}
   793 	    }
   794 	}
   796 	/* size */
   797 	type = TYPE_INTN;
   798 	if (c == 'h') {
   799 	    type = TYPE_INT16;
   800 	    c = *fmt++;
   801 	} else if (c == 'L') {
   802 	    /* XXX not quite sure here */
   803 	    type = TYPE_INT64;
   804 	    c = *fmt++;
   805 	} else if (c == 'l') {
   806 	    type = TYPE_INT32;
   807 	    c = *fmt++;
   808 	    if (c == 'l') {
   809 		type = TYPE_INT64;
   810 		c = *fmt++;
   811 	    }
   812 	}
   814 	/* format */
   815 	hexp = hex;
   816 	switch (c) {
   817 	  case 'd': case 'i':			/* decimal/integer */
   818 	    radix = 10;
   819 	    goto fetch_and_convert;
   821 	  case 'o':				/* octal */
   822 	    radix = 8;
   823 	    type |= 1;
   824 	    goto fetch_and_convert;
   826 	  case 'u':				/* unsigned decimal */
   827 	    radix = 10;
   828 	    type |= 1;
   829 	    goto fetch_and_convert;
   831 	  case 'x':				/* unsigned hex */
   832 	    radix = 16;
   833 	    type |= 1;
   834 	    goto fetch_and_convert;
   836 	  case 'X':				/* unsigned HEX */
   837 	    radix = 16;
   838 	    hexp = HEX;
   839 	    type |= 1;
   840 	    goto fetch_and_convert;
   842 	  fetch_and_convert:
   843 	    switch (type) {
   844 	      case TYPE_INT16:
   845 		u.l = nas ? nap->u.i : va_arg(ap, int);
   846 		if (u.l < 0) {
   847 		    u.l = -u.l;
   848 		    flags |= FLAG_NEG;
   849 		}
   850 		goto do_long;
   851 	      case TYPE_UINT16:
   852 		u.l = (nas ? nap->u.i : va_arg(ap, int)) & 0xffff;
   853 		goto do_long;
   854 	      case TYPE_INTN:
   855 		u.l = nas ? nap->u.i : va_arg(ap, int);
   856 		if (u.l < 0) {
   857 		    u.l = -u.l;
   858 		    flags |= FLAG_NEG;
   859 		}
   860 		goto do_long;
   861 	      case TYPE_UINTN:
   862 		u.l = (long)(nas ? nap->u.ui : va_arg(ap, unsigned int));
   863 		goto do_long;
   865 	      case TYPE_INT32:
   866 		u.l = nas ? nap->u.i32 : va_arg(ap, PRInt32);
   867 		if (u.l < 0) {
   868 		    u.l = -u.l;
   869 		    flags |= FLAG_NEG;
   870 		}
   871 		goto do_long;
   872 	      case TYPE_UINT32:
   873 		u.l = (long)(nas ? nap->u.ui32 : va_arg(ap, PRUint32));
   874 	      do_long:
   875 		rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
   876 		if (rv < 0) {
   877 		    return rv;
   878 		}
   879 		break;
   881 	      case TYPE_INT64:
   882 		u.ll = nas ? nap->u.ll : va_arg(ap, PRInt64);
   883 		if (!LL_GE_ZERO(u.ll)) {
   884 		    LL_NEG(u.ll, u.ll);
   885 		    flags |= FLAG_NEG;
   886 		}
   887 		goto do_longlong;
   888 	      case TYPE_UINT64:
   889 		u.ll = nas ? nap->u.ull : va_arg(ap, PRUint64);
   890 	      do_longlong:
   891 		rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
   892 		if (rv < 0) {
   893 		    return rv;
   894 		}
   895 		break;
   896 	    }
   897 	    break;
   899 	  case 'e':
   900 	  case 'E':
   901 	  case 'f':
   902 	  case 'g':
   903 	    u.d = nas ? nap->u.d : va_arg(ap, double);
   904 	    if( nas != NULL ){
   905 		i = fmt - dolPt;
   906 		if( i < sizeof( pattern ) ){
   907 		    pattern[0] = '%';
   908 		    memcpy( &pattern[1], dolPt, i );
   909 		    rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
   910 		}
   911 	    } else
   912 		rv = cvt_f(ss, u.d, fmt0, fmt);
   914 	    if (rv < 0) {
   915 		return rv;
   916 	    }
   917 	    break;
   919 	  case 'c':
   920 	    u.ch = nas ? nap->u.i : va_arg(ap, int);
   921             if ((flags & FLAG_LEFT) == 0) {
   922                 while (width-- > 1) {
   923                     rv = (*ss->stuff)(ss, " ", 1);
   924                     if (rv < 0) {
   925                         return rv;
   926                     }
   927                 }
   928             }
   929 	    rv = (*ss->stuff)(ss, &u.ch, 1);
   930 	    if (rv < 0) {
   931 		return rv;
   932 	    }
   933             if (flags & FLAG_LEFT) {
   934                 while (width-- > 1) {
   935                     rv = (*ss->stuff)(ss, " ", 1);
   936                     if (rv < 0) {
   937                         return rv;
   938                     }
   939                 }
   940             }
   941 	    break;
   943 	  case 'p':
   944 	    if (sizeof(void *) == sizeof(PRInt32)) {
   945 	    	type = TYPE_UINT32;
   946 	    } else if (sizeof(void *) == sizeof(PRInt64)) {
   947 	    	type = TYPE_UINT64;
   948 	    } else if (sizeof(void *) == sizeof(int)) {
   949 		type = TYPE_UINTN;
   950 	    } else {
   951 		PR_ASSERT(0);
   952 		break;
   953 	    }
   954 	    radix = 16;
   955 	    goto fetch_and_convert;
   957 #ifndef WIN32
   958 	  case 'S':
   959 	    /* XXX not supported I suppose */
   960 	    PR_ASSERT(0);
   961 	    break;
   962 #endif
   964 #if 0
   965 	  case 'C':
   966 	  case 'E':
   967 	  case 'G':
   968 	    /* XXX not supported I suppose */
   969 	    PR_ASSERT(0);
   970 	    break;
   971 #endif
   973 #ifdef WIN32
   974 	  case 'S':
   975 	    u.ws = nas ? nap->u.ws : va_arg(ap, const WCHAR*);
   977 	    /* Get the required size in rv */
   978 	    rv = WideCharToMultiByte(CP_ACP, 0, u.ws, -1, NULL, 0, NULL, NULL);
   979 	    if (rv == 0)
   980 		rv = 1;
   981 	    pBuf = PR_MALLOC(rv);
   982 	    WideCharToMultiByte(CP_ACP, 0, u.ws, -1, pBuf, (int)rv, NULL, NULL);
   983 	    pBuf[rv-1] = '\0';
   985 	    rv = cvt_s(ss, pBuf, width, prec, flags);
   987 	    /* We don't need the allocated buffer anymore */
   988 	    PR_Free(pBuf);
   989 	    if (rv < 0) {
   990 		return rv;
   991 	    }
   992 	    break;
   994 #endif
   996 	  case 's':
   997 	    u.s = nas ? nap->u.s : va_arg(ap, const char*);
   998 	    rv = cvt_s(ss, u.s, width, prec, flags);
   999 	    if (rv < 0) {
  1000 		return rv;
  1002 	    break;
  1004 	  case 'n':
  1005 	    u.ip = nas ? nap->u.ip : va_arg(ap, int*);
  1006 	    if (u.ip) {
  1007 		*u.ip = ss->cur - ss->base;
  1009 	    break;
  1011 	  default:
  1012 	    /* Not a % token after all... skip it */
  1013 #if 0
  1014 	    PR_ASSERT(0);
  1015 #endif
  1016 	    rv = (*ss->stuff)(ss, "%", 1);
  1017 	    if (rv < 0) {
  1018 		return rv;
  1020 	    rv = (*ss->stuff)(ss, fmt - 1, 1);
  1021 	    if (rv < 0) {
  1022 		return rv;
  1027     /* Stuff trailing NUL */
  1028     rv = (*ss->stuff)(ss, "\0", 1);
  1030     if( nas && ( nas != nasArray ) ){
  1031 	PR_DELETE( nas );
  1034     return rv;
  1037 /************************************************************************/
  1039 static int FuncStuff(SprintfState *ss, const char *sp, PRUint32 len)
  1041     int rv;
  1043     rv = (*ss->func)(ss->arg, sp, len);
  1044     if (rv < 0) {
  1045 	return rv;
  1047     ss->maxlen += len;
  1048     return 0;
  1051 PR_IMPLEMENT(PRUint32) PR_sxprintf(PRStuffFunc func, void *arg, 
  1052                                  const char *fmt, ...)
  1054     va_list ap;
  1055     PRUint32 rv;
  1057     va_start(ap, fmt);
  1058     rv = PR_vsxprintf(func, arg, fmt, ap);
  1059     va_end(ap);
  1060     return rv;
  1063 PR_IMPLEMENT(PRUint32) PR_vsxprintf(PRStuffFunc func, void *arg, 
  1064                                   const char *fmt, va_list ap)
  1066     SprintfState ss;
  1067     int rv;
  1069     ss.stuff = FuncStuff;
  1070     ss.func = func;
  1071     ss.arg = arg;
  1072     ss.maxlen = 0;
  1073     rv = dosprintf(&ss, fmt, ap);
  1074     return (rv < 0) ? (PRUint32)-1 : ss.maxlen;
  1077 /*
  1078 ** Stuff routine that automatically grows the malloc'd output buffer
  1079 ** before it overflows.
  1080 */
  1081 static int GrowStuff(SprintfState *ss, const char *sp, PRUint32 len)
  1083     ptrdiff_t off;
  1084     char *newbase;
  1085     PRUint32 newlen;
  1087     off = ss->cur - ss->base;
  1088     if (off + len >= ss->maxlen) {
  1089 	/* Grow the buffer */
  1090 	newlen = ss->maxlen + ((len > 32) ? len : 32);
  1091 	if (ss->base) {
  1092 	    newbase = (char*) PR_REALLOC(ss->base, newlen);
  1093 	} else {
  1094 	    newbase = (char*) PR_MALLOC(newlen);
  1096 	if (!newbase) {
  1097 	    /* Ran out of memory */
  1098 	    return -1;
  1100 	ss->base = newbase;
  1101 	ss->maxlen = newlen;
  1102 	ss->cur = ss->base + off;
  1105     /* Copy data */
  1106     while (len) {
  1107 	--len;
  1108 	*ss->cur++ = *sp++;
  1110     PR_ASSERT((PRUint32)(ss->cur - ss->base) <= ss->maxlen);
  1111     return 0;
  1114 /*
  1115 ** sprintf into a malloc'd buffer
  1116 */
  1117 PR_IMPLEMENT(char *) PR_smprintf(const char *fmt, ...)
  1119     va_list ap;
  1120     char *rv;
  1122     va_start(ap, fmt);
  1123     rv = PR_vsmprintf(fmt, ap);
  1124     va_end(ap);
  1125     return rv;
  1128 /*
  1129 ** Free memory allocated, for the caller, by PR_smprintf
  1130 */
  1131 PR_IMPLEMENT(void) PR_smprintf_free(char *mem)
  1133 	PR_DELETE(mem);
  1136 PR_IMPLEMENT(char *) PR_vsmprintf(const char *fmt, va_list ap)
  1138     SprintfState ss;
  1139     int rv;
  1141     ss.stuff = GrowStuff;
  1142     ss.base = 0;
  1143     ss.cur = 0;
  1144     ss.maxlen = 0;
  1145     rv = dosprintf(&ss, fmt, ap);
  1146     if (rv < 0) {
  1147 	if (ss.base) {
  1148 	    PR_DELETE(ss.base);
  1150 	return 0;
  1152     return ss.base;
  1155 /*
  1156 ** Stuff routine that discards overflow data
  1157 */
  1158 static int LimitStuff(SprintfState *ss, const char *sp, PRUint32 len)
  1160     PRUint32 limit = ss->maxlen - (ss->cur - ss->base);
  1162     if (len > limit) {
  1163 	len = limit;
  1165     while (len) {
  1166 	--len;
  1167 	*ss->cur++ = *sp++;
  1169     return 0;
  1172 /*
  1173 ** sprintf into a fixed size buffer. Make sure there is a NUL at the end
  1174 ** when finished.
  1175 */
  1176 PR_IMPLEMENT(PRUint32) PR_snprintf(char *out, PRUint32 outlen, const char *fmt, ...)
  1178     va_list ap;
  1179     PRUint32 rv;
  1181     va_start(ap, fmt);
  1182     rv = PR_vsnprintf(out, outlen, fmt, ap);
  1183     va_end(ap);
  1184     return rv;
  1187 PR_IMPLEMENT(PRUint32) PR_vsnprintf(char *out, PRUint32 outlen,const char *fmt,
  1188                                   va_list ap)
  1190     SprintfState ss;
  1191     PRUint32 n;
  1193     PR_ASSERT((PRInt32)outlen > 0);
  1194     if ((PRInt32)outlen <= 0) {
  1195 	return 0;
  1198     ss.stuff = LimitStuff;
  1199     ss.base = out;
  1200     ss.cur = out;
  1201     ss.maxlen = outlen;
  1202     (void) dosprintf(&ss, fmt, ap);
  1204     /* If we added chars, and we didn't append a null, do it now. */
  1205     if( (ss.cur != ss.base) && (*(ss.cur - 1) != '\0') )
  1206         *(ss.cur - 1) = '\0';
  1208     n = ss.cur - ss.base;
  1209     return n ? n - 1 : n;
  1212 PR_IMPLEMENT(char *) PR_sprintf_append(char *last, const char *fmt, ...)
  1214     va_list ap;
  1215     char *rv;
  1217     va_start(ap, fmt);
  1218     rv = PR_vsprintf_append(last, fmt, ap);
  1219     va_end(ap);
  1220     return rv;
  1223 PR_IMPLEMENT(char *) PR_vsprintf_append(char *last, const char *fmt, va_list ap)
  1225     SprintfState ss;
  1226     int rv;
  1228     ss.stuff = GrowStuff;
  1229     if (last) {
  1230 	int lastlen = strlen(last);
  1231 	ss.base = last;
  1232 	ss.cur = last + lastlen;
  1233 	ss.maxlen = lastlen;
  1234     } else {
  1235 	ss.base = 0;
  1236 	ss.cur = 0;
  1237 	ss.maxlen = 0;
  1239     rv = dosprintf(&ss, fmt, ap);
  1240     if (rv < 0) {
  1241 	if (ss.base) {
  1242 	    PR_DELETE(ss.base);
  1244 	return 0;
  1246     return ss.base;

mercurial