📄 jsprf.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * 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 Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//*** Portable safe sprintf code.**** Author: Kipp E.B. Hickman*/#include "jsstddef.h"#include <stdarg.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include "jsprf.h"#include "jslong.h"#include "jsutil.h" /* Added by JSIFY */#include "jspubtd.h"#include "jsstr.h"/*** Note: on some platforms va_list is defined as an array,** and requires array notation.*/#ifdef HAVE_VA_COPY#define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar)#elif defined(HAVE_VA_LIST_AS_ARRAY)#define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]#else#define VARARGS_ASSIGN(foo, bar) (foo) = (bar)#endif/*** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it)*//*** XXX This needs to be internationalized!*/typedef struct SprintfStateStr SprintfState;struct SprintfStateStr { int (*stuff)(SprintfState *ss, const char *sp, JSUint32 len); char *base; char *cur; JSUint32 maxlen; int (*func)(void *arg, const char *sp, JSUint32 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 */};#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_WSTRING 11#define TYPE_UNKNOWN 20#define FLAG_LEFT 0x1#define FLAG_SIGNED 0x2#define FLAG_SPACED 0x4#define FLAG_ZEROS 0x8#define FLAG_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 & FLAG_LEFT) == 0)) { /* Right adjusting */ if (flags & FLAG_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, (JSUint32)srclen); if (rv < 0) { return rv; } if ((width > 0) && ((flags & FLAG_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 & FLAG_NEG) { sign = '-'; signwidth = 1; } else if (flags & FLAG_SIGNED) { sign = '+'; signwidth = 1; } else if (flags & FLAG_SPACED) { sign = ' '; signwidth = 1; } } cvtwidth = signwidth + srclen; if (prec > 0) { if (prec > srclen) { precwidth = prec - srclen; /* Need zero filling */ cvtwidth += precwidth; } } if ((flags & FLAG_ZEROS) && (prec < 0)) { if (width > cvtwidth) { zerowidth = width - cvtwidth; /* Zero filling */ cvtwidth += zerowidth; } } if (flags & FLAG_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, (JSUint32)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, JSInt64 num, int width, int prec, int radix, int type, int flags, const char *hexp){ char cvtbuf[100]; char *cvt; int digits; JSInt64 rad; /* according to the man page this needs to happen */ if ((prec == 0) && (JSLL_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. */ JSLL_I2L(rad, radix); cvt = cvtbuf + sizeof(cvtbuf); digits = 0; while (!JSLL_IS_ZERO(num)) { JSInt32 digit; JSInt64 quot, rem; JSLL_UDIVMOD(", &rem, num, rad); JSLL_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; JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin))); if (amount >= (int)sizeof(fin)) { /* Totally bogus % command to sprintf. Just ignore it */ return 0; } memcpy(fin, fmt0, (size_t)amount); fin[amount] = 0; /* Convert floating point using the native sprintf code */#ifdef DEBUG { const char *p = fin; while (*p) { JS_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! */ JS_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);}static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, int flags){ int result; /* * Supply NULL as the JSContext; errors are not reported, * and malloc() is used to allocate the buffer buffer. */ if (ws) { int slen = js_strlen(ws); char *s = js_DeflateString(NULL, ws, slen); if (!s) return -1; /* JSStuffFunc error indicator. */ result = cvt_s(ss, s, width, prec, flags); free(s); } else { result = cvt_s(ss, NULL, width, prec, flags); } return result;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -