aboutsummaryrefslogtreecommitdiff
path: root/src/library.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library.js')
-rw-r--r--src/library.js316
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,