initial commit
This commit is contained in:
		
						commit
						d217d96d5c
					
				
							
								
								
									
										26
									
								
								.flowconfig
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										26
									
								
								.flowconfig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| [ignore] | ||||
| .*/node_modules/.* | ||||
| .*/dist/.* | ||||
| .*/test.js | ||||
| .*/printj.js | ||||
| 
 | ||||
| .*/bits/.* | ||||
| .*/ctest/.* | ||||
| .*/misc/.* | ||||
| .*/tests/.* | ||||
| .*/stress/.* | ||||
| 
 | ||||
| .*/demo/browser.js | ||||
| 
 | ||||
| [include] | ||||
| printj.flow.js | ||||
| lib/loop_code.js | ||||
| lib/loop_char.js | ||||
| lib/index_code.js | ||||
| lib/index_char.js | ||||
| lib/regex.js | ||||
| 
 | ||||
| [libs] | ||||
| bits/flow.js | ||||
| 
 | ||||
| [options] | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| node_modules | ||||
| misc/coverage.html | ||||
| 
 | ||||
							
								
								
									
										6
									
								
								.jscs.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										6
									
								
								.jscs.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| { | ||||
|   "requireCommaBeforeLineBreak": true, | ||||
|   "disallowTrailingWhitespace": true, | ||||
|   "disallowTrailingComma": true | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										16
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| language: node_js | ||||
| node_js: | ||||
|   - "6" | ||||
|   - "5" | ||||
|   - "4" | ||||
|   - "0.12" | ||||
|   - "0.10" | ||||
|   - "0.8" | ||||
| before_install: | ||||
|   - "npm install -g npm@next" | ||||
|   - "npm install -g mocha" | ||||
|   - "npm install codepage" | ||||
|   - "npm install blanket" | ||||
|   - "npm install coveralls mocha-lcov-reporter" | ||||
| after_success: | ||||
|   - "make coveralls-spin" | ||||
							
								
								
									
										14
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										14
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| Copyright (C) 2016-present  SheetJS | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| 
 | ||||
							
								
								
									
										80
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										80
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| LIB=printj | ||||
| REQS=loop_code | ||||
| ADDONS= | ||||
| AUXTARGETS=lib/loop_char.js lib/loop_code.js lib/index_char.js lib/index_code.js lib/regex.js | ||||
| HTMLLINT=index.html | ||||
| 
 | ||||
| ULIB=$(shell echo $(LIB) | tr a-z A-Z) | ||||
| DEPS=$(sort $(wildcard bits/*.js)) | ||||
| TARGET=$(LIB).js | ||||
| FLOWTARGET=$(LIB).flow.js | ||||
| 
 | ||||
| ## Main Targets
 | ||||
| 
 | ||||
| .PHONY: all | ||||
| all: $(TARGET) ## Build library and auxiliary scripts
 | ||||
| 
 | ||||
| .PHONY: lib | ||||
| lib: | ||||
| 	OUTDIR=$(PWD)/lib make -C bits | ||||
| 
 | ||||
| $(TARGET): %.js : %.flow.js | ||||
| 	node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@ | ||||
| 
 | ||||
| $(FLOWTARGET): $(DEPS) lib | ||||
| 	cp lib/$(REQS).js $(FLOWTARGET) | ||||
| 
 | ||||
| bits/01_version.js: package.json | ||||
| 	echo "PRINTJ.version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@ | ||||
| 
 | ||||
| .PHONY: clean | ||||
| clean: clean-stress ## Remove targets and build artifacts
 | ||||
| 	@OUTDIR=$(PWD)/lib make -C bits clean | ||||
| 	rm -f $(TARGET) $(FLOWTARGET) | ||||
| 
 | ||||
| ## Testing
 | ||||
| 
 | ||||
| .PHONY: test mocha | ||||
| test mocha: test.js ## Run test suite
 | ||||
| 	mocha -R spec -t 20000 | ||||
| 
 | ||||
| .PHONY: stress ## Run stress tests
 | ||||
| stress: | ||||
| 	@make -C stress clean | ||||
| 	@make -C stress | ||||
| 	@make -C stress test | ||||
| 
 | ||||
| .PHONY: clean-stress | ||||
| clean-stress: ## Remove stress tests 
 | ||||
| 	@make -C stress clean | ||||
| 
 | ||||
| ## Code Checking
 | ||||
| 
 | ||||
| .PHONY: lint | ||||
| lint: ## Run jshint and jscs checks
 | ||||
| 	@jshint --show-non-errors $(TARGET) $(AUXTARGETS) | ||||
| 	@jshint --show-non-errors package.json | ||||
| 	@jshint --show-non-errors --extract=always $(HTMLLINT) | ||||
| 	@jscs lib/*.js | ||||
| 
 | ||||
| .PHONY: flow | ||||
| flow: lint ## Run flow checker
 | ||||
| 	@flow check --all --show-all-errors | ||||
| 
 | ||||
| .PHONY: cov | ||||
| cov: misc/coverage.html ## Run coverage test
 | ||||
| 
 | ||||
| misc/coverage.html: $(TARGET) test.js | ||||
| 	mocha --require blanket -R html-cov -t 20000 > $@ | ||||
| 
 | ||||
| .PHONY: coveralls | ||||
| coveralls: ## Coverage Test + Send to coveralls.io
 | ||||
| 	mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js | ||||
| 
 | ||||
| .PHONY: help | ||||
| help: | ||||
| 	@grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | bash misc/help.sh | ||||
| 
 | ||||
| #* To show a spinner, append "-spin" to any target e.g. cov-spin
 | ||||
| %-spin: | ||||
| 	@make $* & bash misc/spin.sh $$! | ||||
							
								
								
									
										976
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										976
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,976 @@ | ||||
| # printj | ||||
| 
 | ||||
| Extended `sprintf` implementation (for the browser and nodejs).  Emphasis on | ||||
| compliance and performance. | ||||
| 
 | ||||
| ```JS | ||||
| PRINTJ.sprintf("Hello %s!", "World"); | ||||
| ``` | ||||
| 
 | ||||
| A self-contained specification of the printf format string is included below in [this README](#printf-format-string-specification), as well as a summary of the | ||||
| [support against various printf implementations](#support-summary) | ||||
| 
 | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
| With [npm](https://www.npmjs.org/package/printj): | ||||
| 
 | ||||
|     $ npm install printj | ||||
| 
 | ||||
| In the browser: | ||||
| 
 | ||||
|     <script src="printj.js"></script> | ||||
| 
 | ||||
| The browser exposes a variable `PRINTJ` | ||||
| 
 | ||||
| When installed globally, npm installs a script `printj` that renders the format | ||||
| string with the given arguments.  Running the script with `-h` displays help. | ||||
| 
 | ||||
| The script will manipulate `module.exports` if available (e.g. in a CommonJS | ||||
| `require` context).  This is not always desirable.  To prevent the behavior, | ||||
| define `DO_NOT_EXPORT_PRINTJ` | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| In all cases, the relevant function takes a format and arguments to be rendered. | ||||
| 
 | ||||
| The return value is a JS string. | ||||
| 
 | ||||
| - `PRINTJ.sprintf(format, ...args)` assumes the arguments are passed directly | ||||
| 
 | ||||
| - `PRINTJ.vsprintf(format, argv)` assumes the arguments are passed in an array | ||||
| 
 | ||||
| For example: | ||||
| 
 | ||||
| ```js | ||||
| > // var PRINTJ = require('printj');       // uncomment this line if in node | ||||
| > var sprintf = PRINTJ.sprintf, vsprintf = PRINTJ.vsprintf;  | ||||
| > sprintf("Hello %s", "SheetJS")           // 'Hello SheetJS' | ||||
| > sprintf("%d + %d = %d", 2,3,2+3)         // '2 + 3 = 5' | ||||
| > vsprintf("%d + %d = %d", [2,3,5])        // '2 + 3 = 5' | ||||
| > sprintf("%1$02hhx %1$u %1$i %1$o", -69)  // 'bb 4294967227 -69 37777777673' | ||||
| ``` | ||||
| 
 | ||||
| The command line script takes a format and arguments: | ||||
| 
 | ||||
| ``` | ||||
| usage: printj [options] <format> [args...] | ||||
| 
 | ||||
| Options: | ||||
|     -h, --help      output usage information | ||||
|     -d, --dump      print debug information about format string | ||||
| 
 | ||||
| Arguments are treated as strings unless prefaced by a type indicator: | ||||
|     n:<integer>     call parseInt (ex. n:3 -> 3) | ||||
|     f:<float>       call parseFloat (ex. f:3.1 -> 3.1) | ||||
|     b:<boolean>     false when lowercase value is "FALSE" or "0", else true | ||||
|     s:<string>      interpret as string (ex. s:n:3 -> "n:3") | ||||
|     j:<JSON>        interpret as an object using JSON.parse | ||||
|     e:<JS>          evaluate argument (ex. e:1+1 -> 2, e:"1"+1 -> "11") | ||||
| 
 | ||||
| samples: | ||||
|     $ printj '|%02hhx%d|' n:50 e:0x7B                # |32123| | ||||
|     $ printj '|%2$d + %3$d is %1$d|' e:1+2 n:1 n:2   # |1 + 2 is 3| | ||||
|     $ printj '|%s is %s|' s:1+2 e:1+2                # |1+2 is 3| | ||||
|     $ printj '|%c %c|' s:69 n:69                     # |6 E| | ||||
| ``` | ||||
| 
 | ||||
| ## Testing | ||||
| 
 | ||||
| `make test` will run the nodejs-based test. | ||||
| 
 | ||||
| `make stress` will run a larger test encompassing every possible conversion.  It | ||||
| requires access to a C compiler. | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
| Please consult the attached LICENSE file for details.  All rights not explicitly | ||||
| granted by the Apache 2.0 license are reserved by the Original Author. | ||||
| 
 | ||||
| ## Badges  | ||||
| 
 | ||||
| [](https://travis-ci.org/SheetJS/printj) | ||||
| 
 | ||||
| [](https://coveralls.io/r/SheetJS/printj?branch=master) | ||||
| 
 | ||||
| [](https://github.com/SheetJS/printj) | ||||
| 
 | ||||
| # printf format string specification | ||||
| 
 | ||||
| The `printf` family of functions attempt to generate and output a string of | ||||
| characters from a series of arguments, following a user-supplied "format string" | ||||
| specification.  The format string contains normal characters that are written to | ||||
| the output string as well as specifiers that describe which parameter to insert | ||||
| and how to render the parameter.  This specification describes how a conformant | ||||
| implementation should process the format string and generate an output string. | ||||
| Any discrepancies between this document and the reference implementation are | ||||
| considered bugs in the implementation. | ||||
| 
 | ||||
| ### Original C Interface | ||||
| 
 | ||||
| Every function in the `printf` family follows the same logic to generate strings | ||||
| but have different interfaces reflecting different input and output behaviors. | ||||
| Some functions have wide variants that use wide `wchar_t *` strings rather than | ||||
| normal C `char *`.  The following variants are required by the POSIX spec: | ||||
| 
 | ||||
| |  function  | max length |  output destination   | vintage |  wide ver  | | ||||
| |------------|------------|-----------------------|---------|------------| | ||||
| | `printf`   | unbounded  | standard output       | K&R     | `wprintf`  | | ||||
| | `fprintf`  | unbounded  | stream (`FILE *`)     | K&R     | `fwprintf` | | ||||
| | `sprintf`  | unbounded  | string (`char *`)     | K&R     | `swprintf` | | ||||
| | `snprintf` | parameter  | string (`char *`)     | C99     |            | | ||||
| | `dprintf`  | unbounded  | POSIX file descriptor | POSIX   |            | | ||||
| 
 | ||||
| Each function has a dual function, whose name begins with `v`, that accepts the | ||||
| parameters as a `va_list` rather than formal parameters.  In all cases, they | ||||
| return the number of characters written or a negative value to indicate error: | ||||
| 
 | ||||
| ```C | ||||
| int   sprintf(char *ostr, const char *fmt, ...); | ||||
| int  vsprintf(char *ostr, const char *fmt, va_list arg_list); | ||||
| 
 | ||||
| int  swprintf(wchar_t *ostr, const wchar_t *fmt, ...); | ||||
| int vswprintf(wchar_t *ostr, const wchar_t *fmt, va_list arg_list); | ||||
| ``` | ||||
| 
 | ||||
| ### JS and C strings | ||||
| 
 | ||||
| C "strings" are really just arrays of numbers.  An external code page (such as | ||||
| ASCII) maps those numbers to characters.  K&R defines two types of strings: | ||||
| basic character set strings (`char *`) and extended character set strings  | ||||
| (`wchar_t *`). In contrast, JS has a true string value type. | ||||
| 
 | ||||
| Unlike in C, JS strings do not treat the null character as an end-of-string | ||||
| marker.  As a result, characters beyond the first null character will be used. | ||||
| 
 | ||||
| The JS equivalent of a C extended string would be an array of the individual | ||||
| character codes.  The C basic string equivalent would involve specifying a code | ||||
| page and mapping back.  The `codepage` JS library supports common codepages. | ||||
| 
 | ||||
| While capturing the essence of C strings, using arrays of character codes is not | ||||
| idiomatic JS.  Few developers leverage this and the downsides far exceed the | ||||
| benefits of a more direct translation.  The effect can be feigned, as shown in | ||||
| the `js2c` code sample at the end of the document. | ||||
| 
 | ||||
| ### JS Interface | ||||
| 
 | ||||
| In the absence of a standard output or even a standard concept of a stream, the | ||||
| non-string outputs are irrelevant.  Similarly there is no JS analogue of wide | ||||
| characters.  While useful, lack of direct memory management obviates `snprintf`. | ||||
| This implementation exports the remaining functions, `sprintf` and `vsprintf`. | ||||
| 
 | ||||
| Instead of replicating the original C signature and `errno`, functions directly | ||||
| return the output string and throw Errors: | ||||
| 
 | ||||
| ```typescript | ||||
| function  sprintf(fmt:string, ...args):string; | ||||
| function vsprintf(fmt:string, args:Array<any>):string; | ||||
| ``` | ||||
| 
 | ||||
| The C functions return the number of characters written to the string, which is | ||||
| directly accessible in JS via the `length` property.  A direct replica of the | ||||
| various string functions are included at the end of the document. | ||||
| 
 | ||||
| ## Specifier heritage and regular expression | ||||
| 
 | ||||
| Note: The regular expressions follow perl `/x` style.  Whitespace characters | ||||
| outside of character classes are ignored.  `#` is a comment character and every | ||||
| character until the end of the line is ignored.  To convert to a standard regex: | ||||
| 
 | ||||
| ```js | ||||
| regex_string.replace(/#.*$/gm,"").replace(/^\s*/gm,"").replace(/\s*\n/gm,""); | ||||
| ``` | ||||
| 
 | ||||
| Based on K&R, conversions originally followed the format: | ||||
| 
 | ||||
|  - required: leading `%` | ||||
|  - optional: `-` (POSIX refers to this as the "flags") | ||||
|  - optional: positive number or `*` (POSIX "width") | ||||
|  - optional: period followed by positive number or `*` (POSIX "precision") | ||||
|  - optional: an `h` or `l` to indicate size of data (POSIX "length") | ||||
|  - required: character describing output behavior (POSIX "conversion specifier") | ||||
| 
 | ||||
| This is captured by the regular expression: | ||||
| 
 | ||||
| ```perl | ||||
| /%(?: | ||||
|     ([-])?                             # flags (only minus sign) | ||||
|     (\d+|\*)?                          # width | ||||
|     (?:\.(\d+|\*))?                    # period + precision | ||||
|     ([hl])?                            # length | ||||
|     ([dioxXucsfeEgGp%])                # conversion specifier | ||||
| )/x | ||||
| ``` | ||||
| 
 | ||||
| Various implementations of `printf` have added different functionality. | ||||
| 
 | ||||
| ANSI standards up through C99: | ||||
| 
 | ||||
|  - more flags `"+"` `" "` `"0"` `"#"` | ||||
|  - more lengths `"L"` `"hh"` `"ll"` `"j"` `"z"` `"t"` | ||||
|  - more conversions `"F"` `"a"` `"A"` `"n"` | ||||
| 
 | ||||
| The POSIX specification of `printf` added: | ||||
| 
 | ||||
|  - positional parameters to identify argument indices | ||||
|  - more flags `"'"` | ||||
|  - more conversions `"C"` `"S"` | ||||
|  - clarifications regarding corner cases and "undefined behavior" | ||||
| 
 | ||||
| BSD implementations added: | ||||
| 
 | ||||
|  - more lengths `"q"` | ||||
|  - more conversions `"D"` `"U"` `"O"` | ||||
| 
 | ||||
| glibc (GNU) added: | ||||
| 
 | ||||
|  - more lengths `"Z"` | ||||
|  - more conversions `"m"` | ||||
| 
 | ||||
| Windows C Runtime (CRT) added: | ||||
| 
 | ||||
|  - more lengths `"I"` `"I32"` `"I64"` `"w"` | ||||
| 
 | ||||
| glibc and CRT both added `Z`. glibc uses `Z` for the length `size_t`. CRT uses | ||||
| `Z` as a conversion for length-prefixed strings.  This implementation takes the | ||||
| former approach, handling `Z` in the same way as `z`. | ||||
| 
 | ||||
| BSD and IBM C library both added `D`.  BSD uses `D` as a conversion, namely as | ||||
| an alias of `ld`.  IBM uses `D` for the length for `_Decimal64`, a decimal | ||||
| floating point type, in accordance with ISO/IEC TR 24732.  This implementation | ||||
| takes the former approach. | ||||
| 
 | ||||
| This implementation also adds new conversions: | ||||
| 
 | ||||
|  - `"b"` and `"B"` for binary (base-2) integer renderings | ||||
|  - `"y"` and `"Y"` for true/false and yes/no Boolean conversions | ||||
|  - `"J"` for JSON | ||||
|  - `"T"` and `"V"` for JS typeof and valueOf inspection | ||||
| 
 | ||||
| Combining the various extensions yields the following regular expression: | ||||
| 
 | ||||
| ```perl | ||||
| /%(?: | ||||
|     %|                                  # literal %% (flags etc prohibited) | ||||
|     (\d+\$)?                            # positional parameter | ||||
|     ([-+ 0\x23\x27]*)?                  # flags | ||||
|     (\d*|\*(?:\d+\$)?)                  # width | ||||
|     (?:\.(\d+|\*(?:\d+\$)?))?           # precision | ||||
|     (hh?|ll?|[LzjtqZIw])?               # length | ||||
|     ([diouxXfFeEgGaAcCsSpnDUOmbByYJVT]) # conversion specifier | ||||
| )/x | ||||
| ``` | ||||
| This implementation explicitly does not support certain non-standard extensions: | ||||
| 
 | ||||
|  - AltiVec vector length extensions (`v` with `h`/`l`/`ll`): | ||||
|  - CRT fixed width lengths `I32` and `I64` | ||||
| 
 | ||||
| ## Conversion Specifier Quick Reference Table | ||||
| 
 | ||||
| |  C  |   Type   | Summary                                                     | | ||||
| |-----|:--------:|-------------------------------------------------------------| | ||||
| | `a` | floating | base-2 exp form w/ hex mantissa and dec exponent, lowercase | | ||||
| | `A` | floating | base-2 exp form w/ hex mantissa and dec exponent, uppercase | | ||||
| | `b` | extended | cast to C `unsigned int`,   standard form binary            | | ||||
| | `B` | extended | cast to C `unsigned long`,  standard form binary            | | ||||
| | `c` |   text   | print `latin-1` char from number OR first char of string    | | ||||
| | `C` |   text   | print `UCS-2`   char from number OR first char of string    | | ||||
| | `d` | integral | cast to C `int`,   standard form decimal                    | | ||||
| | `D` | integral | cast to C `long`,  standard form decimal                    | | ||||
| | `e` | floating | base-10 exp form w/dec mantissa and dec exponent, lowercase | | ||||
| | `E` | floating | base-10 exp form w/dec mantissa and dec exponent, uppercase | | ||||
| | `f` | floating | base-10 decimal form, lowercase extended values             | | ||||
| | `F` | floating | base-10 decimal form, uppercase extended values             | | ||||
| | `g` | floating | print using `e` or `f` conversion based on value/precision  | | ||||
| | `G` | floating | print using `E` or `F` conversion based on value/precision  | | ||||
| | `i` | integral | cast to C `int`,   standard form decimal (alias of `d`)     | | ||||
| | `J` | extended | prints objects using JSON or `util.inspect`                 | | ||||
| | `m` |   misc   | prints info about Error objects (JS equivalent of `errno`)  | | ||||
| | `n` |   misc   | do not print! stores number of chars written to arg `.len`  | | ||||
| | `o` | integral | cast to C `unsigned int`,   standard form octal             | | ||||
| | `O` | integral | cast to C `unsigned long`,  standard form octal             | | ||||
| | `p` |   misc   | print `"l"` field of object (fake pointer)                  | | ||||
| | `s` |   text   | print string argument                                       | | ||||
| | `S` |   text   | print string argument (alias of `"s"`)                      | | ||||
| | `T` | extended | print type information (`typeof` or `Object toString`)      | | ||||
| | `u` | integral | cast to C `unsigned int`,   standard form decimal           | | ||||
| | `U` | integral | cast to C `unsigned long`,  standard form decimal           | | ||||
| | `V` | extended | print primitive value (`valueOf`)                           | | ||||
| | `x` | integral | cast to C `unsigned int`,   standard form hex, lowercase    | | ||||
| | `X` | integral | cast to C `unsigned long`,  standard form hex, uppercase    | | ||||
| | `y` | extended | prints `true`/`false` or `yes`/`no` based on Boolean value  | | ||||
| | `Y` | extended | prints `TRUE`/`FALSE` or `YES`/`NO` based on Boolean value  | | ||||
| | `%` |   misc   | print the literal `%` character                             | | ||||
| 
 | ||||
| ## Parameter Selection | ||||
| 
 | ||||
| The default behavior is to consume arguments in order: | ||||
| 
 | ||||
| ```C | ||||
| printf("Count to 3: %d %d %d", 1, 2, 3); // Count to 3: 1 2 3 | ||||
| ``` | ||||
| 
 | ||||
| POSIX `printf` permits explicit argument selection, bypassing the standard | ||||
| behavior of using the arguments in order.  To select the `n`-th argument, use | ||||
| `n$` immediately after the `%` token to select an argument for the conversion: | ||||
| 
 | ||||
| ```C | ||||
| printf("%d %d %d",       1, 2, 3);        // 1 2 3 (implicit order 1, 2, 3 ) | ||||
| printf("%1$s %2$s %3$s", "a", "b", "c");  // a b c (explicit order 1, 2, 3 ) | ||||
| printf("%1$s %3$s %2$s", "a", "b", "c");  // a c b (explicit order 1, 3, 2 ) | ||||
| ``` | ||||
| 
 | ||||
| The POSIX standard asserts that mixing positional and non-positional conversions | ||||
| is undefined behavior.  This implementation handles mixing by tracking the index | ||||
| for non-positional conversions: | ||||
| 
 | ||||
| ```C | ||||
| printf("%s %4$s %s %5$s %s", "a", "b", "c", "d", "e"); // a d b e c | ||||
| ``` | ||||
| 
 | ||||
| The POSIX standard requires that if an argument is used in the format, every | ||||
| preceding argument must be used.  This implementation relaxes that requirement: | ||||
| 
 | ||||
| ```C | ||||
| printf("%3$s", "a", "b", "c"); // c (technically invalid since "a"/"b" unused) | ||||
| ``` | ||||
| 
 | ||||
| ## Dynamic Specifiers | ||||
| 
 | ||||
| The width and precision specifiers may include the dynamic specifier `*` which | ||||
| instructs the engine to read the next argument (assumed to be an integer).  Just | ||||
| as with the positional parameter, `idx$` immediately after the `*` token selects | ||||
| the numeric argument. | ||||
| 
 | ||||
| For example: | ||||
| 
 | ||||
| ```C | ||||
| printf("|%5s|", "sheetjs");               // |sheetjs|    (width = 5) | ||||
| printf("|%*s|", 5, "sheetjs");            // |sheetjs|    (width first argument) | ||||
| printf("|%2$*1$s|", 5, "sheetjs", 10);    // |sheetjs|    (width is argument #1) | ||||
| 
 | ||||
| printf("|%10s|", "sheetjs");              // |   sheetjs| (width = 10) | ||||
| printf("|%2$*3$s|", 5, "sheetjs", 10);    // |   sheetjs| (width is argument #3) | ||||
| ``` | ||||
| 
 | ||||
| Arguments are generally consumed in order as presented in the format string: | ||||
| 
 | ||||
| ```C | ||||
| printf("|%s|", val); | ||||
| printf("|%*s|", width, val); | ||||
| printf("|%.*s|", prec, val); | ||||
| printf("|%*.*s|", width, prec, val); | ||||
| printf("|%0*.*d|", 4, 2, 1);  // |  01| width=4 prec=2 value=1 | ||||
| ``` | ||||
| 
 | ||||
| Positional arguments can be applied to width and precision: | ||||
| 
 | ||||
| ```C | ||||
| printf("|%*.*d|", width, prec, val); | ||||
| printf("|%2$0*3$.*1$d|", prec, val, width); | ||||
| printf("|%0*.*d|", 4, 2, 1);        // |  01| width=4 prec=2 value=1 flags='0' | ||||
| printf("|%1$0*3$.*2$d|", 1, 2, 4);  // |  01| width=4 prec=2 value=1 flags='0' | ||||
| ``` | ||||
| 
 | ||||
| A negative width is interpreted as the `-` flag with a positive width: | ||||
| 
 | ||||
| ```C | ||||
| printf("|%*.*d|",   4, 2, 1);        // |  01| width=4 prec=2 value=1 flags='' | ||||
| printf("|%-*.*d|",  4, 2, 1);        // |01  | width=4 prec=2 value=1 flags='-' | ||||
| printf("|%*.*d|",  -4, 2, 1);        // |01  | width=4 prec=2 value=1 flags='-' | ||||
| printf("|%-*.*d|", -4, 2, 1);        // |01  | width=4 prec=2 value=1 flags='-' | ||||
| ``` | ||||
| 
 | ||||
| A negative precision is discarded: | ||||
| 
 | ||||
| ```C | ||||
| printf("|%*s|\n", 4, "sheetjs");       // |sheetjs|  width=4 | ||||
| printf("|%*.*s|\n", 4,  3, "sheetjs"); // | she|     width=4 prec=3 | ||||
| printf("|%*.*s|\n", 4,  2, "sheetjs"); // |  sh|     width=4 prec=2 | ||||
| printf("|%*.*s|\n", 4,  1, "sheetjs"); // |   s|     width=4 prec=1 | ||||
| printf("|%*.*s|\n", 4,  0, "sheetjs"); // |    |     width=4 prec=0 | ||||
| printf("|%*.*s|\n", 4, -1, "sheetjs"); // |sheetjs|  width=4 (prec ignored) | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| # C Data Model | ||||
| 
 | ||||
| JS has one numeric type `Number` which represents an IEEE754 double-precision | ||||
| (64-bit) floating point number.  C has a multitude of numeric types, including | ||||
| floating point as well as integer types.  The sizes of those data types are | ||||
| implementation-dependent.  A "C data model" specifies the sizes of the core C | ||||
| data types. | ||||
| 
 | ||||
| ### Integer Types | ||||
| 
 | ||||
| POSIX `printf` specification references 8 integer types in integer conversions: | ||||
| 
 | ||||
| | C data type |  fmt  | unsigned type        |  fmt  | signed type   |  fmt  | | ||||
| |-------------|------:|----------------------|------:|---------------|------:| | ||||
| | `char`      |       | `unsigned char`      | `hhu` | `signed char` | `hhd` | | ||||
| | `short`     |  `hd` | `unsigned short`     |  `hu` |               |       | | ||||
| | `int`       |   `d` | `unsigned int`       |   `u` |               |       | | ||||
| | `long`      |  `ld` | `unsigned long`      |  `lu` |               |       | | ||||
| | `long long` | `lld` | `unsigned long long` | `llu` |               |       | | ||||
| | `size_t`    |  `zu` |                      |       | `ssize_t`     |  `zd` | | ||||
| | `intmax_t`  |  `jd` | `uintmax_t`          |  `ju` |               |       | | ||||
| | `ptrdiff_t` |  `td` |                      |       |               |       | | ||||
| 
 | ||||
| C99 does not officially define a signed `size_t` or unsigned `ptrdiff_t` type. | ||||
| POSIX does define `ssize_t` but no equivalent `uptrdiff_t`. | ||||
| 
 | ||||
| BSD additionally recognizes the types `quad_t` and `u_quad_t`, which this | ||||
| implementation treats as `long long int` and `unsigned long long int`. | ||||
| 
 | ||||
| ### Character and String Types | ||||
| 
 | ||||
| Two integer types are used in character and string conversions: | ||||
| 
 | ||||
| | type        |  fmt  | | ||||
| |-------------|------:| | ||||
| | `wchar_t`   |  `ls` | | ||||
| | `wint_t`    |  `lc` | | ||||
| 
 | ||||
| Both wide types `wchar_t` and `wint_t` can be signed or unsigned according to | ||||
| C99.  Both types are used only in character and string conversions.  Based on | ||||
| K&R "printable characters are always positive", the types are assumed unsigned. | ||||
| 
 | ||||
| ### Floating Point Number Types | ||||
| 
 | ||||
| K&R recognizes 3 floating point types.  C99 later tied it to IEC 60559: | ||||
| 
 | ||||
| |  C data type  | precision | total bits | exponent | mantissa |  fmt  |  | ||||
| |:--------------|:----------|:----------:|:--------:|:--------:|------:| | ||||
| | `float`       | single    |    `32`    |    `8`   |   `23`   |       | | ||||
| | `double`      | double    |    `64`    |   `11`   |   `52`   |   `f` | | ||||
| | `long double` | extended  |    `80`    |   `15`   |   `64`   |  `Lf` | | ||||
| 
 | ||||
| ## Implementation | ||||
| 
 | ||||
| Numerous "C data models", specifying the bit/byte sizes of the various types, | ||||
| have been and continue to be used.  For example, OSX and other modern 64-bit | ||||
| UNIX flavors use the "LP64" C data model.  64-bit Windows currently uses the | ||||
| "LLP64" model.  32-bit systems generally use the "ILP32" model.  The 8-bit byte | ||||
| sizes for the various types under the various models are defined in ctypes.json | ||||
| in the `Models` object as per the following table: | ||||
| 
 | ||||
| | type        | ctypes.json | LP64 | ILP32 | LLP64 | | ||||
| |-------------|-------------|-----:|------:|------:| | ||||
| | `char`      | `char`      |   1  |    1  |    1  | | ||||
| | `short`     | `short`     |   2  |    2  |    2  | | ||||
| | `int`       | `int`       |   4  |    4  |    4  | | ||||
| | `long`      | `long`      |   8  |    4  |    4  | | ||||
| | `long long` | `longlong`  |   8  |    8  |    8  | | ||||
| | `wchar_t`   | `wchar_t`   |   4  |    4  |    2  | | ||||
| | `wint_t`    | `wint_t`    |   4  |    4  |    2  | | ||||
| | `size_t`    | `size_t`    |   8  |    4  |    8  | | ||||
| | `intmax_t`  | `intmax_t`  |   8  |    8  |    8  | | ||||
| | `ptrdiff_t` | `ptrdiff_t` |   8  |    4  |    8  | | ||||
| 
 | ||||
| By default the source assumes the LP64 data model.  Other data models are | ||||
| supported in the source tree, controlled by the JSFLAGS variable in the build | ||||
| process.  Set the `JS_MODEL` variable to the desired index as specified in the | ||||
| `ModelNames` array in `bits/ctype.json`: | ||||
| 
 | ||||
| ```bash | ||||
| $ <bits/ctypes.json jq -r '.ModelNames|.[]'  # LP64 ILP32 LLP64 | ||||
| $ JSFLAGS=-DJS_MODEL=0 make                  # LP64 | ||||
| $ JSFLAGS=-DJS_MODEL=1 make                  # ILP32 | ||||
| $ JSFLAGS=-DJS_MODEL=2 make                  # LLP64 | ||||
| ``` | ||||
| 
 | ||||
| To create a custom model, add the spec to `bits/ctypes.json` by appending the | ||||
| model name to the end of the `ModelNames` array and adding an entry to the | ||||
| `Models` object.  The current models are defined as follows: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   "ModelNames":["LP64", "ILP32", "LLP64"], | ||||
|   "Models": { | ||||
|     "LP64":  { "char":1, "short":2, "int":4, "long":8, "longlong":8, "wint_t":4, "wchar_t":4, "size_t":8, "intmax_t":8, "ptrdiff_t":8 }, | ||||
|     "ILP32": { "char":1, "short":2, "int":4, "long":4, "longlong":8, "wint_t":4, "wchar_t":4, "size_t":4, "intmax_t":8, "ptrdiff_t":4 }, | ||||
|     "LLP64": { "char":1, "short":2, "int":4, "long":4, "longlong":8, "wint_t":2, "wchar_t":2, "size_t":8, "intmax_t":8, "ptrdiff_t":8 } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| # Integer Conversions | ||||
| 
 | ||||
| This section covers the conversions `diouxXDUO`.  The base-2 conversions `bB` | ||||
| are an extension and are discussed at the end, but the same basic rules apply. | ||||
| 
 | ||||
| JS has one Number type (representing an IEEE754 8-byte floating point number) | ||||
| that is capable of representing a 32-bit integer.  It cannot represent the full | ||||
| range of 64-bit integers exactly.  Care is taken to avoid operations that may | ||||
| inadvertently result in a conversion to a smaller integral type. | ||||
| 
 | ||||
| ## Restricting Integer Values | ||||
| 
 | ||||
| JS Bitwise operations convert numbers to 32-bit integers before performing | ||||
| operations.  With the exception of the unsigned right shift operator `>>>`, all | ||||
| operations act on signed integers.  For example: | ||||
| 
 | ||||
| ```js | ||||
| Math.pow(2,31) | 0;        // -2147483648 == -Math.pow(2,31) | ||||
| (Math.pow(2,32)-2) ^ 0;    // -2 | ||||
| -1 >>> 0                   // 4294967295 == Math.pow(2,32) - 1 | ||||
| ``` | ||||
| 
 | ||||
| JS Number can exactly represent every integer in the range `-2^53 .. 2^53`.  For | ||||
| lengths exceeding 32 bits, `Math.round` is appropriate. | ||||
| 
 | ||||
| | bits | unsigned                  | signed                                    | | ||||
| |------|---------------------------|-------------------------------------------| | ||||
| | 8    | `V & 0xFF`                | `V &= 0xFF; if(V > 0x7F) V-= 0x100`       | | ||||
| | 16   | `V & 0xFFFF`              | `V &= 0xFFFF; if(V > 0x7FFF) V-= 0x10000` | | ||||
| | 32   | `V >>> 0`                 | `V | 0`                                   | | ||||
| | 64   | `Math.abs(Math.round(V))` | `Math.round(V)`                           | | ||||
| 
 | ||||
| ## Length Specifiers for Integer Conversions | ||||
| 
 | ||||
| When a length specifier implies a certain size (such as `hh` for a single-byte | ||||
| integer), the number will be converted before rendering strings.  For example: | ||||
| 
 | ||||
| ```C | ||||
| printf("%1$02hhx %1$02hx %1$02lx %1$02llx\n", 256);       // 00 100 100 100 | ||||
| printf("%1$02hhx %1$02hx %1$02lx %1$02llx\n", 4096);      // 00 1000 1000 1000 | ||||
| printf("%1$02hhx %1$02hx %1$02lx %1$02llx\n", 65536);     // 00 00 10000 10000 | ||||
| ``` | ||||
| 
 | ||||
| Values are restricted by first limiting the result to a specified number of | ||||
| bytes (appropriate bit-and) and then adding or subtracting to ensure the value | ||||
| is signed or unsigned according to the conversion specifier.  If a length is | ||||
| specified, it overrides the implied length of the conversion.  The following | ||||
| table describes the behavior of this implementation: | ||||
| 
 | ||||
| | implied C type                      | ctypes.json | length | conv default |  | ||||
| |:------------------------------------|:------------|:------:|:-------------| | ||||
| | `int` or `unsigned int`             | `int`       | (none) | d i o u x X  | | ||||
| | `char` or `unsigned char`           | `char`      |   hh   | | ||||
| | `short` or `unsigned short`         | `short`     |    h   | | ||||
| | `long` or `unsigned long`           | `long`      |    l   | D U O        | | ||||
| | `long long` or `unsigned long long` | `longlong`  | L ll q |  | ||||
| | `intmax_t` or `uintmax_t`           | `intmax_t`  |    j   | | ||||
| | `size_t` or `ssize_t`               | `size_t`    |   z Z  | | ||||
| | `ptrdiff_t` or unsigned variant     | `ptrdiff_t` |    t   | | ||||
| 
 | ||||
| ## Rendering Unsigned Integers in Base 10 ("u" and "U" conversions) | ||||
| 
 | ||||
| `num.toString(10)` produces the correct result for exact integers.   | ||||
| 
 | ||||
| `"u"` conversion restricts values to `int`; `"U"` restricts to `long`.  | ||||
| 
 | ||||
| ## Rendering Unsigned Integers in Base 8 ("o" and "O" conversions) | ||||
| 
 | ||||
| Even though `num.toString(8)` is implementation-dependent, all browser | ||||
| implementations use standard form for integers in the exact range.  | ||||
| 
 | ||||
| The alternate form (`#`) prints a `"0"` prefix. | ||||
| 
 | ||||
| `"o"` conversion restricts values to `int`; `"O"` restricts to `long`.  | ||||
| 
 | ||||
| ## Rendering Unsigned Integers in Base 16 ("x" and "X" conversions) | ||||
| 
 | ||||
| Even though `num.toString(16)` is implementation-dependent, all browser | ||||
| implementations use standard form for integers in the exact range.  | ||||
| 
 | ||||
| The alternate form (`#`) prints a `"0x"` or `"0X"` prefix. | ||||
| 
 | ||||
| Unlike `"U" "O" "D"`, `"X"` conversion uses `A-F` instead of `a-f` in hex. | ||||
| 
 | ||||
| ## Rendering Signed Integers in Base 10 ("d" "i" and "D" conversions) | ||||
| 
 | ||||
| `num.toString(10)` produces the correct result for exact integers.  The flags | ||||
| `" +"` control prefixes for positive integers. | ||||
| 
 | ||||
| `"di"` conversions restrict values to `int`; `"D"` restricts to `long`.  | ||||
| 
 | ||||
| 
 | ||||
| # Floating Point Conversions | ||||
| 
 | ||||
| This section covers the conversions `fFeEgGaA`. | ||||
| 
 | ||||
| Due to C variadic argument promotion rules, `float` types are always promoted to | ||||
| `double`.  None of the conversions or length specifiers signal that an argument | ||||
| is to be interpreted as a `float`.  There is no JS canonical representation of | ||||
| an extended floating point number, so JS `Number` suffices. | ||||
| 
 | ||||
| ## Infinity, NaN, and Negative Zero | ||||
| 
 | ||||
| JS recognizes a few special IEEE754 values, as described in the following table: | ||||
| 
 | ||||
| |   JS value  | JS Expression | Description                                    | | ||||
| |------------:|:--------------|:-----------------------------------------------| | ||||
| |  `Infinity` | `1./0.`       | Positive limiting value `lim{x->0+} 1/x`       | | ||||
| | `-Infinity` | `-1./0.`      | Negative limiting value `lim{x->0+} -1/x`      | | ||||
| |       `NaN` | `0./0.`       | Placeholder for "not-a-number" e.g. `0./0.`    | | ||||
| |       `-0.` | `-1/Infinity` | Negative limiting value `lim{x->0-} x`         | | ||||
| 
 | ||||
| JS `Number` methods render different strings from the POSIX spec: | ||||
| 
 | ||||
| |   JS value  | POSIX string                                  | JS string     | | ||||
| |------------:|:----------------------------------------------|--------------:| | ||||
| |  `Infinity` |  `"inf"  "INF"` or  `"infinity"  "INFINITY"`  |  `"Infinity"` | | ||||
| | `-Infinity` | `"-inf" "-INF"` or `"-infinity" "-INFINITY"`  | `"-Infinity"` | | ||||
| |       `NaN` | `"[-]nan" "[-]NAN"` w/opt parenthesized chars |       `"NaN"` | | ||||
| |       `-0.` | uses negative sign (e.g. `"-0"` under `"%f"`) | same as `+0.` | | ||||
| 
 | ||||
| This implementation performs the required adjustments. | ||||
| 
 | ||||
| ## Exponential Form ("e" and "E" conversions) | ||||
| 
 | ||||
| Aside from the special cases discussed above, JS `num.toExponential(prec)` | ||||
| differs from POSIX `printf("%1$.*2$e", num, prec)` in the exponent field: JS | ||||
| writes exponents with the fewest digits (POSIX requires 2+ digits).  This is | ||||
| easily fixed by inspecting the output string and inserting a "0" when needed. | ||||
| 
 | ||||
| The optional `#` flag forces the decimal point to appear when precision is 0. | ||||
| This is also easily corrected by adding a decimal point just before the "e". | ||||
| 
 | ||||
| ## Standard Form ("f" and "F" conversions) | ||||
| 
 | ||||
| The POSIX spec only requires that the number of digits after the decimal point | ||||
| is equal to the precision.  It does not specify how many digits appear before | ||||
| the decimal point, nor does it specify how to handle numbers that cannot be | ||||
| exactly represented. | ||||
| 
 | ||||
| For values less than `1e21` the JS `num.toFixed(n)` generally matches `%f` with | ||||
| the specified precision.  However, for larger values `toFixed` defaults to the | ||||
| exponential form. | ||||
| 
 | ||||
| ## Value-dependent Form ("g" and "G" conversions) | ||||
| 
 | ||||
| The final form (exponential or standard) is determined based on the value.  The | ||||
| threshold is different from the JS `toString` / `toPrecision` thresholds and | ||||
| depends on the specified precision as well as the base-10 exponent: | ||||
| 
 | ||||
| |   Value   |  `"%.3g"`  | `toPrecision(3)` | | ||||
| |----------:|:-----------|:-----------------| | ||||
| | 1.2345e-4 | `0.000123` | `0.000123`       | | ||||
| | 1.2345e-5 | `1.23e-05` | `0.0000123`      | | ||||
| | 1.2345e-6 | `1.23e-06` | `0.00000123`     | | ||||
| | 1.2345e-7 | `1.23e-07` | `1.23e-7`        | | ||||
| 
 | ||||
| According to JS spec, `toPrecision` uses standard form when `precision > E` and | ||||
| `E >= -6`.  For printf standard form is used when `precision > E` and `E >= -4`. | ||||
| 
 | ||||
| ## Hex-Mantissa Decimal-Binary-Exponent Form ("a" and "A" conversions) | ||||
| 
 | ||||
| A general exponential form involves 3 parameters: radix of the mantissa, base of | ||||
| the exponent expression, and radix of the exponent expression.  The standard | ||||
| exponential form uses decimal for all three parts.  For base 16, there are quite | ||||
| a few reasonable combinations.  Consider the value `1.234567e-80`: | ||||
| 
 | ||||
| | Mant | Exp Base | Radix-10 (sigil `";"`) | Radix-16 (sigil `";"`) | | ||||
| |:----:|:--------:|:-----------------------|:-----------------------| | ||||
| |  10  |    10    | `1.234567;-80`         | `1.234567;-50`         | | ||||
| |  16  |    10    | `1.3c0c9539b8887;-80`  | `1.3c0c9539b8887;-50`  | | ||||
| |  16  |    16    | `5.daf8c8f5f4104;-67`  | `5.daf8c8f5f4104;-43`  | | ||||
| |  16  |     4    | `1.76be323d7d041;-133` | `1.76be323d7d041;-85`  | | ||||
| |  16  |     2    | `1.76be323d7d041;-266` | `1.76be323d7d041;-10a` | | ||||
| 
 | ||||
| POSIX `"%a"` uses a hex mantissa (16), decimal exponent radix (10), and binary | ||||
| exponent base (2).  The general normalized form requires that the integral part | ||||
| of the mantissa to exceed 0 and not to exceed `exponent base - 1` except in the | ||||
| special case of `0`.  The sigil is `p` and exponent sign is always used. | ||||
| 
 | ||||
| JS `num.toString(radix)` is implementation-dependent for valid non-10 radices | ||||
| (`2-9, 11-36`).  IE uses hex-mantissa decimal-hex-exponent form when the | ||||
| absolute value of the base-2 exponent exceeds 60.  Otherwise, IE uses an exact | ||||
| standard hexadecimal form.  Chrome, Safari and other browsers always use the | ||||
| exact standard hexadecimal form.  Both forms are easily converted to `"%a"` by  | ||||
| calculating and dividing by the appropriate power of 2. | ||||
| 
 | ||||
| For each non-zero normal floating point value, there are 4 acceptable strings | ||||
| that represent the value, derived by multiplying the normalized value by powers | ||||
| of 2 and adjusting the exponent accordingly: | ||||
| 
 | ||||
| | Value   | Normalized     | Alternate `*2` | Alternate `*4` | Alternate `*8` | | ||||
| |:--------|:---------------|:---------------|:---------------|:---------------| | ||||
| | `1`     | `1p+0`         | `2p-1`         | `4p-2`         | `8p-3`         | | ||||
| | `.2`    | `1.9999999p-3` | `3.3333333p-4` | `6.6666666p-5` | `c.cccccccp-6` | | ||||
| | `.69`   | `1.6147ae1p-1` | `2.c28f5c2p-2` | `5.851eb85p-3` | `b.0a3d70ap-4` | | ||||
| | `6.e20` | `1.043561p+69` | `2.086ac3p+68` | `4.10d586p+67` | `8.21ab0dp+66` | | ||||
| 
 | ||||
| JS engines follow the glibc model: multiply by a suitable power of 16 so that | ||||
| the mantissa is between 1 and 16, render left to right one digit at a time, then | ||||
| fix the result at the end.  FreeBSD and OSX always show the normalized form. | ||||
| This implementation defaults to the normalized form.  To switch to the glibc  | ||||
| form, define `DO_NOT_NORMALIZE` in the `JSFLAGS` variable when building: | ||||
| 
 | ||||
| ```bash | ||||
| $ JSFLAGS=-DDO_NOT_NORMALIZE make | ||||
| ``` | ||||
| 
 | ||||
| # Character Conversions | ||||
| 
 | ||||
| This section covers the conversions `sScC`. | ||||
| 
 | ||||
| ## Rendering Strings ("s" and "S" conversions) | ||||
| 
 | ||||
| JS has no concept of "wide strings" (`wchar_t *` in C), so the length modifiers | ||||
| are ignored.  `s` and `S` are treated as equivalent. | ||||
| 
 | ||||
| Arguments are first interpreted as strings by calling the `String` function. | ||||
| Implementing `toString` on the argument to be converted may lead to unexpected | ||||
| results: | ||||
| 
 | ||||
| ```C | ||||
| var O = {valueOf:function() {return 456;}, toString:function() {return "123"}}; | ||||
| printf("%1$s %1$d", O); // "123 456" | ||||
| ``` | ||||
| 
 | ||||
| If a positive precision is specified, up to that many characters will be taken | ||||
| from the string.  Otherwise the entire string will be used: | ||||
| 
 | ||||
| ```C | ||||
| printf("|%s|", "sheetjs");    // '|sheetjs|' (no precision) | ||||
| printf("|%.9s|", "sheetjs");  // '|sheetjs|' (string shorter than precision) | ||||
| printf("|%.5s|", "sheetjs");  // '|sheet|'   (string truncated) | ||||
| ``` | ||||
| 
 | ||||
| Lengths are measured using the JS string length accessor.  Since there is no | ||||
| attempt to correct for multi-character sequences like combining marks, the | ||||
| results may be unexpected: | ||||
| 
 | ||||
| ```C | ||||
| printf("%.1s","ñ");  // 'n' not "ñ" | ||||
| ``` | ||||
| 
 | ||||
| If the width is specified and is greater than the width of the string to be | ||||
| rendered, padding will be applied.  If the `"-"` flag is specified, then the | ||||
| string will be right-padded, otherwise it will be left-padded.  If the `"0"` | ||||
| flag is specified, the final string is left-padded with zeroes. The `"-"` flag | ||||
| takes precedence over `0`. | ||||
| 
 | ||||
| ```C | ||||
| printf(   "|%s|", "sheetjs");   // '|sheetjs|'   (no width) | ||||
| printf(  "|%5s|", "sheetjs");   // '|sheetjs|'   (string longer than width) | ||||
| printf(  "|%9s|", "sheetjs");   // '|  sheetjs|' (no flag = left pad spaces) | ||||
| printf( "|%09s|", "sheetjs");   // '|00sheetjs|' ("0" = left pad "0") | ||||
| printf( "|%-9s|", "sheetjs");   // '|sheetjs  |' ("-" = right pad space) | ||||
| printf("|%-09s|", "sheetjs");   // '|sheetjs  |' ("0" ignored) | ||||
| ``` | ||||
| 
 | ||||
| ## Rendering Characters ("c" and "C" conversions) | ||||
| 
 | ||||
| JS has no concept of "wide characters" (`wchar_t` in C).  The length modifier is | ||||
| used in determining whether the number should be interpreted as one or two | ||||
| 16-bit character codes (when the "C" format or the "l" or "ll" specifiers are | ||||
| used) or a single 8-bit char code.  Precision and flags are ignored. | ||||
| 
 | ||||
| # Non-Numeric Conversions | ||||
| 
 | ||||
| ## The literal "%" symbol ("%" conversion) | ||||
| 
 | ||||
| All other parameters are ignored. | ||||
| 
 | ||||
| ## Interpreting and Rendering Pointers ("p" conversion) | ||||
| 
 | ||||
| JS has no true concept of pointers.  In array and typed array contexts, it is | ||||
| common to associate a position object that stores the address relative to the | ||||
| start of the array.  This implementation reads the `l` key and interprets as a | ||||
| 32-bit or 52-bit unsigned integer depending on `size_t` in the data model. | ||||
| 
 | ||||
| The normal output format is equivalent to `"%#x"` but the alternate form emits | ||||
| using the `"%d"` format.  When the pointer is invalid, `-1` is rendered.  Only | ||||
| the `"#"` flag is interpreted. | ||||
| 
 | ||||
| ```js | ||||
| var x = {}, y = {l:3}; | ||||
| printf("%1$p %1$#p", y); // 0x3 3 | ||||
| printf("%1$p %1$#p", x); // 0xFFFFFFFF -1 | ||||
| ``` | ||||
| 
 | ||||
| ## Extracting length of a partial conversion ("n" conversion) | ||||
| 
 | ||||
| C `printf` permits a special `n` conversion which interprets the argument as an | ||||
| integral pointer (interpreted size controlled by the length specifier) and | ||||
| writes the number of characters printed to that pointer. | ||||
| 
 | ||||
| JS has no true concept of pointers in the C sense.  The library works around | ||||
| the limitation by interpreting the argument as an object and assigning to the | ||||
| `len` key.  The conversion does not write any characters to the output string: | ||||
| 
 | ||||
| ```js | ||||
| var x = {}; | ||||
| printf("%1$s %2$J%2$n abc", "foo", x); // "foo {} abc", also sets x.len = 6 | ||||
| //     |........|                         |......|  (6 chars at that point) | ||||
| ``` | ||||
| 
 | ||||
| This implementation mutates the object while processing: | ||||
| 
 | ||||
| ```js | ||||
| var x = {}; | ||||
| printf("%1$s %2$J%2$n %3$s %2$J", "foo", x, "bar"); // 'foo {} bar {"len":6}' | ||||
| ``` | ||||
| 
 | ||||
| ## Error messages ("m" conversion) | ||||
| 
 | ||||
| glibc supports an `m` conversion that does not consume arguments.  It renders | ||||
| the string `strerror(errno)` where `strerror` is the libc function and `errno` | ||||
| is the global error number. | ||||
| 
 | ||||
| JS has no equivalent of `errno` and no standard JS runtime exposes a similar | ||||
| global error variable, so `%m` will write the default message `"Success"`.  A | ||||
| positional parameter or `#` flag changes the behavior: | ||||
| 
 | ||||
| |     form     | position | behavior                              | | ||||
| |:------------:|:--------:|---------------------------------------| | ||||
| |     main     |    no    | do not read argument, emit "Success"  | | ||||
| | alt (flag #) |    no    | read and process next argument        | | ||||
| | main or alt  |   yes    | read and process specified argument   | | ||||
| 
 | ||||
| In all forms other than `"%m"`, an argument will be processed as follows: | ||||
| 
 | ||||
| - If the argument is not an instance of an `Error`, emit "Success" | ||||
| - If the `message` field is set, emit the error message. | ||||
| - If the `errno` field is set, emit "Error number " followed by the errno | ||||
| - Otherwise emit "Error " followed by the error interpreted as a String | ||||
| 
 | ||||
| ``` | ||||
| var x = new Error("sheetjs"); | ||||
| x.errno = 69; x.toString = function() { return "SHEETJS"; }; | ||||
| printf("|%#m|", x);      // |sheetjs| | ||||
| delete x.message; | ||||
| printf("|%#m|", x);      // |Error number 69| | ||||
| delete x.errno; | ||||
| printf("|%#m|", x);      // |Error SHEETJS| | ||||
| ``` | ||||
| 
 | ||||
| # Extensions | ||||
| 
 | ||||
| These additional conversions take advantage of unused format characters: | ||||
| 
 | ||||
| ## Rendering Boolean Values ("y" and "Y" conversions) | ||||
| 
 | ||||
| Values are converted to Boolean and tested for truthiness.  The `Y` rendering | ||||
| is the uppercase version of the equivalent rendering with format `y`. | ||||
| 
 | ||||
| 
 | ||||
| |     form     | truthy value  `y` (`Y`) | falsy value `y` (`Y`) | | ||||
| |:------------:|:-----------------------:|:---------------------:| | ||||
| |     main     |     `true` (`TRUE`)     |   `false` (`FALSE`)   | | ||||
| | alt (flag #) |      `yes` (`YES`)      |      `no` (`NO`)      | | ||||
| 
 | ||||
| Width and precision are applied in the same manner as the `s` conversion. | ||||
| 
 | ||||
| ```js | ||||
| printf("|%1$y|%2$Y|%1$#Y|%2$#y|%2$.1y|", 1, 0); // |true|FALSE|YES|no|f| | ||||
| printf("|%05.2Y|%-5.2y|", 1, 0);  // |000TR|fa   | | ||||
| ``` | ||||
| 
 | ||||
| ## Rendering JSON ("J" conversion) | ||||
| 
 | ||||
| The default rendering is the standard output from `JSON.stringify`.  Alternate | ||||
| form (`"#"` flag) renders using `util.inspect` if available. | ||||
| 
 | ||||
| ```js | ||||
| var x = { | ||||
|   a: [1,[2,3,4],5,6,7], | ||||
|   b: { | ||||
|     c: { | ||||
|       d: { e:"f" }, | ||||
|       g:"h", | ||||
|       i:"j" | ||||
|     }, | ||||
|     k:"l", | ||||
|     m:"n", | ||||
|     o:"p"}, | ||||
|   q: "r" | ||||
| }; | ||||
| printf("%J", x) // '{"a":[1,[2,3,4],5,6,7],"b":{"c":{"d":{"e":"f"}, ..(ctnd).. | ||||
| printf("%#J", x) // '{ a: [ 1, [ 2, 3, 4 ], 5, 6, 7 ],\n  b: { c: { ..(ctnd).. | ||||
| ``` | ||||
| 
 | ||||
| Width, precision and other flags are ignored. | ||||
| 
 | ||||
| ## JS typeof and valueOf ("T" and "V" conversion) | ||||
| 
 | ||||
| Under the "T" conversion, the result of `typeof arg` is rendered.  If the `#` | ||||
| flag is specified, the type is derived from `Object.prototype.toString`: | ||||
| 
 | ||||
| ``` | ||||
| printf("%1$T %1$#T", 1);          // 'number Number' | ||||
| printf("%1$T %1$#T", 'foo');      // 'string String' | ||||
| printf("%1$T %1$#T", [1,2,3]);    // 'object Array' | ||||
| printf("%1$T %1$#T", null);       // 'object Null' | ||||
| printf("%1$T %1$#T", undefined);  // 'undefined Undefined' | ||||
| ``` | ||||
| 
 | ||||
| Under the "V" conversion, the result of `arg.valueOf()` is rendered: | ||||
| 
 | ||||
| ``` | ||||
| var _f = function() { return "f"; }; | ||||
| var _3 = function() { return 3; }; | ||||
| printf("%1$d %1$s %1$V", {toString:_f});               // '0 f f' | ||||
| printf("%1$d %1$s %1$V", {valueOf:_3});                // '3 [object Object] 3' | ||||
| printf("%1$d %1$s %1$V", {valueOf:_3, toString:_f});   // '3 f 3' | ||||
| ``` | ||||
| 
 | ||||
| ## Rendering Unsigned Integers in Base 2 ("b" and "B" conversions) | ||||
| 
 | ||||
| The implementation is similar to the octal `"o"` and `"O"` conversions, except | ||||
| for the radix (2 for `"b"` and `"B"`) and the alternate-form prefix (`"0b"`) | ||||
| 
 | ||||
| # Miscellaneous Notes | ||||
| 
 | ||||
| ## Format Characters | ||||
| 
 | ||||
| For compatibility purposes, format characters must be printable ASCII characters | ||||
| (ASCII codes `0x20 - 0x7E`).  The 95 eligible characters are listed below: | ||||
| 
 | ||||
| |  C  |    Type    |  C  |    Type    |  C  |    Type    |  C  |    Type    | | ||||
| |-----|:----------:|-----|:----------:|-----|:----------:|-----|:----------:| | ||||
| | `a` | conversion | `A` | conversion | ` ` |    flag    | `!` |            | | ||||
| | `b` | conversion | `B` | conversion | `"` |            | `#` |    flag    | | ||||
| | `c` | conversion | `C` | conversion | `$` |    other   | `%` | conversion | | ||||
| | `d` | conversion | `D` | conversion | `&` |            | `'` |    flag    | | ||||
| | `e` | conversion | `E` | conversion | `(` |            | `)` |            | | ||||
| | `f` | conversion | `F` | conversion | `*` |    other   | `+` |    flag    | | ||||
| | `g` | conversion | `G` | conversion | `,` |            | `-` |    flag    | | ||||
| | `h` |   length   | `H` |            | `.` |    other   | `/` |            | | ||||
| | `i` | conversion | `I` |   length   | `0` |    digit   | `1` |    digit   | | ||||
| | `j` |   length   | `J` | conversion | `2` |    digit   | `3` |    digit   | | ||||
| | `k` |            | `K` |            | `4` |    digit   | `5` |    digit   | | ||||
| | `l` |   length   | `L` |   length   | `6` |    digit   | `7` |    digit   | | ||||
| | `m` | conversion | `M` |            | `8` |    digit   | `9` |    digit   | | ||||
| | `n` | conversion | `N` |            | `:` |            | `;` |            | | ||||
| | `o` | conversion | `O` | conversion | `<` |            | `=` |            | | ||||
| | `p` | conversion | `P` |            | `>` |            | `?` |            | | ||||
| | `q` |   length   | `Q` |            | `@` |            | `[` |            | | ||||
| | `r` |            | `R` |            | `\` |            | `]` |            | | ||||
| | `s` | conversion | `S` | conversion | `^` |            | `_` |            | | ||||
| | `t` |   length   | `T` | conversion | `~` |            | `{` |            | | ||||
| | `u` | conversion | `U` | conversion | `|` |            | `}` |            | | ||||
| | `v` |            | `V` | conversion | `` ` `` |        | | ||||
| | `w` |   length   | `W` |            | | ||||
| | `x` | conversion | `X` | conversion | | ||||
| | `y` | conversion | `Y` | conversion | | ||||
| | `z` |   length   | `Z` |   length   | | ||||
| 
 | ||||
| ## JS and C strings | ||||
| 
 | ||||
| C provides no guidance on the actual character set.  According to K&R all valid | ||||
| characters in source code must be in a character set that is a subset of the | ||||
| 7-bit ASCII set.  This implementation falls back on the UTF-16 base required by | ||||
| JS.  When converting C literal strings, there are a few differences in escaping: | ||||
| 
 | ||||
| | C escape sequence | Equivalent JS | Notes                                  | | ||||
| |:------------------|:--------------|:---------------------------------------| | ||||
| | `"\a"`            |  `"\007"`     | BEL character will not ring in browser |  | ||||
| | `"\?"`            |  `"?"`        | JS does not handle trigraphs           | | ||||
| | `"\ooo"` (octal)  |  `"\ooo"`     | JS uses Latin-1 for non-ASCII codes    | | ||||
| | `"\xhh"` (hex)    |  `"\xhh"`     | JS uses Latin-1 for non-ASCII codes    | | ||||
| 
 | ||||
| ## Support Summary | ||||
| 
 | ||||
| - Full [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html) conversion support with extensions! | ||||
|   [Conversion Specifier Table](#conversion-specifier-quick-reference-table) | ||||
| - Full support for POSIX flags and positional parameters | ||||
| - Emulation of BSD `quad_t` and `u_quad_t` conversion | ||||
| - Parser accepts but does not emulate CRT wide and unicode character conversions | ||||
| - glibc `Z` length conversion and extended `m` error support  | ||||
| - CRT `I/w` length but no `I32/I64` | ||||
| - Default `LP64` data model but can be configured to support `ILP32` or `LLP64` | ||||
| 
 | ||||
							
								
								
									
										62
									
								
								bin/printj.njs
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										62
									
								
								bin/printj.njs
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,62 @@ | ||||
| #!/usr/bin/env node | ||||
| /* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2 ft=javascript: */ | ||||
| var X = require("../"), argv = process.argv; | ||||
| 
 | ||||
| function help() { | ||||
| [ | ||||
| "usage: printj [options] <format> [args...]", | ||||
| "", | ||||
| "Options:", | ||||
| "    -h, --help      output usage information", | ||||
| "    -d, --dump      print debug information about format string", | ||||
| "", | ||||
| "Arguments are treated as strings unless prefaced by a type indicator:", | ||||
| "    n:<integer>     call parseInt (ex. n:3 -> 3)", | ||||
| "    f:<float>       call parseFloat (ex. f:3.1 -> 3.1)", | ||||
| '    b:<boolean>     false when lowercase value is "FALSE" or "0", else true', | ||||
| "    s:<string>      interpret as string (ex. s:n:3 -> \"n:3\")", | ||||
| "    j:<JSON>        interpret as an object using JSON.parse", | ||||
| "    e:<JS>          evaluate argument (ex. e:1+1 -> 2, e:\"1\"+1 -> \"11\")", | ||||
| "", | ||||
| "samples:", | ||||
| "    $ printj '|%02hhx%d|' n:50 e:0x7B                # |32123|", | ||||
| "    $ printj '|%2$d + %3$d is %1$d|' e:1+2 n:1 n:2   # |1 + 2 is 3| ", | ||||
| "    $ printj '|%s is %s|' s:1+2 e:1+2                # |1+2 is 3|", | ||||
| "    $ printj '|%c %c|' s:69 n:69                     # |6 E|", | ||||
| "", | ||||
| "Support email: dev@sheetjs.com", | ||||
| "Web Demo: http://oss.sheetjs.com/printj/" | ||||
| ].forEach(function(l) { console.log(l); }); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| function parse_arg(arg/*:string*/)/*:any*/ { | ||||
| 	var m = arg.substr(2), p/*:number*/; | ||||
| 	if(arg.charCodeAt(1) == 58) switch((p = arg.charCodeAt(0))) { | ||||
| 		case /*n*/ 110: return parseInt(m); | ||||
| 		case /*f*/ 102: return parseFloat(m); | ||||
| 		case /*b*/  98: return !(m.toUpperCase() == "FALSE" || m == "0"); | ||||
| 		case /*j*/ 106: return JSON.parse(m); | ||||
| 		case /*e*/ 101: return eval(m); | ||||
| 		case /*s*/ 115: return m; | ||||
| 	} | ||||
| 	return arg; | ||||
| } | ||||
| 
 | ||||
| var args/*:Array<any>*/ = []; | ||||
| var fmt = "", n = 0; | ||||
| for(var i = 2; i < argv.length; ++i) switch(argv[i]) { | ||||
| 	case "--help": case "-h": return help(); | ||||
| 	case "--dump": case "-d": if(fmt.length==0) fmt = argv[++i]; return dump(fmt); | ||||
| 	default: if(n++ == 0) fmt = argv[i]; else args.push(parse_arg(argv[i])); | ||||
| } | ||||
| 
 | ||||
| console.log(X.vsprintf(fmt, args)); | ||||
| return 0; | ||||
| 
 | ||||
| function dump(fmt) { | ||||
| 	if(!fmt) { console.error("printj: missing format argument"); return 1; } | ||||
| 	X._tokenize(fmt).forEach(function(x){console.log(x);}); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										1
									
								
								bits/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								bits/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| 30_ctypes.js | ||||
							
								
								
									
										27
									
								
								bits/00_header.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										27
									
								
								bits/00_header.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| /* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint sub:true, eqnull:true */ | ||||
| /*exported PRINTJ */ | ||||
| /*:: declare var DO_NOT_EXPORT_PRINTJ: any; */ | ||||
| /*:: declare var define: any; */ | ||||
| var PRINTJ/*:any*/; | ||||
| (function (factory/*:(a:any)=>void*/)/*:void*/ { | ||||
| 	/*jshint ignore:start */ | ||||
| 	if(typeof DO_NOT_EXPORT_PRINTJ === 'undefined') { | ||||
| 		if('object' === typeof exports) { | ||||
| 			factory(exports); | ||||
| 		} else if ('function' === typeof define && define.amd) { | ||||
| 			define(function () { | ||||
| 				var module/*:any*/ = {}; | ||||
| 				factory(module); | ||||
| 				return module; | ||||
| 			}); | ||||
| 		} else { | ||||
| 			factory(PRINTJ = {}); | ||||
| 		} | ||||
| 	} else { | ||||
| 		factory(PRINTJ = {}); | ||||
| 	} | ||||
| 	/*jshint ignore:end */ | ||||
| }(function(PRINTJ) { | ||||
| #include "01_version.js" | ||||
							
								
								
									
										1
									
								
								bits/01_version.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								bits/01_version.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| PRINTJ.version = '0.1.0'; | ||||
							
								
								
									
										78
									
								
								bits/10_tokenize.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										78
									
								
								bits/10_tokenize.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| #ifdef USE_CHAR | ||||
| #define GETCHAR C = fmt.charAt(i); | ||||
| #else | ||||
| #define GETCHAR c = fmt.charCodeAt(i); | ||||
| #endif | ||||
| 
 | ||||
| #define DRAIN(idx) if(start < idx) out.push(["L", fmt.substring(start, idx)]); | ||||
| function tokenize(fmt/*:string*/)/*:ParsedFmt*/ { | ||||
| 	var out/*:ParsedFmt*/ = []; | ||||
| 	var start/*:number*/ = 0; | ||||
| 
 | ||||
| #ifdef USE_REGEX | ||||
| 
 | ||||
| 	var m/*:?Array<string>*/; | ||||
| 	while((m = REGEX.exec(fmt))) { | ||||
| 		DRAIN(m.index) | ||||
| 		start = m.index + m[0].length; | ||||
| 		if(m[0] === "%%") out.push(["%","%"]); | ||||
| 		else out.push([m[6], m[0], m[1], m[2], m[3], m[4], m[5]]); | ||||
| 	} | ||||
| 
 | ||||
| #else /* NOT USE_REGEX */ | ||||
| 
 | ||||
| 	var i/*:number*/ = 0; | ||||
| 	var infmt/*:boolean*/ = false; | ||||
| 	var fmtparam/*:string*/ = "", fmtflags/*:string*/ = "", fmtwidth/*:string*/ = "", fmtprec/*:string*/ = "", fmtlen/*:string*/ = ""; | ||||
| 
 | ||||
| #if defined(USE_CHAR) | ||||
| 	var C/*:string*/ = '?'; | ||||
| #else /* USE_CODE */ | ||||
| 	var c/*:number*/ = 0; | ||||
| #endif /* USE_CHAR */ | ||||
| 
 | ||||
| #if defined(USE_INDEX) | ||||
| 	while((i=fmt.indexOf("%", start)) != -1) { | ||||
| 		DRAIN(i) | ||||
| 		start = i++; | ||||
| 		infmt = true; | ||||
| 		while(infmt) { | ||||
| 			GETCHAR | ||||
| #ifdef USE_CHAR | ||||
| #include "12_switchchar.js" | ||||
| #else /* USE_CODE */ | ||||
| #include "11_switchcode.js" | ||||
| #endif /* USE_CHAR */ | ||||
| 			++i; | ||||
| 		} | ||||
| 	} | ||||
| #elif defined(USE_LOOP) | ||||
| 
 | ||||
| 	var L/*:number*/ = fmt.length; | ||||
| 
 | ||||
| 	for(; i < L; ++i) { | ||||
| 		GETCHAR | ||||
| 		if(!infmt) { | ||||
| #ifdef USE_CHAR | ||||
| 			if(C !== "%") continue; | ||||
| #else /* USE_CODE */ | ||||
| 			if(c !== 37) continue; | ||||
| #endif /* USE_CHAR */ | ||||
| 			DRAIN(i) | ||||
| 			start = i; | ||||
| 			infmt = true; | ||||
| 			continue; | ||||
| 		} | ||||
| #ifdef USE_CHAR | ||||
| #include "12_switchchar.js" | ||||
| #else /* USE_CODE */ | ||||
| #include "11_switchcode.js" | ||||
| #endif /* USE_CHAR */ | ||||
| 	} | ||||
| #endif /* USE_INDEX / USE_LOOP */ | ||||
| 
 | ||||
| #endif /* USE_REGEX */ | ||||
| 
 | ||||
| 	if(start < fmt.length) out.push(["L", fmt.substring(start)]); | ||||
| 	return out; | ||||
| } | ||||
							
								
								
									
										91
									
								
								bits/11_switchcode.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										91
									
								
								bits/11_switchcode.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| 		if(c >= 48 && c < 58)	{ | ||||
| 				if(fmtprec.length) fmtprec += String.fromCharCode(c); | ||||
| 				else if(c == 48 && !fmtwidth.length) fmtflags += String.fromCharCode(c); | ||||
| 				else fmtwidth += String.fromCharCode(c); | ||||
| 		} else switch(c) { | ||||
| 			/* positional */ | ||||
| 			case 36: | ||||
| 				if(fmtprec.length) fmtprec += "$"; | ||||
| 				else if(fmtwidth.charAt(0) == "*") fmtwidth += "$"; | ||||
| 				else { fmtparam = fmtwidth + "$"; fmtwidth = ""; } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* flags */ | ||||
| 			case 39: fmtflags += "'"; break; | ||||
| 			case 45: fmtflags += "-"; break; | ||||
| 			case 43: fmtflags += "+"; break; | ||||
| 			case 32: fmtflags += " "; break; | ||||
| 			case 35: fmtflags += "#"; break; | ||||
| 
 | ||||
| 			/* width and precision */ | ||||
| 			case 46: fmtprec = "."; break; | ||||
| 			case 42: | ||||
| 				if(fmtprec.charAt(0) == ".") fmtprec += "*"; | ||||
| 				else fmtwidth += "*"; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* length */ | ||||
| 			case 104: | ||||
| 			case 108: | ||||
| 				if(fmtlen.length > 1) throw "bad length " + fmtlen + String(c); | ||||
| 				fmtlen += String.fromCharCode(c); | ||||
| 				break; | ||||
| 
 | ||||
| 			case  76: | ||||
| 			case 106: | ||||
| 			case 122: | ||||
| 			case 116: | ||||
| 			case 113: | ||||
| 			case  90: | ||||
| 			case 119: | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + String.fromCharCode(c); | ||||
| 				fmtlen = String.fromCharCode(c); | ||||
| 				break; | ||||
| 
 | ||||
| 			case 73: | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + 'I'; | ||||
| 				fmtlen = 'I'; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* conversion */ | ||||
| 			case 100: | ||||
| 			case 105: | ||||
| 			case 111: | ||||
| 			case 117: | ||||
| 			case 120: | ||||
| 			case 88: | ||||
| 			case 102: | ||||
| 			case 70: | ||||
| 			case 101: | ||||
| 			case 69: | ||||
| 			case 103: | ||||
| 			case 71: | ||||
| 			case 97: | ||||
| 			case 65: | ||||
| 			case 99: | ||||
| 			case 67: | ||||
| 			case 115: | ||||
| 			case 83: | ||||
| 			case 112: | ||||
| 			case 110: | ||||
| 			case 68: | ||||
| 			case 85: | ||||
| 			case 79: | ||||
| 			case 109: | ||||
| 			case 98: | ||||
| 			case 66: | ||||
| 			case 121: | ||||
| 			case 89: | ||||
| 			case 74: | ||||
| 			case 86: | ||||
| 			case 84: | ||||
| 			case 37: | ||||
| 				infmt = false; | ||||
| 				if(fmtprec.length > 1) fmtprec = fmtprec.substr(1); | ||||
| 				out.push([String.fromCharCode(c), fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]); | ||||
| 				start = i+1; | ||||
| 				fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = ""; | ||||
| 				break; | ||||
| 			default: | ||||
| 				throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|"); | ||||
| 		} | ||||
							
								
								
									
										3
									
								
								bits/12_regexp.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								bits/12_regexp.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| var REGEX/*:RegExp*/ = /%(?:%|(\d+\$)?([-+ 0#']*)?(\d*|\*(?:\d+\$)?)(?:\.(\d+|\*(?:\d+\$)?))?(hh?|ll?|[LzjtqZIw])?([diouxXfFeEgGaAcCsSpnDUOmbByYJVT]))/g; | ||||
| /*                |A------AB----------BC----------------CD-----------------------DE-------------------EF---------------------------------F| */ | ||||
| 
 | ||||
							
								
								
									
										91
									
								
								bits/12_switchchar.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										91
									
								
								bits/12_switchchar.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| 		if(C >= "0" && C <= "9")	{ | ||||
| 				if(fmtprec.length) fmtprec += C; | ||||
| 				else if(C == "0" && !fmtwidth.length) fmtflags += C; | ||||
| 				else fmtwidth += C; | ||||
| 		} else switch(C) { | ||||
| 			/* positional */ | ||||
| 			case '$': | ||||
| 				if(fmtprec.length) fmtprec += "$"; | ||||
| 				else if(fmtwidth.charAt(0) == "*") fmtwidth += "$"; | ||||
| 				else { fmtparam = fmtwidth + "$"; fmtwidth = ""; } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* flags */ | ||||
| 			case "'": fmtflags += "'"; break; | ||||
| 			case '-': fmtflags += "-"; break; | ||||
| 			case '+': fmtflags += "+"; break; | ||||
| 			case ' ': fmtflags += " "; break; | ||||
| 			case '#': fmtflags += "#"; break; | ||||
| 
 | ||||
| 			/* width and precision */ | ||||
| 			case '.': fmtprec = "."; break; | ||||
| 			case '*': | ||||
| 				if(fmtprec.charAt(0) == ".") fmtprec += "*"; | ||||
| 				else fmtwidth += "*"; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* length */ | ||||
| 			case 'h': | ||||
| 			case 'l': | ||||
| 				if(fmtlen !== "" && fmtlen !== C) throw "bad length " + fmtlen + C; | ||||
| 				fmtlen += C; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'L': | ||||
| 			case 'j': | ||||
| 			case 'z': | ||||
| 			case 't': | ||||
| 			case 'q': | ||||
| 			case 'Z': | ||||
| 			case 'w': | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + C; | ||||
| 				fmtlen = C; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'I': | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + 'I'; | ||||
| 				fmtlen = 'I'; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* conversion */ | ||||
| 			case 'd': | ||||
| 			case 'i': | ||||
| 			case 'o': | ||||
| 			case 'u': | ||||
| 			case 'x': | ||||
| 			case 'X': | ||||
| 			case 'f': | ||||
| 			case 'F': | ||||
| 			case 'e': | ||||
| 			case 'E': | ||||
| 			case 'g': | ||||
| 			case 'G': | ||||
| 			case 'a': | ||||
| 			case 'A': | ||||
| 			case 'c': | ||||
| 			case 'C': | ||||
| 			case 's': | ||||
| 			case 'S': | ||||
| 			case 'p': | ||||
| 			case 'n': | ||||
| 			case 'D': | ||||
| 			case 'U': | ||||
| 			case 'O': | ||||
| 			case 'm': | ||||
| 			case 'b': | ||||
| 			case 'B': | ||||
| 			case 'y': | ||||
| 			case 'Y': | ||||
| 			case 'J': | ||||
| 			case 'V': | ||||
| 			case 'T': | ||||
| 			case '%': | ||||
| 				infmt = false; | ||||
| 				if(fmtprec.length > 1) fmtprec = fmtprec.substr(1); | ||||
| 				out.push([C, fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]); | ||||
| 				start = i+1; | ||||
| 				fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = ""; | ||||
| 				break; | ||||
| 			default: | ||||
| 				throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|"); | ||||
| 		} | ||||
							
								
								
									
										61
									
								
								bits/30_ctypes.njs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										61
									
								
								bits/30_ctypes.njs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| /* vim: set ts=2 ft=javascript: */ | ||||
| 
 | ||||
| var ctypes = require("./ctypes.json"); | ||||
| var models = ctypes.Models; | ||||
| var modelnames = ctypes.ModelNames; | ||||
| 
 | ||||
| console.log("#ifndef CTYPES_JS_"); | ||||
| console.log("#define CTYPES_JS_"); | ||||
| console.log(""); | ||||
| modelnames.forEach(function(m, i) { console.log("#define JS_MODEL_" + m + " " + i); }); | ||||
| console.log(""); | ||||
| 
 | ||||
| console.log("#ifndef JS_MODEL\n#define JS_MODEL JS_MODEL_" + modelnames[0] + "\n#endif\n"); | ||||
| 
 | ||||
| function print_model(model) { | ||||
| [ | ||||
| "#define SIZEOF_CHAR " + model.char, | ||||
| "#define SIZEOF_WCHAR_T " + model.wchar_t, | ||||
| "", | ||||
| "#define SIZEOF_SHORT " + model.short, | ||||
| "#define SIZEOF_INT " + model.int, | ||||
| "#define SIZEOF_WINT_T " + model.wint_t, | ||||
| "#define SIZEOF_LONG " + model.long, | ||||
| "#define SIZEOF_LONG_LONG " + model.longlong, | ||||
| "", | ||||
| "#define SIZEOF_SIZE_T " + model.size_t, | ||||
| "#define SIZEOF_INTMAX_T " + model.intmax_t, | ||||
| "#define SIZEOF_PTRDIFF_T " + model.ptrdiff_t, | ||||
| ].forEach(function(l) { console.log(l); }); | ||||
| } | ||||
| 
 | ||||
| modelnames.forEach(function(m,i) { | ||||
| 	console.log("#" + (i == 0 ? "" : "el") + "if JS_MODEL == JS_MODEL_" + m); | ||||
| 	print_model(models[m]); | ||||
| }); | ||||
| 
 | ||||
| console.log("#else"); | ||||
| var warn = modelnames.map(function(m, i) { return i + " (" + m + ")"; }).join(" or "); | ||||
| 
 | ||||
| console.log("#error 'Unsupported JS_MODEL, should be " + warn + "'\n#endif\n"); | ||||
| 
 | ||||
| function make_124_mask(T) { | ||||
| 	var name = "SIZEOF_" + T, mask = "MASK_" + T; | ||||
| 	return [ | ||||
| 		"#ifdef "   + name, | ||||
| 		"#if "      + name + " == 1", | ||||
| 		"#define "  + mask + " 0xFF", | ||||
| 		"#elif "    + name + " == 2", | ||||
| 		"#define "  + mask + " 0xFFFF", | ||||
| 		"#elif "    + name + " == 4", | ||||
| 		"#define "  + mask + " 0xFFFFFFFF", | ||||
| 		"#endif", | ||||
| 		"#endif /*" + name + "*/" | ||||
| 	].join("\n"); | ||||
| } | ||||
| 
 | ||||
| console.log(make_124_mask("CHAR")); | ||||
| console.log(""); | ||||
| console.log(make_124_mask("WCHAR_T")); | ||||
| console.log(""); | ||||
| console.log("#endif  /*CTYPES_JS_*/"); | ||||
							
								
								
									
										55
									
								
								bits/40_macros.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										55
									
								
								bits/40_macros.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | ||||
| #define isnan isNaN | ||||
| //#define PAD_(x,c) (x >= 0 ? new Array(((x)|0) + 1).join((c)) : "")
 | ||||
| var padstr = { | ||||
| 	" ": "                                 ", | ||||
| 	"0": "000000000000000000000000000000000", | ||||
| 	"7": "777777777777777777777777777777777", | ||||
| 	"f": "fffffffffffffffffffffffffffffffff" | ||||
| }; | ||||
| #define PAD_(x,c) (x >= 0 ? padstr[c].substr(0,x) : "") | ||||
| #ifdef DO_NOT_INLINE | ||||
| function pads(x/*:number*/, c/*:string*/)/*:string*/ { return PAD_(x,c); } | ||||
| #define PADS(x,c) pads(x,c) | ||||
| #else | ||||
| #define PADS(x,c) PAD_(x,c)  | ||||
| #endif | ||||
| 
 | ||||
| #define PAD(x)    pad = PADS(x, " ") | ||||
| 
 | ||||
| #define PREC_STR(O, prec) if(prec >= 0) O = O.substr(0, prec); | ||||
| 
 | ||||
| #define WIDTH(O, width, flags) \ | ||||
| 	if(width > O.length || -width > O.length) { \ | ||||
| 		if((flags.indexOf("-") == -1 || width < 0) && flags.indexOf("0") != -1) { \ | ||||
| 			pad = PADS(width - O.length, "0"); \ | ||||
| 			O = pad + O; \ | ||||
| 		} else { \ | ||||
| 			PAD(width - O.length); \ | ||||
| 			O = flags.indexOf("-") > -1 ? O + pad : pad + O; \ | ||||
| 		} \ | ||||
| 	} | ||||
| 
 | ||||
| #ifndef SIZEOF_WCHAR_T | ||||
| #error SIZEOF_WCHAR_T must be 1, 2, or 4 | ||||
| #elif SIZEOF_WCHAR_T == 1 || SIZEOF_WCHAR_T == 2 || SIZEOF_WCHAR_T == 4 | ||||
| #define WCHAR_TO_STR(O,cc) { cc &= MASK_WCHAR_T; O = String.fromCharCode(cc); } | ||||
| #else | ||||
| #error SIZEOF_WCHAR_T must be 1, 2, or 4 | ||||
| #endif | ||||
| 
 | ||||
| #define CHAR_TO_STR(O,cc) cc &= MASK_CHAR; O = String.fromCharCode(cc); | ||||
| 
 | ||||
| #if SIZEOF_SIZE_T > 4 /* TODO: negative ptrs? */ | ||||
| #define CONV_SIZE_T(x) x = Math.abs(x); | ||||
| #define SIZE_T_TO_HEX(n) n.toString(16)  | ||||
| #else | ||||
| #define CONV_SIZE_T(x) x = (x>>>0); | ||||
| #define SIZE_T_TO_HEX(n) n.toString(16) | ||||
| #endif  | ||||
| 
 | ||||
| 
 | ||||
| #define IDX_POS 2 | ||||
| #define IDX_FLAGS 3 | ||||
| #define IDX_WIDTH 4 | ||||
| #define IDX_PREC 5 | ||||
| #define IDX_LEN 6 | ||||
							
								
								
									
										82
									
								
								bits/50_doit.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										82
									
								
								bits/50_doit.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | ||||
| #include "30_ctypes.js" | ||||
| #include "40_macros.js" | ||||
| /*:: declare var util:any; */ | ||||
| /*:: declare var require: any; */ | ||||
| if(typeof util=='undefined' && typeof require!=='undefined')util=require("util"); | ||||
| var u_inspect/*:(o:any)=>string*/ = (typeof util != 'undefined') ? util.inspect : JSON.stringify; | ||||
| 
 | ||||
| 
 | ||||
| function doit(t/*:ParsedFmt*/, args/*:Array<any>*/)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = []; | ||||
| 	var argidx/*:number*/ = 0, idx/*:number*/ = 0; | ||||
| 	var Vnum/*:number*/ = 0; | ||||
| 	var pad/*:string*/ = ""; | ||||
| 	for(var i = 0; i < t.length; ++i) { | ||||
| 		var m/*:Array<any>*/ = t[i], c/*:number*/ = (m[0]/*:string*/).charCodeAt(0); | ||||
| 		/* m order: conv full param flags width prec length */ | ||||
| 
 | ||||
| 		if(c === /*L*/ 76) { o.push(m[1]); continue; } | ||||
| 		if(c === /*%*/ 37) { o.push("%"); continue; } | ||||
| 
 | ||||
| 		var O/*:string*/ = ""; | ||||
| 		var isnum/*:number*/ = 0, radix/*:number*/ = 10, bytes/*:number*/ = SIZEOF_INT, sign/*:boolean*/ = false; | ||||
| 
 | ||||
| 		/* flags */ | ||||
| 		var flags/*:string*/ = m[IDX_FLAGS]||""; | ||||
| 		var alt = flags.indexOf("#") > -1; | ||||
| 
 | ||||
| 		/* position */ | ||||
| 		if(m[IDX_POS]) argidx = parseInt(m[IDX_POS])-1; | ||||
| 		/* %m special case */ | ||||
| 		else if(c === /*m*/ 109 && !alt) { o.push("Success"); continue; } | ||||
| 
 | ||||
| #define GRAB_INT(NAME, IDX, DFL) \ | ||||
| 		var NAME/*:number*/ = DFL; \ | ||||
| 		if(m[IDX] != null && m[IDX].length > 0) { \ | ||||
| 			if(m[IDX].charAt(0) !== '*') NAME = parseInt(m[IDX], 10); \ | ||||
| 			else if(m[IDX].length === 1) NAME = args[idx++]; \ | ||||
| 			else NAME = args[parseInt(m[IDX].substr(1), 10)-1]; \ | ||||
| 		} | ||||
| 
 | ||||
| 		/* grab width */ | ||||
| 		GRAB_INT(width, IDX_WIDTH, 0) | ||||
| 
 | ||||
| 		/* grab precision */ | ||||
| 		GRAB_INT(prec, IDX_PREC, -1) | ||||
| 
 | ||||
| 		/* position not specified */ | ||||
| 		if(!m[IDX_POS]) argidx = idx++; | ||||
| 
 | ||||
| 		/* grab argument */ | ||||
| 		var arg/*:any*/ = args[argidx]; | ||||
| 
 | ||||
| 		/* grab length */ | ||||
| 		var len/*:string*/ = m[IDX_LEN] || ""; | ||||
| 
 | ||||
| #define INT isnum = -1 | ||||
| #define SGN(s) sign = s | ||||
| #define LONG bytes = SIZEOF_LONG | ||||
| #define RADIX(n) radix = (n) | ||||
| #define NUM(n) isnum = (n) | ||||
| 
 | ||||
| 		switch(c) { | ||||
| 			/* str cCsS */ | ||||
| #include "51_convstr.js" | ||||
| 			/* int diDuUoOxXbB */ | ||||
| #include "52_convint.js" | ||||
| 			/* flt fegFEGaA */ | ||||
| #include "53_convflt.js" | ||||
| 			/* misc pnmJVTyY */ | ||||
| #include "54_convmisc.js" | ||||
| 		} | ||||
| 
 | ||||
| 		if(isnum == -1) { | ||||
| #include "60_integer.js" | ||||
| 		} else if(isnum > 0) { | ||||
| #include "70_float.js" | ||||
| 		} | ||||
| 
 | ||||
| 		o.push(O); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
							
								
								
									
										22
									
								
								bits/51_convstr.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								bits/51_convstr.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| 			case /*S*/  83: | ||||
| 			case /*s*/ 115: | ||||
| 				/* only valid flag is "-" for left justification */ | ||||
| 				O = String(arg); | ||||
| 				PREC_STR(O, prec) | ||||
| 				WIDTH(O, width, flags) | ||||
| 				break; | ||||
| 
 | ||||
| 			/* first char of string or convert */ | ||||
| 			case /*C*/  67: | ||||
| 			case /*c*/  99: | ||||
| 				switch(typeof arg) { | ||||
| 					case "number": | ||||
| 						var cc/*:number*/ = arg; | ||||
| 						if(c == 67 || len.charCodeAt(0) === /*l*/ 108) WCHAR_TO_STR(O, cc) | ||||
| 						else CHAR_TO_STR(O, cc) | ||||
| 						break; | ||||
| 					case "string": O = arg.charAt(0); break; | ||||
| 					default: O = String(arg).charAt(0); | ||||
| 				} | ||||
| 				WIDTH(O, width, flags) | ||||
| 				break; | ||||
							
								
								
									
										24
									
								
								bits/52_convint.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										24
									
								
								bits/52_convint.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| 			/* signed integer */ | ||||
| 			case /*D*/  68: LONG; | ||||
| 			/* falls through */ | ||||
| 			case /*d*/ 100: | ||||
| 			case /*i*/ 105: INT; SGN(true); break; | ||||
| 
 | ||||
| 			/* unsigned integer */ | ||||
| 			case /*U*/  85: LONG; | ||||
| 			/* falls through */ | ||||
|  			case /*u*/ 117: INT; break; | ||||
| 
 | ||||
| 			/* unsigned octal */ | ||||
| 			case /*O*/  79: LONG; | ||||
| 			/* falls through */ | ||||
| 			case /*o*/ 111: INT; RADIX(8); break; | ||||
| 
 | ||||
| 			/* unsigned hex */ | ||||
| 			case /*x*/ 120: INT; RADIX(-16); break; | ||||
| 			case /*X*/  88: INT; RADIX(16); break; | ||||
| 
 | ||||
| 			/* unsigned binary (extension) */ | ||||
| 			case /*B*/  66: LONG; | ||||
| 			/* falls through */ | ||||
| 			case /*b*/  98: INT; RADIX(2); break; | ||||
							
								
								
									
										13
									
								
								bits/53_convflt.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										13
									
								
								bits/53_convflt.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| 			/* floating point logic */ | ||||
| 			case /*F*/  70: | ||||
| 			case /*f*/ 102: NUM(1); break; | ||||
| 
 | ||||
| 			case /*E*/  69: | ||||
| 			case /*e*/ 101: NUM(2); break; | ||||
| 
 | ||||
| 			case /*G*/  71: | ||||
| 			case /*g*/ 103: NUM(3); break; | ||||
| 
 | ||||
| 			/* floating hex */ | ||||
| 			case /*A*/  65: | ||||
| 			case /*a*/  97: NUM(4); break; | ||||
							
								
								
									
										42
									
								
								bits/54_convmisc.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										42
									
								
								bits/54_convmisc.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| 			/* JS has no concept of pointers so interpret the `l` key as an address */ | ||||
| 			case /*p*/ 112: | ||||
| 				Vnum = typeof arg == "number" ? arg : Number(arg.l); | ||||
| 				if(isnan(Vnum)) Vnum = -1; | ||||
| 				if(alt) O = Vnum.toString(10); | ||||
| 				else { | ||||
| 					CONV_SIZE_T(Vnum) | ||||
| 					O = "0x" + SIZE_T_TO_HEX(Vnum).toLowerCase(); | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			/* store length in the `len` key */ | ||||
| 			case /*n*/ 110: | ||||
| 				if(arg) { arg.len=0; for(var oo = 0; oo < o.length; ++oo) arg.len += o[oo].length; } | ||||
| 				continue; | ||||
| 
 | ||||
| 			/* process error */ | ||||
| 			case /*m*/ 109: | ||||
| 				if(!(arg instanceof Error)) O = "Success"; | ||||
| 				else if(arg.message) O = arg.message; | ||||
| 				else if(arg.errno) O = "Error number " + arg.errno; | ||||
| 				else O = "Error " + String(arg); | ||||
| 				break; | ||||
| 
 | ||||
| 			/* JS-specific conversions (extension) */ | ||||
| 			case /*J*/  74: O = (alt ? u_inspect : JSON.stringify)(arg); break; | ||||
| 			case /*V*/  86: O = String(arg.valueOf()); break; | ||||
| 			case /*T*/  84: | ||||
| 				if(alt) { /* from '[object %s]' extract %s */ | ||||
| 					O = Object.prototype.toString.call(arg).substr(8); | ||||
| 					O = O.substr(0, O.length - 1); | ||||
| 				} else O = typeof arg; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* boolean (extension) */ | ||||
| 			case /*Y*/  89: | ||||
| 			case /*y*/ 121: | ||||
| 				O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false"); | ||||
| 				if(c == /*Y*/ 89) O = O.toUpperCase(); | ||||
| 				PREC_STR(O, prec) | ||||
| 				WIDTH(O, width, flags) | ||||
| 				break; | ||||
							
								
								
									
										39
									
								
								bits/55_bytelen.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										39
									
								
								bits/55_bytelen.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| #define SETBYTES(n) { bytes = n; } | ||||
| #define SETBYTESC(n) { if(bytes == SIZEOF_INT) bytes = n; } | ||||
| 			switch(len) { | ||||
| 				/* char */ | ||||
| 				case "hh": SETBYTES(SIZEOF_CHAR) break; | ||||
| 				/* short */ | ||||
| 				case "h":  SETBYTES(SIZEOF_SHORT) break; | ||||
| 
 | ||||
| 				/* long */ | ||||
| 				case "l":  SETBYTESC(SIZEOF_LONG) break; | ||||
| 
 | ||||
| 				/* long long */ | ||||
| 				case "L": | ||||
| 				case "q": | ||||
| 				case "ll": SETBYTESC(SIZEOF_LONG_LONG) break; | ||||
| 
 | ||||
| 				/* intmax_t */ | ||||
| 				case "j":  SETBYTESC(SIZEOF_INTMAX_T) break; | ||||
| 
 | ||||
| 				/* ptrdiff_t */ | ||||
| 				case "t":  SETBYTESC(SIZEOF_PTRDIFF_T) break; | ||||
| 
 | ||||
| 				/* size_t */ | ||||
| 				case "z": | ||||
| 				case "Z":  SETBYTESC(SIZEOF_SIZE_T) break; | ||||
| 
 | ||||
| 				/* CRT size_t or ptrdiff_t */ | ||||
| 				case "I": | ||||
| #if SIZEOF_PTRDIFF_T == SIZEOF_SIZE_T | ||||
| 					SETBYTESC(SIZEOF_SIZE_T) | ||||
| #else | ||||
| 					if(sign) SETBYTESC(SIZEOF_PTRDIFF_T) | ||||
| 					else SETBYTESC(SIZEOF_SIZE_T) | ||||
| #endif | ||||
| 					break; | ||||
| 
 | ||||
| 				/* CRT wchar_t */ | ||||
| 				case "w": break; | ||||
| 			} | ||||
							
								
								
									
										87
									
								
								bits/60_integer.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										87
									
								
								bits/60_integer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| 			Vnum = Number(arg); | ||||
| 
 | ||||
| 			/* parse byte length field */ | ||||
| #include "55_bytelen.js" | ||||
| 
 | ||||
| 			/* restrict value */ | ||||
| #define _DOIT(msk, max) Vnum = (Vnum & msk); if(sign && (Vnum > max)) Vnum -= (msk + 1) | ||||
| 			switch(bytes) { | ||||
| 				case 1: _DOIT(0xFF, 0x7F); break; | ||||
| 				case 2: _DOIT(0xFFFF, 0x7FFF); break; | ||||
| 				case 4: Vnum = sign ? (Vnum | 0) : (Vnum >>> 0); break; | ||||
| 				default: Vnum = Math.round(Vnum); break; | ||||
| 			} | ||||
| #undef _DOIT | ||||
| 
 | ||||
| 			/* generate string */ | ||||
| 			if(bytes > 4 && Vnum < 0 && !sign) { | ||||
| 				if(radix == 16 || radix == -16) { | ||||
| 					O = (Vnum>>>0).toString(16); | ||||
| 					Vnum = Math.floor((Vnum - (Vnum >>> 0)) / Math.pow(2,32)); | ||||
| 					O = (Vnum>>>0).toString(16) + PADS(8 - O.length, "0") + O; | ||||
| 					O = PADS(16 - O.length, "f") + O; | ||||
| 					if(radix == 16) O = O.toUpperCase(); | ||||
| 				} else if(radix == 8) { | ||||
| 					O = (Vnum>>>0).toString(8); | ||||
| 					O = PADS(10 - O.length, "0") + O; | ||||
| 					Vnum = Math.floor((Vnum - ((Vnum >>> 0)&0x3FFFFFFF)) / Math.pow(2,30)); | ||||
| 					O = (Vnum>>>0).toString(8) + O.substr(O.length - 10); | ||||
| 					O = O.substr(O.length - 20); | ||||
| 					O = "1" + PADS(21 - O.length, "7") + O; | ||||
| 				} else { | ||||
| 					Vnum = (-Vnum) % 1e16; | ||||
| 					var d1/*:Array<number>*/ = [1,8,4,4,6,7,4,4,0,7,3,7,0,9,5,5,1,6,1,6]; | ||||
| 					var di = d1.length - 1; | ||||
| 					while(Vnum > 0) { | ||||
| 						if((d1[di] -= (Vnum % 10)) < 0) { d1[di] += 10; d1[di-1]--; } | ||||
| 						--di; Vnum = Math.floor(Vnum / 10); | ||||
| 					} | ||||
| 					O = d1.join(""); | ||||
| 				} | ||||
| 			} else { | ||||
| 				if(radix === -16) O = Vnum.toString(16).toLowerCase(); | ||||
| 				else if(radix === 16) O = Vnum.toString(16).toUpperCase(); | ||||
| 				else O = Vnum.toString(radix); | ||||
| 			} | ||||
| 
 | ||||
| 			/* apply precision */ | ||||
| 			if(prec ===0 && O == "0" && !(radix == 8 && alt)) O = ""; /* bail out */ | ||||
| 			else { | ||||
| 				if(O.length < prec + (O.substr(0,1) == "-" ? 1 : 0)) { | ||||
| 					if(O.substr(0,1) != "-") O = PADS(prec - O.length, "0") + O; | ||||
| 					else O = O.substr(0,1) + PADS(prec + 1 - O.length, "0") + O.substr(1); | ||||
| 				} | ||||
| 
 | ||||
| 				/* add prefix for # form */ | ||||
| 				if(!sign && alt && Vnum !== 0) switch(radix) { | ||||
| 					case -16: O = "0x" + O; break; | ||||
| 					case  16: O = "0X" + O; break; | ||||
| 					case   8: if(O.charAt(0) != "0") O =  "0" + O; break; | ||||
| 					case   2: O = "0b" + O; break; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			/* add sign character */ | ||||
| 			if(sign && O.charAt(0) != "-") { | ||||
| 				if(flags.indexOf("+") > -1) O = "+" + O; | ||||
| 				else if(flags.indexOf(" ") > -1) O = " " + O; | ||||
| 			} | ||||
| 			/* width */ | ||||
| 			if(width > 0) { | ||||
| 				if(O.length < width) { | ||||
| 					if(flags.indexOf("-") > -1) { | ||||
| 						O = O + PADS((width - O.length), " "); | ||||
| 					} else if(flags.indexOf("0") > -1 && prec < 0 && O.length > 0) { | ||||
| 						if(prec > O.length) O = PADS((prec - O.length), "0") + O; | ||||
| 						pad = PADS((width - O.length), (prec > 0 ? " " : "0")); | ||||
| 						if(O.charCodeAt(0) < 48) { | ||||
| 							if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3); | ||||
| 							else O = O.substr(0,1) + pad + O.substring(1); | ||||
| 						} | ||||
| 						else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2); | ||||
| 						else O = pad + O; | ||||
| 					} else { | ||||
| 						O = PADS((width - O.length), " ") + O; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
							
								
								
									
										137
									
								
								bits/70_float.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										137
									
								
								bits/70_float.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,137 @@ | ||||
| 			Vnum = Number(arg); | ||||
| 			if(len == "L") bytes = 12; | ||||
| 			var isf = isFinite(Vnum); | ||||
| 			if(!isf) { /* Infinity or NaN */ | ||||
| 				if(Vnum < 0) O = "-"; | ||||
| 				else if(flags.indexOf("+") > -1) O = "+"; | ||||
| 				else if(flags.indexOf(" ") > -1) O = " "; | ||||
| 				O += (isnan(Vnum)) ? "nan" : "inf"; | ||||
| 			} else { | ||||
| 				var E/*:number*/ = 0; | ||||
| 
 | ||||
| 				if(prec == -1 && isnum != 4) prec = 6; | ||||
| 
 | ||||
| 				/* g/G conditional behavior */ | ||||
| 				if(isnum == 3) { | ||||
| 					O = Vnum.toExponential(1); | ||||
| 					E = +O.substr(O.indexOf("e") + 1); | ||||
| 					if(prec === 0) prec = 1; | ||||
| 					if(prec > E && E >= -4) { NUM(11); prec = prec -(E + 1); } | ||||
| 					else { NUM(12); prec = prec - 1; } | ||||
| 				} | ||||
| 
 | ||||
| 				/* sign: workaround for negative zero */ | ||||
| 				var sg/*:string*/ = (Vnum < 0 || 1/Vnum == -Infinity) ? "-" : ""; | ||||
| 				if(Vnum < 0) Vnum = -Vnum; | ||||
| 
 | ||||
| 				switch(isnum) { | ||||
| 					/* f/F standard */ | ||||
| 					case 1: case 11: | ||||
| 						if(Vnum < Math.pow(10,21)) { | ||||
| 							O = Vnum.toFixed(prec); | ||||
| 							if(isnum == 1) { if(prec===0 &&alt&& O.indexOf(".")==-1) O+="."; } | ||||
| 							else if(!alt) O=O.replace(/(\.\d*[1-9])0*$/,"$1").replace(/\.0*$/,""); | ||||
| 							else if(O.indexOf(".") == -1) O+= "."; | ||||
| 							break; | ||||
| 						} | ||||
| 						O = Vnum.toExponential(20); | ||||
| 						E = +O.substr(O.indexOf("e")+1); | ||||
| 						O = O.charAt(0) + O.substr(2,O.indexOf("e")-2); | ||||
| 						O = O + PADS(E - O.length + 1, "0"); | ||||
| 						if(alt || (prec > 0 && isnum !== 11)) O = O + "." + PADS(prec, "0"); | ||||
| 						break; | ||||
| 
 | ||||
| 					/* e/E exponential */ | ||||
| 					case 2: case 12: | ||||
| 						O = Vnum.toExponential(prec); | ||||
| 						E = O.indexOf("e"); | ||||
| 						if(O.length - E === 3) O = O.substr(0, E+2) + "0" + O.substr(E+2); | ||||
| 						if(alt && O.indexOf(".") == -1) O = O.substr(0,E) +"."+ O.substr(E); | ||||
| 						else if(!alt && isnum == 12) O = O.replace(/\.0*e/, "e").replace(/\.(\d*[1-9])0*e/, ".$1e"); | ||||
| 						break; | ||||
| 
 | ||||
| 					/* a/A hex */ | ||||
| 					case 4: | ||||
| 						if(Vnum===0){O= "0x0"+((alt||prec>0)?"."+PADS(prec,"0"):"")+"p+0"; break;} | ||||
| 						O = Vnum.toString(16); | ||||
| 						/* First char 0-9 */ | ||||
| 						var ac/*:number*/ = O.charCodeAt(0); | ||||
| 						if(ac == 48) { | ||||
| 							ac = 2; E = -4; Vnum *= 16; | ||||
| 							while(O.charCodeAt(ac++) == 48) { E -= 4; Vnum *= 16; } | ||||
| 							O = Vnum.toString(16); | ||||
| 							ac = O.charCodeAt(0); | ||||
| 						} | ||||
| 
 | ||||
| 						var ai/*:number*/ = O.indexOf("."); | ||||
| 						if(O.indexOf("(") > -1) { | ||||
| 							/* IE exponential form */ | ||||
| 							var am/*:?Array<any>*/ = O.match(/\(e(.*)\)/); | ||||
| 							var ae/*:number*/ = am ? (+am[1]) : 0; | ||||
| 							E += 4 * ae; Vnum /= Math.pow(16, ae); | ||||
| 						} else if(ai > 1) { | ||||
| 							E += 4 * (ai - 1); Vnum /= Math.pow(16, ai - 1); | ||||
| 						} else if(ai == -1) { | ||||
| 							E += 4 * (O.length - 1); Vnum /= Math.pow(16, O.length - 1); | ||||
| 						} | ||||
| 
 | ||||
| 						/* at this point 1 <= Vnum < 16 */ | ||||
| #ifndef DO_NOT_NORMALIZE | ||||
| 						if(bytes > 8) { | ||||
| 							if(ac < 50) { E -= 3; Vnum *= 8; } | ||||
| 							else if(ac < 52) { E -= 2; Vnum *= 4; } | ||||
| 							else if(ac < 56) { E -= 1; Vnum *= 2; } | ||||
| 							/* at this point 8 <= Vnum < 16 */ | ||||
| 						} else { | ||||
| 							if(ac >= 56) { E += 3; Vnum /= 8; } | ||||
| 							else if(ac >= 52) { E += 2; Vnum /= 4; } | ||||
| 							else if(ac >= 50) { E += 1; Vnum /= 2; } | ||||
| 							/* at this point 1 <= Vnum < 2 */ | ||||
| 						} | ||||
| #endif | ||||
| 
 | ||||
| 						O = Vnum.toString(16); | ||||
| 						if(O.length > 1) { | ||||
| 							if(O.length > prec+2 && O.charCodeAt(prec+2) >= 56) { | ||||
| 								var _f = O.charCodeAt(0) == 102; | ||||
| 								O = (Vnum + 8 * Math.pow(16, -prec-1)).toString(16); | ||||
| 								if(_f && O.charCodeAt(0) == 49) E += 4; | ||||
| 							} | ||||
| 							if(prec > 0) { | ||||
| 								O = O.substr(0, prec + 2); | ||||
| 								if(O.length < prec + 2) { | ||||
| 									if(O.charCodeAt(0) < 48) O = O.charAt(0) + PADS((prec + 2 - O.length), "0") + O.substr(1); | ||||
| 									else O += PADS((prec + 2 - O.length), "0"); | ||||
| 								} | ||||
| 							} else if(prec === 0) O = O.charAt(0) + (alt ? "." : ""); | ||||
| 						} else if(prec > 0) O = O + "." + PADS(prec,"0"); | ||||
| 						else if(alt) O = O + "."; | ||||
| 						O = "0x" + O + "p" + (E>=0 ? "+" + E : E); | ||||
| 						break; | ||||
| 				} | ||||
| 
 | ||||
| 				if(sg === "") { | ||||
| 					if(flags.indexOf("+") > -1) sg = "+"; | ||||
| 					else if(flags.indexOf(" ") > -1) sg = " "; | ||||
| 				} | ||||
| 
 | ||||
| 				O = sg + O; | ||||
| 			} | ||||
| 
 | ||||
| 			/* width */ | ||||
| 			if(width > O.length) { | ||||
| 				if(flags.indexOf("-") > -1) { | ||||
| 					O = O + PADS((width - O.length), " "); | ||||
| 				} else if(flags.indexOf("0") > -1 && O.length > 0 && isf) { | ||||
| 					pad = PADS((width - O.length), "0"); | ||||
| 					if(O.charCodeAt(0) < 48) { | ||||
| 						if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3); | ||||
| 						else O = O.substr(0,1) + pad + O.substring(1); | ||||
| 					} | ||||
| 					else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2); | ||||
| 					else O = pad + O; | ||||
| 				} else { | ||||
| 					O = PADS((width - O.length), " ") + O; | ||||
| 				} | ||||
| 			} | ||||
| 			if(c < 96) O = O.toUpperCase(); | ||||
							
								
								
									
										8
									
								
								bits/80_wrapper.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								bits/80_wrapper.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| function vsprintf(fmt/*:string*/, args/*:Array<any>*/) { return doit(tokenize(fmt), args); } | ||||
| 
 | ||||
| //function sprintf() { return doit(tokenize(arguments[0]), Array.prototype.slice.call(arguments, 1)); }
 | ||||
| function sprintf()/*:string*/ { | ||||
| 	var args/*:Array<any>*/ = new Array(arguments.length - 1); | ||||
| 	for(var i = 0; i < args.length; ++i) args[i] = arguments[i+1]; | ||||
| 	return doit(tokenize(arguments[0]), args); | ||||
| } | ||||
							
								
								
									
										4
									
								
								bits/90_exports.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										4
									
								
								bits/90_exports.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| PRINTJ.sprintf = sprintf; | ||||
| PRINTJ.vsprintf = vsprintf; | ||||
| PRINTJ._doit = doit; | ||||
| PRINTJ._tokenize = tokenize; | ||||
							
								
								
									
										2
									
								
								bits/99_footer.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								bits/99_footer.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| #include "90_exports.js" | ||||
| })); | ||||
							
								
								
									
										24
									
								
								bits/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										24
									
								
								bits/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| ifndef OUTDIR | ||||
| 	OUTDIR=$(PWD)/lib | ||||
| endif | ||||
| 
 | ||||
| JSFILES=$(wildcard *.js) | ||||
| LIBS=$(filter-out $(wildcard [0-9]*_*.js),$(wildcard *.js)) | ||||
| 
 | ||||
| OUTLIBS=$(patsubst %,$(OUTDIR)/%,$(LIBS)) | ||||
| 
 | ||||
| CPPFLAGS=-P -C -Wno-invalid-pp-token -fdollars-in-identifiers -nostdinc -Wundef -undef $(JSFLAGS) | ||||
| 
 | ||||
| .PHONY: lib | ||||
| lib: init $(JSFILES) | ||||
| 	for i in $(LIBS); do cpp $(CPPFLAGS) $$i | uniq > $(OUTDIR)/$$i; done | ||||
| 
 | ||||
| .PHONY: init | ||||
| init: 30_ctypes.js | ||||
| 
 | ||||
| 30_ctypes.js: 30_ctypes.njs | ||||
| 	node 30_ctypes.njs > 30_ctypes.js | ||||
| 
 | ||||
| .PHONY: clean | ||||
| clean: | ||||
| 	rm $(OUTLIBS) 30_ctypes.js | ||||
							
								
								
									
										8
									
								
								bits/ctypes.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								bits/ctypes.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| { | ||||
| 	"ModelNames":["LP64", "ILP32", "LLP64"], | ||||
| 	"Models": { | ||||
| 		"LP64":  { "char":1, "short":2, "int":4, "long":8, "longlong":8, "wint_t":4, "wchar_t":4, "size_t":8, "intmax_t":8, "ptrdiff_t":8 }, | ||||
| 		"ILP32": { "char":1, "short":2, "int":4, "long":4, "longlong":8, "wint_t":4, "wchar_t":4, "size_t":4, "intmax_t":8, "ptrdiff_t":4 }, | ||||
| 		"LLP64": { "char":1, "short":2, "int":4, "long":4, "longlong":8, "wint_t":2, "wchar_t":2, "size_t":8, "intmax_t":8, "ptrdiff_t":8 } | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										11
									
								
								bits/flow.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										11
									
								
								bits/flow.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| /*:: | ||||
| type ParsedFmt = Array<Array<any>>; | ||||
| type Args = Array<any>; | ||||
| declare module "exit-on-epipe" { }; | ||||
| declare module "./" { | ||||
| 	declare function sprintf(fmt:string, ...args:any):string; | ||||
| 	declare function vsprintf(fmt:string, args:Args):string; | ||||
| 	declare function _doit(t:ParsedFmt, args:Args):string; | ||||
| 	declare function _tokenize(fmt:string):ParsedFmt; | ||||
| }; | ||||
| */ | ||||
							
								
								
									
										7
									
								
								bits/index_char.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								bits/index_char.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "00_header.js" | ||||
| #define USE_INDEX | ||||
| #define USE_CHAR | ||||
| #include "10_tokenize.js" | ||||
| #include "50_doit.js" | ||||
| #include "80_wrapper.js" | ||||
| #include "99_footer.js" | ||||
							
								
								
									
										7
									
								
								bits/index_code.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								bits/index_code.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "00_header.js" | ||||
| #define USE_INDEX | ||||
| #define USE_CODE | ||||
| #include "10_tokenize.js" | ||||
| #include "50_doit.js" | ||||
| #include "80_wrapper.js" | ||||
| #include "99_footer.js" | ||||
							
								
								
									
										7
									
								
								bits/loop_char.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								bits/loop_char.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "00_header.js" | ||||
| #define USE_LOOP | ||||
| #define USE_CHAR | ||||
| #include "10_tokenize.js" | ||||
| #include "50_doit.js" | ||||
| #include "80_wrapper.js" | ||||
| #include "99_footer.js" | ||||
							
								
								
									
										7
									
								
								bits/loop_code.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								bits/loop_code.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "00_header.js" | ||||
| #define USE_LOOP | ||||
| #define USE_CODE | ||||
| #include "10_tokenize.js" | ||||
| #include "50_doit.js" | ||||
| #include "80_wrapper.js" | ||||
| #include "99_footer.js" | ||||
							
								
								
									
										7
									
								
								bits/regex.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								bits/regex.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| #include "00_header.js" | ||||
| #include "12_regexp.js" | ||||
| #define USE_REGEX | ||||
| #include "10_tokenize.js" | ||||
| #include "50_doit.js" | ||||
| #include "80_wrapper.js" | ||||
| #include "99_footer.js" | ||||
							
								
								
									
										70
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										70
									
								
								index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,70 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- printj.js (C) 2016-present SheetJS http://sheetjs.com --> | ||||
| <!-- vim: set ts=2: --> | ||||
| <html> | ||||
| <head> | ||||
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||
| <title>PRINTJ Live Demo</title> | ||||
| <style> | ||||
| table, td { | ||||
| 	border: 1px dotted black; | ||||
| 	text-align: left; | ||||
| } | ||||
| </style> | ||||
| </head> | ||||
| <body> | ||||
| <b>PRINTJ Live Demo</b><br /> | ||||
| <a href="https://git.io/printj">Source Code Repo</a><br /> | ||||
| <a href="https://git.io/printj_issues">Issues?  Something look weird?  Click here and report an issue</a><br /> | ||||
| <br /> | ||||
| <pre> | ||||
| usage: var printf = PRINTJ.sprintf; | ||||
| 
 | ||||
| This implementation supports the full POSIX set of conversions.  Consult the enclosed README for full details. | ||||
| </pre> | ||||
| <div><a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html">POSIX documentation</a></div><br /> | ||||
| <table id="data"> | ||||
| <tr><th>example</th><th>result</th></tr> | ||||
| </table> | ||||
| <script type="text/javascript">/* jshint browser:true, evil:true */</script> | ||||
| <script src="printj.js"></script> | ||||
| <script type="text/javascript"> | ||||
| var table = document.getElementById("data"); | ||||
| var ex = [ | ||||
| 	'printf("|Hello %s|", "SheetJS")', | ||||
| 	'printf("|%1$d %1$o %1$u %1$x %1$X|", 1234)', | ||||
| 	'printf("|%1$d %1$o %1$u %1$x %1$X|", -1234)', | ||||
| 	'printf("|%1$d %1$o %1$u %1$x %1$X %1$lld|", 2813308004)', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", 1.2)', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", Math.PI)', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", Math.LOG2E)', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", -Math.LOG10E)', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", Infinity)', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", -0)', | ||||
| 	'printf("|%012s|", "SheetJS")', | ||||
| 	'printf("|%-12s|", "SheetJS")', | ||||
| 	'printf("|%1$f %1$F %1$e %1$E %1$g %1$G %1$a %1$A|", 1.4142E69)', | ||||
| 	'printf("%%")' | ||||
| ]; | ||||
| window.onload = function() { | ||||
| 	var printf = PRINTJ.sprintf; | ||||
| 	ex.forEach(function(m) { | ||||
| 		var row = table.insertRow(table.rows.length); | ||||
| 		var c1 = row.insertCell(0); c1.innerHTML = "<pre>" + m + "</pre>"; | ||||
| 		var c2 = row.insertCell(1); c2.innerHTML = "<pre>" + eval(m) + "</pre>"; | ||||
| 	}); | ||||
| }; | ||||
| </script> | ||||
| <script type="text/javascript"> | ||||
| 	var _gaq = _gaq || []; | ||||
| 	_gaq.push(['_setAccount', 'UA-36810333-1']); | ||||
| 	_gaq.push(['_trackPageview']); | ||||
| 
 | ||||
| 	(function() { | ||||
| 		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | ||||
| 		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | ||||
| 		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | ||||
| 	})(); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										6
									
								
								lib/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										6
									
								
								lib/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| flow.js | ||||
| index_char.js | ||||
| index_code.js | ||||
| loop_char.js | ||||
| loop_code.js | ||||
| regex.js | ||||
							
								
								
									
										5
									
								
								lib/impl.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								lib/impl.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| [ | ||||
| 	"loop_char", | ||||
| 	"loop_code", | ||||
| 	"regex" | ||||
| ] | ||||
							
								
								
									
										42
									
								
								misc/help.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										42
									
								
								misc/help.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,42 @@ | ||||
| #!/bin/bash | ||||
| # make_help.sh -- process listing of targets and special items in Makefile | ||||
| # Copyright (C) 2016-present  SheetJS | ||||
| # | ||||
| # usage in makefile: pipe the output of the following command: | ||||
| #     @grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | ||||
| # | ||||
| # lines starting with "## " are treated as subtitles | ||||
| # lines starting with "#* " are treated as plaintext comments | ||||
| # multiple targets with "## " after the ":" are rendered as separate targets | ||||
| # if the presumed default target is labeled, it will be assigned a unique color | ||||
| 
 | ||||
| awk ' | ||||
| BEGIN{recipes=0;} | ||||
| 	!/#[#*] .*$/ {next;} | ||||
| 	{multi=0; isrecipe=0;} | ||||
| 	/^[^#]*:/ {isrecipe=1; ++recipes;} | ||||
| 	/^[^ :]* .*:/ {multi=1} | ||||
| 	multi==0 && isrecipe>0 { if(recipes > 1) print; else print $0, "[default]"; next} | ||||
| 	isrecipe == 0 {print; next} | ||||
| 	multi>0 { | ||||
| 		k=split($0, msg, "##"); m=split($0, a, ":"); n=split(a[1], b, " "); | ||||
| 		for(i=1; i<=n; ++i) print b[i] ":", "##" msg[2], (recipes==1 && i==1 ? "[default]" : "") | ||||
| 	} | ||||
| END {} | ||||
| ' | if [[ -t 1 ]]; then | ||||
| awk ' | ||||
| BEGIN {FS = ":.*?## "} | ||||
| 	{color=36} | ||||
| 	/\[default\]/ {color=35} | ||||
| 	NF==1 && /^##/ {color=34} | ||||
| 	NF==1 && /^#\*/ {color=20; $1 = substr($1, 4)} | ||||
| 	{printf "\033[" color "m%-20s\033[0m %s\n", $1, $2;} | ||||
| END{}' - | ||||
| else | ||||
| awk ' | ||||
| BEGIN {FS = ":.*?## "} | ||||
| 	/^#\* / {$1 = substr($1, 4)} | ||||
| 	{printf "%-20s %s\n", $1, $2;} | ||||
| END{}' - | ||||
| fi | ||||
| 
 | ||||
							
								
								
									
										14
									
								
								misc/spin.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										14
									
								
								misc/spin.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #!/bin/bash | ||||
| # spin.sh -- show a spinner (for coverage test) | ||||
| # Copyright (C) 2014-present  SheetJS | ||||
| 
 | ||||
| wpid=$1 | ||||
| delay=1 | ||||
| str="|/-\\" | ||||
| while [ $(ps -a|awk '$1=='$wpid' {print $1}') ]; do | ||||
|   t=${str#?} | ||||
|   printf " [%c]" "$str" | ||||
|   str=$t${str%"$t"} | ||||
|   sleep $delay | ||||
|   printf "\b\b\b\b" | ||||
| done | ||||
							
								
								
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										29
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| { | ||||
| 	"name": "printj", | ||||
| 	"version": "0.1.0", | ||||
| 	"author": "sheetjs", | ||||
| 	"description": "Pure-JS printf", | ||||
| 	"keywords": [ "printf", "sprintf", "format", "string" ], | ||||
| 	"bin": { | ||||
| 		"printj": "./bin/printj.njs" | ||||
| 	}, | ||||
| 	"main": "./printj", | ||||
| 	"dependencies": { | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"mocha":"" | ||||
| 	}, | ||||
| 	"repository": { "type":"git", "url":"git://github.com/SheetJS/printj.git" }, | ||||
| 	"scripts": { | ||||
| 		"test": "make test" | ||||
| 	}, | ||||
| 	"config": { | ||||
| 		"blanket": { | ||||
| 			"pattern": "printj.js" | ||||
| 		} | ||||
| 	}, | ||||
| 	"files": ["printj.js", "bin/printj.njs", "LICENSE", "README.md"], | ||||
| 	"bugs": { "url": "https://github.com/SheetJS/printj/issues" }, | ||||
| 	"license": "Apache-2.0", | ||||
| 	"engines": { "node": ">=0.8" } | ||||
| } | ||||
							
								
								
									
										605
									
								
								printj.flow.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										605
									
								
								printj.flow.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,605 @@ | ||||
| 
 | ||||
| /* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint sub:true, eqnull:true */ | ||||
| /*exported PRINTJ */ | ||||
| /*:: declare var DO_NOT_EXPORT_PRINTJ: any; */ | ||||
| /*:: declare var define: any; */ | ||||
| var PRINTJ/*:any*/; | ||||
| (function (factory/*:(a:any)=>void*/)/*:void*/ { | ||||
| 	/*jshint ignore:start */ | ||||
| 	if(typeof DO_NOT_EXPORT_PRINTJ === 'undefined') { | ||||
| 		if('object' === typeof exports) { | ||||
| 			factory(exports); | ||||
| 		} else if ('function' === typeof define && define.amd) { | ||||
| 			define(function () { | ||||
| 				var module/*:any*/ = {}; | ||||
| 				factory(module); | ||||
| 				return module; | ||||
| 			}); | ||||
| 		} else { | ||||
| 			factory(PRINTJ = {}); | ||||
| 		} | ||||
| 	} else { | ||||
| 		factory(PRINTJ = {}); | ||||
| 	} | ||||
| 	/*jshint ignore:end */ | ||||
| }(function(PRINTJ) { | ||||
| 
 | ||||
| PRINTJ.version = '0.1.0'; | ||||
| 
 | ||||
| function tokenize(fmt/*:string*/)/*:ParsedFmt*/ { | ||||
| 	var out/*:ParsedFmt*/ = []; | ||||
| 	var start/*:number*/ = 0; | ||||
| 
 | ||||
| 	var i/*:number*/ = 0; | ||||
| 	var infmt/*:boolean*/ = false; | ||||
| 	var fmtparam/*:string*/ = "", fmtflags/*:string*/ = "", fmtwidth/*:string*/ = "", fmtprec/*:string*/ = "", fmtlen/*:string*/ = ""; | ||||
| 
 | ||||
| 	var c/*:number*/ = 0; | ||||
| 
 | ||||
| 	var L/*:number*/ = fmt.length; | ||||
| 
 | ||||
| 	for(; i < L; ++i) { | ||||
| 		c = fmt.charCodeAt(i); | ||||
| 		if(!infmt) { | ||||
| 
 | ||||
| 			if(c !== 37) continue; | ||||
| 
 | ||||
| 			if(start < i) out.push(["L", fmt.substring(start, i)]); | ||||
| 			start = i; | ||||
| 			infmt = true; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if(c >= 48 && c < 58)	{ | ||||
| 				if(fmtprec.length) fmtprec += String.fromCharCode(c); | ||||
| 				else if(c == 48 && !fmtwidth.length) fmtflags += String.fromCharCode(c); | ||||
| 				else fmtwidth += String.fromCharCode(c); | ||||
| 		} else switch(c) { | ||||
| 			/* positional */ | ||||
| 			case 36: | ||||
| 				if(fmtprec.length) fmtprec += "$"; | ||||
| 				else if(fmtwidth.charAt(0) == "*") fmtwidth += "$"; | ||||
| 				else { fmtparam = fmtwidth + "$"; fmtwidth = ""; } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* flags */ | ||||
| 			case 39: fmtflags += "'"; break; | ||||
| 			case 45: fmtflags += "-"; break; | ||||
| 			case 43: fmtflags += "+"; break; | ||||
| 			case 32: fmtflags += " "; break; | ||||
| 			case 35: fmtflags += "#"; break; | ||||
| 
 | ||||
| 			/* width and precision */ | ||||
| 			case 46: fmtprec = "."; break; | ||||
| 			case 42: | ||||
| 				if(fmtprec.charAt(0) == ".") fmtprec += "*"; | ||||
| 				else fmtwidth += "*"; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* length */ | ||||
| 			case 104: | ||||
| 			case 108: | ||||
| 				if(fmtlen.length > 1) throw "bad length " + fmtlen + String(c); | ||||
| 				fmtlen += String.fromCharCode(c); | ||||
| 				break; | ||||
| 
 | ||||
| 			case  76: | ||||
| 			case 106: | ||||
| 			case 122: | ||||
| 			case 116: | ||||
| 			case 113: | ||||
| 			case  90: | ||||
| 			case 119: | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + String.fromCharCode(c); | ||||
| 				fmtlen = String.fromCharCode(c); | ||||
| 				break; | ||||
| 
 | ||||
| 			case 73: | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + 'I'; | ||||
| 				fmtlen = 'I'; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* conversion */ | ||||
| 			case 100: | ||||
| 			case 105: | ||||
| 			case 111: | ||||
| 			case 117: | ||||
| 			case 120: | ||||
| 			case 88: | ||||
| 			case 102: | ||||
| 			case 70: | ||||
| 			case 101: | ||||
| 			case 69: | ||||
| 			case 103: | ||||
| 			case 71: | ||||
| 			case 97: | ||||
| 			case 65: | ||||
| 			case 99: | ||||
| 			case 67: | ||||
| 			case 115: | ||||
| 			case 83: | ||||
| 			case 112: | ||||
| 			case 110: | ||||
| 			case 68: | ||||
| 			case 85: | ||||
| 			case 79: | ||||
| 			case 109: | ||||
| 			case 98: | ||||
| 			case 66: | ||||
| 			case 121: | ||||
| 			case 89: | ||||
| 			case 74: | ||||
| 			case 86: | ||||
| 			case 84: | ||||
| 			case 37: | ||||
| 				infmt = false; | ||||
| 				if(fmtprec.length > 1) fmtprec = fmtprec.substr(1); | ||||
| 				out.push([String.fromCharCode(c), fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]); | ||||
| 				start = i+1; | ||||
| 				fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = ""; | ||||
| 				break; | ||||
| 			default: | ||||
| 				throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|"); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	if(start < fmt.length) out.push(["L", fmt.substring(start)]); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| //#define PAD_(x,c) (x >= 0 ? new Array(((x)|0) + 1).join((c)) : "")
 | ||||
| var padstr = { | ||||
| 	" ": "                                 ", | ||||
| 	"0": "000000000000000000000000000000000", | ||||
| 	"7": "777777777777777777777777777777777", | ||||
| 	"f": "fffffffffffffffffffffffffffffffff" | ||||
| }; | ||||
| 
 | ||||
| /*:: declare var util:any; */ | ||||
| /*:: declare var require: any; */ | ||||
| if(typeof util=='undefined' && typeof require!=='undefined')util=require("util"); | ||||
| var u_inspect/*:(o:any)=>string*/ = (typeof util != 'undefined') ? util.inspect : JSON.stringify; | ||||
| 
 | ||||
| function doit(t/*:ParsedFmt*/, args/*:Array<any>*/)/*:string*/ { | ||||
| 	var o/*:Array<string>*/ = []; | ||||
| 	var argidx/*:number*/ = 0, idx/*:number*/ = 0; | ||||
| 	var Vnum/*:number*/ = 0; | ||||
| 	var pad/*:string*/ = ""; | ||||
| 	for(var i = 0; i < t.length; ++i) { | ||||
| 		var m/*:Array<any>*/ = t[i], c/*:number*/ = (m[0]/*:string*/).charCodeAt(0); | ||||
| 		/* m order: conv full param flags width prec length */ | ||||
| 
 | ||||
| 		if(c === /*L*/ 76) { o.push(m[1]); continue; } | ||||
| 		if(c === /*%*/ 37) { o.push("%"); continue; } | ||||
| 
 | ||||
| 		var O/*:string*/ = ""; | ||||
| 		var isnum/*:number*/ = 0, radix/*:number*/ = 10, bytes/*:number*/ = 4, sign/*:boolean*/ = false; | ||||
| 
 | ||||
| 		/* flags */ | ||||
| 		var flags/*:string*/ = m[3]||""; | ||||
| 		var alt = flags.indexOf("#") > -1; | ||||
| 
 | ||||
| 		/* position */ | ||||
| 		if(m[2]) argidx = parseInt(m[2])-1; | ||||
| 		/* %m special case */ | ||||
| 		else if(c === /*m*/ 109 && !alt) { o.push("Success"); continue; } | ||||
| 
 | ||||
| 		/* grab width */ | ||||
| 		var width =  0; if(m[ 4] != null && m[ 4].length > 0) { if(m[ 4].charAt(0) !== '*') width = parseInt(m[ 4], 10); else if(m[ 4].length === 1) width = args[idx++]; else width = args[parseInt(m[ 4].substr(1), 10)-1]; } | ||||
| 
 | ||||
| 		/* grab precision */ | ||||
| 		var prec =  -1; if(m[ 5] != null && m[ 5].length > 0) { if(m[ 5].charAt(0) !== '*') prec = parseInt(m[ 5], 10); else if(m[ 5].length === 1) prec = args[idx++]; else prec = args[parseInt(m[ 5].substr(1), 10)-1]; } | ||||
| 
 | ||||
| 		/* position not specified */ | ||||
| 		if(!m[2]) argidx = idx++; | ||||
| 
 | ||||
| 		/* grab argument */ | ||||
| 		var arg/*:any*/ = args[argidx]; | ||||
| 
 | ||||
| 		/* grab length */ | ||||
| 		var len/*:string*/ = m[6] || ""; | ||||
| 
 | ||||
| 		switch(c) { | ||||
| 			/* str cCsS */ | ||||
| 
 | ||||
| 			case /*S*/  83: | ||||
| 			case /*s*/ 115: | ||||
| 				/* only valid flag is "-" for left justification */ | ||||
| 				O = String(arg); | ||||
| 				if( prec >= 0) O = O.substr(0,  prec); | ||||
| 				if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 ||  width < 0) &&  flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O =  flags.indexOf("-") > -1 ? O + pad : pad + O; } } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* first char of string or convert */ | ||||
| 			case /*C*/  67: | ||||
| 			case /*c*/  99: | ||||
| 				switch(typeof arg) { | ||||
| 					case "number": | ||||
| 						var cc/*:number*/ = arg; | ||||
| 						if(c == 67 || len.charCodeAt(0) === /*l*/ 108) {  cc &= 0xFFFFFFFF; O = String.fromCharCode( cc); } | ||||
| 						else  cc &= 0xFF; O = String.fromCharCode( cc); | ||||
| 						break; | ||||
| 					case "string": O = arg.charAt(0); break; | ||||
| 					default: O = String(arg).charAt(0); | ||||
| 				} | ||||
| 				if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 ||  width < 0) &&  flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O =  flags.indexOf("-") > -1 ? O + pad : pad + O; } } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* int diDuUoOxXbB */ | ||||
| 
 | ||||
| 			/* signed integer */ | ||||
| 			case /*D*/  68: bytes = 8; | ||||
| 			/* falls through */ | ||||
| 			case /*d*/ 100: | ||||
| 			case /*i*/ 105: isnum = -1; sign = true; break; | ||||
| 
 | ||||
| 			/* unsigned integer */ | ||||
| 			case /*U*/  85: bytes = 8; | ||||
| 			/* falls through */ | ||||
|  			case /*u*/ 117: isnum = -1; break; | ||||
| 
 | ||||
| 			/* unsigned octal */ | ||||
| 			case /*O*/  79: bytes = 8; | ||||
| 			/* falls through */ | ||||
| 			case /*o*/ 111: isnum = -1; radix = (8); break; | ||||
| 
 | ||||
| 			/* unsigned hex */ | ||||
| 			case /*x*/ 120: isnum = -1; radix = (-16); break; | ||||
| 			case /*X*/  88: isnum = -1; radix = (16); break; | ||||
| 
 | ||||
| 			/* unsigned binary (extension) */ | ||||
| 			case /*B*/  66: bytes = 8; | ||||
| 			/* falls through */ | ||||
| 			case /*b*/  98: isnum = -1; radix = (2); break; | ||||
| 
 | ||||
| 			/* flt fegFEGaA */ | ||||
| 
 | ||||
| 			/* floating point logic */ | ||||
| 			case /*F*/  70: | ||||
| 			case /*f*/ 102: isnum = (1); break; | ||||
| 
 | ||||
| 			case /*E*/  69: | ||||
| 			case /*e*/ 101: isnum = (2); break; | ||||
| 
 | ||||
| 			case /*G*/  71: | ||||
| 			case /*g*/ 103: isnum = (3); break; | ||||
| 
 | ||||
| 			/* floating hex */ | ||||
| 			case /*A*/  65: | ||||
| 			case /*a*/  97: isnum = (4); break; | ||||
| 
 | ||||
| 			/* misc pnmJVTyY */ | ||||
| 
 | ||||
| 			/* JS has no concept of pointers so interpret the `l` key as an address */ | ||||
| 			case /*p*/ 112: | ||||
| 				Vnum = typeof arg == "number" ? arg : Number(arg.l); | ||||
| 				if(isNaN(Vnum)) Vnum = -1; | ||||
| 				if(alt) O = Vnum.toString(10); | ||||
| 				else { | ||||
| 					Vnum = Math.abs(Vnum); | ||||
| 					O = "0x" + Vnum.toString(16).toLowerCase(); | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			/* store length in the `len` key */ | ||||
| 			case /*n*/ 110: | ||||
| 				if(arg) { arg.len=0; for(var oo = 0; oo < o.length; ++oo) arg.len += o[oo].length; } | ||||
| 				continue; | ||||
| 
 | ||||
| 			/* process error */ | ||||
| 			case /*m*/ 109: | ||||
| 				if(!(arg instanceof Error)) O = "Success"; | ||||
| 				else if(arg.message) O = arg.message; | ||||
| 				else if(arg.errno) O = "Error number " + arg.errno; | ||||
| 				else O = "Error " + String(arg); | ||||
| 				break; | ||||
| 
 | ||||
| 			/* JS-specific conversions (extension) */ | ||||
| 			case /*J*/  74: O = (alt ? u_inspect : JSON.stringify)(arg); break; | ||||
| 			case /*V*/  86: O = String(arg.valueOf()); break; | ||||
| 			case /*T*/  84: | ||||
| 				if(alt) { /* from '[object %s]' extract %s */ | ||||
| 					O = Object.prototype.toString.call(arg).substr(8); | ||||
| 					O = O.substr(0, O.length - 1); | ||||
| 				} else O = typeof arg; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* boolean (extension) */ | ||||
| 			case /*Y*/  89: | ||||
| 			case /*y*/ 121: | ||||
| 				O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false"); | ||||
| 				if(c == /*Y*/ 89) O = O.toUpperCase(); | ||||
| 				if( prec >= 0) O = O.substr(0,  prec); | ||||
| 				if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 ||  width < 0) &&  flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O =  flags.indexOf("-") > -1 ? O + pad : pad + O; } } | ||||
| 				break; | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		if(isnum == -1) { | ||||
| 
 | ||||
| 			Vnum = Number(arg); | ||||
| 
 | ||||
| 			/* parse byte length field */ | ||||
| 
 | ||||
| 			switch(len) { | ||||
| 				/* char */ | ||||
| 				case "hh": { bytes = 1; } break; | ||||
| 				/* short */ | ||||
| 				case "h":  { bytes = 2; } break; | ||||
| 
 | ||||
| 				/* long */ | ||||
| 				case "l":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* long long */ | ||||
| 				case "L": | ||||
| 				case "q": | ||||
| 				case "ll": { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* intmax_t */ | ||||
| 				case "j":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* ptrdiff_t */ | ||||
| 				case "t":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* size_t */ | ||||
| 				case "z": | ||||
| 				case "Z":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* CRT size_t or ptrdiff_t */ | ||||
| 				case "I": | ||||
| 
 | ||||
| 					{ if(bytes == 4) bytes = 8; } | ||||
| 
 | ||||
| 					break; | ||||
| 
 | ||||
| 				/* CRT wchar_t */ | ||||
| 				case "w": break; | ||||
| 			} | ||||
| 
 | ||||
| 			/* restrict value */ | ||||
| 
 | ||||
| 			switch(bytes) { | ||||
| 				case 1: Vnum = (Vnum & 0xFF); if(sign && (Vnum >  0x7F)) Vnum -= (0xFF + 1); break; | ||||
| 				case 2: Vnum = (Vnum & 0xFFFF); if(sign && (Vnum >  0x7FFF)) Vnum -= (0xFFFF + 1); break; | ||||
| 				case 4: Vnum = sign ? (Vnum | 0) : (Vnum >>> 0); break; | ||||
| 				default: Vnum = Math.round(Vnum); break; | ||||
| 			} | ||||
| 
 | ||||
| 			/* generate string */ | ||||
| 			if(bytes > 4 && Vnum < 0 && !sign) { | ||||
| 				if(radix == 16 || radix == -16) { | ||||
| 					O = (Vnum>>>0).toString(16); | ||||
| 					Vnum = Math.floor((Vnum - (Vnum >>> 0)) / Math.pow(2,32)); | ||||
| 					O = (Vnum>>>0).toString(16) + (8 - O.length >= 0 ? padstr[ "0"].substr(0,8 - O.length) : "") + O; | ||||
| 					O = (16 - O.length >= 0 ? padstr[ "f"].substr(0,16 - O.length) : "") + O; | ||||
| 					if(radix == 16) O = O.toUpperCase(); | ||||
| 				} else if(radix == 8) { | ||||
| 					O = (Vnum>>>0).toString(8); | ||||
| 					O = (10 - O.length >= 0 ? padstr[ "0"].substr(0,10 - O.length) : "") + O; | ||||
| 					Vnum = Math.floor((Vnum - ((Vnum >>> 0)&0x3FFFFFFF)) / Math.pow(2,30)); | ||||
| 					O = (Vnum>>>0).toString(8) + O.substr(O.length - 10); | ||||
| 					O = O.substr(O.length - 20); | ||||
| 					O = "1" + (21 - O.length >= 0 ? padstr[ "7"].substr(0,21 - O.length) : "") + O; | ||||
| 				} else { | ||||
| 					Vnum = (-Vnum) % 1e16; | ||||
| 					var d1/*:Array<number>*/ = [1,8,4,4,6,7,4,4,0,7,3,7,0,9,5,5,1,6,1,6]; | ||||
| 					var di = d1.length - 1; | ||||
| 					while(Vnum > 0) { | ||||
| 						if((d1[di] -= (Vnum % 10)) < 0) { d1[di] += 10; d1[di-1]--; } | ||||
| 						--di; Vnum = Math.floor(Vnum / 10); | ||||
| 					} | ||||
| 					O = d1.join(""); | ||||
| 				} | ||||
| 			} else { | ||||
| 				if(radix === -16) O = Vnum.toString(16).toLowerCase(); | ||||
| 				else if(radix === 16) O = Vnum.toString(16).toUpperCase(); | ||||
| 				else O = Vnum.toString(radix); | ||||
| 			} | ||||
| 
 | ||||
| 			/* apply precision */ | ||||
| 			if(prec ===0 && O == "0" && !(radix == 8 && alt)) O = ""; /* bail out */ | ||||
| 			else { | ||||
| 				if(O.length < prec + (O.substr(0,1) == "-" ? 1 : 0)) { | ||||
| 					if(O.substr(0,1) != "-") O = (prec - O.length >= 0 ? padstr[ "0"].substr(0,prec - O.length) : "") + O; | ||||
| 					else O = O.substr(0,1) + (prec + 1 - O.length >= 0 ? padstr[ "0"].substr(0,prec + 1 - O.length) : "") + O.substr(1); | ||||
| 				} | ||||
| 
 | ||||
| 				/* add prefix for # form */ | ||||
| 				if(!sign && alt && Vnum !== 0) switch(radix) { | ||||
| 					case -16: O = "0x" + O; break; | ||||
| 					case  16: O = "0X" + O; break; | ||||
| 					case   8: if(O.charAt(0) != "0") O =  "0" + O; break; | ||||
| 					case   2: O = "0b" + O; break; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			/* add sign character */ | ||||
| 			if(sign && O.charAt(0) != "-") { | ||||
| 				if(flags.indexOf("+") > -1) O = "+" + O; | ||||
| 				else if(flags.indexOf(" ") > -1) O = " " + O; | ||||
| 			} | ||||
| 			/* width */ | ||||
| 			if(width > 0) { | ||||
| 				if(O.length < width) { | ||||
| 					if(flags.indexOf("-") > -1) { | ||||
| 						O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : ""); | ||||
| 					} else if(flags.indexOf("0") > -1 && prec < 0 && O.length > 0) { | ||||
| 						if(prec > O.length) O = ((prec - O.length) >= 0 ? padstr[ "0"].substr(0,(prec - O.length)) : "") + O; | ||||
| 						pad = ((width - O.length) >= 0 ? padstr[ (prec > 0 ? " " : "0")].substr(0,(width - O.length)) : ""); | ||||
| 						if(O.charCodeAt(0) < 48) { | ||||
| 							if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3); | ||||
| 							else O = O.substr(0,1) + pad + O.substring(1); | ||||
| 						} | ||||
| 						else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2); | ||||
| 						else O = pad + O; | ||||
| 					} else { | ||||
| 						O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 		} else if(isnum > 0) { | ||||
| 
 | ||||
| 			Vnum = Number(arg); | ||||
| 			if(len == "L") bytes = 12; | ||||
| 			var isf = isFinite(Vnum); | ||||
| 			if(!isf) { /* Infinity or NaN */ | ||||
| 				if(Vnum < 0) O = "-"; | ||||
| 				else if(flags.indexOf("+") > -1) O = "+"; | ||||
| 				else if(flags.indexOf(" ") > -1) O = " "; | ||||
| 				O += (isNaN(Vnum)) ? "nan" : "inf"; | ||||
| 			} else { | ||||
| 				var E/*:number*/ = 0; | ||||
| 
 | ||||
| 				if(prec == -1 && isnum != 4) prec = 6; | ||||
| 
 | ||||
| 				/* g/G conditional behavior */ | ||||
| 				if(isnum == 3) { | ||||
| 					O = Vnum.toExponential(1); | ||||
| 					E = +O.substr(O.indexOf("e") + 1); | ||||
| 					if(prec === 0) prec = 1; | ||||
| 					if(prec > E && E >= -4) { isnum = (11); prec = prec -(E + 1); } | ||||
| 					else { isnum = (12); prec = prec - 1; } | ||||
| 				} | ||||
| 
 | ||||
| 				/* sign: workaround for negative zero */ | ||||
| 				var sg/*:string*/ = (Vnum < 0 || 1/Vnum == -Infinity) ? "-" : ""; | ||||
| 				if(Vnum < 0) Vnum = -Vnum; | ||||
| 
 | ||||
| 				switch(isnum) { | ||||
| 					/* f/F standard */ | ||||
| 					case 1: case 11: | ||||
| 						if(Vnum < Math.pow(10,21)) { | ||||
| 							O = Vnum.toFixed(prec); | ||||
| 							if(isnum == 1) { if(prec===0 &&alt&& O.indexOf(".")==-1) O+="."; } | ||||
| 							else if(!alt) O=O.replace(/(\.\d*[1-9])0*$/,"$1").replace(/\.0*$/,""); | ||||
| 							else if(O.indexOf(".") == -1) O+= "."; | ||||
| 							break; | ||||
| 						} | ||||
| 						O = Vnum.toExponential(20); | ||||
| 						E = +O.substr(O.indexOf("e")+1); | ||||
| 						O = O.charAt(0) + O.substr(2,O.indexOf("e")-2); | ||||
| 						O = O + (E - O.length + 1 >= 0 ? padstr[ "0"].substr(0,E - O.length + 1) : ""); | ||||
| 						if(alt || (prec > 0 && isnum !== 11)) O = O + "." + (prec >= 0 ? padstr[ "0"].substr(0,prec) : ""); | ||||
| 						break; | ||||
| 
 | ||||
| 					/* e/E exponential */ | ||||
| 					case 2: case 12: | ||||
| 						O = Vnum.toExponential(prec); | ||||
| 						E = O.indexOf("e"); | ||||
| 						if(O.length - E === 3) O = O.substr(0, E+2) + "0" + O.substr(E+2); | ||||
| 						if(alt && O.indexOf(".") == -1) O = O.substr(0,E) +"."+ O.substr(E); | ||||
| 						else if(!alt && isnum == 12) O = O.replace(/\.0*e/, "e").replace(/\.(\d*[1-9])0*e/, ".$1e"); | ||||
| 						break; | ||||
| 
 | ||||
| 					/* a/A hex */ | ||||
| 					case 4: | ||||
| 						if(Vnum===0){O= "0x0"+((alt||prec>0)?"."+(prec >= 0 ? padstr["0"].substr(0,prec) : ""):"")+"p+0"; break;} | ||||
| 						O = Vnum.toString(16); | ||||
| 						/* First char 0-9 */ | ||||
| 						var ac/*:number*/ = O.charCodeAt(0); | ||||
| 						if(ac == 48) { | ||||
| 							ac = 2; E = -4; Vnum *= 16; | ||||
| 							while(O.charCodeAt(ac++) == 48) { E -= 4; Vnum *= 16; } | ||||
| 							O = Vnum.toString(16); | ||||
| 							ac = O.charCodeAt(0); | ||||
| 						} | ||||
| 
 | ||||
| 						var ai/*:number*/ = O.indexOf("."); | ||||
| 						if(O.indexOf("(") > -1) { | ||||
| 							/* IE exponential form */ | ||||
| 							var am/*:?Array<any>*/ = O.match(/\(e(.*)\)/); | ||||
| 							var ae/*:number*/ = am ? (+am[1]) : 0; | ||||
| 							E += 4 * ae; Vnum /= Math.pow(16, ae); | ||||
| 						} else if(ai > 1) { | ||||
| 							E += 4 * (ai - 1); Vnum /= Math.pow(16, ai - 1); | ||||
| 						} else if(ai == -1) { | ||||
| 							E += 4 * (O.length - 1); Vnum /= Math.pow(16, O.length - 1); | ||||
| 						} | ||||
| 
 | ||||
| 						/* at this point 1 <= Vnum < 16 */ | ||||
| 
 | ||||
| 						if(bytes > 8) { | ||||
| 							if(ac < 50) { E -= 3; Vnum *= 8; } | ||||
| 							else if(ac < 52) { E -= 2; Vnum *= 4; } | ||||
| 							else if(ac < 56) { E -= 1; Vnum *= 2; } | ||||
| 							/* at this point 8 <= Vnum < 16 */ | ||||
| 						} else { | ||||
| 							if(ac >= 56) { E += 3; Vnum /= 8; } | ||||
| 							else if(ac >= 52) { E += 2; Vnum /= 4; } | ||||
| 							else if(ac >= 50) { E += 1; Vnum /= 2; } | ||||
| 							/* at this point 1 <= Vnum < 2 */ | ||||
| 						} | ||||
| 
 | ||||
| 						O = Vnum.toString(16); | ||||
| 						if(O.length > 1) { | ||||
| 							if(O.length > prec+2 && O.charCodeAt(prec+2) >= 56) { | ||||
| 								var _f = O.charCodeAt(0) == 102; | ||||
| 								O = (Vnum + 8 * Math.pow(16, -prec-1)).toString(16); | ||||
| 								if(_f && O.charCodeAt(0) == 49) E += 4; | ||||
| 							} | ||||
| 							if(prec > 0) { | ||||
| 								O = O.substr(0, prec + 2); | ||||
| 								if(O.length < prec + 2) { | ||||
| 									if(O.charCodeAt(0) < 48) O = O.charAt(0) + ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "") + O.substr(1); | ||||
| 									else O += ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : ""); | ||||
| 								} | ||||
| 							} else if(prec === 0) O = O.charAt(0) + (alt ? "." : ""); | ||||
| 						} else if(prec > 0) O = O + "." + (prec >= 0 ? padstr["0"].substr(0,prec) : ""); | ||||
| 						else if(alt) O = O + "."; | ||||
| 						O = "0x" + O + "p" + (E>=0 ? "+" + E : E); | ||||
| 						break; | ||||
| 				} | ||||
| 
 | ||||
| 				if(sg === "") { | ||||
| 					if(flags.indexOf("+") > -1) sg = "+"; | ||||
| 					else if(flags.indexOf(" ") > -1) sg = " "; | ||||
| 				} | ||||
| 
 | ||||
| 				O = sg + O; | ||||
| 			} | ||||
| 
 | ||||
| 			/* width */ | ||||
| 			if(width > O.length) { | ||||
| 				if(flags.indexOf("-") > -1) { | ||||
| 					O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : ""); | ||||
| 				} else if(flags.indexOf("0") > -1 && O.length > 0 && isf) { | ||||
| 					pad = ((width - O.length) >= 0 ? padstr[ "0"].substr(0,(width - O.length)) : ""); | ||||
| 					if(O.charCodeAt(0) < 48) { | ||||
| 						if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3); | ||||
| 						else O = O.substr(0,1) + pad + O.substring(1); | ||||
| 					} | ||||
| 					else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2); | ||||
| 					else O = pad + O; | ||||
| 				} else { | ||||
| 					O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O; | ||||
| 				} | ||||
| 			} | ||||
| 			if(c < 96) O = O.toUpperCase(); | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		o.push(O); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| function vsprintf(fmt/*:string*/, args/*:Array<any>*/) { return doit(tokenize(fmt), args); } | ||||
| 
 | ||||
| //function sprintf() { return doit(tokenize(arguments[0]), Array.prototype.slice.call(arguments, 1)); }
 | ||||
| function sprintf()/*:string*/ { | ||||
| 	var args/*:Array<any>*/ = new Array(arguments.length - 1); | ||||
| 	for(var i = 0; i < args.length; ++i) args[i] = arguments[i+1]; | ||||
| 	return doit(tokenize(arguments[0]), args); | ||||
| } | ||||
| 
 | ||||
| PRINTJ.sprintf = sprintf; | ||||
| PRINTJ.vsprintf = vsprintf; | ||||
| PRINTJ._doit = doit; | ||||
| PRINTJ._tokenize = tokenize; | ||||
| 
 | ||||
| })); | ||||
| 
 | ||||
							
								
								
									
										601
									
								
								printj.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										601
									
								
								printj.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,601 @@ | ||||
| 
 | ||||
| /* printj.js (C) 2016-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint sub:true, eqnull:true */ | ||||
| /*exported PRINTJ */ | ||||
| var PRINTJ; | ||||
| (function (factory) { | ||||
| 	/*jshint ignore:start */ | ||||
| 	if(typeof DO_NOT_EXPORT_PRINTJ === 'undefined') { | ||||
| 		if('object' === typeof exports) { | ||||
| 			factory(exports); | ||||
| 		} else if ('function' === typeof define && define.amd) { | ||||
| 			define(function () { | ||||
| 				var module = {}; | ||||
| 				factory(module); | ||||
| 				return module; | ||||
| 			}); | ||||
| 		} else { | ||||
| 			factory(PRINTJ = {}); | ||||
| 		} | ||||
| 	} else { | ||||
| 		factory(PRINTJ = {}); | ||||
| 	} | ||||
| 	/*jshint ignore:end */ | ||||
| }(function(PRINTJ) { | ||||
| 
 | ||||
| PRINTJ.version = '0.1.0'; | ||||
| 
 | ||||
| function tokenize(fmt) { | ||||
| 	var out = []; | ||||
| 	var start = 0; | ||||
| 
 | ||||
| 	var i = 0; | ||||
| 	var infmt = false; | ||||
| 	var fmtparam = "", fmtflags = "", fmtwidth = "", fmtprec = "", fmtlen = ""; | ||||
| 
 | ||||
| 	var c = 0; | ||||
| 
 | ||||
| 	var L = fmt.length; | ||||
| 
 | ||||
| 	for(; i < L; ++i) { | ||||
| 		c = fmt.charCodeAt(i); | ||||
| 		if(!infmt) { | ||||
| 
 | ||||
| 			if(c !== 37) continue; | ||||
| 
 | ||||
| 			if(start < i) out.push(["L", fmt.substring(start, i)]); | ||||
| 			start = i; | ||||
| 			infmt = true; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if(c >= 48 && c < 58)	{ | ||||
| 				if(fmtprec.length) fmtprec += String.fromCharCode(c); | ||||
| 				else if(c == 48 && !fmtwidth.length) fmtflags += String.fromCharCode(c); | ||||
| 				else fmtwidth += String.fromCharCode(c); | ||||
| 		} else switch(c) { | ||||
| 			/* positional */ | ||||
| 			case 36: | ||||
| 				if(fmtprec.length) fmtprec += "$"; | ||||
| 				else if(fmtwidth.charAt(0) == "*") fmtwidth += "$"; | ||||
| 				else { fmtparam = fmtwidth + "$"; fmtwidth = ""; } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* flags */ | ||||
| 			case 39: fmtflags += "'"; break; | ||||
| 			case 45: fmtflags += "-"; break; | ||||
| 			case 43: fmtflags += "+"; break; | ||||
| 			case 32: fmtflags += " "; break; | ||||
| 			case 35: fmtflags += "#"; break; | ||||
| 
 | ||||
| 			/* width and precision */ | ||||
| 			case 46: fmtprec = "."; break; | ||||
| 			case 42: | ||||
| 				if(fmtprec.charAt(0) == ".") fmtprec += "*"; | ||||
| 				else fmtwidth += "*"; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* length */ | ||||
| 			case 104: | ||||
| 			case 108: | ||||
| 				if(fmtlen.length > 1) throw "bad length " + fmtlen + String(c); | ||||
| 				fmtlen += String.fromCharCode(c); | ||||
| 				break; | ||||
| 
 | ||||
| 			case  76: | ||||
| 			case 106: | ||||
| 			case 122: | ||||
| 			case 116: | ||||
| 			case 113: | ||||
| 			case  90: | ||||
| 			case 119: | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + String.fromCharCode(c); | ||||
| 				fmtlen = String.fromCharCode(c); | ||||
| 				break; | ||||
| 
 | ||||
| 			case 73: | ||||
| 				if(fmtlen !== "") throw "bad length " + fmtlen + 'I'; | ||||
| 				fmtlen = 'I'; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* conversion */ | ||||
| 			case 100: | ||||
| 			case 105: | ||||
| 			case 111: | ||||
| 			case 117: | ||||
| 			case 120: | ||||
| 			case 88: | ||||
| 			case 102: | ||||
| 			case 70: | ||||
| 			case 101: | ||||
| 			case 69: | ||||
| 			case 103: | ||||
| 			case 71: | ||||
| 			case 97: | ||||
| 			case 65: | ||||
| 			case 99: | ||||
| 			case 67: | ||||
| 			case 115: | ||||
| 			case 83: | ||||
| 			case 112: | ||||
| 			case 110: | ||||
| 			case 68: | ||||
| 			case 85: | ||||
| 			case 79: | ||||
| 			case 109: | ||||
| 			case 98: | ||||
| 			case 66: | ||||
| 			case 121: | ||||
| 			case 89: | ||||
| 			case 74: | ||||
| 			case 86: | ||||
| 			case 84: | ||||
| 			case 37: | ||||
| 				infmt = false; | ||||
| 				if(fmtprec.length > 1) fmtprec = fmtprec.substr(1); | ||||
| 				out.push([String.fromCharCode(c), fmt.substring(start, i+1), fmtparam, fmtflags, fmtwidth, fmtprec, fmtlen]); | ||||
| 				start = i+1; | ||||
| 				fmtlen = fmtprec = fmtwidth = fmtflags = fmtparam = ""; | ||||
| 				break; | ||||
| 			default: | ||||
| 				throw new Error("Invalid format string starting with |" + fmt.substring(start, i+1) + "|"); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	if(start < fmt.length) out.push(["L", fmt.substring(start)]); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| //#define PAD_(x,c) (x >= 0 ? new Array(((x)|0) + 1).join((c)) : "")
 | ||||
| var padstr = { | ||||
| 	" ": "                                 ", | ||||
| 	"0": "000000000000000000000000000000000", | ||||
| 	"7": "777777777777777777777777777777777", | ||||
| 	"f": "fffffffffffffffffffffffffffffffff" | ||||
| }; | ||||
| 
 | ||||
| if(typeof util=='undefined' && typeof require!=='undefined')util=require("util"); | ||||
| var u_inspect = (typeof util != 'undefined') ? util.inspect : JSON.stringify; | ||||
| 
 | ||||
| function doit(t, args) { | ||||
| 	var o = []; | ||||
| 	var argidx = 0, idx = 0; | ||||
| 	var Vnum = 0; | ||||
| 	var pad = ""; | ||||
| 	for(var i = 0; i < t.length; ++i) { | ||||
| 		var m = t[i], c = (m[0]).charCodeAt(0); | ||||
| 		/* m order: conv full param flags width prec length */ | ||||
| 
 | ||||
| 		if(c === /*L*/ 76) { o.push(m[1]); continue; } | ||||
| 		if(c === /*%*/ 37) { o.push("%"); continue; } | ||||
| 
 | ||||
| 		var O = ""; | ||||
| 		var isnum = 0, radix = 10, bytes = 4, sign = false; | ||||
| 
 | ||||
| 		/* flags */ | ||||
| 		var flags = m[3]||""; | ||||
| 		var alt = flags.indexOf("#") > -1; | ||||
| 
 | ||||
| 		/* position */ | ||||
| 		if(m[2]) argidx = parseInt(m[2])-1; | ||||
| 		/* %m special case */ | ||||
| 		else if(c === /*m*/ 109 && !alt) { o.push("Success"); continue; } | ||||
| 
 | ||||
| 		/* grab width */ | ||||
| 		var width =  0; if(m[ 4] != null && m[ 4].length > 0) { if(m[ 4].charAt(0) !== '*') width = parseInt(m[ 4], 10); else if(m[ 4].length === 1) width = args[idx++]; else width = args[parseInt(m[ 4].substr(1), 10)-1]; } | ||||
| 
 | ||||
| 		/* grab precision */ | ||||
| 		var prec =  -1; if(m[ 5] != null && m[ 5].length > 0) { if(m[ 5].charAt(0) !== '*') prec = parseInt(m[ 5], 10); else if(m[ 5].length === 1) prec = args[idx++]; else prec = args[parseInt(m[ 5].substr(1), 10)-1]; } | ||||
| 
 | ||||
| 		/* position not specified */ | ||||
| 		if(!m[2]) argidx = idx++; | ||||
| 
 | ||||
| 		/* grab argument */ | ||||
| 		var arg = args[argidx]; | ||||
| 
 | ||||
| 		/* grab length */ | ||||
| 		var len = m[6] || ""; | ||||
| 
 | ||||
| 		switch(c) { | ||||
| 			/* str cCsS */ | ||||
| 
 | ||||
| 			case /*S*/  83: | ||||
| 			case /*s*/ 115: | ||||
| 				/* only valid flag is "-" for left justification */ | ||||
| 				O = String(arg); | ||||
| 				if( prec >= 0) O = O.substr(0,  prec); | ||||
| 				if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 ||  width < 0) &&  flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O =  flags.indexOf("-") > -1 ? O + pad : pad + O; } } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* first char of string or convert */ | ||||
| 			case /*C*/  67: | ||||
| 			case /*c*/  99: | ||||
| 				switch(typeof arg) { | ||||
| 					case "number": | ||||
| 						var cc = arg; | ||||
| 						if(c == 67 || len.charCodeAt(0) === /*l*/ 108) {  cc &= 0xFFFFFFFF; O = String.fromCharCode( cc); } | ||||
| 						else  cc &= 0xFF; O = String.fromCharCode( cc); | ||||
| 						break; | ||||
| 					case "string": O = arg.charAt(0); break; | ||||
| 					default: O = String(arg).charAt(0); | ||||
| 				} | ||||
| 				if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 ||  width < 0) &&  flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O =  flags.indexOf("-") > -1 ? O + pad : pad + O; } } | ||||
| 				break; | ||||
| 
 | ||||
| 			/* int diDuUoOxXbB */ | ||||
| 
 | ||||
| 			/* signed integer */ | ||||
| 			case /*D*/  68: bytes = 8; | ||||
| 			/* falls through */ | ||||
| 			case /*d*/ 100: | ||||
| 			case /*i*/ 105: isnum = -1; sign = true; break; | ||||
| 
 | ||||
| 			/* unsigned integer */ | ||||
| 			case /*U*/  85: bytes = 8; | ||||
| 			/* falls through */ | ||||
|  			case /*u*/ 117: isnum = -1; break; | ||||
| 
 | ||||
| 			/* unsigned octal */ | ||||
| 			case /*O*/  79: bytes = 8; | ||||
| 			/* falls through */ | ||||
| 			case /*o*/ 111: isnum = -1; radix = (8); break; | ||||
| 
 | ||||
| 			/* unsigned hex */ | ||||
| 			case /*x*/ 120: isnum = -1; radix = (-16); break; | ||||
| 			case /*X*/  88: isnum = -1; radix = (16); break; | ||||
| 
 | ||||
| 			/* unsigned binary (extension) */ | ||||
| 			case /*B*/  66: bytes = 8; | ||||
| 			/* falls through */ | ||||
| 			case /*b*/  98: isnum = -1; radix = (2); break; | ||||
| 
 | ||||
| 			/* flt fegFEGaA */ | ||||
| 
 | ||||
| 			/* floating point logic */ | ||||
| 			case /*F*/  70: | ||||
| 			case /*f*/ 102: isnum = (1); break; | ||||
| 
 | ||||
| 			case /*E*/  69: | ||||
| 			case /*e*/ 101: isnum = (2); break; | ||||
| 
 | ||||
| 			case /*G*/  71: | ||||
| 			case /*g*/ 103: isnum = (3); break; | ||||
| 
 | ||||
| 			/* floating hex */ | ||||
| 			case /*A*/  65: | ||||
| 			case /*a*/  97: isnum = (4); break; | ||||
| 
 | ||||
| 			/* misc pnmJVTyY */ | ||||
| 
 | ||||
| 			/* JS has no concept of pointers so interpret the `l` key as an address */ | ||||
| 			case /*p*/ 112: | ||||
| 				Vnum = typeof arg == "number" ? arg : Number(arg.l); | ||||
| 				if(isNaN(Vnum)) Vnum = -1; | ||||
| 				if(alt) O = Vnum.toString(10); | ||||
| 				else { | ||||
| 					Vnum = Math.abs(Vnum); | ||||
| 					O = "0x" + Vnum.toString(16).toLowerCase(); | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			/* store length in the `len` key */ | ||||
| 			case /*n*/ 110: | ||||
| 				if(arg) { arg.len=0; for(var oo = 0; oo < o.length; ++oo) arg.len += o[oo].length; } | ||||
| 				continue; | ||||
| 
 | ||||
| 			/* process error */ | ||||
| 			case /*m*/ 109: | ||||
| 				if(!(arg instanceof Error)) O = "Success"; | ||||
| 				else if(arg.message) O = arg.message; | ||||
| 				else if(arg.errno) O = "Error number " + arg.errno; | ||||
| 				else O = "Error " + String(arg); | ||||
| 				break; | ||||
| 
 | ||||
| 			/* JS-specific conversions (extension) */ | ||||
| 			case /*J*/  74: O = (alt ? u_inspect : JSON.stringify)(arg); break; | ||||
| 			case /*V*/  86: O = String(arg.valueOf()); break; | ||||
| 			case /*T*/  84: | ||||
| 				if(alt) { /* from '[object %s]' extract %s */ | ||||
| 					O = Object.prototype.toString.call(arg).substr(8); | ||||
| 					O = O.substr(0, O.length - 1); | ||||
| 				} else O = typeof arg; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* boolean (extension) */ | ||||
| 			case /*Y*/  89: | ||||
| 			case /*y*/ 121: | ||||
| 				O = Boolean(arg) ? (alt ? "yes" : "true") : (alt ? "no" : "false"); | ||||
| 				if(c == /*Y*/ 89) O = O.toUpperCase(); | ||||
| 				if( prec >= 0) O = O.substr(0,  prec); | ||||
| 				if( width > O.length || - width > O.length) { if(( flags.indexOf("-") == -1 ||  width < 0) &&  flags.indexOf("0") != -1) { pad = ( width - O.length >= 0 ? padstr["0"].substr(0, width - O.length) : ""); O = pad + O; } else { pad = ( width - O.length >= 0 ? padstr[" "].substr(0, width - O.length) : ""); O =  flags.indexOf("-") > -1 ? O + pad : pad + O; } } | ||||
| 				break; | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		if(isnum == -1) { | ||||
| 
 | ||||
| 			Vnum = Number(arg); | ||||
| 
 | ||||
| 			/* parse byte length field */ | ||||
| 
 | ||||
| 			switch(len) { | ||||
| 				/* char */ | ||||
| 				case "hh": { bytes = 1; } break; | ||||
| 				/* short */ | ||||
| 				case "h":  { bytes = 2; } break; | ||||
| 
 | ||||
| 				/* long */ | ||||
| 				case "l":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* long long */ | ||||
| 				case "L": | ||||
| 				case "q": | ||||
| 				case "ll": { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* intmax_t */ | ||||
| 				case "j":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* ptrdiff_t */ | ||||
| 				case "t":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* size_t */ | ||||
| 				case "z": | ||||
| 				case "Z":  { if(bytes == 4) bytes = 8; } break; | ||||
| 
 | ||||
| 				/* CRT size_t or ptrdiff_t */ | ||||
| 				case "I": | ||||
| 
 | ||||
| 					{ if(bytes == 4) bytes = 8; } | ||||
| 
 | ||||
| 					break; | ||||
| 
 | ||||
| 				/* CRT wchar_t */ | ||||
| 				case "w": break; | ||||
| 			} | ||||
| 
 | ||||
| 			/* restrict value */ | ||||
| 
 | ||||
| 			switch(bytes) { | ||||
| 				case 1: Vnum = (Vnum & 0xFF); if(sign && (Vnum >  0x7F)) Vnum -= (0xFF + 1); break; | ||||
| 				case 2: Vnum = (Vnum & 0xFFFF); if(sign && (Vnum >  0x7FFF)) Vnum -= (0xFFFF + 1); break; | ||||
| 				case 4: Vnum = sign ? (Vnum | 0) : (Vnum >>> 0); break; | ||||
| 				default: Vnum = Math.round(Vnum); break; | ||||
| 			} | ||||
| 
 | ||||
| 			/* generate string */ | ||||
| 			if(bytes > 4 && Vnum < 0 && !sign) { | ||||
| 				if(radix == 16 || radix == -16) { | ||||
| 					O = (Vnum>>>0).toString(16); | ||||
| 					Vnum = Math.floor((Vnum - (Vnum >>> 0)) / Math.pow(2,32)); | ||||
| 					O = (Vnum>>>0).toString(16) + (8 - O.length >= 0 ? padstr[ "0"].substr(0,8 - O.length) : "") + O; | ||||
| 					O = (16 - O.length >= 0 ? padstr[ "f"].substr(0,16 - O.length) : "") + O; | ||||
| 					if(radix == 16) O = O.toUpperCase(); | ||||
| 				} else if(radix == 8) { | ||||
| 					O = (Vnum>>>0).toString(8); | ||||
| 					O = (10 - O.length >= 0 ? padstr[ "0"].substr(0,10 - O.length) : "") + O; | ||||
| 					Vnum = Math.floor((Vnum - ((Vnum >>> 0)&0x3FFFFFFF)) / Math.pow(2,30)); | ||||
| 					O = (Vnum>>>0).toString(8) + O.substr(O.length - 10); | ||||
| 					O = O.substr(O.length - 20); | ||||
| 					O = "1" + (21 - O.length >= 0 ? padstr[ "7"].substr(0,21 - O.length) : "") + O; | ||||
| 				} else { | ||||
| 					Vnum = (-Vnum) % 1e16; | ||||
| 					var d1 = [1,8,4,4,6,7,4,4,0,7,3,7,0,9,5,5,1,6,1,6]; | ||||
| 					var di = d1.length - 1; | ||||
| 					while(Vnum > 0) { | ||||
| 						if((d1[di] -= (Vnum % 10)) < 0) { d1[di] += 10; d1[di-1]--; } | ||||
| 						--di; Vnum = Math.floor(Vnum / 10); | ||||
| 					} | ||||
| 					O = d1.join(""); | ||||
| 				} | ||||
| 			} else { | ||||
| 				if(radix === -16) O = Vnum.toString(16).toLowerCase(); | ||||
| 				else if(radix === 16) O = Vnum.toString(16).toUpperCase(); | ||||
| 				else O = Vnum.toString(radix); | ||||
| 			} | ||||
| 
 | ||||
| 			/* apply precision */ | ||||
| 			if(prec ===0 && O == "0" && !(radix == 8 && alt)) O = ""; /* bail out */ | ||||
| 			else { | ||||
| 				if(O.length < prec + (O.substr(0,1) == "-" ? 1 : 0)) { | ||||
| 					if(O.substr(0,1) != "-") O = (prec - O.length >= 0 ? padstr[ "0"].substr(0,prec - O.length) : "") + O; | ||||
| 					else O = O.substr(0,1) + (prec + 1 - O.length >= 0 ? padstr[ "0"].substr(0,prec + 1 - O.length) : "") + O.substr(1); | ||||
| 				} | ||||
| 
 | ||||
| 				/* add prefix for # form */ | ||||
| 				if(!sign && alt && Vnum !== 0) switch(radix) { | ||||
| 					case -16: O = "0x" + O; break; | ||||
| 					case  16: O = "0X" + O; break; | ||||
| 					case   8: if(O.charAt(0) != "0") O =  "0" + O; break; | ||||
| 					case   2: O = "0b" + O; break; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			/* add sign character */ | ||||
| 			if(sign && O.charAt(0) != "-") { | ||||
| 				if(flags.indexOf("+") > -1) O = "+" + O; | ||||
| 				else if(flags.indexOf(" ") > -1) O = " " + O; | ||||
| 			} | ||||
| 			/* width */ | ||||
| 			if(width > 0) { | ||||
| 				if(O.length < width) { | ||||
| 					if(flags.indexOf("-") > -1) { | ||||
| 						O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : ""); | ||||
| 					} else if(flags.indexOf("0") > -1 && prec < 0 && O.length > 0) { | ||||
| 						if(prec > O.length) O = ((prec - O.length) >= 0 ? padstr[ "0"].substr(0,(prec - O.length)) : "") + O; | ||||
| 						pad = ((width - O.length) >= 0 ? padstr[ (prec > 0 ? " " : "0")].substr(0,(width - O.length)) : ""); | ||||
| 						if(O.charCodeAt(0) < 48) { | ||||
| 							if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3); | ||||
| 							else O = O.substr(0,1) + pad + O.substring(1); | ||||
| 						} | ||||
| 						else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2); | ||||
| 						else O = pad + O; | ||||
| 					} else { | ||||
| 						O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 		} else if(isnum > 0) { | ||||
| 
 | ||||
| 			Vnum = Number(arg); | ||||
| 			if(len == "L") bytes = 12; | ||||
| 			var isf = isFinite(Vnum); | ||||
| 			if(!isf) { /* Infinity or NaN */ | ||||
| 				if(Vnum < 0) O = "-"; | ||||
| 				else if(flags.indexOf("+") > -1) O = "+"; | ||||
| 				else if(flags.indexOf(" ") > -1) O = " "; | ||||
| 				O += (isNaN(Vnum)) ? "nan" : "inf"; | ||||
| 			} else { | ||||
| 				var E = 0; | ||||
| 
 | ||||
| 				if(prec == -1 && isnum != 4) prec = 6; | ||||
| 
 | ||||
| 				/* g/G conditional behavior */ | ||||
| 				if(isnum == 3) { | ||||
| 					O = Vnum.toExponential(1); | ||||
| 					E = +O.substr(O.indexOf("e") + 1); | ||||
| 					if(prec === 0) prec = 1; | ||||
| 					if(prec > E && E >= -4) { isnum = (11); prec = prec -(E + 1); } | ||||
| 					else { isnum = (12); prec = prec - 1; } | ||||
| 				} | ||||
| 
 | ||||
| 				/* sign: workaround for negative zero */ | ||||
| 				var sg = (Vnum < 0 || 1/Vnum == -Infinity) ? "-" : ""; | ||||
| 				if(Vnum < 0) Vnum = -Vnum; | ||||
| 
 | ||||
| 				switch(isnum) { | ||||
| 					/* f/F standard */ | ||||
| 					case 1: case 11: | ||||
| 						if(Vnum < Math.pow(10,21)) { | ||||
| 							O = Vnum.toFixed(prec); | ||||
| 							if(isnum == 1) { if(prec===0 &&alt&& O.indexOf(".")==-1) O+="."; } | ||||
| 							else if(!alt) O=O.replace(/(\.\d*[1-9])0*$/,"$1").replace(/\.0*$/,""); | ||||
| 							else if(O.indexOf(".") == -1) O+= "."; | ||||
| 							break; | ||||
| 						} | ||||
| 						O = Vnum.toExponential(20); | ||||
| 						E = +O.substr(O.indexOf("e")+1); | ||||
| 						O = O.charAt(0) + O.substr(2,O.indexOf("e")-2); | ||||
| 						O = O + (E - O.length + 1 >= 0 ? padstr[ "0"].substr(0,E - O.length + 1) : ""); | ||||
| 						if(alt || (prec > 0 && isnum !== 11)) O = O + "." + (prec >= 0 ? padstr[ "0"].substr(0,prec) : ""); | ||||
| 						break; | ||||
| 
 | ||||
| 					/* e/E exponential */ | ||||
| 					case 2: case 12: | ||||
| 						O = Vnum.toExponential(prec); | ||||
| 						E = O.indexOf("e"); | ||||
| 						if(O.length - E === 3) O = O.substr(0, E+2) + "0" + O.substr(E+2); | ||||
| 						if(alt && O.indexOf(".") == -1) O = O.substr(0,E) +"."+ O.substr(E); | ||||
| 						else if(!alt && isnum == 12) O = O.replace(/\.0*e/, "e").replace(/\.(\d*[1-9])0*e/, ".$1e"); | ||||
| 						break; | ||||
| 
 | ||||
| 					/* a/A hex */ | ||||
| 					case 4: | ||||
| 						if(Vnum===0){O= "0x0"+((alt||prec>0)?"."+(prec >= 0 ? padstr["0"].substr(0,prec) : ""):"")+"p+0"; break;} | ||||
| 						O = Vnum.toString(16); | ||||
| 						/* First char 0-9 */ | ||||
| 						var ac = O.charCodeAt(0); | ||||
| 						if(ac == 48) { | ||||
| 							ac = 2; E = -4; Vnum *= 16; | ||||
| 							while(O.charCodeAt(ac++) == 48) { E -= 4; Vnum *= 16; } | ||||
| 							O = Vnum.toString(16); | ||||
| 							ac = O.charCodeAt(0); | ||||
| 						} | ||||
| 
 | ||||
| 						var ai = O.indexOf("."); | ||||
| 						if(O.indexOf("(") > -1) { | ||||
| 							/* IE exponential form */ | ||||
| 							var am = O.match(/\(e(.*)\)/); | ||||
| 							var ae = am ? (+am[1]) : 0; | ||||
| 							E += 4 * ae; Vnum /= Math.pow(16, ae); | ||||
| 						} else if(ai > 1) { | ||||
| 							E += 4 * (ai - 1); Vnum /= Math.pow(16, ai - 1); | ||||
| 						} else if(ai == -1) { | ||||
| 							E += 4 * (O.length - 1); Vnum /= Math.pow(16, O.length - 1); | ||||
| 						} | ||||
| 
 | ||||
| 						/* at this point 1 <= Vnum < 16 */ | ||||
| 
 | ||||
| 						if(bytes > 8) { | ||||
| 							if(ac < 50) { E -= 3; Vnum *= 8; } | ||||
| 							else if(ac < 52) { E -= 2; Vnum *= 4; } | ||||
| 							else if(ac < 56) { E -= 1; Vnum *= 2; } | ||||
| 							/* at this point 8 <= Vnum < 16 */ | ||||
| 						} else { | ||||
| 							if(ac >= 56) { E += 3; Vnum /= 8; } | ||||
| 							else if(ac >= 52) { E += 2; Vnum /= 4; } | ||||
| 							else if(ac >= 50) { E += 1; Vnum /= 2; } | ||||
| 							/* at this point 1 <= Vnum < 2 */ | ||||
| 						} | ||||
| 
 | ||||
| 						O = Vnum.toString(16); | ||||
| 						if(O.length > 1) { | ||||
| 							if(O.length > prec+2 && O.charCodeAt(prec+2) >= 56) { | ||||
| 								var _f = O.charCodeAt(0) == 102; | ||||
| 								O = (Vnum + 8 * Math.pow(16, -prec-1)).toString(16); | ||||
| 								if(_f && O.charCodeAt(0) == 49) E += 4; | ||||
| 							} | ||||
| 							if(prec > 0) { | ||||
| 								O = O.substr(0, prec + 2); | ||||
| 								if(O.length < prec + 2) { | ||||
| 									if(O.charCodeAt(0) < 48) O = O.charAt(0) + ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : "") + O.substr(1); | ||||
| 									else O += ((prec + 2 - O.length) >= 0 ? padstr[ "0"].substr(0,(prec + 2 - O.length)) : ""); | ||||
| 								} | ||||
| 							} else if(prec === 0) O = O.charAt(0) + (alt ? "." : ""); | ||||
| 						} else if(prec > 0) O = O + "." + (prec >= 0 ? padstr["0"].substr(0,prec) : ""); | ||||
| 						else if(alt) O = O + "."; | ||||
| 						O = "0x" + O + "p" + (E>=0 ? "+" + E : E); | ||||
| 						break; | ||||
| 				} | ||||
| 
 | ||||
| 				if(sg === "") { | ||||
| 					if(flags.indexOf("+") > -1) sg = "+"; | ||||
| 					else if(flags.indexOf(" ") > -1) sg = " "; | ||||
| 				} | ||||
| 
 | ||||
| 				O = sg + O; | ||||
| 			} | ||||
| 
 | ||||
| 			/* width */ | ||||
| 			if(width > O.length) { | ||||
| 				if(flags.indexOf("-") > -1) { | ||||
| 					O = O + ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : ""); | ||||
| 				} else if(flags.indexOf("0") > -1 && O.length > 0 && isf) { | ||||
| 					pad = ((width - O.length) >= 0 ? padstr[ "0"].substr(0,(width - O.length)) : ""); | ||||
| 					if(O.charCodeAt(0) < 48) { | ||||
| 						if(O.charAt(2).toLowerCase() == "x") O = O.substr(0,3) + pad + O.substring(3); | ||||
| 						else O = O.substr(0,1) + pad + O.substring(1); | ||||
| 					} | ||||
| 					else if(O.charAt(1).toLowerCase() == "x") O = O.substr(0,2) + pad + O.substring(2); | ||||
| 					else O = pad + O; | ||||
| 				} else { | ||||
| 					O = ((width - O.length) >= 0 ? padstr[ " "].substr(0,(width - O.length)) : "") + O; | ||||
| 				} | ||||
| 			} | ||||
| 			if(c < 96) O = O.toUpperCase(); | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		o.push(O); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
| 
 | ||||
| function vsprintf(fmt, args) { return doit(tokenize(fmt), args); } | ||||
| 
 | ||||
| //function sprintf() { return doit(tokenize(arguments[0]), Array.prototype.slice.call(arguments, 1)); }
 | ||||
| function sprintf() { | ||||
| 	var args = new Array(arguments.length - 1); | ||||
| 	for(var i = 0; i < args.length; ++i) args[i] = arguments[i+1]; | ||||
| 	return doit(tokenize(arguments[0]), args); | ||||
| } | ||||
| 
 | ||||
| PRINTJ.sprintf = sprintf; | ||||
| PRINTJ.vsprintf = vsprintf; | ||||
| PRINTJ._doit = doit; | ||||
| PRINTJ._tokenize = tokenize; | ||||
| 
 | ||||
| })); | ||||
| 
 | ||||
							
								
								
									
										6
									
								
								stress/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										6
									
								
								stress/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| stress | ||||
| stress.h | ||||
| stress.njs | ||||
| tests.h | ||||
| t1 | ||||
| t2 | ||||
							
								
								
									
										31
									
								
								stress/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										31
									
								
								stress/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| CPPFLAGS=-Wno-format -Wno-constant-conversion | ||||
| FLAGS=-P -C -Wno-invalid-pp-token -Wno-format | ||||
| NODEOPTS=--max_old_space_size=4096 | ||||
| 
 | ||||
| .PHONY: all | ||||
| all: stress stress.njs | ||||
| 
 | ||||
| .PHONY: tests | ||||
| tests: tests.h | ||||
| 
 | ||||
| tests.h: generate_testcase.njs | ||||
| 	node generate_testcase.njs > tests.h | ||||
| 
 | ||||
| stress.h: generate_stress.njs | ||||
| 	node $< > $@ | ||||
| 
 | ||||
| stress: stress.c stress.h tests.h | ||||
| 	gcc $(CPPFLAGS) -o $@ $< | ||||
| 
 | ||||
| stress.njs: stress.js stress.h tests.h  | ||||
| 	cpp -DJAVASCRIPT $(FLAGS) $< > $@ | ||||
| 
 | ||||
| .PHONY: test | ||||
| test: | ||||
| 	./stress | bash ./fix.sh > t1 | ||||
| 	node $(NODEOPTS) stress.njs | bash ./fix.sh > t2 | ||||
| 	diff -q t1 t2 | ||||
| 
 | ||||
| .PHONY: clean | ||||
| clean: | ||||
| 	@rm -f stress stress.njs tests.h stress.h t1 t2 | ||||
							
								
								
									
										44
									
								
								stress/common.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										44
									
								
								stress/common.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| #define SUFFIX(arg, suffix) arg ## suffix | ||||
| #define PREFIX(arg, prefix) prefix ## arg | ||||
| #ifdef JAVASCRIPT | ||||
| #define INFINITY Infinity | ||||
| 
 | ||||
| #define CAST_U(x) x | ||||
| #define CAST_LD(x) x | ||||
| #define CAST_WSTR(x) x | ||||
| #define CAST_CHAR(x) (typeof (x) == 'string' ? (x).charCodeAt(0) : x) | ||||
| #define CAST_UCHAR(x) (typeof (x) == 'string' ? (x).charCodeAt(0) : x) | ||||
| #define CAST_SHORT(x) x | ||||
| #define CAST_USHORT(x) x | ||||
| #define CAST_L(x) x | ||||
| #define CAST_UL(x) x | ||||
| #define CAST_LL(x) x | ||||
| #define CAST_ULL(x) x | ||||
| #define CAST_INTMAX_T(x) x | ||||
| #define CAST_UINTMAX_T(x) x | ||||
| #define CAST_SIZE_T(x) x | ||||
| #define CAST_SSIZE_T(x) x | ||||
| #define CAST_PTRDIFF_T(x) x | ||||
| #define CAST_UINTPTR_T(x) x | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #define CAST_U(x)         SUFFIX(x, u) | ||||
| #define CAST_LD(x)        SUFFIX(x, L) | ||||
| #define CAST_WSTR(x)      PREFIX(x, L) | ||||
| #define CAST_CHAR(x)      x | ||||
| #define CAST_UCHAR(x)     (unsigned char)x | ||||
| #define CAST_SHORT(x)     (short)x | ||||
| #define CAST_USHORT(x)    (unsigned short)CAST_U(x) | ||||
| 
 | ||||
| #define CAST_L(x)         SUFFIX(x, l) | ||||
| #define CAST_UL(x)        SUFFIX(x, ul) | ||||
| #define CAST_LL(x)        SUFFIX(x, ll) | ||||
| #define CAST_ULL(x)       SUFFIX(x, ull) | ||||
| #define CAST_INTMAX_T(x)  (intmax_t)x | ||||
| #define CAST_UINTMAX_T(x) (uintmax_t)x | ||||
| #define CAST_SIZE_T(x)    (size_t)x | ||||
| #define CAST_SSIZE_T(x)   (ssize_t)x | ||||
| #define CAST_PTRDIFF_T(x) (ptrdiff_t)x | ||||
| #define CAST_UINTPTR_T(x) (uintptr_t)x | ||||
| #endif | ||||
							
								
								
									
										3
									
								
								stress/fix.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								stress/fix.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,3 @@ | ||||
| #!/bin/bash | ||||
| # remove last digit from %a %A outputs due to implementation-dependent rounding | ||||
| cat - | sed 's/.p/0p/; s/.P/0P/' | ||||
							
								
								
									
										127
									
								
								stress/generate_stress.njs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										127
									
								
								stress/generate_stress.njs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,127 @@ | ||||
| /* vim: set ft=javascript: */ | ||||
| 
 | ||||
| var S = { | ||||
| 	/* valid formats */ | ||||
| 	"formats":"diouxXfeEgGaAcsCS".split(""), | ||||
| 	/* flags and applicable convs */ | ||||
| 	"flags": [ | ||||
| 		["'", "diufFgG"], | ||||
| 		["-", "diouxXfeEgGaAcsCS"], | ||||
| 		["+", "diaAeEfFgG"], | ||||
| 		[" ", "diaAeEfFgG"], | ||||
| 		["#", "oxXaAeEfFgG"], | ||||
| 		["0", "diouxXaAeEfFgG"] | ||||
| 	], | ||||
| 	/* lengths and applicable convs */ | ||||
| 	"lengths": [ | ||||
| 		["hh", "diouxX"], | ||||
| 		["h",  "diouxX"], | ||||
| 		["l",  "diouxXcs"], | ||||
| 		["ll", "diouxX"], | ||||
| 		["j",  "diouxX"], | ||||
| 		["z",  "diouxX"], | ||||
| 		["t",  "diouxX"], | ||||
| 		["L",  "aAeEfFgG"] | ||||
| 	], | ||||
| 	"widths": [ "", "0", "1", "2", "4", "6", "8", "12" ], | ||||
| 	"precs":  [ "", "0", "1", "2", "4", "6", "8", "12" ].map(function(x) { return x == "" ? "" : "." + x; }), | ||||
| 	/* implied data types */ | ||||
| 	"types": [ | ||||
| 		["i", "dicC"], | ||||
| 		["u", "ouxX"], | ||||
| 		["d", "feEfFgGaA"], | ||||
| 		["s", "sS"], | ||||
| 	], | ||||
| 	/* override for lengths */ | ||||
| 	"typelen": { "C": "l", "S": "l" } | ||||
| }; | ||||
| 
 | ||||
| /* | ||||
| 	int i; unsigned int u; | ||||
| 	double d; long double ld; | ||||
| 	char *s; wchar_t *ws; | ||||
| 	signed char hhi; unsigned char hhu; short hi; unsigned short hu; | ||||
| 	long li; unsigned long lu; long long lli; unsigned long long llu; | ||||
| 	intmax_t ji; uintmax_t ju; size_t zi, ssize_t zu; ptrdiff_t ti; uintptr_t tu; | ||||
|  */ | ||||
| function getarg(format/*:string*/, length/*:string*/)/*:string*/ { | ||||
| 	var type = types[format]; | ||||
| 	if(!length) length = S.typelen[format] || ""; | ||||
| 	if(!length) return type; | ||||
| 	switch(type) { | ||||
| 		case 's': return "ws"; | ||||
| 		case 'd': if(length == "L") return "ld"; | ||||
| 		case 'i': case 'u': return length + type;  | ||||
| 	} | ||||
| 	return type; | ||||
| } | ||||
| 
 | ||||
| var platform = require("os").platform(); | ||||
| 
 | ||||
| function doit(format/*:string*/, flag/*:string*/, length/*:string*/, width/*:string*/, prec/*:string*/) { | ||||
| 	/* skip wide char */ | ||||
| 	if(format == "C" || (format == "c" && length == "l")) return; | ||||
| 	/* skip char */ | ||||
| 	if(format == "c") return; | ||||
| 	/* skip precision-less long double */ | ||||
| 	if(format.toLowerCase() == "a" && length == "L" && prec == "") return; | ||||
| 
 | ||||
| 	var fmt = "%" + flag + width + prec + length + format; | ||||
| 	var printf_stmt = 'printf("' + fmt + '\\n", ' + getarg(format, length) + ');'; | ||||
| 	console.log(printf_stmt); | ||||
| } | ||||
| 
 | ||||
| function pick(arr/*:Array<string>*/)/*:Array<string>*/ { | ||||
| 	var O = []; | ||||
| 	for(var i = 0; i < (1<<arr.length); ++i) { | ||||
| 		var o = ""; | ||||
| 		for(var j = 0; j < arr.length; ++j) if(i & (1<<j)) o += arr[j]; | ||||
| 		O.push(o); | ||||
| 	} | ||||
| 	return O; | ||||
| } | ||||
| 
 | ||||
| var flags = {}, lengths = {}, types = {}; | ||||
| S.formats.forEach(function(f) { flags[f]=[]; lengths[f]=[""]; types[f]=""; }); | ||||
| 
 | ||||
| S.types.forEach(function(f) { var g = f[1].split(""); g.forEach(function(h) { types[h] = f[0]; }); }); | ||||
| 
 | ||||
| S.lengths.forEach(function(f) { | ||||
| 	var g = f[1].split(""); | ||||
| 	g.forEach(function(h) { if(lengths[h]) lengths[h].push(f[0]); }); | ||||
| }); | ||||
| 
 | ||||
| S.flags.forEach(function(f) { | ||||
| 	var g = f[1].split(""); | ||||
| 	g.forEach(function(h) { if(flags[h]) flags[h].push(f[0]); }); | ||||
| }); | ||||
| S.formats.forEach(function(f) { flags[f] = pick(flags[f]); }); | ||||
| 
 | ||||
| var filters = { | ||||
| 	dint: "diu", | ||||
| 	oint: "o", | ||||
| 	hint: "xX", | ||||
| 	ddbl: "feEgG", | ||||
| 	hdbl: "aA", | ||||
| 	chr: "cC", | ||||
| 	str: "sS" | ||||
| }; | ||||
| filters.int = filters.dint + filters.hint + filters.oint; | ||||
| filters.dbl = filters.ddbl + filters.hdbl; | ||||
| filters.all = filters.int + filters.dbl + filters.chr + filters.str; | ||||
| 
 | ||||
| var filter = filters.all; | ||||
| 
 | ||||
| 
 | ||||
| S.formats.forEach(function(format) { | ||||
| 	if(filter && filter.indexOf(format) == -1) return; | ||||
| 	flags[format].forEach(function(flag) { | ||||
| 		lengths[format].forEach(function(length) { | ||||
| 			S.widths.forEach(function(width) { | ||||
| 				S.precs.forEach(function(prec) { | ||||
| 					doit(format, flag, length, width, prec); | ||||
| 				}); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
							
								
								
									
										88
									
								
								stress/generate_testcase.njs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										88
									
								
								stress/generate_testcase.njs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| /* unsigned int */ | ||||
| var uints =	[ "0", "1", "2", "4", "8", "16", "32", "64", "69", "128", "256", "259", "512", "1024", "1559","2048", "3333", "4096", "5678", "8192", "10111", "16384", "24681", "32768", "45678", "65536", "121211", "131072", "141427", "262144", "314159", "524288", "888888", "1048576", "1515151", "2097152", "3333333", "4194304", "4565456", "8388608", "13245125", "16777216", "27182818", "33554432", "34567654", "67108864", "99999999", "134217728", "201201201", "268435456", "298929892","536870912", "1000000000", "1073741824", "2011021011", "2147483648", "3743743743", "4294967296", "7876787678", "8589934592", "11111111111", "17179869184", "21347111829", "34359738368", "45678901234", "68719476736", "78987898789", "137438953472", "137438953473", "274877906944", "274877906945", "549755813888", "549755813889", "1099511627776", "1099511627777", "2199023255552", "2199023255553", "4398046511104", "4398046511105", "8796093022208", "8796093022209", "17592186044416", "17592186044417", "35184372088832", "35184372088833", "70368744177664", "70368744177665", "140737488355328", "140737488355329", "281474976710656", "281494978750657", "562949953421312", "562949953421313","1125899906842624","1125899906843625", "2251799813685248" ] | ||||
| 
 | ||||
| /* int */ | ||||
| var ints = []; for(var i = 0; i < uints.length; ++i) ints.push((i % 2 ? "-" : "") + uints[i]); | ||||
| 
 | ||||
| function posneg(o,i) { i.forEach(function(x) { o.push(x); o.push("-" + x); }); } | ||||
| 
 | ||||
| /* double / long double */ | ||||
| var pdbl = [ | ||||
| 	"0.", "INFINITY", "1.", "500.", ".0003", | ||||
| 	"1.2", ".000000000069", "69000000000.", | ||||
| 	"2.51", "4.37e19", "8.17e-19", | ||||
| 	"3.141", "2.718e19", "5.772e-19" | ||||
| ]; | ||||
| var doubles = []; posneg(doubles, pdbl); | ||||
| 
 | ||||
| /* char * / wchar_t * */ | ||||
| var strings = ['"v"', '"pq"', '"var"', '"rama"', '"sheet"', '"sheets"', '"sheetjs"', '"somberi"', '"function"', '"variadics"', '"javascript"', '"sesquipedalian"']; | ||||
| 
 | ||||
| /* signed char */ | ||||
| var schar = ["'\\0'", "'A'", "'z'", "'q'", "-1", "-127", "-128", "12345", "-12345"]; | ||||
| /* unsigned char */ | ||||
| var uchar = ["'\\0'", "'A'", "'z'", "'Q'", "-1", "-127", "-128", "12345", "45678"]; | ||||
| 
 | ||||
| /* unsigned long */ | ||||
| var ulongs = ["10", "30", "100", "300", "1000", "1234", "3000", "4321"]; | ||||
| 
 | ||||
| /* long */ | ||||
| var longs = []; posneg(longs, ulongs); | ||||
| 
 | ||||
| /* unsigned long long */ | ||||
| var ullongs = ["123", "456", "4543216", "1123412343", "100000000000", "2131000000000", "987654321", "1000123000000", "1234567890", "2718281828", "31415926535", "677215664901", "16180339887", "4669201609", "2813308004"]; | ||||
| 
 | ||||
| for(var i = 1; i < uints.length; i+=2) ullongs.push(uints[i]); | ||||
| 
 | ||||
| /* long long */ | ||||
| var llongs = []; posneg(llongs, ullongs); | ||||
| 
 | ||||
| var tests = [ | ||||
| 	ints, | ||||
| 	uints, | ||||
| 	doubles, | ||||
| 	doubles, | ||||
| 	strings, strings, | ||||
| 	schar, uchar, | ||||
| 	ints, | ||||
| 	uints, | ||||
| 	longs, | ||||
| 	ulongs, | ||||
| 	llongs, | ||||
| 	ullongs, | ||||
| 	llongs, | ||||
| 	ullongs, | ||||
| 	ullongs, | ||||
| 	llongs, | ||||
| 	llongs, | ||||
| 	ullongs | ||||
| ] | ||||
| 
 | ||||
| var maxlen = 0; | ||||
| for(var i = 0; i < tests.length; ++i) maxlen = Math.max(maxlen,tests[i].length); | ||||
| for(var j = 0; j < maxlen; ++j) { | ||||
| 	var args = []; | ||||
| 	for(i=0; i < tests.length; ++i) args.push(tests[i][j % tests[i].length]); | ||||
| [ "stress(", | ||||
| "	" + args[0] + ",", | ||||
| "	CAST_U(" + args[1] + "),", | ||||
| "	" + args[2] + ",", | ||||
| "	" + (args[3].match(/INF/) ? "" : "CAST_LD") + "(" + args[3] + "),", | ||||
| "	" + args[4] + ",", | ||||
| "	CAST_WSTR(" + args[5] + "),", | ||||
| "	CAST_CHAR(" + args[6] + "),", | ||||
| "	CAST_UCHAR(" + args[7] + "),", | ||||
| "	CAST_SHORT(" + args[8] + "),", | ||||
| "	CAST_USHORT(" + args[9] + "),", | ||||
| "	CAST_L(" + args[10] + "),", | ||||
| "	CAST_UL(" + args[11] + "),", | ||||
| "	CAST_LL(" + args[12] + "),", | ||||
| "	CAST_ULL(" + args[13] + "),", | ||||
| "	CAST_INTMAX_T(" + args[14] + "),", | ||||
| "	CAST_UINTMAX_T(" + args[15] + "),", | ||||
| "	CAST_SIZE_T(" + args[16] + "),", | ||||
| "	CAST_SSIZE_T(" + args[17] + "),", | ||||
| "	CAST_PTRDIFF_T(" + args[18] + "),", | ||||
| "	CAST_UINTPTR_T(" + args[19] + ")", | ||||
| ");\n"].forEach(function(x) { console.log(x); }); | ||||
| } | ||||
							
								
								
									
										22
									
								
								stress/stress.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								stress/stress.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| #include <wchar.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| #include <stddef.h> | ||||
| #include <math.h> | ||||
| 
 | ||||
| #include "common.h" | ||||
| 
 | ||||
| void stress( | ||||
| 	int i, unsigned int u, | ||||
| 	double d, long double ld, | ||||
| 	char *s, wchar_t *ws, | ||||
| 	signed char hhi, unsigned char hhu, short hi, unsigned short hu, | ||||
| 	long li, unsigned long lu, long long lli, unsigned long long llu, | ||||
| 	intmax_t ji, uintmax_t ju, size_t zi, ssize_t zu, ptrdiff_t ti, uintptr_t tu | ||||
| ) { | ||||
| #include "stress.h" | ||||
| } | ||||
| 
 | ||||
| int main() { | ||||
| 	#include "tests.h" | ||||
| } | ||||
							
								
								
									
										23
									
								
								stress/stress.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										23
									
								
								stress/stress.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| #ifndef JAVASCRIPT | ||||
| #define JAVASCRIPT | ||||
| #endif | ||||
| var sprintf = require("../"); | ||||
| var printf = function() { | ||||
| 	var o = sprintf.sprintf.apply(null, arguments); | ||||
| 	process.stdout.write(o); | ||||
| } | ||||
| 
 | ||||
| function stress( | ||||
| 	i, u, | ||||
| 	d, ld, | ||||
| 	s, ws, | ||||
| 	hhi, hhu, hi, hu, | ||||
| 	li, lu, lli, llu, | ||||
| 	ji, ju, zi, zu, ti, tu | ||||
| ) { | ||||
| #include "stress.h" | ||||
| } | ||||
| 
 | ||||
| #include "common.h" | ||||
| 
 | ||||
| #include "tests.h" | ||||
							
								
								
									
										39
									
								
								test.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										39
									
								
								test.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| var assert = require("assert"); | ||||
| 
 | ||||
| var IMPL = require("./lib/impl.json"); | ||||
| var COMPARE = require("./tests/compare.json"); | ||||
| var PRINTF = require("./tests/printf"); | ||||
| 
 | ||||
| var IMPLS = {}, IMPLA = []; | ||||
| IMPL.forEach(function(impl, i) { IMPLS[impl] = IMPLA[i] = require("./lib/" + impl); }); | ||||
| IMPL.push("base"); IMPLS["base"] = IMPLA[IMPL.length-1] = require("./"); | ||||
| 
 | ||||
| function compare_parse(a,b) { | ||||
| 	assert.equal(a.length, b.length); | ||||
| 	for(var i = 0; i < a.length; ++i) { | ||||
| 		for(var j = 0; j < a[i].length; ++j) { | ||||
| 			if((a[i][j] || "") != (b[i][j] || "")) { | ||||
| 				throw i + "," + j + " " + a[i] + " " + b[i]; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| describe('consensus', function() { | ||||
| 	it('tokenizer', function() { | ||||
| 		COMPARE.forEach(function(m) { | ||||
| 			var base = IMPLA[0]._tokenize(m); | ||||
| 			for(var i = 1; i < IMPLA.length; ++i) compare_parse(base, IMPLA[i]._tokenize(m)); | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| describe('correctness', function() { | ||||
| 	IMPL.forEach(function(n,i) { | ||||
| 		it(n, function() { | ||||
| 			PRINTF.forEach(function(v) { | ||||
| 				assert.equal(IMPLA[i].sprintf.apply(IMPLA[i], v[0]), v[1]); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
							
								
								
									
										12
									
								
								tests/compare.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								tests/compare.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| [ | ||||
| 	"Hello World!", | ||||
| 	"Hello %s!", | ||||
| 	"Hello %s %s%s!", | ||||
| 	"Hello %s %s%s %s%s%s :(", | ||||
| 	"Hello %s %s%s %s%s%s %s%s%s%s", | ||||
| 	"Hello %x %s%02hhx %s%X%s %s%X%s%X", | ||||
| 	"Hello %s %s%s %s%s%s %s%s%s%s %s%s%s%s%102f %f", | ||||
| 	"Hello %1$s!", | ||||
| 	"Hello %1$*.*s!", | ||||
| 	"Hello %1$*2$.*3$s!" | ||||
| ] | ||||
							
								
								
									
										89926
									
								
								tests/printf.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										89926
									
								
								tests/printf.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user