aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js26
-rw-r--r--src/intertyper.js19
-rw-r--r--src/jsifier.js30
-rw-r--r--src/library.js2344
-rw-r--r--src/library_browser.js19
-rw-r--r--src/library_egl.js9
-rw-r--r--src/library_fs.js1374
-rw-r--r--src/library_glut.js2
-rw-r--r--src/library_memfs.js243
-rw-r--r--src/library_openal.js265
-rw-r--r--src/library_sdl.js96
-rw-r--r--src/library_sockfs.js18
-rw-r--r--src/library_tty.js121
-rw-r--r--src/modules.js8
-rw-r--r--src/parseTools.js23
-rw-r--r--src/postamble.js61
-rw-r--r--src/preamble.js8
-rw-r--r--src/settings.js124
-rw-r--r--src/shell.js7
19 files changed, 2542 insertions, 2255 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 1a752305..2a7d64f5 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -765,7 +765,15 @@ function analyzer(data, sidePass) {
}
break;
}
- case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem':
+ case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem': {
+ if (sourceBits < 32) {
+ // when we add illegal types like i24, we must work on the singleton chunks
+ item.assignTo += '$0';
+ item.params[0].ident += '$0';
+ item.params[1].ident += '$0';
+ }
+ // fall through
+ }
case 'uitofp': case 'sitofp': case 'fptosi': case 'fptoui': {
// We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop
i++;
@@ -945,9 +953,23 @@ function analyzer(data, sidePass) {
if (type[0] == '{' || type[0] == '<') {
type = nonPointing;
var packed = type[0] == '<';
+ var internal = type;
+ if (packed) {
+ if (internal[internal.length-1] != '>') {
+ warnOnce('ignoring type ' + internal);
+ return; // function pointer or such
+ }
+ internal = internal.substr(1, internal.length-2);
+ }
+ assert(internal[0] == '{', internal);
+ if (internal[internal.length-1] != '}') {
+ warnOnce('ignoring type ' + internal);
+ return; // function pointer or such
+ }
+ internal = internal.substr(2, internal.length-4);
Types.types[type] = {
name_: type,
- fields: splitTokenList(tokenize(type.substr(2 + packed, type.length - 4 - 2*packed)).tokens).map(function(segment) {
+ fields: splitTokenList(tokenize(internal).tokens).map(function(segment) {
return segment[0].text;
}),
packed: packed,
diff --git a/src/intertyper.js b/src/intertyper.js
index abfbdacb..31e97bd0 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -360,11 +360,22 @@ function intertyper(data, sidePass, baseLineNums) {
warn('Ignoring module asm: ' + item.tokens[2].text);
return '/dev/null';
}
+ if (token0Text == 'attributes')
+ return '/dev/null';
}
if (tokensLength >= 3 && (token0Text == 'call' || token1Text == 'call'))
return 'Call';
- if (token0Text == 'target')
+ if (token0Text == 'target') {
+ if (token1Text == 'triple') {
+ var triple = item.tokens[3].text;
+ triple = triple.substr(1, triple.length-2);
+ var expected = TARGET_LE32 ? 'le32-unknown-nacl' : 'i386-pc-linux-gnu';
+ if (triple !== expected) {
+ warn('using an unexpected LLVM triple: ' + [triple, ' !== ', expected] + ' (are you using emcc for everything and not clang?)');
+ }
+ }
return '/dev/null';
+ }
if (token0Text == ';')
return '/dev/null';
if (tokensLength >= 3 && token0Text == 'invoke')
@@ -700,6 +711,12 @@ function intertyper(data, sidePass, baseLineNums) {
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
+ var i = 0;
+ splitTokenList(tokensLeft[3].item.tokens).map(function(element) {
+ var ident = toNiceIdent(element[1].text);
+ var type = element[0].text;
+ item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident);
+ });
return { forward: null, ret: [item], item: item };
}
if (item.ident.substr(-2) == '()') {
diff --git a/src/jsifier.js b/src/jsifier.js
index b377202d..c92526d2 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -658,6 +658,10 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
+ if (func.hasVarArgsCall) {
+ func.JS += INDENTATION + 'var tempVarArgs = 0;\n';
+ }
+
// Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up.
func.JS += INDENTATION + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n';
@@ -1234,6 +1238,7 @@ function JSify(data, functionsOnly, givenFunctions) {
+ (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
+ 'return null } })();';
}
+ ret = makeVarArgsCleanup(ret);
if (item.assignTo) {
ret = 'var ' + item.assignTo + ' = ' + ret;
@@ -1446,12 +1451,13 @@ function JSify(data, functionsOnly, givenFunctions) {
});
if (hasVarArgs && !useJSArgs) {
+ funcData.hasVarArgsCall = true;
if (varargs.length === 0) {
varargs = [0];
varargsTypes = ['i32'];
}
var offset = 0;
- varargs = '(tempInt=' + RuntimeGenerator.stackAlloc(varargs.length, ',') + ',' +
+ varargs = '(tempVarArgs=' + RuntimeGenerator.stackAlloc(varargs.length, ',') + ',' +
varargs.map(function(arg, i) {
var type = varargsTypes[i];
if (type == 0) return null;
@@ -1459,17 +1465,17 @@ function JSify(data, functionsOnly, givenFunctions) {
var ret;
assert(offset % Runtime.STACK_ALIGN == 0); // varargs must be aligned
if (!varargsByVals[i]) {
- ret = makeSetValue(getFastValue('tempInt', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ',');
+ ret = makeSetValue(getFastValue('tempVarArgs', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ',');
offset += Runtime.alignMemory(Runtime.getNativeFieldSize(type), Runtime.STACK_ALIGN);
} else {
var size = calcAllocatedSize(removeAllPointing(type));
- ret = makeCopyValues(getFastValue('tempInt', '+', offset), arg, size, null, null, varargsByVals[i], ',');
+ ret = makeCopyValues(getFastValue('tempVarArgs', '+', offset), arg, size, null, null, varargsByVals[i], ',');
offset += Runtime.forceAlign(size, Runtime.STACK_ALIGN);
}
return ret;
}).filter(function(arg) {
return arg !== null;
- }).join(',') + ',tempInt)';
+ }).join(',') + ',tempVarArgs)';
varargs = asmCoercion(varargs, 'i32');
}
@@ -1557,10 +1563,24 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret;
}
+
+ function makeVarArgsCleanup(js) {
+ if (js.indexOf('(tempVarArgs=') >= 0) {
+ if (js[js.length-1] == ';') {
+ return js + ' STACKTOP=tempVarArgs;';
+ } else {
+ assert(js.indexOf(';') < 0);
+ return '((' + js + '), STACKTOP=tempVarArgs)';
+ }
+ }
+ return js;
+ }
+
makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
makeFuncLineActor('call', function(item) {
if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';';
- return makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
+ var ret = makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
+ return makeVarArgsCleanup(ret);
});
makeFuncLineActor('unreachable', function(item) {
diff --git a/src/library.js b/src/library.js
index a6a38cfe..ee49ae1f 100644
--- a/src/library.js
+++ b/src/library.js
@@ -18,1726 +18,12 @@
// Memory allocated during startup, in postsets, should only be ALLOC_STATIC
LibraryManager.library = {
- // ==========================================================================
- // File system base.
- // ==========================================================================
-
// keep this low in memory, because we flatten arrays with them in them
stdin: 'allocate(1, "i32*", ALLOC_STATIC)',
stdout: 'allocate(1, "i32*", ALLOC_STATIC)',
stderr: 'allocate(1, "i32*", ALLOC_STATIC)',
_impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)',
- $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', 'stdin', 'stdout', 'stderr', 'fflush'],
- $FS__postset: 'FS.staticInit();' +
- '__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() } });' +
- // export some names through closure
- 'Module["FS_createFolder"] = FS.createFolder;' +
- 'Module["FS_createPath"] = FS.createPath;' +
- 'Module["FS_createDataFile"] = FS.createDataFile;' +
- 'Module["FS_createPreloadedFile"] = FS.createPreloadedFile;' +
- 'Module["FS_createLazyFile"] = FS.createLazyFile;' +
- 'Module["FS_createLink"] = FS.createLink;' +
- 'Module["FS_createDevice"] = FS.createDevice;',
- $FS: {
- root: null,
- nodes: [null],
- devices: [null],
- streams: [null],
- nextInode: 1,
- name_table: new Array(4096),
- currentPath: '/',
- initialized: false,
- // Whether we are currently ignoring permissions. Useful when preparing the
- // filesystem and creating files inside read-only folders.
- // This is set to false when the runtime is initialized, allowing you
- // to modify the filesystem freely before run() is called.
- ignorePermissions: true,
-
- ErrnoError: function(errno) {
- this.errno = errno;
- for (var key in ERRNO_CODES) {
- if (ERRNO_CODES[key] === errno) {
- this.code = key;
- break;
- }
- }
- this.message = ERRNO_MESSAGES[errno];
- },
-
- handleFSError: function(e) {
- if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + new Error().stack;
- return ___setErrNo(e.errno);
- },
-
- //
- // nodes
- //
- hashName: function(parentid, name) {
- var hash = 0;
- for (var i = 0; i < name.length; i++) {
- hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
- }
- return (parentid + hash) % FS.name_table.length;
- },
- hashAddNode: function(node) {
- var hash = FS.hashName(node.parent.id, node.name);
- node.name_next = FS.name_table[hash];
- FS.name_table[hash] = node;
- },
- hashRemoveNode: function(node) {
- var hash = FS.hashName(node.parent.id, node.name);
- if (FS.name_table[hash] === node) {
- FS.name_table[hash] = node.name_next;
- } else {
- var current = FS.name_table[hash];
- while (current) {
- if (current.name_next === node) {
- current.name_next = node.name_next;
- break;
- }
- current = current.name_next;
- }
- }
- },
- lookupNode: function(parent, name) {
- var err = FS.mayLookup(parent);
- if (err) {
- throw new FS.ErrnoError(err);
- }
- var hash = FS.hashName(parent.id, name);
- for (var node = FS.name_table[hash]; node; node = node.name_next) {
- if (node.parent.id === parent.id && node.name === name) {
- return node;
- }
- }
- // if we failed to find it in the cache, call into the VFS
- return VFS.lookup(parent, name);
- },
- createNode: function(parent, name, mode, rdev) {
- var node = {
- id: FS.nextInode++,
- name: name,
- mode: mode,
- node_ops: {},
- stream_ops: {},
- rdev: rdev,
- parent: null,
- mount: null
- };
- if (!parent) {
- parent = node; // root node sets parent to itself
- }
- node.parent = parent;
- node.mount = parent.mount;
- // compatibility
- var readMode = {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
- var writeMode = {{{ cDefine('S_IWUGO') }}};
- Object.defineProperty(node, 'read', {
- get: function() { return (node.mode & readMode) === readMode; },
- set: function(val) { val ? node.mode |= readMode : node.mode &= ~readMode; }
- });
- Object.defineProperty(node, 'write', {
- get: function() { return (node.mode & writeMode) === writeMode; },
- set: function(val) { val ? node.mode |= writeMode : node.mode &= ~writeMode; }
- });
- // TODO add:
- // isFolder
- // isDevice
- FS.hashAddNode(node);
- return node;
- },
- destroyNode: function(node) {
- FS.hashRemoveNode(node);
- },
- isRoot: function(node) {
- return node === node.parent;
- },
- isMountpoint: function(node) {
- return node.mounted;
- },
- isFile: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFREG') }}};
- },
- isDir: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFDIR') }}};
- },
- isLink: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFLNK') }}};
- },
- isChrdev: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFCHR') }}};
- },
- isBlkdev: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFBLK') }}};
- },
- isFIFO: function(mode) {
- return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFIFO') }}};
- },
-
- //
- // paths
- //
- cwd: function() {
- return FS.currentPath;
- },
- lookupPath: function(path, opts) {
- path = PATH.resolve(FS.currentPath, path);
- opts = opts || { recurse_count: 0 };
-
- if (opts.recurse_count > 8) { // max recursive lookup of 8
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
-
- // split the path
- var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
- return !!p;
- }), false);
-
- // start at the root
- var current = FS.root;
- var current_path = '/';
-
- for (var i = 0; i < parts.length; i++) {
- var islast = (i === parts.length-1);
- if (islast && opts.parent) {
- // stop resolving
- break;
- }
-
- current = FS.lookupNode(current, parts[i]);
- current_path = PATH.join(current_path, parts[i]);
-
- // jump to the mount's root node if this is a mountpoint
- if (FS.isMountpoint(current)) {
- current = current.mount.root;
- }
-
- // follow symlinks
- // by default, lookupPath will not follow a symlink if it is the final path component.
- // setting opts.follow = true will override this behavior.
- if (!islast || opts.follow) {
- var count = 0;
- while (FS.isLink(current.mode)) {
- var link = VFS.readlink(current_path);
- current_path = PATH.resolve(PATH.dirname(current_path), link);
-
- var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
- current = lookup.node;
-
- if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
- throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
- }
- }
- }
- }
-
- return { path: current_path, node: current };
- },
- getPath: function(node) {
- var path;
- while (true) {
- if (FS.isRoot(node)) {
- return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint;
- }
- path = path ? PATH.join(node.name, path) : node.name;
- node = node.parent;
- }
- },
-
- //
- // permissions
- //
- flagModes: {
- '"r"': {{{ cDefine('O_RDONLY') }}},
- '"rs"': {{{ cDefine('O_RDONLY') }}} | {{{ cDefine('O_SYNC') }}},
- '"r+"': {{{ cDefine('O_RDWR') }}},
- '"w"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}},
- '"wx"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"xw"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"w+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}},
- '"wx+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
- '"xw+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
- '"a"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}},
- '"ax"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"xa"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_EXCL') }}},
- '"a+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}},
- '"ax+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}},
- '"xa+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}} | {{{ cDefine('O_EXCL') }}}
- },
- // convert the 'r', 'r+', etc. to it's corresponding set of O_* flags
- modeStringToFlags: function(str) {
- var flags = FS.flagModes[str];
- if (typeof flags === 'undefined') {
- throw new Error('Unknown file open mode: ' + str);
- }
- return flags;
- },
- // convert O_* bitmask to a string for nodePermissions
- flagsToPermissionString: function(flag) {
- var accmode = flag & {{{ cDefine('O_ACCMODE') }}};
- var perms = ['r', 'w', 'rw'][accmode];
- if ((flag & {{{ cDefine('O_TRUNC') }}})) {
- perms += 'w';
- }
- return perms;
- },
- nodePermissions: function(node, perms) {
- if (FS.ignorePermissions) {
- return 0;
- }
- // return 0 if any user, group or owner bits are set.
- if (perms.indexOf('r') !== -1 && !(node.mode & {{{ cDefine('S_IRUGO') }}})) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf('w') !== -1 && !(node.mode & {{{ cDefine('S_IWUGO') }}})) {
- return ERRNO_CODES.EACCES;
- } else if (perms.indexOf('x') !== -1 && !(node.mode & {{{ cDefine('S_IXUGO') }}})) {
- return ERRNO_CODES.EACCES;
- }
- return 0;
- },
- mayLookup: function(dir) {
- return FS.nodePermissions(dir, 'x');
- },
- mayMknod: function(mode) {
- switch (mode & {{{ cDefine('S_IFMT') }}}) {
- case {{{ cDefine('S_IFREG') }}}:
- case {{{ cDefine('S_IFCHR') }}}:
- case {{{ cDefine('S_IFBLK') }}}:
- case {{{ cDefine('S_IFIFO') }}}:
- case {{{ cDefine('S_IFSOCK') }}}:
- return 0;
- default:
- return ERRNO_CODES.EINVAL;
- }
- },
- mayCreate: function(dir, name) {
- try {
- var node = FS.lookupNode(dir, name);
- return ERRNO_CODES.EEXIST;
- } catch (e) {
- }
- return FS.nodePermissions(dir, 'wx');
- },
- mayDelete: function(dir, name, isdir) {
- var node;
- try {
- node = FS.lookupNode(dir, name);
- } catch (e) {
- return e.errno;
- }
- var err = FS.nodePermissions(dir, 'wx');
- if (err) {
- return err;
- }
- if (isdir) {
- if (!FS.isDir(node.mode)) {
- return ERRNO_CODES.ENOTDIR;
- }
- if (FS.isRoot(node) || FS.getPath(node) === FS.currentPath) {
- return ERRNO_CODES.EBUSY;
- }
- } else {
- if (FS.isDir(node.mode)) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return 0;
- },
- mayOpen: function(node, flags) {
- if (!node) {
- return ERRNO_CODES.ENOENT;
- }
- if (FS.isLink(node.mode)) {
- return ERRNO_CODES.ELOOP;
- } else if (FS.isDir(node.mode)) {
- if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY')}}} || // opening for write
- (flags & {{{ cDefine('O_TRUNC') }}})) {
- return ERRNO_CODES.EISDIR;
- }
- }
- return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
- },
-
- //
- // devices
- //
- // each character device consists of a device id + stream operations.
- // when a character device node is created (e.g. /dev/stdin) it is
- // assigned a device id that lets us map back to the actual device.
- // by default, each character device stream (e.g. _stdin) uses chrdev_stream_ops.
- // however, once opened, the stream's operations are overridden with
- // the operations of the device its underlying node maps back to.
- chrdev_stream_ops: {
- open: function(stream) {
- var device = FS.getDevice(stream.node.rdev);
- // override node's stream ops with the device's
- stream.stream_ops = device.stream_ops;
- // forward the open call
- if (stream.stream_ops.open) {
- stream.stream_ops.open(stream);
- }
- },
- llseek: function() {
- throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);
- }
- },
- major: function(dev) {
- return ((dev) >> 8);
- },
- minor: function(dev) {
- return ((dev) & 0xff);
- },
- makedev: function(ma, mi) {
- return ((ma) << 8 | (mi));
- },
- registerDevice: function(dev, ops) {
- FS.devices[dev] = { stream_ops: ops };
- },
- getDevice: function(dev) {
- return FS.devices[dev];
- },
-
- //
- // streams
- //
- MAX_OPEN_FDS: 4096,
- nextfd: function(fd_start, fd_end) {
- fd_start = fd_start || 1;
- fd_end = fd_end || FS.MAX_OPEN_FDS;
- for (var fd = fd_start; fd <= fd_end; fd++) {
- if (!FS.streams[fd]) {
- return fd;
- }
- }
- throw new FS.ErrnoError(ERRNO_CODES.EMFILE);
- },
- getStream: function(fd) {
- return FS.streams[fd];
- },
- createStream: function(stream, fd_start, fd_end) {
- var fd = FS.nextfd(fd_start, fd_end);
- stream.fd = fd;
- // compatibility
- Object.defineProperty(stream, 'object', {
- get: function() { return stream.node; },
- set: function(val) { stream.node = val; }
- });
- Object.defineProperty(stream, 'isRead', {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; }
- });
- Object.defineProperty(stream, 'isWrite', {
- get: function() { return (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; }
- });
- Object.defineProperty(stream, 'isAppend', {
- get: function() { return (stream.flags & {{{ cDefine('O_APPEND') }}}); }
- });
- FS.streams[fd] = stream;
- return stream;
- },
- closeStream: function(fd) {
- FS.streams[fd] = null;
- },
-
- //
- // general
- //
- createDefaultDirectories: function() {
- VFS.mkdir('/tmp', 0777);
- },
- createDefaultDevices: function() {
- // create /dev
- VFS.mkdir('/dev', 0777);
- // setup /dev/null
- FS.registerDevice(FS.makedev(1, 3), {
- read: function() { return 0; },
- write: function() { return 0; }
- });
- VFS.mkdev('/dev/null', 0666, FS.makedev(1, 3));
- // setup /dev/tty and /dev/tty1
- // stderr needs to print output using Module['printErr']
- // so we register a second tty just for it.
- TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
- TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
- VFS.mkdev('/dev/tty', 0666, FS.makedev(5, 0));
- VFS.mkdev('/dev/tty1', 0666, FS.makedev(6, 0));
- // we're not going to emulate the actual shm device,
- // just create the tmp dirs that reside in it commonly
- VFS.mkdir('/dev/shm', 0777);
- VFS.mkdir('/dev/shm/tmp', 0777);
- },
- createStandardStreams: function() {
- // TODO deprecate the old functionality of a single
- // input / output callback and that utilizes FS.createDevice
- // and instead require a unique set of stream ops
-
- // by default, we symlink the standard streams to the
- // default tty devices. however, if the standard streams
- // have been overwritten we create a unique device for
- // them instead.
- if (Module['stdin']) {
- FS.createDevice('/dev', 'stdin', Module['stdin']);
- } else {
- VFS.symlink('/dev/tty', '/dev/stdin');
- }
- if (Module['stdout']) {
- FS.createDevice('/dev', 'stdout', null, Module['stdout']);
- } else {
- VFS.symlink('/dev/tty', '/dev/stdout');
- }
- if (Module['stderr']) {
- FS.createDevice('/dev', 'stderr', null, Module['stderr']);
- } else {
- VFS.symlink('/dev/tty1', '/dev/stderr');
- }
-
- // open default streams for the stdin, stdout and stderr devices
- var stdin = VFS.open('/dev/stdin', 'r');
- {{{ makeSetValue(makeGlobalUse('_stdin'), 0, 'stdin.fd', 'void*') }}};
- assert(stdin.fd === 1, 'invalid handle for stdin (' + stdin.fd + ')');
-
- var stdout = VFS.open('/dev/stdout', 'w');
- {{{ makeSetValue(makeGlobalUse('_stdout'), 0, 'stdout.fd', 'void*') }}};
- assert(stdout.fd === 2, 'invalid handle for stdout (' + stdout.fd + ')');
-
- var stderr = VFS.open('/dev/stderr', 'w');
- {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 'stderr.fd', 'void*') }}};
- assert(stderr.fd === 3, 'invalid handle for stderr (' + stderr.fd + ')');
- },
- staticInit: function() {
- FS.root = FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
- VFS.mount(MEMFS, {}, '/');
-
- FS.createDefaultDirectories();
- FS.createDefaultDevices();
- },
- init: function(input, output, error) {
- assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)');
- FS.init.initialized = true;
-
- // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
- Module['stdin'] = input || Module['stdin'];
- Module['stdout'] = output || Module['stdout'];
- Module['stderr'] = error || Module['stderr'];
-
- FS.createStandardStreams();
- },
- quit: function() {
- FS.init.initialized = false;
- for (var i = 0; i < FS.streams.length; i++) {
- var stream = FS.streams[i];
- if (!stream) {
- continue;
- }
- VFS.close(stream);
- }
- },
-
- //
- // compatibility
- //
- getMode: function(canRead, canWrite) {
- var mode = 0;
- if (canRead) mode |= {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}};
- if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}};
- return mode;
- },
- joinPath: function(parts, forceRelative) {
- var path = PATH.join.apply(null, parts);
- if (forceRelative && path[0] == '/') path = path.substr(1);
- return path;
- },
- absolutePath: function(relative, base) {
- return PATH.resolve(base, relative);
- },
- standardizePath: function(path) {
- return PATH.normalize(path);
- },
- findObject: function(path, dontResolveLastLink) {
- var ret = FS.analyzePath(path, dontResolveLastLink);
- if (ret.exists) {
- return ret.object;
- } else {
- ___setErrNo(ret.error);
- return null;
- }
- },
- analyzePath: function(path, dontResolveLastLink) {
- // operate from within the context of the symlink's target
- try {
- var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
- path = lookup.path;
- } catch (e) {
- }
- var ret = {
- isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
- parentExists: false, parentPath: null, parentObject: null
- };
- try {
- var lookup = FS.lookupPath(path, { parent: true });
- ret.parentExists = true;
- ret.parentPath = lookup.path;
- ret.parentObject = lookup.node;
- ret.name = PATH.basename(path);
- lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
- ret.exists = true;
- ret.path = lookup.path;
- ret.object = lookup.node;
- ret.name = lookup.node.name;
- ret.isRoot = lookup.path === '/';
- } catch (e) {
- ret.error = e.errno;
- };
- return ret;
- },
- createFolder: function(parent, name, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return VFS.mkdir(path, mode);
- },
- createPath: function(parent, path, canRead, canWrite) {
- parent = typeof parent === 'string' ? parent : FS.getPath(parent);
- var parts = path.split('/').reverse();
- while (parts.length) {
- var part = parts.pop();
- if (!part) continue;
- var current = PATH.join(parent, part);
- try {
- VFS.mkdir(current, 0777);
- } catch (e) {
- // ignore EEXIST
- }
- parent = current;
- }
- return current;
- },
- createFile: function(parent, name, properties, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- return VFS.create(path, mode);
- },
- createDataFile: function(parent, name, data, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = FS.getMode(canRead, canWrite);
- var node = VFS.create(path, mode);
- if (data) {
- if (typeof data === 'string') {
- var arr = new Array(data.length);
- for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
- data = arr;
- }
- // make sure we can write to the file
- VFS.chmod(path, mode | {{{ cDefine('S_IWUGO') }}});
- var stream = VFS.open(path, 'w');
- VFS.write(stream, data, 0, data.length, 0);
- VFS.close(stream);
- VFS.chmod(path, mode);
- }
- return node;
- },
- createDevice: function(parent, name, input, output) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = input && output ? 0777 : (input ? 0333 : 0555);
- if (!FS.createDevice.major) FS.createDevice.major = 64;
- var dev = FS.makedev(FS.createDevice.major++, 0);
- // Create a fake device that a set of stream ops to emulate
- // the old behavior.
- FS.registerDevice(dev, {
- open: function(stream) {
- stream.seekable = false;
- },
- close: function(stream) {
- // flush any pending line data
- if (output && output.buffer && output.buffer.length) {
- output({{{ charCode('\n') }}});
- }
- },
- read: function(stream, buffer, offset, length, pos /* ignored */) {
- var bytesRead = 0;
- for (var i = 0; i < length; i++) {
- var result;
- try {
- result = input();
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- if (result === undefined && bytesRead === 0) {
- throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
- }
- if (result === null || result === undefined) break;
- bytesRead++;
- buffer[offset+i] = result;
- }
- if (bytesRead) {
- stream.node.timestamp = Date.now();
- }
- return bytesRead;
- },
- write: function(stream, buffer, offset, length, pos) {
- for (var i = 0; i < length; i++) {
- try {
- output(buffer[offset+i]);
- } catch (e) {
- throw new FS.ErrnoError(ERRNO_CODES.EIO);
- }
- }
- if (length) {
- stream.node.timestamp = Date.now();
- }
- return i;
- }
- });
- return VFS.mkdev(path, mode, dev);
- },
- createLink: function(parent, name, target, canRead, canWrite) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);