diff options
Diffstat (limited to 'src/library.js')
-rw-r--r-- | src/library.js | 316 |
1 files changed, 246 insertions, 70 deletions
diff --git a/src/library.js b/src/library.js index 5b85c56f..bb73c48a 100644 --- a/src/library.js +++ b/src/library.js @@ -28,7 +28,14 @@ LibraryManager.library = { $FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'], $FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' + '__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' + - '__ATEXIT__.push({ func: function() { FS.quit() } });', + '__ATEXIT__.push({ func: function() { FS.quit() } });' + + // export some names through closure + 'Module["FS_createFolder"] = FS.createFolder;' + + 'Module["FS_createPath"] = FS.createPath;' + + 'Module["FS_createDataFile"] = FS.createDataFile;' + + 'Module["FS_createLazyFile"] = FS.createLazyFile;' + + 'Module["FS_createLink"] = FS.createLink;' + + 'Module["FS_createDevice"] = FS.createDevice;', $FS: { // The path to the current folder. currentPath: '/', @@ -90,18 +97,18 @@ LibraryManager.library = { #if FS_LOG var inputPath = path; function log() { - print('FS.analyzePath("' + inputPath + '", ' + - dontResolveLastLink + ', ' + - linksVisited + ') => {' + - 'isRoot: ' + ret.isRoot + ', ' + - 'exists: ' + ret.exists + ', ' + - 'error: ' + ret.error + ', ' + - 'name: "' + ret.name + '", ' + - 'path: "' + ret.path + '", ' + - 'object: ' + ret.object + ', ' + - 'parentExists: ' + ret.parentExists + ', ' + - 'parentPath: "' + ret.parentPath + '", ' + - 'parentObject: ' + ret.parentObject + '}'); + Module['print']('FS.analyzePath("' + inputPath + '", ' + + dontResolveLastLink + ', ' + + linksVisited + ') => {' + + 'isRoot: ' + ret.isRoot + ', ' + + 'exists: ' + ret.exists + ', ' + + 'error: ' + ret.error + ', ' + + 'name: "' + ret.name + '", ' + + 'path: "' + ret.path + '", ' + + 'object: ' + ret.object + ', ' + + 'parentExists: ' + ret.parentExists + ', ' + + 'parentPath: "' + ret.parentPath + '", ' + + 'parentObject: ' + ret.parentObject + '}'); } #endif path = FS.absolutePath(path); @@ -177,11 +184,11 @@ LibraryManager.library = { // Creates a file system record: file, link, device or folder. createObject: function(parent, name, properties, canRead, canWrite) { #if FS_LOG - print('FS.createObject("' + parent + '", ' + - '"' + name + '", ' + - JSON.stringify(properties) + ', ' + - canRead + ', ' + - canWrite + ')'); + Module['print']('FS.createObject("' + parent + '", ' + + '"' + name + '", ' + + JSON.stringify(properties) + ', ' + + canRead + ', ' + + canWrite + ')'); #endif if (!parent) parent = '/'; if (typeof parent === 'string') parent = FS.findObject(parent); @@ -257,11 +264,20 @@ LibraryManager.library = { var properties = {isDevice: false, contents: data}; return FS.createFile(parent, name, properties, canRead, canWrite); }, - // Creates a file record for lazy-loading from a URL. + // Creates a file record for lazy-loading from a URL. XXX This requires a synchronous + // XHR, which is not possible in browsers except in a web worker! Use preloading, + // either --preload-file in emcc or FS.createPreloadedFile createLazyFile: function(parent, name, url, canRead, canWrite) { var properties = {isDevice: false, url: url}; return FS.createFile(parent, name, properties, canRead, canWrite); }, + // Preloads a file asynchronously. You can call this before run, for example in + // preRun. run will be delayed until this file arrives and is set up. + createPreloadedFile: function(parent, name, url, canRead, canWrite) { + Browser.asyncLoad(url, function(data) { + FS.createDataFile(parent, name, data, canRead, canWrite); + }); + }, // Creates a link to a sepcific local path. createLink: function(parent, name, target, canRead, canWrite) { var properties = {isDevice: false, link: target}; @@ -340,6 +356,7 @@ LibraryManager.library = { typeof window.prompt == 'function') { // Browser. result = window.prompt('Input: '); + if (result === null) result = String.fromCharCode(0); // cancel ==> EOF } else if (typeof readline == 'function') { // Command line. result = readline(); @@ -371,8 +388,10 @@ LibraryManager.library = { if (!error.printer) error.printer = Module['print']; if (!error.buffer) error.buffer = []; - // Create the temporary folder. - FS.createFolder('/', 'tmp', true, true); + // Create the temporary folder, if not already created + try { + FS.createFolder('/', 'tmp', true, true); + } catch(e) {} // Create the I/O devices. var devFolder = FS.createFolder('/', 'dev', true, true); @@ -1476,7 +1495,7 @@ LibraryManager.library = { lseek: function(fildes, offset, whence) { // off_t lseek(int fildes, off_t offset, int whence); // http://pubs.opengroup.org/onlinepubs/000095399/functions/lseek.html - if (FS.streams[fildes] && !FS.streams[fildes].isDevice) { + if (FS.streams[fildes] && !FS.streams[fildes].object.isDevice) { var stream = FS.streams[fildes]; var position = offset; if (whence === 1) { // SEEK_CUR. @@ -1867,7 +1886,7 @@ LibraryManager.library = { #if CATCH_EXIT_CODE throw new ExitStatus(); -#else +#else throw 'exit(' + status + ') called, at ' + new Error().stack; #endif }, @@ -2217,6 +2236,9 @@ LibraryManager.library = { if (!self.called) { STATICTOP = alignMemoryPage(STATICTOP); // make sure we start out aligned self.called = true; +#if GC_SUPPORT + _sbrk.DYNAMIC_START = STATICTOP; +#endif } var ret = STATICTOP; if (bytes != 0) Runtime.staticAlloc(bytes); @@ -2242,6 +2264,15 @@ LibraryManager.library = { // TODO: Document. _scanString__deps: ['_isFloat'], _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[' '] = 1; + __scanString.whiteSpace['\t'] = 1; + __scanString.whiteSpace['\n'] = 1; + } // Supports %x, %4x, %d.%d, %s, %f, %lf. // TODO: Support all format specifiers. format = Pointer_stringify(format); @@ -2249,6 +2280,7 @@ LibraryManager.library = { var argsi = 0; var fields = 0; var argIndex = 0; + var next; for (var formatIndex = 0; formatIndex < format.length; formatIndex++) { if (next <= 0) return fields; var next = get(); @@ -2264,11 +2296,14 @@ LibraryManager.library = { if (formatIndex != maxSpecifierStart) { max_ = parseInt(format.slice(maxSpecifierStart, formatIndex), 10); } - // TODO: Handle type size modifier. var long_ = false; + var half = false; if (format[formatIndex] == 'l') { long_ = true; formatIndex++; + } else if (format[formatIndex] == 'h') { + half = true; + formatIndex++; } var type = format[formatIndex]; formatIndex++; @@ -2288,13 +2323,18 @@ LibraryManager.library = { buffer.pop(); unget(); } + unget(); + next = get(); } else { + var first = true; while ((curr < max_ || isNaN(max_)) && next > 0) { - if ((type === 'd' && next >= '0'.charCodeAt(0) && next <= '9'.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 === 's') && + if (!(next in __scanString.whiteSpace) && // stop on whitespace + (type == 's' || + ((type === 'd' || type == 'u') && ((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)))) && (formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up buffer.push(String.fromCharCode(next)); next = get(); @@ -2302,6 +2342,7 @@ LibraryManager.library = { } else { break; } + first = false; } } if (buffer.length === 0) return 0; // Failure. @@ -2309,8 +2350,12 @@ LibraryManager.library = { var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getNativeFieldSize('void*'); switch (type) { - case 'd': - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}} + case 'd': case 'u': + if (half) { + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}}; + } else { + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}}; + } break; case 'x': {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}} @@ -2330,6 +2375,12 @@ LibraryManager.library = { break; } fields++; + } else if (format[formatIndex] in __scanString.whiteSpace) { + while (next in __scanString.whiteSpace) { + next = get(); + if (next <= 0) return fields; // End of input. + } + unget(); } else { // Not a specifier. if (format[formatIndex].charCodeAt(0) !== next) { @@ -2666,24 +2717,19 @@ LibraryManager.library = { }); } else if (next == 's'.charCodeAt(0)) { // String. - var arg = getNextArg('i8*'); - var copiedString; - if (arg) { - copiedString = String_copy(arg); - if (precisionSet && copiedString.length > precision) { - copiedString = copiedString.slice(0, precision); - } - } else { - copiedString = intArrayFromString('(null)', true); - } + var arg = getNextArg('i8*') || 0; // 0 holds '(null)' + var argLength = String_len(arg); + if (precisionSet) argLength = Math.min(String_len(arg), precision); if (!flagLeftAlign) { - while (copiedString.length < width--) { + while (argLength < width--) { ret.push(' '.charCodeAt(0)); } } - ret = ret.concat(copiedString); + for (var i = 0; i < argLength; i++) { + ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}}); + } if (flagLeftAlign) { - while (copiedString.length < width--) { + while (argLength < width--) { ret.push(' '.charCodeAt(0)); } } @@ -2808,7 +2854,7 @@ LibraryManager.library = { streamObj.error = true; return -1; } else { - return {{{ makeGetValue('_fgetc.ret', '0', 'i8') }}}; + return {{{ makeGetValue('_fgetc.ret', '0', 'i8', null, 1) }}}; } }, getc: 'fgetc', @@ -3413,6 +3459,8 @@ LibraryManager.library = { strtod__deps: ['isspace', 'isdigit'], strtod: function(str, endptr) { + var origin = str; + // Skip space. while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++; @@ -3429,26 +3477,35 @@ LibraryManager.library = { var ret = 0; // Get whole part. + var whole = false; while(1) { chr = {{{ makeGetValue('str', 0, 'i8') }}}; if (!_isdigit(chr)) break; + whole = true; ret = ret*10 + chr - '0'.charCodeAt(0); str++; } // Get fractional part. + var fraction = false; if ({{{ makeGetValue('str', 0, 'i8') }}} == '.'.charCodeAt(0)) { str++; var mul = 1/10; while(1) { chr = {{{ makeGetValue('str', 0, 'i8') }}}; if (!_isdigit(chr)) break; + fraction = true; ret += mul*(chr - '0'.charCodeAt(0)); mul /= 10; str++; } } + if (!whole && !fraction) { + {{{ makeSetValue('endptr', 0, 'origin', '*') }}} + return 0; + } + // Get exponent part. chr = {{{ makeGetValue('str', 0, 'i8') }}}; if (chr == 'e'.charCodeAt(0) || chr == 'E'.charCodeAt(0)) { @@ -3480,6 +3537,9 @@ LibraryManager.library = { return ret * multiplier; }, + strtod_l: 'strtod', // no locale support yet + strtold: 'strtod', // XXX add real support for long double + strtold_l: 'strtold', // no locale support yet _parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'], _parseInt: function(str, endptr, base, min, max, bits, unsign) { @@ -3956,19 +4016,35 @@ LibraryManager.library = { }, strspn: function(pstr, pset) { - var str = String_copy(pstr, true); - var set = String_copy(pset); - var i = 0; - while (set.indexOf(str[i]) != -1) i++; // Must halt, as 0 is in str but not set - return i; + var str = pstr, set, strcurr, setcurr; + while (1) { + strcurr = {{{ makeGetValue('str', '0', 'i8') }}}; + if (!strcurr) return str - pstr; + set = pset; + while (1) { + setcurr = {{{ makeGetValue('set', '0', 'i8') }}}; + if (!setcurr || setcurr == strcurr) break; + set++; + } + if (!setcurr) return str - pstr; + str++; + } }, strcspn: function(pstr, pset) { - var str = String_copy(pstr, true); - var set = String_copy(pset, true); - var i = 0; - while (set.indexOf(str[i]) == -1) i++; // Must halt, as 0 is in both - return i; + var str = pstr, set, strcurr, setcurr; + while (1) { + strcurr = {{{ makeGetValue('str', '0', 'i8') }}}; + if (!strcurr) return str - pstr; + set = pset; + while (1) { + setcurr = {{{ makeGetValue('set', '0', 'i8') }}}; + if (!setcurr || setcurr == strcurr) break; + set++; + } + if (setcurr) return str - pstr; + str++; + } }, strcpy: function(pdest, psrc) { @@ -4149,10 +4225,36 @@ LibraryManager.library = { return newStr; }, + strndup__deps: ['strdup'], + strndup: function(ptr, size) { + var len = String_len(ptr); + + if (size >= len) { + return _strdup(ptr); + } + + if (size < 0) { + size = 0; + } + + var newStr = _malloc(size + 1); + {{{ makeCopyValues('newStr', 'ptr', 'size', 'null', null, 1) }}}; + {{{ makeSetValue('newStr', 'size', '0', 'i8') }}}; + return newStr; + }, + strpbrk: function(ptr1, ptr2) { - var searchSet = Runtime.set.apply(null, String_copy(ptr2)); - while ({{{ makeGetValue('ptr1', 0, 'i8') }}}) { - if ({{{ makeGetValue('ptr1', 0, 'i8') }}} in searchSet) return ptr1; + var curr; + var searchSet = {}; + while (1) { + var curr = {{{ makeGetValue('ptr2++', 0, 'i8') }}}; + if (!curr) break; + searchSet[curr] = 1; + } + while (1) { + curr = {{{ makeGetValue('ptr1', 0, 'i8') }}}; + if (!curr) break; + if (curr in searchSet) return ptr1; ptr1++; } return 0; @@ -4280,19 +4382,13 @@ LibraryManager.library = { isdigit: function(chr) { return chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0); }, - isdigit_l__deps: ['isdigit'], - isdigit_l: function(chr, loc) { - return _isdigit(chr); - }, + isdigit_l: 'isdigit', // no locale support yet isxdigit: function(chr) { return (chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0)) || (chr >= 'a'.charCodeAt(0) && chr <= 'f'.charCodeAt(0)) || (chr >= 'A'.charCodeAt(0) && chr <= 'F'.charCodeAt(0)); }, - isxdigit_l__deps: ['isxdigit'], - isxdigit_l: function(chr, loc) { - return _isxdigit(chr); - }, + isxdigit_l: 'isxdigit', // no locale support yet isalnum: function(chr) { return (chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0)) || (chr >= 'a'.charCodeAt(0) && chr <= 'z'.charCodeAt(0)) || @@ -4422,6 +4518,21 @@ LibraryManager.library = { */ }, + llvm_bswap_i16: function(x) { + x = unSign(x, 32); + var bytes = []; + bytes[0] = x & 255; + x >>= 8; + bytes[1] = x & 255; + x >>= 8; + var ret = 0; + ret <<= 8; + ret += bytes[0]; + ret <<= 8; + ret += bytes[1]; + return ret; + }, + llvm_bswap_i32: function(x) { x = unSign(x, 32); var bytes = []; @@ -4436,7 +4547,7 @@ LibraryManager.library = { } return ret; }, - + llvm_ctlz_i32: function(x) { for (var i=0; i<32; i++) { if ( (x & (1 << (31-i))) != 0 ) { @@ -4615,12 +4726,12 @@ LibraryManager.library = { // return the type of the catch block which should be called. for (var i = 0; i < typeArray.length; i++) { if (___cxa_does_inherit(typeArray[i], throwntype, thrown)) - return { 'f0':thrown, 'f1':typeArray[i]}; + return { f0:thrown, f1:typeArray[i] }; } // Shouldn't happen unless we have bogus data in typeArray // or encounter a type for which emscripten doesn't have suitable // typeinfo defined. Best-efforts match just in case. - return {'f0':thrown,'f1':throwntype}; + return { f0:thrown, f1 :throwntype }; }, // Recursively walks up the base types of 'possibilityType' @@ -4682,6 +4793,42 @@ LibraryManager.library = { // type_info for void*. _ZTIPv: [0], + llvm_uadd_with_overflow_i8: function(x, y) { + x = x & 0xff; + y = y & 0xff; + return { + f0: (x+y) & 0xff, + f1: x+y > 255 + }; + }, + + llvm_umul_with_overflow_i8: function(x, y) { + x = x & 0xff; + y = y & 0xff; + return { + f0: (x*y) & 0xff, + f1: x*y > 255 + }; + }, + + llvm_uadd_with_overflow_i16: function(x, y) { + x = x & 0xffff; + y = y & 0xffff; + return { + f0: (x+y) & 0xffff, + f1: x+y > 65535 + }; + }, + + llvm_umul_with_overflow_i16: function(x, y) { + x = x & 0xffff; + y = y & 0xffff; + return { + f0: (x*y) & 0xffff, + f1: x*y > 65535 + }; + }, + llvm_uadd_with_overflow_i32: function(x, y) { x = x>>>0; y = y>>>0; @@ -4700,6 +4847,24 @@ LibraryManager.library = { }; }, + llvm_uadd_with_overflow_i64__deps: [function() { preciseI64MathUsed = 1 }], + llvm_uadd_with_overflow_i64: function(xl, xh, yl, yh) { + i64Math.add(xl, xh, yl, yh); + return { + f0: i64Math.result, + f1: 0 // XXX Need to hack support for this in long.js + }; + }, + + llvm_umul_with_overflow_i64__deps: [function() { preciseI64MathUsed = 1 }], + llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) { + i64Math.mul(xl, xh, yl, yh); + return { + f0: i64Math.result, + f1: 0 // XXX Need to hack support for this in long.js + }; + }, + llvm_stacksave: function() { var self = _llvm_stacksave; if (!self.LLVM_SAVEDSTACKS) { @@ -4739,6 +4904,11 @@ LibraryManager.library = { llvm_lifetime_start: function() {}, llvm_lifetime_end: function() {}, + llvm_invariant_start: function() {}, + llvm_invariant_end: function() {}, + + llvm_objectsize_i32: function() { return -1 }, // TODO: support this + // ========================================================================== // math.h // ========================================================================== @@ -4963,7 +5133,7 @@ LibraryManager.library = { if (isNaN(x)) return {{{ cDefine('FP_NAN') }}}; if (!isFinite(x)) return {{{ cDefine('FP_INFINITE') }}}; if (x == 0) return {{{ cDefine('FP_ZERO') }}}; - // FP_SUBNORMAL..? + // FP_SUBNORMAL..? return {{{ cDefine('FP_NORMAL') }}}; }, __fpclassifyd: '__fpclassifyf', @@ -5367,6 +5537,7 @@ LibraryManager.library = { // TODO: Implement. return 0; }, + strftime_l: 'strftime', // no locale support yet strptime: function(buf, format, tm) { // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); @@ -5374,6 +5545,7 @@ LibraryManager.library = { // TODO: Implement. return 0; }, + strptime_l: 'strptime', // no locale support yet getdate: function(string) { // struct tm *getdate(const char *string); @@ -6080,6 +6252,10 @@ LibraryManager.library = { return eval(Pointer_stringify(ptr)); }, + emscripten_random: function() { + return Math.random(); + }, + $Profiling: { max_: 0, times: null, |