aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js43
-rw-r--r--src/embind/embind.js26
-rw-r--r--src/embind/emval.js15
-rw-r--r--src/intertyper.js2
-rw-r--r--src/jsifier.js34
-rw-r--r--src/library.js646
-rw-r--r--src/library_browser.js31
-rw-r--r--src/library_gl.js10
-rw-r--r--src/library_sdl.js132
-rw-r--r--src/modules.js19
-rw-r--r--src/parseTools.js10
-rw-r--r--src/preamble.js3
-rw-r--r--src/relooper/Relooper.cpp2
-rw-r--r--src/runtime.js14
-rw-r--r--src/settings.js12
-rw-r--r--src/shell.js80
16 files changed, 809 insertions, 270 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index de9a7940..b1f0b585 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -502,18 +502,38 @@ function analyzer(data, sidePass) {
{ intertype: 'value', ident: j.toString(), type: 'i32' }
]
});
- var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
- toAdd.push({
+ var newItem = {
intertype: 'load',
assignTo: element.ident,
- pointerType: actualSizeType + '*',
- valueType: actualSizeType,
- type: actualSizeType, // XXX why is this missing from intertyper?
- pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' },
+ pointerType: 'i32*',
+ valueType: 'i32',
+ type: 'i32',
+ pointer: { intertype: 'value', ident: tempVar, type: 'i32*' },
ident: tempVar,
- pointerType: actualSizeType + '*',
align: value.align
- });
+ };
+ var newItem2 = null;
+ // The last one may be smaller than 32 bits
+ if (element.bits < 32) {
+ newItem.assignTo += '$preadd$';
+ newItem2 = {
+ intertype: 'mathop',
+ op: 'and',
+ assignTo: element.ident,
+ type: 'i32',
+ params: [{
+ intertype: 'value',
+ type: 'i32',
+ ident: newItem.assignTo
+ }, {
+ intertype: 'value',
+ type: 'i32',
+ ident: (0xffffffff >>> (32 - element.bits)).toString()
+ }],
+ };
+ }
+ toAdd.push(newItem);
+ if (newItem2) toAdd.push(newItem2);
j++;
});
Types.needAnalysis['[0 x i32]'] = 0;
@@ -1433,15 +1453,14 @@ function analyzer(data, sidePass) {
func.labelsDict = {};
func.labelIds = {};
func.labelIdsInverse = {};
- func.labelIds[toNiceIdent('%0')] = 1;
- func.labelIdsInverse[0] = toNiceIdent('%0');
- func.labelIdCounter = 2;
+ func.labelIdCounter = 1;
func.labels.forEach(function(label) {
if (!(label.ident in func.labelIds)) {
func.labelIds[label.ident] = func.labelIdCounter++;
func.labelIdsInverse[func.labelIdCounter-1] = label.ident;
}
});
+ var entryIdent = func.labels[0].ident;
// Minify label ids to numeric ids.
func.labels.forEach(function(label) {
@@ -1478,7 +1497,7 @@ function analyzer(data, sidePass) {
function getActualLabelId(labelId) {
if (func.labelsDict[labelId]) return labelId;
// If not present, it must be a surprisingly-named entry (or undefined behavior, in which case, still ok to use the entry)
- labelId = func.labelIds[ENTRY_IDENT];
+ labelId = func.labelIds[entryIdent];
assert(func.labelsDict[labelId]);
return labelId;
}
diff --git a/src/embind/embind.js b/src/embind/embind.js
index 91386c69..f0cd0c74 100644
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -5,9 +5,9 @@
/*global __emval_register, _emval_handle_array, __emval_decref*/
/*global ___getTypeName*/
/*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */
-var InternalError = Module.InternalError = extendError(Error, 'InternalError');
-var BindingError = Module.BindingError = extendError(Error, 'BindingError');
-var UnboundTypeError = Module.UnboundTypeError = extendError(BindingError, 'UnboundTypeError');
+var InternalError = Module['InternalError'] = extendError(Error, 'InternalError');
+var BindingError = Module['BindingError'] = extendError(Error, 'BindingError');
+var UnboundTypeError = Module['UnboundTypeError'] = extendError(BindingError, 'UnboundTypeError');
function throwInternalError(message) {
throw new InternalError(message);
@@ -638,7 +638,7 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker,
var tupleRegistrations = {};
-function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) {
+function __embind_register_value_array(rawType, name, rawConstructor, rawDestructor) {
tupleRegistrations[rawType] = {
name: readLatin1String(name),
rawConstructor: FUNCTION_TABLE[rawConstructor],
@@ -647,7 +647,7 @@ function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) {
};
}
-function __embind_register_tuple_element(
+function __embind_register_value_array_element(
rawTupleType,
getterReturnType,
getter,
@@ -666,7 +666,7 @@ function __embind_register_tuple_element(
});
}
-function __embind_finalize_tuple(rawTupleType) {
+function __embind_finalize_value_array(rawTupleType) {
var reg = tupleRegistrations[rawTupleType];
delete tupleRegistrations[rawTupleType];
var elements = reg.elements;
@@ -725,7 +725,7 @@ function __embind_finalize_tuple(rawTupleType) {
var structRegistrations = {};
-function __embind_register_struct(
+function __embind_register_value_object(
rawType,
name,
rawConstructor,
@@ -739,7 +739,7 @@ function __embind_register_struct(
};
}
-function __embind_register_struct_field(
+function __embind_register_value_object_field(
structType,
fieldName,
getterReturnType,
@@ -760,7 +760,7 @@ function __embind_register_struct_field(
});
}
-function __embind_finalize_struct(structType) {
+function __embind_finalize_value_object(structType) {
var reg = structRegistrations[structType];
delete structRegistrations[structType];
@@ -879,11 +879,11 @@ var genericPointerToWireType = function(destructors, handle) {
if (handle.$$.smartPtrType === this) {
ptr = handle.$$.smartPtr;
} else {
- var clonedHandle = handle.clone();
+ var clonedHandle = handle['clone']();
ptr = this.rawShare(
ptr,
__emval_register(function() {
- clonedHandle.delete();
+ clonedHandle['delete']();
})
);
if (destructors !== null) {
@@ -1088,7 +1088,7 @@ function getInstanceTypeName(handle) {
return handle.$$.ptrType.registeredClass.name;
}
-ClassHandle.prototype.isAliasOf = function(other) {
+ClassHandle.prototype['isAliasOf'] = function(other) {
if (!(this instanceof ClassHandle)) {
return false;
}
@@ -1118,7 +1118,7 @@ function throwInstanceAlreadyDeleted(obj) {
throwBindingError(getInstanceTypeName(obj) + ' instance already deleted');
}
-ClassHandle.prototype.clone = function() {
+ClassHandle.prototype['clone'] = function() {
if (!this.$$.ptr) {
throwInstanceAlreadyDeleted(this);
}
diff --git a/src/embind/emval.js b/src/embind/emval.js
index 77270597..0d075188 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -4,6 +4,7 @@
/*global createNamedFunction*/
/*global readLatin1String, writeStringToMemory*/
/*global requireRegisteredType, throwBindingError*/
+/*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */
var Module = Module || {};
@@ -100,7 +101,7 @@ function __emval_new_cstring(v) {
function __emval_take_value(type, v) {
type = requireRegisteredType(type, '_emval_take_value');
- v = type.fromWireType(v);
+ v = type['fromWireType'](v);
return __emval_register(v);
}
@@ -203,7 +204,7 @@ function __emval_as(handle, returnType) {
returnType = requireRegisteredType(returnType, 'emval::as');
var destructors = [];
// caller owns destructing
- return returnType.toWireType(destructors, _emval_handle_array[handle].value);
+ return returnType['toWireType'](destructors, _emval_handle_array[handle].value);
}
function parseParameters(argCount, argTypes, argWireTypes) {
@@ -212,7 +213,7 @@ function parseParameters(argCount, argTypes, argWireTypes) {
var argType = requireRegisteredType(
HEAP32[(argTypes >> 2) + i],
"parameter " + i);
- a[i] = argType.fromWireType(argWireTypes[i]);
+ a[i] = argType['fromWireType'](argWireTypes[i]);
}
return a;
}
@@ -223,7 +224,7 @@ function __emval_call(handle, argCount, argTypes) {
var args = new Array(argCount);
for (var i = 0; i < argCount; ++i) {
- args[i] = types[i].fromWireType(arguments[3 + i]);
+ args[i] = types[i]['fromWireType'](arguments[3 + i]);
}
var fn = _emval_handle_array[handle].value;
@@ -247,8 +248,8 @@ function __emval_get_method_caller(argCount, argTypes) {
var retType = types[0];
var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$";
- var args1 = ["Runtime", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"];
- var args2 = [Runtime, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType];
+ var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"];
+ var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType];
var argsList = ""; // 'arg0, arg1, arg2, ... , argN'
var argsListWired = ""; // 'arg0Wired, ..., argNWired'
@@ -260,7 +261,7 @@ function __emval_get_method_caller(argCount, argTypes) {
}
var invokerFnBody =
- "return Runtime.addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" +
+ "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" +
"requireHandle(handle);\n" +
"name = getStringOrSymbol(name);\n";
diff --git a/src/intertyper.js b/src/intertyper.js
index 94d937e1..abfbdacb 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -503,6 +503,7 @@ function intertyper(data, sidePass, baseLineNums) {
// variable
var ident = item.tokens[0].text;
var private_ = findTokenText(item, 'private') >= 0 || findTokenText(item, 'internal') >= 0;
+ var named = findTokenText(item, 'unnamed_addr') < 0;
cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]);
var external = false;
if (item.tokens[2].text === 'external') {
@@ -516,6 +517,7 @@ function intertyper(data, sidePass, baseLineNums) {
type: item.tokens[2].text,
external: external,
private_: private_,
+ named: named,
lineNum: item.lineNum
};
if (!NAMED_GLOBALS) {
diff --git a/src/jsifier.js b/src/jsifier.js
index 82b78d0a..b377202d 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -286,6 +286,8 @@ function JSify(data, functionsOnly, givenFunctions) {
allocator = 'ALLOC_NONE';
}
+ Variables.globals[item.ident].named = item.named;
+
if (ASM_JS && (MAIN_MODULE || SIDE_MODULE) && !item.private_ && !NAMED_GLOBALS && isIndexableGlobal(item.ident)) {
// We need this to be named (and it normally would not be), so that it can be linked to and used from other modules
Variables.globals[item.ident].linkable = 1;
@@ -602,6 +604,8 @@ function JSify(data, functionsOnly, givenFunctions) {
var associatedSourceFile = "NO_SOURCE";
}
+ if (DLOPEN_SUPPORT) Functions.getIndex(func.ident);
+
func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
if (PGO) {
@@ -1207,7 +1211,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// in an assignment
var disabled = DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST);
var phiSets = calcPhiSets(item);
- var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone);
+ var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true);
var ret;
@@ -1364,7 +1368,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret;
});
- function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn) {
+ function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn, invoke) {
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
@@ -1429,7 +1433,7 @@ function JSify(data, functionsOnly, givenFunctions) {
args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
if (ASM_JS) {
- if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || funcData.setjmpTable) {
+ if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || funcData.setjmpTable) {
args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
} else {
args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) });
@@ -1470,7 +1474,6 @@ function JSify(data, functionsOnly, givenFunctions) {
}
args = args.concat(varargs);
- var argsText = args.join(', ');
// Inline if either we inline whenever we can (and we can), or if there is no noninlined version
var inline = LibraryManager.library[simpleIdent + '__inline'];
@@ -1492,16 +1495,35 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
+ if (callIdent in Functions.implementedFunctions) {
+ // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as.
+ var numArgs = Functions.implementedFunctions[callIdent].length - 1;
+ if (numArgs !== args.length) {
+ if (VERBOSE) warnOnce('Fixing function call arguments based on signature, on ' + [callIdent, args.length, numArgs]);
+ while (args.length > numArgs) { args.pop(); argsTypes.pop() }
+ while (args.length < numArgs) { args.push('0'); argsTypes.push('i32') }
+ }
+ }
+
var returnType = 'void';
if ((byPointer || ASM_JS) && hasReturn) {
returnType = getReturnType(type);
+ if (callIdent in Functions.implementedFunctions) {
+ // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as
+ var trueType = Functions.getSignatureReturnType(Functions.implementedFunctions[callIdent]);
+ if (trueType !== returnType && !isIdenticallyImplemented(trueType, returnType)) {
+ if (VERBOSE) warnOnce('Fixing function call based on return type from signature, on ' + [callIdent, returnType, trueType]);
+ returnType = trueType;
+ }
+ }
}
if (byPointer) {
var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
if (ASM_JS) {
assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
- if (!byPointerForced && !funcData.setjmpTable) {
+ var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke;
+ if (functionTableCall) {
// normal asm function pointer call
callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
Functions.neededTables[sig] = 1;
@@ -1516,7 +1538,7 @@ function JSify(data, functionsOnly, givenFunctions) {
assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)';
}
- if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
+ if (!ASM_JS || functionTableCall) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
}
var ret = callIdent + '(' + args.join(', ') + ')';
diff --git a/src/library.js b/src/library.js
index c5618b53..e650a545 100644
--- a/src/library.js
+++ b/src/library.js
@@ -559,25 +559,28 @@ LibraryManager.library = {
};
}
var utf8 = new Runtime.UTF8Processor();
- function simpleOutput(val) {
- if (val === null || val === {{{ charCode('\n') }}}) {
- output.printer(output.buffer.join(''));
- output.buffer = [];
- } else {
- output.buffer.push(utf8.processCChar(val));
- }
+ function createSimpleOutput() {
+ var fn = function (val) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
+ fn.printer(fn.buffer.join(''));
+ fn.buffer = [];
+ } else {
+ fn.buffer.push(utf8.processCChar(val));
+ }
+ };
+ return fn;
}
if (!output) {
stdoutOverridden = false;
- output = simpleOutput;
+ output = createSimpleOutput();
}
if (!output.printer) output.printer = Module['print'];
if (!output.buffer) output.buffer = [];
if (!error) {
stderrOverridden = false;
- error = simpleOutput;
+ error = createSimpleOutput();
}
- if (!error.printer) error.printer = Module['print'];
+ if (!error.printer) error.printer = Module['printErr'];
if (!error.buffer) error.buffer = [];
// Create the temporary folder, if not already created
@@ -1045,27 +1048,45 @@ LibraryManager.library = {
mknod: function(path, mode, dev) {
// int mknod(const char *path, mode_t mode, dev_t dev);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mknod.html
- if (dev !== 0 || !(mode & 0xC000)) { // S_IFREG | S_IFDIR.
- // Can't create devices or pipes through mknod().
+ path = Pointer_stringify(path);
+ var fmt = (mode & {{{ cDefine('S_IFMT') }}});
+ if (fmt !== {{{ cDefine('S_IFREG') }}} && fmt !== {{{ cDefine('S_IFCHR') }}} &&
+ fmt !== {{{ cDefine('S_IFBLK') }}} && fmt !== {{{ cDefine('S_IFIFO') }}} &&
+ fmt !== {{{ cDefine('S_IFSOCK') }}}) {
+ // not valid formats for mknod
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
- } else {
- var properties = {contents: [], isFolder: Boolean(mode & 0x4000)}; // S_IFDIR.
- path = FS.analyzePath(Pointer_stringify(path));
- try {
- FS.createObject(path.parentObject, path.name, properties,
- mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
- return 0;
- } catch (e) {
- return -1;
- }
+ }
+ if (fmt === {{{ cDefine('S_IFCHR') }}} || fmt === {{{ cDefine('S_IFBLK') }}} ||
+ fmt === {{{ cDefine('S_IFIFO') }}} || fmt === {{{ cDefine('S_IFSOCK') }}}) {
+ // not supported currently
+ ___setErrNo(ERRNO_CODES.EPERM);
+ return -1;
+ }
+ path = FS.analyzePath(path);
+ var properties = { contents: [], isFolder: false }; // S_IFDIR.
+ try {
+ FS.createObject(path.parentObject, path.name, properties,
+ mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
+ return 0;
+ } catch (e) {
+ return -1;
}
},
mkdir__deps: ['mknod'],
mkdir: function(path, mode) {
// int mkdir(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
- return _mknod(path, 0x4000 | (mode & 0x180), 0); // S_IFDIR, S_IRUSR | S_IWUSR.
+ path = Pointer_stringify(path);
+ path = FS.analyzePath(path);
+ var properties = { contents: [], isFolder: true };
+ try {
+ FS.createObject(path.parentObject, path.name, properties,
+ mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
+ return 0;
+ } catch (e) {
+ return -1;
+ }
},
mkfifo__deps: ['__setErrNo', '$ERRNO_CODES'],
mkfifo: function(path, mode) {
@@ -1079,10 +1100,13 @@ LibraryManager.library = {
return -1;
},
chmod__deps: ['$FS'],
- chmod: function(path, mode) {
+ chmod: function(path, mode, dontResolveLastLink) {
// int chmod(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/chmod.html
- var obj = FS.findObject(Pointer_stringify(path));
+ // NOTE: dontResolveLastLink is a shortcut for lchmod(). It should never be
+ // used in client code.
+ path = typeof path !== 'string' ? Pointer_stringify(path) : path;
+ var obj = FS.findObject(path, dontResolveLastLink);
if (obj === null) return -1;
obj.read = mode & 0x100; // S_IRUSR.
obj.write = mode & 0x80; // S_IWUSR.
@@ -1093,15 +1117,16 @@ LibraryManager.library = {
fchmod: function(fildes, mode) {
// int fchmod(int fildes, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html
- if (!FS.streams[fildes]) {
+ var stream = FS.streams[fildes];
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else {
- var pathArray = intArrayFromString(FS.streams[fildes].path);
- return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode);
}
+ return _chmod(stream.path, mode);
+ },
+ lchmod: function(path, mode) {
+ return _chmod(path, mode, true);
},
- lchmod: function() { throw 'TODO: lchmod' },
umask__deps: ['$FS'],
umask: function(newMask) {
@@ -1115,6 +1140,7 @@ LibraryManager.library = {
},
stat64: 'stat',
fstat64: 'fstat',
+ lstat64: 'lstat',
__01fstat64_: 'fstat',
__01stat64_: 'stat',
__01lstat64_: 'lstat',
@@ -1775,6 +1801,8 @@ LibraryManager.library = {
} else if (nbyte < 0 || offset < 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
+ } else if (offset >= stream.object.contents.length) {
+ return 0;
} else {
var bytesRead = 0;
while (stream.ungotten.length && nbyte > 0) {
@@ -1784,6 +1812,8 @@ LibraryManager.library = {
}
var contents = stream.object.contents;
var size = Math.min(contents.length - offset, nbyte);
+ assert(size >= 0);
+
#if USE_TYPED_ARRAYS == 2
if (contents.subarray) { // typed array
HEAPU8.set(contents.subarray(offset, offset+size), buf);
@@ -1851,6 +1881,7 @@ LibraryManager.library = {
} else {
var ungotSize = stream.ungotten.length;
bytesRead = _pread(fildes, buf, nbyte, stream.position);
+ assert(bytesRead >= -1);
if (bytesRead != -1) {
stream.position += (stream.ungotten.length - ungotSize) + bytesRead;
}
@@ -1867,42 +1898,42 @@ LibraryManager.library = {
rmdir: function(path) {
// int rmdir(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
- path = FS.analyzePath(Pointer_stringify(path));
+ path = Pointer_stringify(path);
+ path = FS.analyzePath(path, true);
if (!path.parentExists || !path.exists) {
___setErrNo(path.error);
return -1;
- } else if (!path.object.write || path.isRoot) {
+ } else if (!path.parentObject.write) {
___setErrNo(ERRNO_CODES.EACCES);
return -1;
} else if (!path.object.isFolder) {
___setErrNo(ERRNO_CODES.ENOTDIR);
return -1;
+ } else if (path.isRoot || path.path == FS.currentPath) {
+ ___setErrNo(ERRNO_CODES.EBUSY);
+ return -1;
} else {
for (var i in path.object.contents) {
___setErrNo(ERRNO_CODES.ENOTEMPTY);
return -1;
}
- if (path.path == FS.currentPath) {
- ___setErrNo(ERRNO_CODES.EBUSY);
- return -1;
- } else {
- delete path.parentObject.contents[path.name];
- return 0;
- }
+ delete path.parentObject.contents[path.name];
+ return 0;
}
},
unlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
unlink: function(path) {
// int unlink(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
- path = FS.analyzePath(Pointer_stringify(path));
+ path = Pointer_stringify(path);
+ path = FS.analyzePath(path, true);
if (!path.parentExists || !path.exists) {
___setErrNo(path.error);
return -1;
} else if (path.object.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
+ ___setErrNo(ERRNO_CODES.EPERM);
return -1;
- } else if (!path.object.write) {
+ } else if (!path.parentObject.write) {
___setErrNo(ERRNO_CODES.EACCES);
return -1;
} else {
@@ -2559,15 +2590,27 @@ LibraryManager.library = {
continue;
}
- // TODO: Support strings like "%5c" etc.
- if (format[formatIndex] === '%' && format[formatIndex+1] == 'c') {
- var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
- argIndex += Runtime.getAlignSize('void*', null, true);
- fields++;
- next = get();
- {{{ makeSetValue('argPtr', 0, 'next', 'i8') }}}
- formatIndex += 2;
- continue;
+ if (format[formatIndex] === '%') {
+ var nextC = format.indexOf('c', formatIndex+1);
+ if (nextC > 0) {
+ var maxx = 1;
+ if (nextC > formatIndex+1) {
+ var sub = format.substring(formatIndex+1, nextC)
+ maxx = parseInt(sub);
+ if (maxx != sub) maxx = 0;
+ }
+ if (maxx) {
+ var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
+ argIndex += Runtime.getAlignSize('void*', null, true);
+ fields++;
+ for (var i = 0; i < maxx; i++) {
+ next = get();
+ {{{ makeSetValue('argPtr++', 0, 'next', 'i8') }}};
+ }
+ formatIndex += nextC - formatIndex + 1;
+ continue;
+ }
+ }
}
// remove whitespace
@@ -4898,7 +4941,9 @@ LibraryManager.library = {
isprint: function(chr) {
return 0x1F < chr && chr < 0x7F;
},
- isgraph: 'isprint',
+ isgraph: function(chr) {
+ return 0x20 < chr && chr < 0x7F;
+ },
// Lookup tables for glibc ctype implementation.
__ctype_b_loc: function() {
// http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html
@@ -5735,10 +5780,14 @@ LibraryManager.library = {
rintf: 'rint',
lrint: 'rint',
lrintf: 'rint',
+#if USE_TYPED_ARRAYS == 2
llrint: function(x) {
x = (x < 0) ? -Math.round(-x) : Math.round(x);
{{{ makeStructuralReturn(splitI64('x')) }}};
},
+#else
+ llrint: 'rint',
+#endif
llrintf: 'llrint',
nearbyint: 'rint',
nearbyintf: 'rint',
@@ -5881,7 +5930,7 @@ LibraryManager.library = {
dlopen: function(filename, flag) {
// void *dlopen(const char *file, int mode);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
- filename = (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename);
+ filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename);
if (DLFCN_DATA.loadedLibNames[filename]) {
// Already loaded; increment ref count and return.
@@ -5890,48 +5939,55 @@ LibraryManager.library = {
return handle;
}
- var target = FS.findObject(filename);
- if (!target || target.isFolder || target.isDevice) {
- DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename;
- return 0;
+ if (filename === '__self__') {
+ var handle = -1;
+ var lib_module = Module;
+ var cached_functions = SYMBOL_TABLE;
} else {
- FS.forceLoadFile(target);
- var lib_data = intArrayToString(target.contents);
- }
+ var target = FS.findObject(filename);
+ if (!target || target.isFolder || target.isDevice) {
+ DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename;
+ return 0;
+ } else {
+ FS.forceLoadFile(target);
+ var lib_data = intArrayToString(target.contents);
+ }
- try {
- var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length);
- } catch (e) {
+ try {
+ var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length);
+ } catch (e) {
#if ASSERTIONS
- Module.printErr('Error in loading dynamic library: ' + e);
+ Module.printErr('Error in loading dynamic library: ' + e);
#endif
- DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
- return 0;
- }
+ DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
+ return 0;
+ }
- // Not all browsers support Object.keys().
- var handle = 1;
- for (var key in DLFCN_DATA.loadedLibs) {
- if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++;
- }
+ // Not all browsers support Object.keys().
+ var handle = 1;
+ for (var key in DLFCN_DATA.loadedLibs) {
+ if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++;
+ }
+
+ // We don't care about RTLD_NOW and RTLD_LAZY.
+ if (flag & 256) { // RTLD_GLOBAL
+ for (var ident in lib_module) {
+ if (lib_module.hasOwnProperty(ident)) {
+ Module[ident] = lib_module[ident];
+ }
+ }
+ }
+ var cached_functions = {};
+ }
DLFCN_DATA.loadedLibs[handle] = {
refcount: 1,
name: filename,
module: lib_module,
- cached_functions: {}
+ cached_functions: cached_functions
};
DLFCN_DATA.loadedLibNames[filename] = handle;
- // We don't care about RTLD_NOW and RTLD_LAZY.
- if (flag & 256) { // RTLD_GLOBAL
- for (var ident in lib_module) {
- if (lib_module.hasOwnProperty(ident)) {
- Module[ident] = lib_module[ident];
- }
- }
- }
-
return handle;
},
// int dlclose(void* handle);
@@ -5944,7 +6000,7 @@ LibraryManager.library = {
return 1;
} else {
var lib_record = DLFCN_DATA.loadedLibs[handle];
- if (lib_record.refcount-- == 0) {
+ if (--lib_record.refcount == 0) {
delete DLFCN_DATA.loadedLibNames[lib_record.name];
delete DLFCN_DATA.loadedLibs[handle];
}
@@ -5963,13 +6019,15 @@ LibraryManager.library = {
return 0;
} else {
var lib = DLFCN_DATA.loadedLibs[handle];
- if (!lib.module.hasOwnProperty(symbol)) {
- DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol +
- '" in dynamic lib: ' + lib.name);
- return 0;
+ // self-dlopen means that lib.module is not a superset of
+ // cached_functions, so check the latter first
+ if (lib.cached_functions.hasOwnProperty(symbol)) {
+ return lib.cached_functions[symbol];
} else {
- if (lib.cached_functions.hasOwnProperty(symbol)) {
- return lib.cached_functions[symbol];
+ if (!lib.module.hasOwnProperty(symbol)) {
+ DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol +
+ '" in dynamic lib: ' + lib.name);
+ return 0;
} else {
var result = lib.module[symbol];
if (typeof result == 'function') {
@@ -6210,15 +6268,345 @@ LibraryManager.library = {
return -1;
},
- strftime: function(s, maxsize, format, timeptr) {
+ _MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+ _MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+ _isLeapYear: function(year) {
+ return year%4 === 0 && (year%100 !== 0 || year%400 === 0);
+ },
+
+ _arraySum: function(array, index) {
+ var sum = 0;
+ for (var i = 0; i <= index; sum += array[i++]);
+ return sum;
+ },
+
+ _addDays__deps: ['_isLeapYear', '_MONTH_DAYS_LEAP', '_MONTH_DAYS_REGULAR'],
+ _addDays: function(date, days) {
+ var newDate = new Date(date.getTime());
+ while(days > 0) {
+ var leap = __isLeapYear(newDate.getFullYear());
+ var currentMonth = newDate.getMonth();
+ var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
+
+ if (days > daysInCurrentMonth-newDate.getDate()) {
+ // we spill over to next month
+ days -= (daysInCurrentMonth-newDate.getDate()+1);
+ newDate.setDate(1);
+ if (currentMonth < 11) {
+ newDate.setMonth(currentMonth+1)
+ } else {
+ newDate.setMonth(0);