PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsprf.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 1262 lines | 913 code | 150 blank | 199 comment | 253 complexity | 4dc8f471b63af55f52046a225dbc22ef MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is Mozilla Communicator client code, released
  16. * March 31, 1998.
  17. *
  18. * The Initial Developer of the Original Code is
  19. * Netscape Communications Corporation.
  20. * Portions created by the Initial Developer are Copyright (C) 1998
  21. * the Initial Developer. All Rights Reserved.
  22. *
  23. * Contributor(s):
  24. *
  25. * Alternatively, the contents of this file may be used under the terms of
  26. * either of the GNU General Public License Version 2 or later (the "GPL"),
  27. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28. * in which case the provisions of the GPL or the LGPL are applicable instead
  29. * of those above. If you wish to allow use of your version of this file only
  30. * under the terms of either the GPL or the LGPL, and not to allow others to
  31. * use your version of this file under the terms of the MPL, indicate your
  32. * decision by deleting the provisions above and replace them with the notice
  33. * and other provisions required by the GPL or the LGPL. If you do not delete
  34. * the provisions above, a recipient may use your version of this file under
  35. * the terms of any one of the MPL, the GPL or the LGPL.
  36. *
  37. * ***** END LICENSE BLOCK ***** */
  38. /*
  39. ** Portable safe sprintf code.
  40. **
  41. ** Author: Kipp E.B. Hickman
  42. */
  43. #include "jsstddef.h"
  44. #include <stdarg.h>
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <stdlib.h>
  48. #include "jsprf.h"
  49. #include "jslong.h"
  50. #include "jsutil.h" /* Added by JSIFY */
  51. #include "jspubtd.h"
  52. #include "jsstr.h"
  53. /*
  54. ** Note: on some platforms va_list is defined as an array,
  55. ** and requires array notation.
  56. */
  57. #ifdef HAVE_VA_COPY
  58. #define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar)
  59. #elif defined(HAVE_VA_LIST_AS_ARRAY)
  60. #define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0]
  61. #else
  62. #define VARARGS_ASSIGN(foo, bar) (foo) = (bar)
  63. #endif
  64. /*
  65. ** WARNING: This code may *NOT* call JS_LOG (because JS_LOG calls it)
  66. */
  67. /*
  68. ** XXX This needs to be internationalized!
  69. */
  70. typedef struct SprintfStateStr SprintfState;
  71. struct SprintfStateStr {
  72. int (*stuff)(SprintfState *ss, const char *sp, JSUint32 len);
  73. char *base;
  74. char *cur;
  75. JSUint32 maxlen;
  76. int (*func)(void *arg, const char *sp, JSUint32 len);
  77. void *arg;
  78. };
  79. /*
  80. ** Numbered Arguement State
  81. */
  82. struct NumArgState{
  83. int type; /* type of the current ap */
  84. va_list ap; /* point to the corresponding position on ap */
  85. };
  86. #define NAS_DEFAULT_NUM 20 /* default number of NumberedArgumentState array */
  87. #define TYPE_INT16 0
  88. #define TYPE_UINT16 1
  89. #define TYPE_INTN 2
  90. #define TYPE_UINTN 3
  91. #define TYPE_INT32 4
  92. #define TYPE_UINT32 5
  93. #define TYPE_INT64 6
  94. #define TYPE_UINT64 7
  95. #define TYPE_STRING 8
  96. #define TYPE_DOUBLE 9
  97. #define TYPE_INTSTR 10
  98. #define TYPE_WSTRING 11
  99. #define TYPE_UNKNOWN 20
  100. #define FLAG_LEFT 0x1
  101. #define FLAG_SIGNED 0x2
  102. #define FLAG_SPACED 0x4
  103. #define FLAG_ZEROS 0x8
  104. #define FLAG_NEG 0x10
  105. /*
  106. ** Fill into the buffer using the data in src
  107. */
  108. static int fill2(SprintfState *ss, const char *src, int srclen, int width,
  109. int flags)
  110. {
  111. char space = ' ';
  112. int rv;
  113. width -= srclen;
  114. if ((width > 0) && ((flags & FLAG_LEFT) == 0)) { /* Right adjusting */
  115. if (flags & FLAG_ZEROS) {
  116. space = '0';
  117. }
  118. while (--width >= 0) {
  119. rv = (*ss->stuff)(ss, &space, 1);
  120. if (rv < 0) {
  121. return rv;
  122. }
  123. }
  124. }
  125. /* Copy out the source data */
  126. rv = (*ss->stuff)(ss, src, (JSUint32)srclen);
  127. if (rv < 0) {
  128. return rv;
  129. }
  130. if ((width > 0) && ((flags & FLAG_LEFT) != 0)) { /* Left adjusting */
  131. while (--width >= 0) {
  132. rv = (*ss->stuff)(ss, &space, 1);
  133. if (rv < 0) {
  134. return rv;
  135. }
  136. }
  137. }
  138. return 0;
  139. }
  140. /*
  141. ** Fill a number. The order is: optional-sign zero-filling conversion-digits
  142. */
  143. static int fill_n(SprintfState *ss, const char *src, int srclen, int width,
  144. int prec, int type, int flags)
  145. {
  146. int zerowidth = 0;
  147. int precwidth = 0;
  148. int signwidth = 0;
  149. int leftspaces = 0;
  150. int rightspaces = 0;
  151. int cvtwidth;
  152. int rv;
  153. char sign;
  154. if ((type & 1) == 0) {
  155. if (flags & FLAG_NEG) {
  156. sign = '-';
  157. signwidth = 1;
  158. } else if (flags & FLAG_SIGNED) {
  159. sign = '+';
  160. signwidth = 1;
  161. } else if (flags & FLAG_SPACED) {
  162. sign = ' ';
  163. signwidth = 1;
  164. }
  165. }
  166. cvtwidth = signwidth + srclen;
  167. if (prec > 0) {
  168. if (prec > srclen) {
  169. precwidth = prec - srclen; /* Need zero filling */
  170. cvtwidth += precwidth;
  171. }
  172. }
  173. if ((flags & FLAG_ZEROS) && (prec < 0)) {
  174. if (width > cvtwidth) {
  175. zerowidth = width - cvtwidth; /* Zero filling */
  176. cvtwidth += zerowidth;
  177. }
  178. }
  179. if (flags & FLAG_LEFT) {
  180. if (width > cvtwidth) {
  181. /* Space filling on the right (i.e. left adjusting) */
  182. rightspaces = width - cvtwidth;
  183. }
  184. } else {
  185. if (width > cvtwidth) {
  186. /* Space filling on the left (i.e. right adjusting) */
  187. leftspaces = width - cvtwidth;
  188. }
  189. }
  190. while (--leftspaces >= 0) {
  191. rv = (*ss->stuff)(ss, " ", 1);
  192. if (rv < 0) {
  193. return rv;
  194. }
  195. }
  196. if (signwidth) {
  197. rv = (*ss->stuff)(ss, &sign, 1);
  198. if (rv < 0) {
  199. return rv;
  200. }
  201. }
  202. while (--precwidth >= 0) {
  203. rv = (*ss->stuff)(ss, "0", 1);
  204. if (rv < 0) {
  205. return rv;
  206. }
  207. }
  208. while (--zerowidth >= 0) {
  209. rv = (*ss->stuff)(ss, "0", 1);
  210. if (rv < 0) {
  211. return rv;
  212. }
  213. }
  214. rv = (*ss->stuff)(ss, src, (JSUint32)srclen);
  215. if (rv < 0) {
  216. return rv;
  217. }
  218. while (--rightspaces >= 0) {
  219. rv = (*ss->stuff)(ss, " ", 1);
  220. if (rv < 0) {
  221. return rv;
  222. }
  223. }
  224. return 0;
  225. }
  226. /*
  227. ** Convert a long into its printable form
  228. */
  229. static int cvt_l(SprintfState *ss, long num, int width, int prec, int radix,
  230. int type, int flags, const char *hexp)
  231. {
  232. char cvtbuf[100];
  233. char *cvt;
  234. int digits;
  235. /* according to the man page this needs to happen */
  236. if ((prec == 0) && (num == 0)) {
  237. return 0;
  238. }
  239. /*
  240. ** Converting decimal is a little tricky. In the unsigned case we
  241. ** need to stop when we hit 10 digits. In the signed case, we can
  242. ** stop when the number is zero.
  243. */
  244. cvt = cvtbuf + sizeof(cvtbuf);
  245. digits = 0;
  246. while (num) {
  247. int digit = (((unsigned long)num) % radix) & 0xF;
  248. *--cvt = hexp[digit];
  249. digits++;
  250. num = (long)(((unsigned long)num) / radix);
  251. }
  252. if (digits == 0) {
  253. *--cvt = '0';
  254. digits++;
  255. }
  256. /*
  257. ** Now that we have the number converted without its sign, deal with
  258. ** the sign and zero padding.
  259. */
  260. return fill_n(ss, cvt, digits, width, prec, type, flags);
  261. }
  262. /*
  263. ** Convert a 64-bit integer into its printable form
  264. */
  265. static int cvt_ll(SprintfState *ss, JSInt64 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. JSInt64 rad;
  272. /* according to the man page this needs to happen */
  273. if ((prec == 0) && (JSLL_IS_ZERO(num))) {
  274. return 0;
  275. }
  276. /*
  277. ** Converting decimal is a little tricky. In the unsigned case we
  278. ** need to stop when we hit 10 digits. In the signed case, we can
  279. ** stop when the number is zero.
  280. */
  281. JSLL_I2L(rad, radix);
  282. cvt = cvtbuf + sizeof(cvtbuf);
  283. digits = 0;
  284. while (!JSLL_IS_ZERO(num)) {
  285. JSInt32 digit;
  286. JSInt64 quot, rem;
  287. JSLL_UDIVMOD(&quot, &rem, num, rad);
  288. JSLL_L2I(digit, rem);
  289. *--cvt = hexp[digit & 0xf];
  290. digits++;
  291. num = quot;
  292. }
  293. if (digits == 0) {
  294. *--cvt = '0';
  295. digits++;
  296. }
  297. /*
  298. ** Now that we have the number converted without its sign, deal with
  299. ** the sign and zero padding.
  300. */
  301. return fill_n(ss, cvt, digits, width, prec, type, flags);
  302. }
  303. /*
  304. ** Convert a double precision floating point number into its printable
  305. ** form.
  306. **
  307. ** XXX stop using sprintf to convert floating point
  308. */
  309. static int cvt_f(SprintfState *ss, double d, const char *fmt0, const char *fmt1)
  310. {
  311. char fin[20];
  312. char fout[300];
  313. int amount = fmt1 - fmt0;
  314. JS_ASSERT((amount > 0) && (amount < (int)sizeof(fin)));
  315. if (amount >= (int)sizeof(fin)) {
  316. /* Totally bogus % command to sprintf. Just ignore it */
  317. return 0;
  318. }
  319. memcpy(fin, fmt0, (size_t)amount);
  320. fin[amount] = 0;
  321. /* Convert floating point using the native sprintf code */
  322. #ifdef DEBUG
  323. {
  324. const char *p = fin;
  325. while (*p) {
  326. JS_ASSERT(*p != 'L');
  327. p++;
  328. }
  329. }
  330. #endif
  331. sprintf(fout, fin, d);
  332. /*
  333. ** This assert will catch overflow's of fout, when building with
  334. ** debugging on. At least this way we can track down the evil piece
  335. ** of calling code and fix it!
  336. */
  337. JS_ASSERT(strlen(fout) < sizeof(fout));
  338. return (*ss->stuff)(ss, fout, strlen(fout));
  339. }
  340. /*
  341. ** Convert a string into its printable form. "width" is the output
  342. ** width. "prec" is the maximum number of characters of "s" to output,
  343. ** where -1 means until NUL.
  344. */
  345. static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
  346. int flags)
  347. {
  348. int slen;
  349. if (prec == 0)
  350. return 0;
  351. /* Limit string length by precision value */
  352. slen = s ? strlen(s) : 6;
  353. if (prec > 0) {
  354. if (prec < slen) {
  355. slen = prec;
  356. }
  357. }
  358. /* and away we go */
  359. return fill2(ss, s ? s : "(null)", slen, width, flags);
  360. }
  361. static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec,
  362. int flags)
  363. {
  364. int result;
  365. /*
  366. * Supply NULL as the JSContext; errors are not reported,
  367. * and malloc() is used to allocate the buffer buffer.
  368. */
  369. if (ws) {
  370. int slen = js_strlen(ws);
  371. char *s = js_DeflateString(NULL, ws, slen);
  372. if (!s)
  373. return -1; /* JSStuffFunc error indicator. */
  374. result = cvt_s(ss, s, width, prec, flags);
  375. free(s);
  376. } else {
  377. result = cvt_s(ss, NULL, width, prec, flags);
  378. }
  379. return result;
  380. }
  381. /*
  382. ** BuildArgArray stands for Numbered Argument list Sprintf
  383. ** for example,
  384. ** fmp = "%4$i, %2$d, %3s, %1d";
  385. ** the number must start from 1, and no gap among them
  386. */
  387. static struct NumArgState* BuildArgArray( const char *fmt, va_list ap, int* rv, struct NumArgState* nasArray )
  388. {
  389. int number = 0, cn = 0, i;
  390. const char *p;
  391. char c;
  392. struct NumArgState *nas;
  393. /*
  394. ** first pass:
  395. ** detemine how many legal % I have got, then allocate space
  396. */
  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;
  405. while( c != 0 ){
  406. if( c > '9' || c < '0' ){
  407. if( c == '$' ){ /* numbered argument csae */
  408. if( i > 0 ){
  409. *rv = -1;
  410. return NULL;
  411. }
  412. number++;
  413. } else { /* non-numbered argument case */
  414. if( number > 0 ){
  415. *rv = -1;
  416. return NULL;
  417. }
  418. i = 1;
  419. }
  420. break;
  421. }
  422. c = *p++;
  423. }
  424. }
  425. if( number == 0 ){
  426. return NULL;
  427. }
  428. if( number > NAS_DEFAULT_NUM ){
  429. nas = (struct NumArgState*)malloc( number * sizeof( struct NumArgState ) );
  430. if( !nas ){
  431. *rv = -1;
  432. return NULL;
  433. }
  434. } else {
  435. nas = nasArray;
  436. }
  437. for( i = 0; i < number; i++ ){
  438. nas[i].type = TYPE_UNKNOWN;
  439. }
  440. /*
  441. ** second pass:
  442. ** set nas[].type
  443. */
  444. p = fmt;
  445. while( ( c = *p++ ) != 0 ){
  446. if( c != '%' ) continue;
  447. c = *p++;
  448. if( c == '%' ) continue;
  449. cn = 0;
  450. while( c && c != '$' ){ /* should improve error check later */
  451. cn = cn*10 + c - '0';
  452. c = *p++;
  453. }
  454. if( !c || cn < 1 || cn > number ){
  455. *rv = -1;
  456. break;
  457. }
  458. /* nas[cn] starts from 0, and make sure nas[cn].type is not assigned */
  459. cn--;
  460. if( nas[cn].type != TYPE_UNKNOWN )
  461. continue;
  462. c = *p++;
  463. /* width */
  464. if (c == '*') {
  465. /* not supported feature, for the argument is not numbered */
  466. *rv = -1;
  467. break;
  468. }
  469. while ((c >= '0') && (c <= '9')) {
  470. c = *p++;
  471. }
  472. /* precision */
  473. if (c == '.') {
  474. c = *p++;
  475. if (c == '*') {
  476. /* not supported feature, for the argument is not numbered */
  477. *rv = -1;
  478. break;
  479. }
  480. while ((c >= '0') && (c <= '9')) {
  481. c = *p++;
  482. }
  483. }
  484. /* size */
  485. nas[cn].type = TYPE_INTN;
  486. if (c == 'h') {
  487. nas[cn].type = TYPE_INT16;
  488. c = *p++;
  489. } else if (c == 'L') {
  490. /* XXX not quite sure here */
  491. nas[cn].type = TYPE_INT64;
  492. c = *p++;
  493. } else if (c == 'l') {
  494. nas[cn].type = TYPE_INT32;
  495. c = *p++;
  496. if (c == 'l') {
  497. nas[cn].type = TYPE_INT64;
  498. c = *p++;
  499. }
  500. }
  501. /* format */
  502. switch (c) {
  503. case 'd':
  504. case 'c':
  505. case 'i':
  506. case 'o':
  507. case 'u':
  508. case 'x':
  509. case 'X':
  510. break;
  511. case 'e':
  512. case 'f':
  513. case 'g':
  514. nas[ cn ].type = TYPE_DOUBLE;
  515. break;
  516. case 'p':
  517. /* XXX should use cpp */
  518. if (sizeof(void *) == sizeof(JSInt32)) {
  519. nas[ cn ].type = TYPE_UINT32;
  520. } else if (sizeof(void *) == sizeof(JSInt64)) {
  521. nas[ cn ].type = TYPE_UINT64;
  522. } else if (sizeof(void *) == sizeof(JSIntn)) {
  523. nas[ cn ].type = TYPE_UINTN;
  524. } else {
  525. nas[ cn ].type = TYPE_UNKNOWN;
  526. }
  527. break;
  528. case 'C':
  529. case 'S':
  530. case 'E':
  531. case 'G':
  532. /* XXX not supported I suppose */
  533. JS_ASSERT(0);
  534. nas[ cn ].type = TYPE_UNKNOWN;
  535. break;
  536. case 's':
  537. nas[ cn ].type = (nas[ cn ].type == TYPE_UINT16) ? TYPE_WSTRING : TYPE_STRING;
  538. break;
  539. case 'n':
  540. nas[ cn ].type = TYPE_INTSTR;
  541. break;
  542. default:
  543. JS_ASSERT(0);
  544. nas[ cn ].type = TYPE_UNKNOWN;
  545. break;
  546. }
  547. /* get a legal para. */
  548. if( nas[ cn ].type == TYPE_UNKNOWN ){
  549. *rv = -1;
  550. break;
  551. }
  552. }
  553. /*
  554. ** third pass
  555. ** fill the nas[cn].ap
  556. */
  557. if( *rv < 0 ){
  558. if( nas != nasArray )
  559. free( nas );
  560. return NULL;
  561. }
  562. cn = 0;
  563. while( cn < number ){
  564. if( nas[cn].type == TYPE_UNKNOWN ){
  565. cn++;
  566. continue;
  567. }
  568. VARARGS_ASSIGN(nas[cn].ap, ap);
  569. switch( nas[cn].type ){
  570. case TYPE_INT16:
  571. case TYPE_UINT16:
  572. case TYPE_INTN:
  573. case TYPE_UINTN: (void)va_arg( ap, JSIntn ); break;
  574. case TYPE_INT32: (void)va_arg( ap, JSInt32 ); break;
  575. case TYPE_UINT32: (void)va_arg( ap, JSUint32 ); break;
  576. case TYPE_INT64: (void)va_arg( ap, JSInt64 ); break;
  577. case TYPE_UINT64: (void)va_arg( ap, JSUint64 ); break;
  578. case TYPE_STRING: (void)va_arg( ap, char* ); break;
  579. case TYPE_WSTRING: (void)va_arg( ap, jschar* ); break;
  580. case TYPE_INTSTR: (void)va_arg( ap, JSIntn* ); break;
  581. case TYPE_DOUBLE: (void)va_arg( ap, double ); break;
  582. default:
  583. if( nas != nasArray )
  584. free( nas );
  585. *rv = -1;
  586. return NULL;
  587. }
  588. cn++;
  589. }
  590. return nas;
  591. }
  592. /*
  593. ** The workhorse sprintf code.
  594. */
  595. static int dosprintf(SprintfState *ss, const char *fmt, va_list ap)
  596. {
  597. char c;
  598. int flags, width, prec, radix, type;
  599. union {
  600. char ch;
  601. jschar wch;
  602. int i;
  603. long l;
  604. JSInt64 ll;
  605. double d;
  606. const char *s;
  607. const jschar* ws;
  608. int *ip;
  609. } u;
  610. const char *fmt0;
  611. static const char hex[] = "0123456789abcdef";
  612. static const char HEX[] = "0123456789ABCDEF";
  613. const char *hexp;
  614. int rv, i;
  615. struct NumArgState *nas = NULL;
  616. struct NumArgState nasArray[ NAS_DEFAULT_NUM ];
  617. char pattern[20];
  618. const char *dolPt = NULL; /* in "%4$.2f", dolPt will poiont to . */
  619. uint8 utf8buf[6];
  620. int utf8len;
  621. /*
  622. ** build an argument array, IF the fmt is numbered argument
  623. ** list style, to contain the Numbered Argument list pointers
  624. */
  625. nas = BuildArgArray( fmt, ap, &rv, nasArray );
  626. if( rv < 0 ){
  627. /* the fmt contains error Numbered Argument format, jliu@netscape.com */
  628. JS_ASSERT(0);
  629. return rv;
  630. }
  631. while ((c = *fmt++) != 0) {
  632. if (c != '%') {
  633. rv = (*ss->stuff)(ss, fmt - 1, 1);
  634. if (rv < 0) {
  635. return rv;
  636. }
  637. continue;
  638. }
  639. fmt0 = fmt - 1;
  640. /*
  641. ** Gobble up the % format string. Hopefully we have handled all
  642. ** of the strange cases!
  643. */
  644. flags = 0;
  645. c = *fmt++;
  646. if (c == '%') {
  647. /* quoting a % with %% */
  648. rv = (*ss->stuff)(ss, fmt - 1, 1);
  649. if (rv < 0) {
  650. return rv;
  651. }
  652. continue;
  653. }
  654. if( nas != NULL ){
  655. /* the fmt contains the Numbered Arguments feature */
  656. i = 0;
  657. while( c && c != '$' ){ /* should imporve error check later */
  658. i = ( i * 10 ) + ( c - '0' );
  659. c = *fmt++;
  660. }
  661. if( nas[i-1].type == TYPE_UNKNOWN ){
  662. if( nas && ( nas != nasArray ) )
  663. free( nas );
  664. return -1;
  665. }
  666. ap = nas[i-1].ap;
  667. dolPt = fmt;
  668. c = *fmt++;
  669. }
  670. /*
  671. * Examine optional flags. Note that we do not implement the
  672. * '#' flag of sprintf(). The ANSI C spec. of the '#' flag is
  673. * somewhat ambiguous and not ideal, which is perhaps why
  674. * the various sprintf() implementations are inconsistent
  675. * on this feature.
  676. */
  677. while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
  678. if (c == '-') flags |= FLAG_LEFT;
  679. if (c == '+') flags |= FLAG_SIGNED;
  680. if (c == ' ') flags |= FLAG_SPACED;
  681. if (c == '0') flags |= FLAG_ZEROS;
  682. c = *fmt++;
  683. }
  684. if (flags & FLAG_SIGNED) flags &= ~FLAG_SPACED;
  685. if (flags & FLAG_LEFT) flags &= ~FLAG_ZEROS;
  686. /* width */
  687. if (c == '*') {
  688. c = *fmt++;
  689. width = va_arg(ap, int);
  690. } else {
  691. width = 0;
  692. while ((c >= '0') && (c <= '9')) {
  693. width = (width * 10) + (c - '0');
  694. c = *fmt++;
  695. }
  696. }
  697. /* precision */
  698. prec = -1;
  699. if (c == '.') {
  700. c = *fmt++;
  701. if (c == '*') {
  702. c = *fmt++;
  703. prec = va_arg(ap, int);
  704. } else {
  705. prec = 0;
  706. while ((c >= '0') && (c <= '9')) {
  707. prec = (prec * 10) + (c - '0');
  708. c = *fmt++;
  709. }
  710. }
  711. }
  712. /* size */
  713. type = TYPE_INTN;
  714. if (c == 'h') {
  715. type = TYPE_INT16;
  716. c = *fmt++;
  717. } else if (c == 'L') {
  718. /* XXX not quite sure here */
  719. type = TYPE_INT64;
  720. c = *fmt++;
  721. } else if (c == 'l') {
  722. type = TYPE_INT32;
  723. c = *fmt++;
  724. if (c == 'l') {
  725. type = TYPE_INT64;
  726. c = *fmt++;
  727. }
  728. }
  729. /* format */
  730. hexp = hex;
  731. switch (c) {
  732. case 'd': case 'i': /* decimal/integer */
  733. radix = 10;
  734. goto fetch_and_convert;
  735. case 'o': /* octal */
  736. radix = 8;
  737. type |= 1;
  738. goto fetch_and_convert;
  739. case 'u': /* unsigned decimal */
  740. radix = 10;
  741. type |= 1;
  742. goto fetch_and_convert;
  743. case 'x': /* unsigned hex */
  744. radix = 16;
  745. type |= 1;
  746. goto fetch_and_convert;
  747. case 'X': /* unsigned HEX */
  748. radix = 16;
  749. hexp = HEX;
  750. type |= 1;
  751. goto fetch_and_convert;
  752. fetch_and_convert:
  753. switch (type) {
  754. case TYPE_INT16:
  755. u.l = va_arg(ap, int);
  756. if (u.l < 0) {
  757. u.l = -u.l;
  758. flags |= FLAG_NEG;
  759. }
  760. goto do_long;
  761. case TYPE_UINT16:
  762. u.l = va_arg(ap, int) & 0xffff;
  763. goto do_long;
  764. case TYPE_INTN:
  765. u.l = va_arg(ap, int);
  766. if (u.l < 0) {
  767. u.l = -u.l;
  768. flags |= FLAG_NEG;
  769. }
  770. goto do_long;
  771. case TYPE_UINTN:
  772. u.l = (long)va_arg(ap, unsigned int);
  773. goto do_long;
  774. case TYPE_INT32:
  775. u.l = va_arg(ap, JSInt32);
  776. if (u.l < 0) {
  777. u.l = -u.l;
  778. flags |= FLAG_NEG;
  779. }
  780. goto do_long;
  781. case TYPE_UINT32:
  782. u.l = (long)va_arg(ap, JSUint32);
  783. do_long:
  784. rv = cvt_l(ss, u.l, width, prec, radix, type, flags, hexp);
  785. if (rv < 0) {
  786. return rv;
  787. }
  788. break;
  789. case TYPE_INT64:
  790. u.ll = va_arg(ap, JSInt64);
  791. if (!JSLL_GE_ZERO(u.ll)) {
  792. JSLL_NEG(u.ll, u.ll);
  793. flags |= FLAG_NEG;
  794. }
  795. goto do_longlong;
  796. case TYPE_UINT64:
  797. u.ll = va_arg(ap, JSUint64);
  798. do_longlong:
  799. rv = cvt_ll(ss, u.ll, width, prec, radix, type, flags, hexp);
  800. if (rv < 0) {
  801. return rv;
  802. }
  803. break;
  804. }
  805. break;
  806. case 'e':
  807. case 'E':
  808. case 'f':
  809. case 'g':
  810. u.d = va_arg(ap, double);
  811. if( nas != NULL ){
  812. i = fmt - dolPt;
  813. if( i < (int)sizeof( pattern ) ){
  814. pattern[0] = '%';
  815. memcpy( &pattern[1], dolPt, (size_t)i );
  816. rv = cvt_f(ss, u.d, pattern, &pattern[i+1] );
  817. }
  818. } else
  819. rv = cvt_f(ss, u.d, fmt0, fmt);
  820. if (rv < 0) {
  821. return rv;
  822. }
  823. break;
  824. case 'c':
  825. if ((flags & FLAG_LEFT) == 0) {
  826. while (width-- > 1) {
  827. rv = (*ss->stuff)(ss, " ", 1);
  828. if (rv < 0) {
  829. return rv;
  830. }
  831. }
  832. }
  833. switch (type) {
  834. case TYPE_INT16:
  835. /* Treat %hc as %c unless js_CStringsAreUTF8. */
  836. if (js_CStringsAreUTF8) {
  837. u.wch = va_arg(ap, int);
  838. utf8len = js_OneUcs4ToUtf8Char (utf8buf, u.wch);
  839. rv = (*ss->stuff)(ss, (char *)utf8buf, utf8len);
  840. break;
  841. }
  842. case TYPE_INTN:
  843. u.ch = va_arg(ap, int);
  844. rv = (*ss->stuff)(ss, &u.ch, 1);
  845. break;
  846. }
  847. if (rv < 0) {
  848. return rv;
  849. }
  850. if (flags & FLAG_LEFT) {
  851. while (width-- > 1) {
  852. rv = (*ss->stuff)(ss, " ", 1);
  853. if (rv < 0) {
  854. return rv;
  855. }
  856. }
  857. }
  858. break;
  859. case 'p':
  860. if (sizeof(void *) == sizeof(JSInt32)) {
  861. type = TYPE_UINT32;
  862. } else if (sizeof(void *) == sizeof(JSInt64)) {
  863. type = TYPE_UINT64;
  864. } else if (sizeof(void *) == sizeof(int)) {
  865. type = TYPE_UINTN;
  866. } else {
  867. JS_ASSERT(0);
  868. break;
  869. }
  870. radix = 16;
  871. goto fetch_and_convert;
  872. #if 0
  873. case 'C':
  874. case 'S':
  875. case 'E':
  876. case 'G':
  877. /* XXX not supported I suppose */
  878. JS_ASSERT(0);
  879. break;
  880. #endif
  881. case 's':
  882. if(type == TYPE_INT16) {
  883. /*
  884. * This would do a simple string/byte conversion
  885. * unless js_CStringsAreUTF8.
  886. */
  887. u.ws = va_arg(ap, const jschar*);
  888. rv = cvt_ws(ss, u.ws, width, prec, flags);
  889. } else {
  890. u.s = va_arg(ap, const char*);
  891. rv = cvt_s(ss, u.s, width, prec, flags);
  892. }
  893. if (rv < 0) {
  894. return rv;
  895. }
  896. break;
  897. case 'n':
  898. u.ip = va_arg(ap, int*);
  899. if (u.ip) {
  900. *u.ip = ss->cur - ss->base;
  901. }
  902. break;
  903. default:
  904. /* Not a % token after all... skip it */
  905. #if 0
  906. JS_ASSERT(0);
  907. #endif
  908. rv = (*ss->stuff)(ss, "%", 1);
  909. if (rv < 0) {
  910. return rv;
  911. }
  912. rv = (*ss->stuff)(ss, fmt - 1, 1);
  913. if (rv < 0) {
  914. return rv;
  915. }
  916. }
  917. }
  918. /* Stuff trailing NUL */
  919. rv = (*ss->stuff)(ss, "\0", 1);
  920. if( nas && ( nas != nasArray ) ){
  921. free( nas );
  922. }
  923. return rv;
  924. }
  925. /************************************************************************/
  926. static int FuncStuff(SprintfState *ss, const char *sp, JSUint32 len)
  927. {
  928. int rv;
  929. rv = (*ss->func)(ss->arg, sp, len);
  930. if (rv < 0) {
  931. return rv;
  932. }
  933. ss->maxlen += len;
  934. return 0;
  935. }
  936. JS_PUBLIC_API(JSUint32) JS_sxprintf(JSStuffFunc func, void *arg,
  937. const char *fmt, ...)
  938. {
  939. va_list ap;
  940. int rv;
  941. va_start(ap, fmt);
  942. rv = JS_vsxprintf(func, arg, fmt, ap);
  943. va_end(ap);
  944. return rv;
  945. }
  946. JS_PUBLIC_API(JSUint32) JS_vsxprintf(JSStuffFunc func, void *arg,
  947. const char *fmt, va_list ap)
  948. {
  949. SprintfState ss;
  950. int rv;
  951. ss.stuff = FuncStuff;
  952. ss.func = func;
  953. ss.arg = arg;
  954. ss.maxlen = 0;
  955. rv = dosprintf(&ss, fmt, ap);
  956. return (rv < 0) ? (JSUint32)-1 : ss.maxlen;
  957. }
  958. /*
  959. ** Stuff routine that automatically grows the malloc'd output buffer
  960. ** before it overflows.
  961. */
  962. static int GrowStuff(SprintfState *ss, const char *sp, JSUint32 len)
  963. {
  964. ptrdiff_t off;
  965. char *newbase;
  966. JSUint32 newlen;
  967. off = ss->cur - ss->base;
  968. if (off + len >= ss->maxlen) {
  969. /* Grow the buffer */
  970. newlen = ss->maxlen + ((len > 32) ? len : 32);
  971. if (ss->base) {
  972. newbase = (char*) realloc(ss->base, newlen);
  973. } else {
  974. newbase = (char*) malloc(newlen);
  975. }
  976. if (!newbase) {
  977. /* Ran out of memory */
  978. return -1;
  979. }
  980. ss->base = newbase;
  981. ss->maxlen = newlen;
  982. ss->cur = ss->base + off;
  983. }
  984. /* Copy data */
  985. while (len) {
  986. --len;
  987. *ss->cur++ = *sp++;
  988. }
  989. JS_ASSERT((JSUint32)(ss->cur - ss->base) <= ss->maxlen);
  990. return 0;
  991. }
  992. /*
  993. ** sprintf into a malloc'd buffer
  994. */
  995. JS_PUBLIC_API(char *) JS_smprintf(const char *fmt, ...)
  996. {
  997. va_list ap;
  998. char *rv;
  999. va_start(ap, fmt);
  1000. rv = JS_vsmprintf(fmt, ap);
  1001. va_end(ap);
  1002. return rv;
  1003. }
  1004. /*
  1005. ** Free memory allocated, for the caller, by JS_smprintf
  1006. */
  1007. JS_PUBLIC_API(void) JS_smprintf_free(char *mem)
  1008. {
  1009. free(mem);
  1010. }
  1011. JS_PUBLIC_API(char *) JS_vsmprintf(const char *fmt, va_list ap)
  1012. {
  1013. SprintfState ss;
  1014. int rv;
  1015. ss.stuff = GrowStuff;
  1016. ss.base = 0;
  1017. ss.cur = 0;
  1018. ss.maxlen = 0;
  1019. rv = dosprintf(&ss, fmt, ap);
  1020. if (rv < 0) {
  1021. if (ss.base) {
  1022. free(ss.base);
  1023. }
  1024. return 0;
  1025. }
  1026. return ss.base;
  1027. }
  1028. /*
  1029. ** Stuff routine that discards overflow data
  1030. */
  1031. static int LimitStuff(SprintfState *ss, const char *sp, JSUint32 len)
  1032. {
  1033. JSUint32 limit = ss->maxlen - (ss->cur - ss->base);
  1034. if (len > limit) {
  1035. len = limit;
  1036. }
  1037. while (len) {
  1038. --len;
  1039. *ss->cur++ = *sp++;
  1040. }
  1041. return 0;
  1042. }
  1043. /*
  1044. ** sprintf into a fixed size buffer. Make sure there is a NUL at the end
  1045. ** when finished.
  1046. */
  1047. JS_PUBLIC_API(JSUint32) JS_snprintf(char *out, JSUint32 outlen, const char *fmt, ...)
  1048. {
  1049. va_list ap;
  1050. int rv;
  1051. JS_ASSERT((JSInt32)outlen > 0);
  1052. if ((JSInt32)outlen <= 0) {
  1053. return 0;
  1054. }
  1055. va_start(ap, fmt);
  1056. rv = JS_vsnprintf(out, outlen, fmt, ap);
  1057. va_end(ap);
  1058. return rv;
  1059. }
  1060. JS_PUBLIC_API(JSUint32) JS_vsnprintf(char *out, JSUint32 outlen,const char *fmt,
  1061. va_list ap)
  1062. {
  1063. SprintfState ss;
  1064. JSUint32 n;
  1065. JS_ASSERT((JSInt32)outlen > 0);
  1066. if ((JSInt32)outlen <= 0) {
  1067. return 0;
  1068. }
  1069. ss.stuff = LimitStuff;
  1070. ss.base = out;
  1071. ss.cur = out;
  1072. ss.maxlen = outlen;
  1073. (void) dosprintf(&ss, fmt, ap);
  1074. /* If we added chars, and we didn't append a null, do it now. */
  1075. if( (ss.cur != ss.base) && (ss.cur[-1] != '\0') )
  1076. ss.cur[-1] = '\0';
  1077. n = ss.cur - ss.base;
  1078. return n ? n - 1 : n;
  1079. }
  1080. JS_PUBLIC_API(char *) JS_sprintf_append(char *last, const char *fmt, ...)
  1081. {
  1082. va_list ap;
  1083. char *rv;
  1084. va_start(ap, fmt);
  1085. rv = JS_vsprintf_append(last, fmt, ap);
  1086. va_end(ap);
  1087. return rv;
  1088. }
  1089. JS_PUBLIC_API(char *) JS_vsprintf_append(char *last, const char *fmt, va_list ap)
  1090. {
  1091. SprintfState ss;
  1092. int rv;
  1093. ss.stuff = GrowStuff;
  1094. if (last) {
  1095. int lastlen = strlen(last);
  1096. ss.base = last;
  1097. ss.cur = last + lastlen;
  1098. ss.maxlen = lastlen;
  1099. } else {
  1100. ss.base = 0;
  1101. ss.cur = 0;
  1102. ss.maxlen = 0;
  1103. }
  1104. rv = dosprintf(&ss, fmt, ap);
  1105. if (rv < 0) {
  1106. if (ss.base) {
  1107. free(ss.base);
  1108. }
  1109. return 0;
  1110. }
  1111. return ss.base;
  1112. }