diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 9 | ||||
-rw-r--r-- | src/compiler.js | 11 | ||||
-rw-r--r-- | src/headless.js | 5 | ||||
-rw-r--r-- | src/jsifier.js | 56 | ||||
-rw-r--r-- | src/library.js | 683 | ||||
-rw-r--r-- | src/library_gl.js | 109 | ||||
-rw-r--r-- | src/library_openal.js | 541 | ||||
-rw-r--r-- | src/library_sdl.js | 29 | ||||
-rw-r--r-- | src/long.js | 7 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/parseTools.js | 59 | ||||
-rw-r--r-- | src/preamble.js | 49 | ||||
-rw-r--r-- | src/runtime.js | 51 | ||||
-rw-r--r-- | src/settings.js | 29 | ||||
-rw-r--r-- | src/utility.js | 9 |
15 files changed, 1185 insertions, 464 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 926ac9d3..92b7d8cf 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -18,7 +18,7 @@ function recomputeLines(func) { // Handy sets var BRANCH_INVOKE = set('branch', 'invoke'); -var LABEL_ENDERS = set('branch', 'return'); +var LABEL_ENDERS = set('branch', 'return', 'switch'); var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic'); var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam'); @@ -653,13 +653,14 @@ function analyzer(data, sidePass) { if (!isNumber(shifts)) { // We can't statically legalize this, do the operation at runtime TODO: optimize assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits'); + assert(PRECISE_I64_MATH, 'Must have precise i64 math for non-constant 64-bit shifts'); + Types.preciseI64MathUsed = 1; value.intertype = 'value'; - value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + + value.ident = 'var ' + value.assignTo + '$0 = _bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' + asmCoercion(sourceElements[0].ident, 'i32') + ',' + asmCoercion(sourceElements[1].ident, 'i32') + ',' + - Runtime['BITSHIFT64_' + value.op.toUpperCase()] + ',' + asmCoercion(value.params[1].ident + '$0', 'i32') + ');' + - 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';'; + 'var ' + value.assignTo + '$1 = tempRet0;'; value.assignTo = null; i++; continue; diff --git a/src/compiler.js b/src/compiler.js index 447d34b7..bb72c7dd 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -141,8 +141,13 @@ if (phase == 'pre') { if (settings_file) { var settings = JSON.parse(read(settings_file)); - for (setting in settings) { - eval(setting + ' = ' + JSON.stringify(settings[setting])); + for (key in settings) { + var value = settings[key]; + if (value[0] == '@') { + // response file type thing, workaround for large inputs: value is @path-to-file + value = JSON.parse(read(value.substr(1))); + } + eval(key + ' = ' + JSON.stringify(value)); } } @@ -163,7 +168,7 @@ if (SAFE_HEAP >= 2) { EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); -DEAD_FUNCTIONS = set(DEAD_FUNCTIONS); +DEAD_FUNCTIONS = numberedSet(DEAD_FUNCTIONS); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; diff --git a/src/headless.js b/src/headless.js index 8e847d27..d81fb5a3 100644 --- a/src/headless.js +++ b/src/headless.js @@ -537,7 +537,7 @@ var document = { case /* GL_MAX_FRAGMENT_UNIFORM_VECTORS */ 0x8DFD: return 4096; case /* GL_MAX_VARYING_VECTORS */ 0x8DFC: return 32; case /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS */ 0x8B4D: return 32; - default: throw 'getParameter ' + pname; + default: console.log('getParameter ' + pname + '?'); return 0; } }, getSupportedExtensions: function() { @@ -686,6 +686,7 @@ var document = { document.callEventListeners('pointerlockchange'); }); }, + exitPointerLock: function(){}, style: {}, eventListeners: {}, addEventListener: document.addEventListener, @@ -748,6 +749,8 @@ var document = { body: { appendChild: function(){}, }, + exitPointerLock: function(){}, + cancelFullScreen: function(){}, }; var alert = function(x) { print(x); diff --git a/src/jsifier.js b/src/jsifier.js index d36f26ce..7db2ee70 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -397,6 +397,20 @@ function JSify(data, functionsOnly, givenFunctions) { } }); + function processLibraryFunction(snippet, ident) { + snippet = snippet.toString(); + assert(snippet.indexOf('XXX missing C define') == -1, + 'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet); + + // name the function; overwrite if it's already named + snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); + if (LIBRARY_DEBUG) { + snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); + snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}'; + } + return snippet; + } + // functionStub substrate.addActor('FunctionStub', { processItem: function(item) { @@ -434,16 +448,7 @@ function JSify(data, functionsOnly, givenFunctions) { snippet = stringifyWithFunctions(snippet); } else if (typeof snippet === 'function') { isFunction = true; - snippet = snippet.toString(); - assert(snippet.indexOf('XXX missing C define') == -1, - 'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet); - - // name the function; overwrite if it's already named - snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); - if (LIBRARY_DEBUG) { - snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); - snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}'; - } + snippet = processLibraryFunction(snippet, ident); if (ASM_JS) Functions.libraryFunctions[ident] = 1; } @@ -507,9 +512,13 @@ function JSify(data, functionsOnly, givenFunctions) { } else if (LibraryManager.library.hasOwnProperty(shortident)) { item.JS = addFromLibrary(shortident); } else if (!LibraryManager.library.hasOwnProperty(shortident + '__inline')) { - item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; - if (WARN_ON_UNDEFINED_SYMBOLS || ASM_JS) { // always warn on undefs in asm, since it breaks validation - warn('Unresolved symbol: ' + item.ident); + if (!(item.ident in DEAD_FUNCTIONS) && !UNRESOLVED_AS_DEAD) { + item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; + if (ASM_JS) { + throw 'Unresolved symbol: ' + item.ident + ', this must be corrected for asm.js validation to succeed. Consider adding it to DEAD_FUNCTIONS.'; + } else if (WARN_ON_UNDEFINED_SYMBOLS) { + warn('Unresolved symbol: ' + item.ident); + } } } return ret; @@ -717,6 +726,7 @@ function JSify(data, functionsOnly, givenFunctions) { ret += indent + 'label = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + getOriginalLabelId(block.entries[0]) + ' */' : '') + '\n'; } // otherwise, should have been set before! if (func.setjmpTable) { + assert(!ASM_JS, 'asm.js mode does not support setjmp yet'); var setjmpTable = {}; ret += indent + 'var mySetjmpIds = {};\n'; ret += indent + 'var setjmpTable = {'; @@ -1316,6 +1326,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { callIdent = ident; } + if (callIdent == '0') return 'abort(-2)'; var args = []; var argsTypes = []; @@ -1420,7 +1431,7 @@ function JSify(data, functionsOnly, givenFunctions) { } if (callIdent in DEAD_FUNCTIONS) { - var ret = 'abort(7)'; + var ret = 'abort(' + DEAD_FUNCTIONS[callIdent] + ')'; if (ASM_JS) ret = asmCoercion(ret, returnType); return ret; } @@ -1563,16 +1574,25 @@ function JSify(data, functionsOnly, givenFunctions) { // This is the main 'post' pass. Print out the generated code that we have here, together with the // rest of the output that we started to print out earlier (see comment on the // "Final shape that will be created"). - if (CORRUPTION_CHECK) { - assert(!ASM_JS); // cannot monkeypatch asm! - print(processMacros(read('corruptionCheck.js'))); - } if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { + if (!INCLUDE_FULL_LIBRARY) { + ['i64Add', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr'].forEach(function(func) { + print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code + Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; + }); + } + print('// EMSCRIPTEN_END_FUNCS\n'); print(read('long.js')); } else { + print('// EMSCRIPTEN_END_FUNCS\n'); print('// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included'); print('var i64Math = null;'); } + + if (CORRUPTION_CHECK) { + assert(!ASM_JS); // cannot monkeypatch asm! + print(processMacros(read('corruptionCheck.js'))); + } if (HEADLESS) { print('if (!ENVIRONMENT_IS_WEB) {'); print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0')); diff --git a/src/library.js b/src/library.js index 3d00a4d5..d5f11cf3 100644 --- a/src/library.js +++ b/src/library.js @@ -504,7 +504,7 @@ LibraryManager.library = { } var utf8 = new Runtime.UTF8Processor(); function simpleOutput(val) { - if (val === null || val === '\n'.charCodeAt(0)) { + if (val === null || val === {{{ charCode('\n') }}}) { output.printer(output.buffer.join('')); output.buffer = []; } else { @@ -600,8 +600,8 @@ LibraryManager.library = { quit: function() { if (!FS.init.initialized) return; // Flush any partially-printed lines in stdout and stderr. Careful, they may have been closed - if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output('\n'.charCodeAt(0)); - if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output('\n'.charCodeAt(0)); + if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output({{{ charCode('\n') }}}); + if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output({{{ charCode('\n') }}}); }, // Standardizes a path. Useful for making comparisons of pathnames work in a consistent manner. @@ -828,11 +828,11 @@ LibraryManager.library = { // Null or empty results in '.'. var me = ___libgenSplitName; if (!me.ret) { - me.ret = allocate(['.'.charCodeAt(0), 0], 'i8', ALLOC_NORMAL); + me.ret = allocate([{{{ charCode('.') }}}, 0], 'i8', ALLOC_NORMAL); } return [me.ret, -1]; } else { - var slash = '/'.charCodeAt(0); + var slash = {{{ charCode('/') }}}; var allSlashes = true; var slashPositions = []; for (var i = 0; {{{ makeGetValue('path', 'i', 'i8') }}} !== 0; i++) { @@ -1730,7 +1730,12 @@ LibraryManager.library = { } var contents = stream.object.contents; var size = Math.min(contents.length - offset, nbyte); - if (contents.subarray || contents.slice) { // typed array or normal array +#if USE_TYPED_ARRAYS == 2 + if (contents.subarray) { // typed array + HEAPU8.set(contents.subarray(offset, offset+size), buf); + } else +#endif + if (contents.slice) { // normal array for (var i = 0; i < size; i++) { {{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}} } @@ -2452,9 +2457,9 @@ LibraryManager.library = { _scanString: function(format, get, unget, varargs) { if (!__scanString.whiteSpace) { __scanString.whiteSpace = {}; - __scanString.whiteSpace[' '.charCodeAt(0)] = 1; - __scanString.whiteSpace['\t'.charCodeAt(0)] = 1; - __scanString.whiteSpace['\n'.charCodeAt(0)] = 1; + __scanString.whiteSpace[{{{ charCode(' ') }}}] = 1; + __scanString.whiteSpace[{{{ charCode('\t') }}}] = 1; + __scanString.whiteSpace[{{{ charCode('\n') }}}] = 1; __scanString.whiteSpace[' '] = 1; __scanString.whiteSpace['\t'] = 1; __scanString.whiteSpace['\n'] = 1; @@ -2514,8 +2519,8 @@ LibraryManager.library = { if (format[formatIndex] === '%') { formatIndex++; var maxSpecifierStart = formatIndex; - while (format[formatIndex].charCodeAt(0) >= '0'.charCodeAt(0) && - format[formatIndex].charCodeAt(0) <= '9'.charCodeAt(0)) { + while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} && + format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) { formatIndex++; } var max_; @@ -2561,11 +2566,11 @@ LibraryManager.library = { while ((curr < max_ || isNaN(max_)) && next > 0) { if (!(next in __scanString.whiteSpace) && // stop on whitespace (type == 's' || - ((type === 'd' || type == 'u' || type == 'i') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) || - (first && next == '-'.charCodeAt(0)))) || - (type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) || - next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) || - next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0)))) && + ((type === 'd' || type == 'u' || type == 'i') && ((next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) || + (first && next == {{{ charCode('-') }}}))) || + (type === 'x' && (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}} || + next >= {{{ charCode('a') }}} && next <= {{{ charCode('f') }}} || + next >= {{{ charCode('A') }}} && next <= {{{ charCode('F') }}}))) && (formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up buffer.push(String.fromCharCode(next)); next = get(); @@ -2633,7 +2638,7 @@ LibraryManager.library = { } return fields; }, - // Performs prtinf-style formatting. + // Performs printf-style formatting. // format: A pointer to the format string. // varargs: A pointer to the start of the arguments list. // Returns the resulting string string as a character array. @@ -2670,7 +2675,7 @@ LibraryManager.library = { curr = {{{ makeGetValue(0, 'textIndex', 'i8') }}}; if (curr === 0) break; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; - if (curr == '%'.charCodeAt(0)) { + if (curr == {{{ charCode('%') }}}) { // Handle flags. var flagAlwaysSigned = false; var flagLeftAlign = false; @@ -2678,16 +2683,16 @@ LibraryManager.library = { var flagZeroPad = false; flagsLoop: while (1) { switch (next) { - case '+'.charCodeAt(0): + case {{{ charCode('+') }}}: flagAlwaysSigned = true; break; - case '-'.charCodeAt(0): + case {{{ charCode('-') }}}: flagLeftAlign = true; break; - case '#'.charCodeAt(0): + case {{{ charCode('#') }}}: flagAlternative = true; break; - case '0'.charCodeAt(0): + case {{{ charCode('0') }}}: if (flagZeroPad) { break flagsLoop; } else { @@ -2703,13 +2708,13 @@ LibraryManager.library = { // Handle width. var width = 0; - if (next == '*'.charCodeAt(0)) { + if (next == {{{ charCode('*') }}}) { width = getNextArg('i32'); textIndex++; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; } else { - while (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) { - width = width * 10 + (next - '0'.charCodeAt(0)); + while (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) { + width = width * 10 + (next - {{{ charCode('0') }}}); textIndex++; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; } @@ -2717,20 +2722,20 @@ LibraryManager.library = { // Handle precision. var precisionSet = false; - if (next == '.'.charCodeAt(0)) { + if (next == {{{ charCode('.') }}}) { var precision = 0; precisionSet = true; textIndex++; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; - if (next == '*'.charCodeAt(0)) { + if (next == {{{ charCode('*') }}}) { precision = getNextArg('i32'); textIndex++; } else { while(1) { var precisionChr = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; - if (precisionChr < '0'.charCodeAt(0) || - precisionChr > '9'.charCodeAt(0)) break; - precision = precision * 10 + (precisionChr - '0'.charCodeAt(0)); + if (precisionChr < {{{ charCode('0') }}} || + precisionChr > {{{ charCode('9') }}}) break; + precision = precision * 10 + (precisionChr - {{{ charCode('0') }}}); textIndex++; } } @@ -2744,7 +2749,7 @@ LibraryManager.library = { switch (String.fromCharCode(next)) { case 'h': var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}}; - if (nextNext == 'h'.charCodeAt(0)) { + if (nextNext == {{{ charCode('h') }}}) { textIndex++; argSize = 1; // char (actually i32 in varargs) } else { @@ -2753,7 +2758,7 @@ LibraryManager.library = { break; case 'l': var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}}; - if (nextNext == 'l'.charCodeAt(0)) { + if (nextNext == {{{ charCode('l') }}}) { textIndex++; argSize = 8; // long long } else { @@ -2777,226 +2782,249 @@ LibraryManager.library = { next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; // Handle type specifier. - if (['d', 'i', 'u', 'o', 'x', 'X', 'p'].indexOf(String.fromCharCode(next)) != -1) { - // Integer. - var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0); - argSize = argSize || 4; - var currArg = getNextArg('i' + (argSize * 8)); + switch (String.fromCharCode(next)) { + case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': { + // Integer. + var signed = next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}; + argSize = argSize || 4; + var currArg = getNextArg('i' + (argSize * 8)); #if PRECISE_I64_MATH - var origArg = currArg; + var origArg = currArg; #endif - var argText; + var argText; #if USE_TYPED_ARRAYS == 2 - // Flatten i64-1 [low, high] into a (slightly rounded) double - if (argSize == 8) { - currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 'u'.charCodeAt(0)); - } + // Flatten i64-1 [low, high] into a (slightly rounded) double + if (argSize == 8) { + currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == {{{ charCode('u') }}}); + } #endif - // Truncate to requested size. - if (argSize <= 4) { - var limit = Math.pow(256, argSize) - 1; - currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8); - } - // Format the number. - var currAbsArg = Math.abs(currArg); - var prefix = ''; - if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) { + // Truncate to requested size. + if (argSize <= 4) { + var limit = Math.pow(256, argSize) - 1; + currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8); + } + // Format the number. + var currAbsArg = Math.abs(currArg); + var prefix = ''; + if (next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}) { #if PRECISE_I64_MATH - if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else + if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else #endif - argText = reSign(currArg, 8 * argSize, 1).toString(10); - } else if (next == 'u'.charCodeAt(0)) { + argText = reSign(currArg, 8 * argSize, 1).toString(10); + } else if (next == {{{ charCode('u') }}}) { #if PRECISE_I64_MATH - if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else + if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else #endif - argText = unSign(currArg, 8 * argSize, 1).toString(10); - currArg = Math.abs(currArg); - } else if (next == 'o'.charCodeAt(0)) { - argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8); - } else if (next == 'x'.charCodeAt(0) || next == 'X'.charCodeAt(0)) { - prefix = flagAlternative ? '0x' : ''; + argText = unSign(currArg, 8 * argSize, 1).toString(10); + currArg = Math.abs(currArg); + } else if (next == {{{ charCode('o') }}}) { + argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8); + } else if (next == {{{ charCode('x') }}} || next == {{{ charCode('X') }}}) { + prefix = flagAlternative ? '0x' : ''; #if PRECISE_I64_MATH - if (argSize == 8 && i64Math) argText = (origArg[1]>>>0).toString(16) + (origArg[0]>>>0).toString(16); else + if (argSize == 8 && i64Math) { + if (origArg[1]) { + argText = (origArg[1]>>>0).toString(16); + var lower = (origArg[0]>>>0).toString(16); + while (lower.length < 8) lower = '0' + lower; + argText += lower; + } else { + argText = (origArg[0]>>>0).toString(16); + } + } else #endif - if (currArg < 0) { - // Represent negative numbers in hex as 2's complement. - currArg = -currArg; - argText = (currAbsArg - 1).toString(16); - var buffer = []; - for (var i = 0; i < argText.length; i++) { - buffer.push((0xF - parseInt(argText[i], 16)).toString(16)); + if (currArg < 0) { + // Represent negative numbers in hex as 2's complement. + currArg = -currArg; + argText = (currAbsArg - 1).toString(16); + var buffer = []; + for (var i = 0; i < argText.length; i++) { + buffer.push((0xF - parseInt(argText[i], 16)).toString(16)); + } + argText = buffer.join(''); + while (argText.length < argSize * 2) argText = 'f' + argText; + } else { + argText = currAbsArg.toString(16); + } + if (next == {{{ charCode('X') }}}) { + prefix = prefix.toUpperCase(); + argText = argText.toUpperCase(); + } + } else if (next == {{{ charCode('p') }}}) { + if (currAbsArg === 0) { + argText = '(nil)'; + } else { + prefix = '0x'; + argText = currAbsArg.toString(16); } - argText = buffer.join(''); - while (argText.length < argSize * 2) argText = 'f' + argText; - } else { - argText = currAbsArg.toString(16); - } - if (next == 'X'.charCodeAt(0)) { - prefix = prefix.toUpperCase(); - argText = argText.toUpperCase(); - } - } else if (next == 'p'.charCodeAt(0)) { - if (currAbsArg === 0) { - argText = '(nil)'; - } else { - prefix = '0x'; - argText = currAbsArg.toString(16); } - } - if (precisionSet) { - while (argText.length < precision) { - argText = '0' + argText; + if (precisionSet) { + while (argText.length < precision) { + argText = '0' + argText; + } } - } - // Add sign if needed - if (flagAlwaysSigned) { - if (currArg < 0) { - prefix = '-' + prefix; - } else { - prefix = '+' + prefix; + // Add sign if needed + if (flagAlwaysSigned) { + if (currArg < 0) { + prefix = '-' + prefix; + } else { + prefix = '+' + prefix; + } } - } - // Add padding. - while (prefix.length + argText.length < width) { - if (flagLeftAlign) { - argText += ' '; - } else { - if (flagZeroPad) { - argText = '0' + argText; + // Add padding. + while (prefix.length + argText.length < width) { + if (flagLeftAlign) { + argText += ' '; } else { - prefix = ' ' + prefix; + if (flagZeroPad) { + argText = '0' + argText; + } else { + prefix = ' ' + prefix; + } } } + + // Insert the result into the buffer. + argText = prefix + argText; + argText.split('').forEach(function(chr) { + ret.push(chr.charCodeAt(0)); + }); + break; } + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': { + // Float. + var currArg = getNextArg('double'); + var argText; + + if (isNaN(currArg)) { + argText = 'nan'; + flagZeroPad = false; + } else if (!isFinite(currArg)) { + argText = (currArg < 0 ? '-' : '') + 'inf'; + flagZeroPad = false; + } else { + var isGeneral = false; + var effectivePrecision = Math.min(precision, 20); + + // Convert g/G to f/F or e/E, as per: + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html + if (next == {{{ charCode('g') }}} || next == {{{ charCode('G') }}}) { + isGeneral = true; + precision = precision || 1; + var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10); + if (precision > exponent && exponent >= -4) { + next = ((next == {{{ charCode('g') }}}) ? 'f' : 'F').charCodeAt(0); + precision -= exponent + 1; + } else { + next = ((next == {{{ charCode('g') }}}) ? 'e' : 'E').charCodeAt(0); + precision--; + } + effectivePrecision = Math.min(precision, 20); + } - // Insert the result into the buffer. - argText = prefix + argText; - argText.split('').forEach(function(chr) { - ret.push(chr.charCodeAt(0)); - }); - } else if (['f', 'F', 'e', 'E', 'g', 'G'].indexOf(String.fromCharCode(next)) != -1) { - // Float. - var currArg = getNextArg('double'); - var argText; - - if (isNaN(currArg)) { - argText = 'nan'; - flagZeroPad = false; - } else if (!isFinite(currArg)) { - argText = (currArg < 0 ? '-' : '') + 'inf'; - flagZeroPad = false; - } else { - var isGeneral = false; - var effectivePrecision = Math.min(precision, 20); - - // Convert g/G to f/F or e/E, as per: - // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html - if (next == 'g'.charCodeAt(0) || next == 'G'.charCodeAt(0)) { - isGeneral = true; - precision = precision || 1; - var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10); - if (precision > exponent && exponent >= -4) { - next = ((next == 'g'.charCodeAt(0)) ? 'f' : 'F').charCodeAt(0); - precision -= exponent + 1; + if (next == {{{ charCode('e') }}} || next == {{{ charCode('E') }}}) { + argText = currArg.toExponential(effectivePrecision); + // Make sure the exponent has at least 2 digits. + if (/[eE][-+]\d$/.test(argText)) { + argText = argText.slice(0, -1) + '0' + argText.slice(-1); + } + } else if (next == {{{ charCode('f') }}} || next == {{{ charCode('F') }}}) { + argText = currArg.toFixed(effectivePrecision); + } + + var parts = argText.split('e'); + if (isGeneral && !flagAlternative) { + // Discard trailing zeros and periods. + while (parts[0].length > 1 && parts[0].indexOf('.') != -1 && + (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) { + parts[0] = parts[0].slice(0, -1); + } } else { - next = ((next == 'g'.charCodeAt(0)) ? 'e' : 'E').charCodeAt(0); - precision--; + // Make sure we have a period in alternative mode. + if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.'; + // Zero pad until required precision. + while (precision > effectivePrecision++) parts[0] += '0'; } - effectivePrecision = Math.min(precision, 20); - } + argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : ''); + + // Capitalize 'E' if needed. + if (next == {{{ charCode('E') }}}) argText = argText.toUpperCase(); - if (next == 'e'.charCodeAt(0) || next == 'E'.charCodeAt(0)) { - argText = currArg.toExponential(effectivePrecision); - // Make sure the exponent has at least 2 digits. - if (/[eE][-+]\d$/.test(argText)) { - argText = argText.slice(0, -1) + '0' + argText.slice(-1); + // Add sign. + if (flagAlwaysSigned && currArg >= 0) { + argText = '+' + argText; } - } else if (next == 'f'.charCodeAt(0) || next == 'F'.charCodeAt(0)) { - argText = currArg.toFixed(effectivePrecision); } - var parts = argText.split('e'); - if (isGeneral && !flagAlternative) { - // Discard trailing zeros and periods. - while (parts[0].length > 1 && parts[0].indexOf('.') != -1 && - (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) { - parts[0] = parts[0].slice(0, -1); + // Add padding. + while (argText.length < width) { + if (flagLeftAlign) { + argText += ' '; + } else { + if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) { + argText = argText[0] + '0' + argText.slice(1); + } else { + argText = (flagZeroPad ? '0' : ' ') + argText; + } } - } else { - // Make sure we have a period in alternative mode. - if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.'; - // Zero pad until required precision. - while (precision > effectivePrecision++) parts[0] += '0'; } - argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : ''); - // Capitalize 'E' if needed. - if (next == 'E'.charCodeAt(0)) argText = argText.toUpperCase(); + // Adjust case. + if (next < {{{ charCode('a') }}}) argText = argText.toUpperCase(); - // Add sign. - if (flagAlwaysSigned && currArg >= 0) { - argText = '+' + argText; - } + // Insert the result into the buffer. + argText.split('').forEach(function(chr) { + ret.push(chr.charCodeAt(0)); + }); + break; } - - // Add padding. - while (argText.length < width) { + case 's': { + // String. + var arg = getNextArg('i8*') || nullString; + var argLength = _strlen(arg); + if (precisionSet) argLength = Math.min(argLength, precision); + if (!flagLeftAlign) { + while (argLength < width--) { + ret.push({{{ charCode(' ') }}}); + } + } + for (var i = 0; i < argLength; i++) { + ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}}); + } if (flagLeftAlign) { - argText += ' '; - } else { - if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) { - argText = argText[0] + '0' + argText.slice(1); - } else { - argText = (flagZeroPad ? '0' : ' ') + argText; + while (argLength < width--) { + ret.push({{{ charCode(' ') }}}); } } + break; } - - // Adjust case. - if (next < 'a'.charCodeAt(0)) argText = argText.toUpperCase(); - - // Insert the result into th |