⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prprf.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//*  * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape Portable Runtime (NSPR). *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1998-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//*** Portable safe sprintf code.**** Author: Kipp E.B. Hickman*/#include <stdarg.h>#include <stddef.h>#include <stdio.h>#include <string.h>#include "primpl.h"#include "prprf.h"#include "prlong.h"#include "prlog.h"#include "prmem.h"/*** Note: on some platforms va_list is defined as an array,** and requires array notation.*/#if (defined(LINUX) && defined(__powerpc__)) || defined(WIN16) || \    defined(QNX) || \    (defined(__NetBSD__) && defined(__powerpc__) && \    __NetBSD_Version__ < 105000000)#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]#else#define VARARGS_ASSIGN(foo, bar) (foo) = (bar)#endif/*** WARNING: This code may *NOT* call PR_LOG (because PR_LOG calls it)*//*** XXX This needs to be internationalized!*/typedef struct SprintfStateStr SprintfState;struct SprintfStateStr {    int (*stuff)(SprintfState *ss, const char *sp, PRUint32 len);    char *base;    char *cur;    PRUint32 maxlen;    int (*func)(void *arg, const char *sp, PRUint32 len);    void *arg;};/*** Numbered Arguement State*/struct NumArgState{    int	    type;		/* type of the current ap                    */    va_list ap;			/* point to the corresponding position on ap */};static PRBool  l10n_debug_init = PR_FALSE;static PRBool  l10n_debug = PR_FALSE;#define NAS_DEFAULT_NUM 20  /* default number of NumberedArgumentState array */#define TYPE_INT16	0#define TYPE_UINT16	1#define TYPE_INTN	2#define TYPE_UINTN	3#define TYPE_INT32	4#define TYPE_UINT32	5#define TYPE_INT64	6#define TYPE_UINT64	7#define TYPE_STRING	8#define TYPE_DOUBLE	9#define TYPE_INTSTR	10#define TYPE_UNKNOWN	20#define _LEFT		0x1#define _SIGNED		0x2#define _SPACED		0x4#define _ZEROS		0x8#define _NEG		0x10/*** Fill into the buffer using the data in src*/static int fill2(SprintfState *ss, const char *src, int srclen, int width,		int flags){    char space = ' ';    int rv;    width -= srclen;    if ((width > 0) && ((flags & _LEFT) == 0)) {	/* Right adjusting */	if (flags & _ZEROS) {	    space = '0';	}	while (--width >= 0) {	    rv = (*ss->stuff)(ss, &space, 1);	    if (rv < 0) {		return rv;	    }	}    }    /* Copy out the source data */    rv = (*ss->stuff)(ss, src, srclen);    if (rv < 0) {	return rv;    }    if ((width > 0) && ((flags & _LEFT) != 0)) {	/* Left adjusting */	while (--width >= 0) {	    rv = (*ss->stuff)(ss, &space, 1);	    if (rv < 0) {		return rv;	    }	}    }    return 0;}/*** Fill a number. The order is: optional-sign zero-filling conversion-digits*/static int fill_n(SprintfState *ss, const char *src, int srclen, int width,		  int prec, int type, int flags){    int zerowidth = 0;    int precwidth = 0;    int signwidth = 0;    int leftspaces = 0;    int rightspaces = 0;    int cvtwidth;    int rv;    char sign;    if ((type & 1) == 0) {	if (flags & _NEG) {	    sign = '-';	    signwidth = 1;	} else if (flags & _SIGNED) {	    sign = '+';	    signwidth = 1;	} else if (flags & _SPACED) {	    sign = ' ';	    signwidth = 1;	}    }    cvtwidth = signwidth + srclen;    if (prec > 0) {	if (prec > srclen) {	    precwidth = prec - srclen;		/* Need zero filling */	    cvtwidth += precwidth;	}    }    if ((flags & _ZEROS) && (prec < 0)) {	if (width > cvtwidth) {	    zerowidth = width - cvtwidth;	/* Zero filling */	    cvtwidth += zerowidth;	}    }    if (flags & _LEFT) {	if (width > cvtwidth) {	    /* Space filling on the right (i.e. left adjusting) */	    rightspaces = width - cvtwidth;	}    } else {	if (width > cvtwidth) {	    /* Space filling on the left (i.e. right adjusting) */	    leftspaces = width - cvtwidth;	}    }    while (--leftspaces >= 0) {	rv = (*ss->stuff)(ss, " ", 1);	if (rv < 0) {	    return rv;	}    }    if (signwidth) {	rv = (*ss->stuff)(ss, &sign, 1);	if (rv < 0) {	    return rv;	}    }    while (--precwidth >= 0) {	rv = (*ss->stuff)(ss, "0", 1);	if (rv < 0) {	    return rv;	}    }    while (--zerowidth >= 0) {	rv = (*ss->stuff)(ss, "0", 1);	if (rv < 0) {	    return rv;	}    }    rv = (*ss->stuff)(ss, src, srclen);    if (rv < 0) {	return rv;    }    while (--rightspaces >= 0) {	rv = (*ss->stuff)(ss, " ", 1);	if (rv < 0) {	    return rv;	}    }    return 0;}/*** Convert a long into its printable form*/static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,		 int type, int flags, const char *hexp){    char cvtbuf[100];    char *cvt;    int digits;    /* according to the man page this needs to happen */    if ((prec == 0) && (num == 0)) {	return 0;    }    /*    ** Converting decimal is a little tricky. In the unsigned case we    ** need to stop when we hit 10 digits. In the signed case, we can    ** stop when the number is zero.    */    cvt = cvtbuf + sizeof(cvtbuf);    digits = 0;    while (num) {	int digit = (((unsigned long)num) % radix) & 0xF;	*--cvt = hexp[digit];	digits++;	num = (long)(((unsigned long)num) / radix);    }    if (digits == 0) {	*--cvt = '0';	digits++;    }    /*    ** Now that we have the number converted without its sign, deal with    ** the sign and zero padding.    */    return fill_n(ss, cvt, digits, width, prec, type, flags);}/*** Convert a 64-bit integer into its printable form*/static int cvt_ll(SprintfState *ss, PRInt64 num, int width, int prec, int radix,		  int type, int flags, const char *hexp){    char cvtbuf[100];    char *cvt;    int digits;    PRInt64 rad;    /* according to the man page this needs to happen */    if ((prec == 0) && (LL_IS_ZERO(num))) {	return 0;    }    /*    ** Converting decimal is a little tricky. In the unsigned case we    ** need to stop when we hit 10 digits. In the signed case, we can    ** stop when the number is zero.    */    LL_I2L(rad, radix);    cvt = cvtbuf + sizeof(cvtbuf);    digits = 0;    while (!LL_IS_ZERO(num)) {	PRInt32 digit;	PRInt64 quot, rem;	LL_UDIVMOD(&quot, &rem, num, rad);	LL_L2I(digit, rem);	*--cvt = hexp[digit & 0xf];	digits++;	num = quot;    }    if (digits == 0) {	*--cvt = '0';	digits++;    }    /*    ** Now that we have the number converted without its sign, deal with    ** the sign and zero padding.    */    return fill_n(ss, cvt, digits, width, prec, type, flags);}/*** Convert a double precision floating point number into its printable** form.**** XXX stop using sprintf to convert floating point*/static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1){    char fin[20];    char fout[300];    int amount = fmt1 - fmt0;    PR_ASSERT((amount > 0) && (amount < sizeof(fin)));    if (amount >= sizeof(fin)) {	/* Totally bogus % command to sprintf. Just ignore it */	return 0;    }    memcpy(fin, fmt0, amount);    fin[amount] = 0;    /* Convert floating point using the native sprintf code */#ifdef DEBUG    {        const char *p = fin;        while (*p) {            PR_ASSERT(*p != 'L');            p++;        }    }#endif    sprintf(fout, fin, d);    /*    ** This assert will catch overflow's of fout, when building with    ** debugging on. At least this way we can track down the evil piece    ** of calling code and fix it!    */    PR_ASSERT(strlen(fout) < sizeof(fout));    return (*ss->stuff)(ss, fout, strlen(fout));}/*** Convert a string into its printable form.  "width" is the output** width. "prec" is the maximum number of characters of "s" to output,** where -1 means until NUL.*/static int cvt_s(SprintfState *ss, const char *s, int width, int prec,		 int flags){    int slen;    if (prec == 0)	return 0;    /* Limit string length by precision value */    slen = s ? strlen(s) : 6;    if (prec > 0) {	if (prec < slen) {	    slen = prec;	}    }    /* and away we go */    return fill2(ss, s ? s : "(null)", slen, width, flags);}/*** BiuldArgArray stands for Numbered Argument list Sprintf** for example,  **	fmp = "%4$i, %2$d, %3s, %1d";** the number must start from 1, and no gap among them*/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. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -